Documentation
¶
Overview ¶
Package attachserve resolves a prompt's attached resources (#1013) into the form each serving surface needs: MCP content items appended to a prompts/get result, and a JSON summary carried by manage_prompt use.
It exists as its own package because it is the one place that needs both pkg/prompt (the attachment links) and pkg/resource (the material, its permissions, and its blobs), and both the MCP prompt layer and the REST attachment handler consume it. Putting it in either of those packages would point a dependency edge the wrong way.
The resolver never fails a prompt. A prompt whose attachment is unreadable, deleted, or unfetchable still serves: the material is reported as unavailable, missing, or unreadable, and the prompt text is unaffected. A procedure that has lost its template is still a procedure, and telling the agent the template is gone is strictly better than refusing to answer.
Index ¶
- Constants
- func Content(items []Resolved) []mcp.Content
- func ScopeOf(res *resource.Resource) prompt.AttachmentScope
- func Summary(items []Resolved) []map[string]any
- type Availability
- type BlobReader
- type Deps
- type Resolved
- type Resolver
- func (r *Resolver) CheckPromotion(ctx context.Context, promptID, targetScope string, targetPersonas []string) error
- func (r *Resolver) Resolve(ctx context.Context, promptID string, claims resource.Claims) []Resolved
- func (r *Resolver) Scopes(ctx context.Context, promptID string) ([]prompt.AttachmentScope, error)
Constants ¶
const DefaultInlineLimit = 64 * 1024
DefaultInlineLimit caps how many bytes of a text attachment are embedded directly in a served prompt. Above it the attachment becomes a resource link the client can read on demand.
64 KiB is chosen to match the largest reference material that is still plausibly worth spending prompt context on unconditionally; a report template or checklist is far below it, a full data extract is far above.
Variables ¶
This section is empty.
Functions ¶
func Content ¶
Content renders resolved attachments as MCP prompt-message content: embedded resources carry the full text, linked resources carry a resource_link the client can read, and anything the caller cannot reach is summarized in a single trailing note.
The framing text is deliberately directive. An agent that receives a template alongside a procedure must fill that template rather than invent its own formatting, and the only place to say so is here, next to the material.
Types ¶
type Availability ¶
type Availability string
Availability describes whether a prompt's attached material reached the caller, and if not, why.
const ( // AvailableEmbedded means the full contents are inline in the result. AvailableEmbedded Availability = "embedded" // AvailableLinked means the caller received a resource link and must read // the resource to get its contents (too large to inline, or binary). AvailableLinked Availability = "linked" // read it. Nothing identifying is disclosed alongside it, not even the // resource id: the caller has no repair action, and an id would be an // existence probe. UnavailableForbidden Availability = "unavailable" UnavailableMissing Availability = "missing" // metadata resolved and only the blob fetch failed, the link is served in // place of the contents; when the metadata read itself failed, nothing is // known about it and it is counted among the undelivered materials. UnavailableUnreadable Availability = "unreadable" )
type BlobReader ¶
type BlobReader interface {
GetObject(ctx context.Context, bucket, key string) (body []byte, contentType string, err error)
}
BlobReader reads a resource's stored bytes. Satisfied by resource.S3Client.
type Deps ¶
type Deps struct {
Attachments prompt.AttachmentStore
Resources resource.Store
Blobs BlobReader
Bucket string
// InlineLimit overrides DefaultInlineLimit when positive.
InlineLimit int
}
Deps carries the collaborators the resolver needs. Attachments and Resources are required; a nil Blobs (or empty Bucket) degrades every text attachment to a link rather than failing, which is the correct behavior for a database-only deployment with no blob backend.
type Resolved ¶
type Resolved struct {
// ResourceID is always set, even when the resource is missing, because it
// is what an author needs in order to repair a broken link.
ResourceID string
// Availability records the outcome. Every other field except ResourceID is
// empty when it is UnavailableForbidden or UnavailableMissing: an
// attachment the caller cannot read must not disclose its name, its
// description, or its size.
Availability Availability
URI string
DisplayName string
Description string
MIMEType string
SizeBytes int64
// Text holds the contents when Availability is AvailableEmbedded.
Text string
}
Resolved is one attachment after lookup, permission check, and (when the material is inlined) blob read.
type Resolver ¶
type Resolver struct {
// contains filtered or unexported fields
}
Resolver resolves prompt attachments for a caller.
func New ¶
New builds a resolver. A nil result is a valid zero-attachment resolver, so callers need no nil checks at every serving site.
func (*Resolver) CheckPromotion ¶
func (r *Resolver) CheckPromotion(ctx context.Context, promptID, targetScope string, targetPersonas []string) error
CheckPromotion reports whether a prompt's current attachments would still satisfy the scope rule at the target scope. It is the gate the promotion request and approval paths call, and it fails closed: a store error blocks the promotion rather than letting it through unchecked.
func (*Resolver) Resolve ¶
Resolve returns a prompt's attachments in authored order, each evaluated for this caller. It returns nil for a prompt with no attachments, and nil rather than an error when the attachment store read fails: a store outage must not take down prompt serving.
func (*Resolver) Scopes ¶
Scopes returns the scope of every resource a prompt attaches, for the authoring-time rule in prompt.CheckAttachScope. It is deliberately caller-independent: the rule asks how widely a resource is visible, not whether one particular reader can see it.
A resource that no longer exists is skipped rather than reported: a broken link cannot violate a scope rule, and blocking a promotion on it would freeze the prompt against every edit until someone detached a link the portal already flags. Any other read failure does block, because an unknown scope is not a safe scope.