llm browser
This commit is contained in:
1 parent
afed023152
commit
a4dbb75195
39 files changed
+3709
-58
No files matched your search
@@ -0,0 +1,146 @@
|
||||
// Package browse renders a remote page the way a text-only agent sees it:
|
||||
// it fetches the URL, converts the HTML to markdown, gathers the llms.txt
|
||||
// companions and robots.txt, and reports agent-readiness checks. The
|
||||
// package is stateless — the Fetcher is its only collaborator.
|
||||
package browse
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ValidationError reports an invalid input value. Handlers map it to 400.
|
||||
type ValidationError struct {
|
||||
Field string
|
||||
Reason string
|
||||
}
|
||||
|
||||
func (e *ValidationError) Error() string { return e.Field + ": " + e.Reason }
|
||||
|
||||
// FetchError reports a remote fetch that failed before an answer arrived
|
||||
// (DNS, TLS, connection refused, …). Handlers map it to 502 — the inspected
|
||||
// site is the problem, not this service.
|
||||
type FetchError struct {
|
||||
URL string
|
||||
Err error
|
||||
}
|
||||
|
||||
func (e *FetchError) Error() string { return "fetch " + e.URL + ": " + e.Err.Error() }
|
||||
func (e *FetchError) Unwrap() error { return e.Err }
|
||||
|
||||
// Severity classifies a Check.
|
||||
type Severity string
|
||||
|
||||
const (
|
||||
SeverityOK Severity = "ok"
|
||||
SeverityInfo Severity = "info"
|
||||
SeverityWarn Severity = "warn"
|
||||
SeverityError Severity = "error"
|
||||
)
|
||||
|
||||
// Check is one validated aspect of the inspected site, written so a human
|
||||
// can act on the detail without reading this package.
|
||||
type Check struct {
|
||||
ID string `json:"id"`
|
||||
Label string `json:"label"`
|
||||
Severity Severity `json:"severity"`
|
||||
Detail string `json:"detail"`
|
||||
}
|
||||
|
||||
// Response is a capped remote fetch result.
|
||||
type Response struct {
|
||||
Status int
|
||||
FinalURL string // after redirects; empty means "same as requested"
|
||||
ContentType string
|
||||
Header http.Header
|
||||
Body []byte
|
||||
Truncated bool
|
||||
}
|
||||
|
||||
// Fetcher retrieves remote documents. It plays the role the Repository
|
||||
// interface plays for database-backed resources: the service depends on the
|
||||
// interface, tests substitute an in-memory fake.
|
||||
type Fetcher interface {
|
||||
Fetch(ctx context.Context, url string) (*Response, error)
|
||||
}
|
||||
|
||||
// PageView is what agents read out of the HTML head plus document shape
|
||||
// statistics that drive the checks.
|
||||
type PageView struct {
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Canonical string `json:"canonical"`
|
||||
RobotsMeta string `json:"robotsMeta"`
|
||||
Lang string `json:"lang"`
|
||||
H1 string `json:"h1"`
|
||||
LinkCount int `json:"linkCount"`
|
||||
DeadLinks int `json:"deadLinks"`
|
||||
ScriptCount int `json:"scriptCount"`
|
||||
ImageCount int `json:"imageCount"`
|
||||
WordCount int `json:"wordCount"`
|
||||
TextLength int `json:"textLength"`
|
||||
}
|
||||
|
||||
// LlmsLink is one `- [title](url): description` entry of an llms.txt file.
|
||||
type LlmsLink struct {
|
||||
Title string `json:"title"`
|
||||
URL string `json:"url"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
// LlmsSection is one `## Heading` block of an llms.txt file.
|
||||
type LlmsSection struct {
|
||||
Heading string `json:"heading"`
|
||||
Description string `json:"description"`
|
||||
Links []LlmsLink `json:"links"`
|
||||
}
|
||||
|
||||
// LlmsDoc is a parsed llms.txt document per llmstxt.org: an H1 title, an
|
||||
// optional blockquote summary, and optional H2 sections of curated links.
|
||||
type LlmsDoc struct {
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Sections []LlmsSection `json:"sections"`
|
||||
LinkCount int `json:"linkCount"`
|
||||
}
|
||||
|
||||
// FileResult is the outcome of fetching one companion file. A Status of 0
|
||||
// means the request itself failed (see Error); 4xx/5xx keep the status but
|
||||
// drop the content.
|
||||
type FileResult struct {
|
||||
URL string `json:"url"`
|
||||
Status int `json:"status"`
|
||||
ContentType string `json:"contentType"`
|
||||
Error string `json:"error,omitempty"`
|
||||
Content string `json:"content"`
|
||||
Truncated bool `json:"truncated"`
|
||||
LlmsDoc *LlmsDoc `json:"llmsDoc,omitempty"`
|
||||
}
|
||||
|
||||
// found reports whether the file exists and answered with content.
|
||||
func (f *FileResult) found() bool { return f != nil && f.Status >= 200 && f.Status < 400 }
|
||||
|
||||
// Files groups the companion documents fetched next to the page.
|
||||
type Files struct {
|
||||
LlmsTxt *FileResult `json:"llmsTxt"`
|
||||
LlmsFullTxt *FileResult `json:"llmsFullTxt"`
|
||||
WellKnownTxt *FileResult `json:"wellKnownLlmsTxt"`
|
||||
RobotsTxt *FileResult `json:"robotsTxt"`
|
||||
}
|
||||
|
||||
// Snapshot is the full agent view of one URL: the rendered markdown, the
|
||||
// companion documents, and the validation checks.
|
||||
type Snapshot struct {
|
||||
RequestedURL string `json:"requestedUrl"`
|
||||
FinalURL string `json:"finalUrl"`
|
||||
Status int `json:"status"`
|
||||
ContentType string `json:"contentType"`
|
||||
DurationMS int64 `json:"durationMs"`
|
||||
FetchedAt time.Time `json:"fetchedAt"`
|
||||
Page *PageView `json:"page,omitempty"`
|
||||
Markdown string `json:"markdown"`
|
||||
MarkdownTruncated bool `json:"markdownTruncated"`
|
||||
Files Files `json:"files"`
|
||||
Checks []Check `json:"checks"`
|
||||
}
|
||||
Reference in new issue
Block a user