Documentation
¶
Overview ¶
Package agentsdk provides the Go SDK for building Airlock agents.
This package will contain the client library that agents use to communicate with the Airlock platform — registering connections, receiving triggers, and streaming run results.
Index ¶
- Constants
- func GetDeps[T any](ctx context.Context) T
- func IsValidatingMigrations() bool
- func ResolveDisplayPart(p *DisplayPart)
- type Access
- type Action
- type Agent
- func (a *Agent) AddExtraPrompt(p *ExtraPrompt)
- func (a *Agent) AddSensitive(values ...string)
- func (a *Agent) Attachment(ctx context.Context, fileID string) (io.ReadCloser, error)
- func (a *Agent) DB() *AgentDB
- func (a *Agent) EmbeddingModel(ctx context.Context, slug string, opts ModelOpts) model.EmbeddingModel
- func (a *Agent) ImageModel(ctx context.Context, slug string, opts ModelOpts) model.ImageModel
- func (a *Agent) LLM(ctx context.Context, slug string, opts ModelOpts) stream.Model
- func (a *Agent) Log(ctx context.Context, level LogLevel, msg string)
- func (a *Agent) Logf(ctx context.Context, level LogLevel, format string, args ...any)
- func (a *Agent) RegisterConnection(c *Connection) *ConnectionHandle
- func (a *Agent) RegisterCron(c *Cron)
- func (a *Agent) RegisterMCP(m *MCP) *MCPHandle
- func (a *Agent) RegisterModel(slot *ModelSlot)
- func (a *Agent) RegisterRoute(r *Route)
- func (a *Agent) RegisterStorage(s *Storage) *StorageHandle
- func (a *Agent) RegisterTool(def AnyTool)
- func (a *Agent) RegisterTopic(t *Topic) *TopicHandle
- func (a *Agent) RegisterWebhook(w *Webhook)
- func (a *Agent) Serve()
- func (a *Agent) SpeechModel(ctx context.Context, slug string, opts ModelOpts) model.SpeechModel
- func (a *Agent) TranscriptionModel(ctx context.Context, slug string, opts ModelOpts) model.TranscriptionModel
- type AgentDB
- func (a *AgentDB) BeginTx(ctx context.Context, opts *sql.TxOptions) (*AgentTx, error)
- func (a *AgentDB) ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error)
- func (a *AgentDB) PingContext(ctx context.Context) error
- func (a *AgentDB) PrepareContext(ctx context.Context, query string) (*sql.Stmt, error)
- func (a *AgentDB) QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error)
- func (a *AgentDB) QueryRowContext(ctx context.Context, query string, args ...any) *sql.Row
- func (a *AgentDB) Underlying() *sql.DB
- type AgentTx
- func (a *AgentTx) Commit() error
- func (a *AgentTx) ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error)
- func (a *AgentTx) PrepareContext(ctx context.Context, query string) (*sql.Stmt, error)
- func (a *AgentTx) QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error)
- func (a *AgentTx) QueryRowContext(ctx context.Context, query string, args ...any) *sql.Row
- func (a *AgentTx) Rollback() error
- func (a *AgentTx) Underlying() *sql.Tx
- type AnyTool
- type AuthInjection
- type AuthRequiredError
- type Config
- type Connection
- type ConnectionAuth
- type ConnectionDef
- type ConnectionHandle
- type ConversationVM
- type ConversationVMConfig
- type CreateRunRequest
- type CreateRunResponse
- type Cron
- type CronDef
- type CronHandlerFunc
- type DisplayPart
- type EventWriter
- type ExtraPrompt
- type ExtraPromptDef
- type FileRef
- type HTTPRequest
- type HTTPResponse
- type HTTPSessionStore
- type LLMProxyRequest
- type LogEntry
- type LogLevel
- type MCP
- type MCPAuth
- type MCPAuthStatus
- type MCPContent
- type MCPDef
- type MCPHandle
- type MCPToolCallRequest
- type MCPToolCallResponse
- type MCPToolSchema
- type MockAirlock
- type MockRequest
- type ModelCapability
- type ModelOpts
- type ModelProxyRequest
- type ModelSlot
- type ModelSlotDef
- type PrintRequest
- type PromptInput
- type ProxyRequest
- type Route
- type RouteDef
- type RouteHandlerFunc
- type RunCompleteRequest
- type Storage
- type StorageDef
- type StorageHandle
- func (h *StorageHandle) Copy(ctx context.Context, src, dst string) error
- func (h *StorageHandle) CopyTo(ctx context.Context, src string, dstZone *StorageHandle, dst string) error
- func (h *StorageHandle) Delete(ctx context.Context, key string) error
- func (h *StorageHandle) Get(ctx context.Context, key string) (io.ReadCloser, error)
- func (h *StorageHandle) List(ctx context.Context, prefix string) ([]StoredFile, error)
- func (h *StorageHandle) Put(ctx context.Context, key string, data io.Reader, contentType string) error
- func (h *StorageHandle) ReadAccess() Access
- func (h *StorageHandle) Ref(key string) StorageRef
- func (h *StorageHandle) Slug() string
- func (h *StorageHandle) Stat(ctx context.Context, key string) (StoredFile, error)
- func (h *StorageHandle) URL(key string) string
- func (h *StorageHandle) WriteAccess() Access
- type StorageRef
- type StoredFile
- type SyncRequest
- type SyncResponse
- type Tool
- type ToolDef
- type Topic
- type TopicDef
- type TopicHandle
- type Webhook
- type WebhookDef
- type WebhookHandlerFunc
Constants ¶
const ( // ErrorKindPlatform: failure upstream of the agent's own code. LLM // provider 4xx, sol/goai stream errors, request transport (body read). // The agent's code couldn't have prevented or fixed this — the "Fix // this error" workflow on the run page is hidden for these. ErrorKindPlatform = "platform" // ErrorKindAgent: failure from agent-defined code paths. Webhook/cron // handlers returning err, panics in user code recovered by the SDK, // post-LLM bookkeeping that hit something the agent owns. The Fix // workflow targets exactly these. ErrorKindAgent = "agent" )
Error kinds passed in RunCompleteRequest.ErrorKind. The agentsdk side classifies structurally — by call-site, not by error string — so airlock can avoid pattern-matching at all.
const Version = "0.1.2" // pre-release; bump when shipping breaking protocol changes
Version is the agentsdk API version. Reported to Airlock during sync. Bump on breaking changes — see CLAUDE.md for versioning rules.
Variables ¶
This section is empty.
Functions ¶
func GetDeps ¶
GetDeps retrieves the typed Deps struct from the Agent bound to ctx. Panics if no agent is bound (must be called from inside a handler), if Deps is nil, or if the type doesn't match. Used by handlers that need the builder's pre-registered application state (connection/MCP handles, config, etc.) — particularly VM functions defined in separate packages where the `agent` variable isn't in scope.
func IsValidatingMigrations ¶
func IsValidatingMigrations() bool
IsValidatingMigrations reports whether the agent is running in migration validation mode (AGENT_VALIDATE_MIGRATIONS=1). Go migrations that touch external services (S3, Airlock API, connection credentials) should return early when this is true — those services are not available during build-time validation.
func ResolveDisplayPart ¶
func ResolveDisplayPart(p *DisplayPart)
resolveDisplayPart infers missing fields on a DisplayPart from available data. 1. If Data is set but MimeType is empty → detect from bytes. 2. If MimeType is set but Type is empty → infer from MIME prefix. 3. If Filename is empty and part has media → generate from type + mimeType.
Types ¶
type Access ¶
type Access string
Access defines who can reach a tool, connection, MCP, topic, or storage zone.
const ( AccessAdmin Access = "admin" AccessUser Access = "user" AccessPublic Access = "public" // AccessInternal is the strictest level — builder Go code only. Items // registered with AccessInternal are never exposed to the JS runtime // and are never reachable from external callers regardless of role. // Use it when you have, say, a storage zone that holds builder-only // caches you don't want the LLM to discover, mutate, or list. AccessInternal Access = "internal" )
type Action ¶
type Action struct {
Type string `json:"type"`
Timestamp time.Time `json:"timestamp"`
DurationMs int64 `json:"durationMs"`
Request any `json:"request,omitempty"`
Response any `json:"response,omitempty"`
Error string `json:"error,omitempty"`
}
Action records a single operation performed during a Run.
type Agent ¶
type Agent struct {
// Deps holds application-level dependencies (connection handles, MCP handles, etc.).
// The builder defines their own typed struct and assigns it here.
// Access from handlers via GetDeps[T](run).
Deps any
// contains filtered or unexported fields
}
Agent is a long-lived singleton, one per container. Created once at startup via New(), lives for the lifetime of the process.
func AgentFromContext ¶
AgentFromContext returns the *Agent associated with a handler's ctx. Returns nil if ctx wasn't produced by a handler (e.g. a plain context.Background() in test code).
func AgentFromMigrationContext ¶
AgentFromMigrationContext returns the Agent associated with a migration context. Panics if called outside of a migration — migrations receive the context via goose, which propagates it from autoMigrate.
func New ¶
New creates an Agent by reading required environment variables. Panics if AIRLOCK_AGENT_ID, AIRLOCK_API_URL, or AIRLOCK_AGENT_TOKEN is missing. Panics if Config.Description is empty.
func (*Agent) AddExtraPrompt ¶
func (a *Agent) AddExtraPrompt(p *ExtraPrompt)
AddExtraPrompt appends a system-prompt fragment that Airlock will include for callers whose resolved access on this agent matches one of the fragment's Access levels. An empty Access slice means the fragment applies to every caller.
Fragments accumulate in registration order and are joined with "\n\n" by Airlock at run dispatch, then appended to the sync-rendered system prompt. Only /prompt-triggered runs (web + bridge) receive extras — webhook and cron handlers run arbitrary Go code and build their own prompts.
func (*Agent) AddSensitive ¶
AddSensitive registers values that should be redacted from LLM messages.
func (*Agent) Attachment ¶
Attachment retrieves a conversation file attachment by its opaque fileID. Different surface from the zoned Storage handles — attachments are content the user uploaded to a chat message and aren't builder-keyed.
func (*Agent) DB ¶
DB returns a lazily-initialized *AgentDB from AIRLOCK_DB_URL. Returns nil if the env var is not set (DB is optional).
AgentDB implements the same DBTX interface that sqlc-generated New() takes, so `mygen.New(agent.DB())` works unchanged. The wrapper is the extension point through which the framework can later record query activity onto the run carried by ctx.
func (*Agent) EmbeddingModel ¶
func (a *Agent) EmbeddingModel(ctx context.Context, slug string, opts ModelOpts) model.EmbeddingModel
EmbeddingModel returns an embedding model proxied through Airlock.
func (*Agent) ImageModel ¶
ImageModel returns an image generation model proxied through Airlock.
func (*Agent) LLM ¶
LLM returns a streaming language model. Capability defaults to CapText if ModelOpts.Capability is empty. Pass the returned model the same ctx when calling Stream.
func (*Agent) Log ¶
Log records a message scoped to the current handler invocation at the given level. Visible in the Runs UI alongside the actions the handler performed; level controls how the UI surfaces it (color/filter).
Use LogLevelInfo for normal progress, LogLevelWarn for recoverable concerns, and LogLevelError for failures the handler chose not to raise. The argument shape is uniform — pick a level rather than reaching for severity-named methods.
func (*Agent) Logf ¶
Logf is the printf-style sibling of Log — formats with fmt.Sprintf and records the result. Use Log for plain strings, Logf when you'd otherwise reach for fmt.Sprintf.
func (*Agent) RegisterConnection ¶
func (a *Agent) RegisterConnection(c *Connection) *ConnectionHandle
RegisterConnection registers an outgoing service connection and returns a handle for proxied requests. Synced to Airlock on Serve(). Use the returned handle for compile-time-bound proxy calls:
gmail := agent.RegisterConnection(&agentsdk.Connection{
Slug: "gmail", Name: "Gmail", BaseURL: "https://gmail.googleapis.com", ...,
})
body, err := gmail.Request(ctx, "GET", "/messages", nil)
func (*Agent) RegisterCron ¶
RegisterCron installs a cron job. Schedule is a standard cron expression (e.g. "0 9 * * *"). Synced to Airlock on Serve() so the scheduler can fire it.
func (*Agent) RegisterMCP ¶
RegisterMCP registers a remote MCP server dependency and returns a handle for calling its tools. Synced to Airlock on Serve(). Use the returned handle for compile-time-bound tool calls:
github := agent.RegisterMCP(&agentsdk.MCP{Slug: "github", URL: "https://api.github.com/mcp"})
result, err := github.CallTool(ctx, "search_repos", args)
func (*Agent) RegisterModel ¶
RegisterModel declares a named model slot the agent will use at runtime via agent.LLM(ctx, slug, ...) / agent.ImageModel(...) / etc. The admin binds a specific model to each slot in the Airlock UI; if no model is bound, calls fall through to the agent's per-capability default and then to the system default. Call before Serve().
Registering a slot is optional — undeclared slugs still work, they just silently fall through to the capability default and won't appear in the admin UI's Models tab.
func (*Agent) RegisterRoute ¶
RegisterRoute installs a custom HTTP route served by this agent and proxied via Airlock's subdomain routing.
func (*Agent) RegisterStorage ¶
func (a *Agent) RegisterStorage(s *Storage) *StorageHandle
RegisterStorage declares an S3-backed storage zone scoped to an Access level. Returns a *StorageHandle for builder Go code and exposes a `storage_{slug}` JS object inside run_js (only to callers whose access satisfies the zone's Access; AccessInternal zones are never exposed to JS at all). Slug also becomes the S3 prefix.
The framework reserves the slug "tmp" for its own scratch storage (truncated tool output, generated media). Builders may pass Slug:"tmp" — the call returns a working handle to the framework's tmp zone but the supplied Access / Description are silently ignored.
uploads := agent.RegisterStorage(&agentsdk.Storage{
Slug: "uploads", Access: agentsdk.AccessUser, Description: "User uploads",
})
err := uploads.Put(ctx, "doc.pdf", reader, "application/pdf")
func (*Agent) RegisterTool ¶
RegisterTool registers a typed, schema-bearing capability the LLM can invoke via run_js. The tool auto-binds as a global inside the goja VM; input from JS is JSON-marshaled and decoded into the author's In struct, Execute runs, and the Out struct is JSON-marshaled back to a native JS value. Input/output JSON schemas are rendered as a TypeScript declaration in the system prompt so the LLM sees typed signatures.
agent.RegisterTool(&agentsdk.Tool[SearchIn, SearchOut]{
Name: "search",
Description: "Search the web.",
Execute: doSearch,
Access: agentsdk.AccessUser,
})
func (*Agent) RegisterTopic ¶
func (a *Agent) RegisterTopic(t *Topic) *TopicHandle
RegisterTopic declares a topic the agent can publish notifications to. Synced to Airlock on Serve(). Use the returned *TopicHandle for compile-time-bound publishing:
alerts := agent.RegisterTopic(&agentsdk.Topic{Slug: "alerts", Description: "System alerts"})
alerts.Publish(ctx, []DisplayPart{{Type: "text", Text: "Server restarted"}})
func (*Agent) RegisterWebhook ¶
RegisterWebhook installs a webhook handler at /webhook/{Path}. Synced to Airlock on Serve() so external callers can reach it via the agent's webhook ingress endpoint.
func (*Agent) Serve ¶
func (a *Agent) Serve()
Serve starts the agent HTTP server. Blocks until SIGINT/SIGTERM. Listens on AIRLOCK_ADDR env var or :8080. Before starting, syncs connections/webhooks/crons with Airlock.
func (*Agent) SpeechModel ¶
SpeechModel returns a text-to-speech model proxied through Airlock.
func (*Agent) TranscriptionModel ¶
func (a *Agent) TranscriptionModel(ctx context.Context, slug string, opts ModelOpts) model.TranscriptionModel
TranscriptionModel returns a speech-to-text model proxied through Airlock.
type AgentDB ¶
type AgentDB struct {
// contains filtered or unexported fields
}
AgentDB wraps the agent's *sql.DB and is the type returned by Agent.DB(). It implements the same DBTX interface that sqlc-generated New() functions take, so builder code that does `mygen.New(agent.DB())` keeps compiling.
Today AgentDB is a thin pass-through. The reason it exists is so the framework can later intercept queries at this layer (record an action on the run carried by ctx, surface query timings in the Runs UI, redact sensitive arguments) without breaking builders or sqlc-generated code. Builders that need the underlying driver-level handle for advanced cases (Stats, Driver, custom drivers) can reach it via Underlying().
func (*AgentDB) BeginTx ¶
BeginTx starts a transaction. The returned *AgentTx implements the same DBTX interface, so `mygen.New(tx)` and `q.WithTx(tx)` both work.
func (*AgentDB) ExecContext ¶
ExecContext satisfies sqlc's DBTX. Forwards to the underlying *sql.DB.
func (*AgentDB) PingContext ¶
PingContext checks database connectivity.
func (*AgentDB) PrepareContext ¶
PrepareContext satisfies sqlc's DBTX. Forwards to the underlying *sql.DB.
func (*AgentDB) QueryContext ¶
QueryContext satisfies sqlc's DBTX. Forwards to the underlying *sql.DB.
func (*AgentDB) QueryRowContext ¶
QueryRowContext satisfies sqlc's DBTX. Forwards to the underlying *sql.DB.
func (*AgentDB) Underlying ¶
Underlying returns the wrapped *sql.DB. Use this only when you need driver-level access that DBTX doesn't expose; otherwise stick to the AgentDB methods so future framework instrumentation applies to your code.
type AgentTx ¶
type AgentTx struct {
// contains filtered or unexported fields
}
AgentTx wraps a *sql.Tx with the same shape as AgentDB so sqlc's q.WithTx(tx) accepts it transparently.
func (*AgentTx) ExecContext ¶
ExecContext satisfies sqlc's DBTX.
func (*AgentTx) PrepareContext ¶
PrepareContext satisfies sqlc's DBTX.
func (*AgentTx) QueryContext ¶
QueryContext satisfies sqlc's DBTX.
func (*AgentTx) QueryRowContext ¶
QueryRowContext satisfies sqlc's DBTX.
func (*AgentTx) Underlying ¶
Underlying returns the wrapped *sql.Tx.
type AnyTool ¶
type AnyTool interface {
// contains filtered or unexported methods
}
AnyTool is the sealed interface produced by *Tool[In, Out]. The unexported toRegistered method means only generic Tool values can satisfy it — authors cannot roll their own AnyTool implementations. Used as the argument type for RegisterTool so a heterogeneous set of generic Tool values can share one entry point.
type AuthInjection ¶
type AuthInjection struct {
Type string `json:"type"` // "bearer", "api_key_header", "bot_token_url_prefix"
Name string `json:"name,omitempty"` // header name for api_key_header (default: "X-API-Key")
}
AuthInjection defines how auth credentials are injected into proxied requests.
type AuthRequiredError ¶
type AuthRequiredError struct {
Slug string `json:"slug"`
ConnName string `json:"connName"`
AuthURL string `json:"authUrl"`
}
AuthRequiredError is returned by ConnectionHandle.Request when a connection needs authorization.
func IsAuthRequired ¶
func IsAuthRequired(err error) (*AuthRequiredError, bool)
IsAuthRequired checks whether err is an *AuthRequiredError.
func (*AuthRequiredError) Error ¶
func (e *AuthRequiredError) Error() string
type Config ¶
type Config struct {
Description string // required — shown to users in the Airlock UI
}
Config holds configuration for creating an Agent.
type Connection ¶
type Connection struct {
Slug string // unique per agent; binds as conn_{slug} in run_js
Name string
Description string
BaseURL string
AuthMode ConnectionAuth
AuthURL string
TokenURL string
Scopes []string
AuthInjection AuthInjection
SetupInstructions string
LLMHint string // appended to the connection block in the system prompt
Access Access // who may invoke conn_{slug}; default AccessUser
}
Connection is the self-contained declaration registered via agent.RegisterConnection — an outgoing service Airlock proxies for the agent with credentials it manages.
type ConnectionAuth ¶
type ConnectionAuth string
ConnectionAuth enumerates the supported authentication strategies for an outgoing service Connection.
const ( ConnectionAuthOAuth ConnectionAuth = "oauth" ConnectionAuthToken ConnectionAuth = "token" ConnectionAuthNone ConnectionAuth = "none" )
type ConnectionDef ¶
type ConnectionDef struct {
Name string `json:"name"`
Description string `json:"description"`
BaseURL string `json:"baseUrl,omitempty"`
AuthMode ConnectionAuth `json:"authMode"`
AuthURL string `json:"authUrl,omitempty"`
TokenURL string `json:"tokenUrl,omitempty"`
Scopes []string `json:"scopes,omitempty"`
AuthInjection AuthInjection `json:"authInjection"`
SetupInstructions string `json:"setupInstructions,omitempty"`
LLMHint string `json:"llmHint,omitempty"`
Access Access `json:"access,omitempty"`
}
ConnectionDef is the wire format used by PUT /api/agent/connections/{slug}. Slug is sent in the URL, not the body.
type ConnectionHandle ¶
type ConnectionHandle struct {
// contains filtered or unexported fields
}
ConnectionHandle is a compile-time binding to a registered connection. Returned by RegisterConnection, used to make proxied HTTP requests.
func (*ConnectionHandle) Request ¶
func (h *ConnectionHandle) Request(ctx context.Context, method, path string, body any) ([]byte, error)
Request sends an HTTP request through Airlock's credential-injecting proxy and returns the raw response body. Body encoding is chosen from its type:
nil — no body []byte, string — sent as-is io.Reader — fully read, sent as-is anything else — JSON-marshalled
Returns *AuthRequiredError if the connection needs authorization.
type ConversationVM ¶
type ConversationVM struct {
// contains filtered or unexported fields
}
ConversationVM holds persistent state for a single conversation. The goja VM is recreated per-run, but the store map survives across prompts.
type ConversationVMConfig ¶
type ConversationVMConfig struct {
IdleTimeout time.Duration // default: 72h
MaxStoreSize int64 // default: 4MB
GCSweepInterval time.Duration // default: 1h
}
ConversationVMConfig configures conversation VM behavior.
func DefaultConversationVMConfig ¶
func DefaultConversationVMConfig() ConversationVMConfig
DefaultConversationVMConfig returns sensible defaults.
type CreateRunRequest ¶
type CreateRunRequest struct {
TriggerType string `json:"triggerType"`
TriggerRef string `json:"triggerRef"`
}
CreateRunRequest is the body for POST /api/agent/run/create.
type CreateRunResponse ¶
type CreateRunResponse struct {
RunID string `json:"runId"`
}
CreateRunResponse is the response from POST /api/agent/run/create.
type Cron ¶
type Cron struct {
Name string // unique per agent
Schedule string // standard cron expression, e.g. "0 9 * * *"
Handler CronHandlerFunc // required
Timeout time.Duration // max execution time (default: 2 min)
Description string
}
Cron is the self-contained declaration registered via agent.RegisterCron. Crons fire by schedule, never by user action — no Access field.
type CronDef ¶
type CronDef struct {
Name string `json:"name"`
Schedule string `json:"schedule"`
TimeoutMs int64 `json:"timeoutMs"`
Description string `json:"description,omitempty"`
}
CronDef is a cron job definition sent during sync.
type CronHandlerFunc ¶
type CronHandlerFunc func(ctx context.Context, ew *EventWriter) error
CronHandlerFunc handles cron-triggered requests.
type DisplayPart ¶
type DisplayPart struct {
Type string `json:"type"` // "text", "image", "file", "audio", "video"
Text string `json:"text,omitempty"` // body text, or caption for media types
Source string `json:"source,omitempty"` // S3 key
URL string `json:"url,omitempty"` // external URL
Data []byte `json:"data,omitempty"` // raw bytes (base64 in JSON)
Filename string `json:"filename,omitempty"`
MimeType string `json:"mimeType,omitempty"`
Alt string `json:"alt,omitempty"` // accessibility text for images
Duration float64 `json:"duration,omitempty"` // seconds, audio/video
}
DisplayPart is a single piece of rich content for user-facing output. Used by both printToUser (VM) and TopicHandle.Publish (Go).
type EventWriter ¶
type EventWriter struct {
// contains filtered or unexported fields
}
EventWriter streams NDJSON events to an HTTP response.
func (*EventWriter) WriteError ¶
func (ew *EventWriter) WriteError(err error) error
WriteError writes an error event.
func (*EventWriter) WriteEvent ¶
func (ew *EventWriter) WriteEvent(event stream.Event) error
WriteEvent serializes a GoAI stream.Event as an NDJSON line.
func (*EventWriter) WriteProgress ¶
func (ew *EventWriter) WriteProgress(message string) error
WriteProgress writes a progress event (for webhook/cron handlers).
type ExtraPrompt ¶
ExtraPrompt is the self-contained declaration passed to agent.AddExtraPrompt. The Text fragment is appended to the system prompt for runs whose caller access matches one of the listed Access levels. Empty Access slice means "applies to every access level."
type ExtraPromptDef ¶
ExtraPromptDef is the wire format sent in SyncRequest.
type FileRef ¶
type FileRef struct {
ID string `json:"id"`
Filename string `json:"filename"`
ContentType string `json:"contentType"`
Size int64 `json:"size"`
}
FileRef references a file attachment in a prompt.
type HTTPRequest ¶
type HTTPRequest struct {
URL string `json:"url"`
Method string `json:"method,omitempty"` // default: GET
Headers map[string]string `json:"headers,omitempty"`
Body string `json:"body,omitempty"`
Timeout int `json:"timeout,omitempty"` // seconds, default: 30, max: 120
SaveAs string `json:"saveAs,omitempty"` // save response body to S3 at this key (binary-safe)
Raw bool `json:"raw,omitempty"` // skip HTML→markdown conversion for HTML responses
}
HTTPRequest is the body for POST /api/agent/http.
type HTTPResponse ¶
type HTTPResponse struct {
Status int `json:"status"`
Headers map[string]string `json:"headers"`
Body string `json:"body,omitempty"`
ContentType string `json:"contentType"` // original upstream Content-Type
Size int `json:"size"`
SavedTo string `json:"savedTo,omitempty"` // S3 key if body was auto-saved
Note string `json:"note,omitempty"` // human-readable note about transformations applied (e.g. HTML→markdown conversion)
}
HTTPResponse is returned from POST /api/agent/http.
type HTTPSessionStore ¶
type HTTPSessionStore struct {
// contains filtered or unexported fields
}
HTTPSessionStore implements session.SessionStore by calling Airlock's API. It is pre-scoped to a single conversation at construction time.
func NewHTTPSessionStore ¶
func NewHTTPSessionStore(client *airlockClient, convID, runID, source string) *HTTPSessionStore
NewHTTPSessionStore creates a store scoped to the given conversation.
type LLMProxyRequest ¶
type LLMProxyRequest struct {
Slug string `json:"slug,omitempty"`
Capability string `json:"capability,omitempty"`
Options json.RawMessage `json:"options"`
}
LLMProxyRequest is the body for POST /api/agent/llm/stream.
type LogEntry ¶
LogEntry is one builder-emitted line: a level and a message. The wire format used by /api/agent/run/complete; also the in-memory shape on the run.
type LogLevel ¶
type LogLevel string
LogLevel categorizes a builder-emitted log line. UI can color/filter on it; the wire format stores it explicitly so the level isn't lost in a flat string.
type MCP ¶
type MCP struct {
Slug string // unique per agent; binds as mcp_{slug} in run_js
Name string
URL string
AuthMode MCPAuth
AuthURL string
TokenURL string
Scopes []string
Access Access // who may invoke mcp_{slug}; default AccessUser
}
MCP is the self-contained declaration registered via agent.RegisterMCP. Slug binds as mcp_{slug} in run_js; the builder uses the returned *MCPHandle to call tools from Go.
type MCPAuth ¶
type MCPAuth string
MCPAuth enumerates the supported authentication strategies for an MCP server. MCPAuthOAuthDiscovery is MCP-specific (RFC 9728 server-advertised OAuth endpoints) and not available on Connection.
type MCPAuthStatus ¶
type MCPAuthStatus struct {
Slug string `json:"slug"`
AuthMode MCPAuth `json:"authMode"`
Authorized bool `json:"authorized"`
AuthURL string `json:"authUrl,omitempty"`
}
MCPAuthStatus reports auth state for an MCP server.
type MCPContent ¶
MCPContent is a single content block in an MCP tool response.
type MCPDef ¶
type MCPDef struct {
Slug string `json:"slug,omitempty"`
Name string `json:"name"`
URL string `json:"url"`
AuthMode MCPAuth `json:"authMode"`
AuthURL string `json:"authUrl,omitempty"`
TokenURL string `json:"tokenUrl,omitempty"`
Scopes []string `json:"scopes,omitempty"`
Access Access `json:"access,omitempty"`
}
MCPDef is the wire format used by PUT /api/agent/mcp-servers/{slug} and (with Slug populated) by SyncRequest.MCPServers. Slug is sent in the URL for the per-slug PUT and in the body for the bulk sync.
type MCPHandle ¶
type MCPHandle struct {
// contains filtered or unexported fields
}
MCPHandle is a compile-time binding to a registered MCP server. Returned by RegisterMCP, used to call tools and build tool sets.
func (*MCPHandle) CallTool ¶
func (h *MCPHandle) CallTool(ctx context.Context, toolName string, args any) (*MCPToolCallResponse, error)
CallTool calls a tool on this MCP server via Airlock's proxy. Args encoding mirrors ConnectionHandle.Request:
nil — sent as {} (MCP requires a JSON object)
[]byte, string, json.RawMessage — assumed to be valid JSON, sent as-is
io.Reader — fully read, assumed JSON, sent as-is
anything else — JSON-marshalled
type MCPToolCallRequest ¶
type MCPToolCallRequest struct {
Tool string `json:"tool"`
Arguments json.RawMessage `json:"arguments"`
}
MCPToolCallRequest is the body for POST /api/agent/mcp/{slug}/tools/call.
type MCPToolCallResponse ¶
type MCPToolCallResponse struct {
Content []MCPContent `json:"content"`
IsError bool `json:"isError"`
}
MCPToolCallResponse is returned from MCP tool call proxy.
type MCPToolSchema ¶
type MCPToolSchema struct {
ServerSlug string `json:"serverSlug"`
Name string `json:"name"`
Description string `json:"description"`
InputSchema json.RawMessage `json:"inputSchema"`
}
MCPToolSchema is a discovered MCP tool schema returned in SyncResponse.
type MockAirlock ¶
type MockAirlock struct {
Server *httptest.Server
// LLMResponse is the NDJSON response returned by POST /api/agent/llm/stream.
// Set this before making prompt requests.
LLMResponse []byte
// contains filtered or unexported fields
}
MockAirlock is an httptest server that implements the Airlock agent API. Use NewMockAirlock() to create one. Exported for agent developers' tests.
func NewMockAirlock ¶
func NewMockAirlock() (*MockAirlock, string)
NewMockAirlock creates a mock Airlock server and returns it along with the base URL.
func (*MockAirlock) Requests ¶
func (m *MockAirlock) Requests() []MockRequest
Requests returns all recorded requests.
func (*MockAirlock) RequestsByPath ¶
func (m *MockAirlock) RequestsByPath(prefix string) []MockRequest
RequestsByPath returns requests matching the given path prefix.
type MockRequest ¶
MockRequest records a request made to the mock Airlock server.
type ModelCapability ¶
type ModelCapability string
ModelCapability describes what kind of model is needed.
const ( CapText ModelCapability = "text" // any chat/language model CapVision ModelCapability = "vision" // chat model that accepts images CapEmbedding ModelCapability = "embedding" // vector embeddings CapImage ModelCapability = "image" // image generation CapSpeech ModelCapability = "speech" // text-to-speech CapTranscription ModelCapability = "transcription" // speech-to-text )
type ModelOpts ¶
type ModelOpts struct {
// Capability selects the model sub-type. Only meaningful for run.LLM()
// (distinguishes text vs vision). For other methods, the method name
// determines the capability and this field is ignored.
Capability ModelCapability `json:"capability,omitempty"`
// Description is optional human-readable context for run logs/UI.
Description string `json:"description,omitempty"`
}
ModelOpts configures a model request. Used with agent.LLM(), agent.ImageModel(), etc.
type ModelProxyRequest ¶
type ModelProxyRequest struct {
Slug string `json:"slug,omitempty"`
Capability string `json:"capability"`
Options json.RawMessage `json:"options"`
}
ModelProxyRequest is the body for non-streaming model endpoints (POST /api/agent/llm/{image,embedding,speech,transcription}).
type ModelSlot ¶
type ModelSlot struct {
Slug string
Capability ModelCapability // required: CapText, CapVision, CapImage, CapSpeech, CapTranscription, CapEmbedding
Description string // human-readable hint shown in the admin UI
}
ModelSlot is the self-contained declaration registered via agent.RegisterModel.
type ModelSlotDef ¶
type ModelSlotDef struct {
Slug string `json:"slug"`
Capability string `json:"capability"`
Description string `json:"description,omitempty"`
}
ModelSlotDef is the wire format sent in SyncRequest. The agent uses Slug at runtime (e.g. `agent.LLM(ctx, slug, ...)`); the admin binds a specific model to the slug in the Airlock UI. When no model is bound, calls fall through to the agent's per-capability default and then to the system default for that capability.
type PrintRequest ¶
type PrintRequest struct {
Parts []DisplayPart `json:"parts"`
Topic string `json:"topic,omitempty"` // empty = direct to conversation
ConversationID string `json:"conversationId,omitempty"` // set for direct prints
RunID string `json:"runId,omitempty"` // originating run, used to sort ephemerals after their run's assistant messages
}
PrintRequest is the body for POST /api/agent/print.
type PromptInput ¶
type PromptInput struct {
Messages []message.Message `json:"messages"`
Message string `json:"message,omitempty"` // New user message text (used with SessionStore)
ConversationID string `json:"conversationId,omitempty"`
ProviderID string `json:"providerId,omitempty"`
ModelID string `json:"modelId,omitempty"`
Temperature *float64 `json:"temperature,omitempty"`
MaxOutputTokens *int `json:"maxOutputTokens,omitempty"`
ProviderOptions json.RawMessage `json:"providerOptions,omitempty"`
Files []FileRef `json:"files,omitempty"`
ResumeRunID string `json:"resumeRunId,omitempty"`
Approved *bool `json:"approved,omitempty"`
SupportedModalities []string `json:"supportedModalities,omitempty"` // e.g. ["text", "image", "pdf", "audio", "video"]
Source string `json:"source,omitempty"` // "user" (default), "system" (injected by Airlock)
// ExtraSystemPrompt is an access-filtered concatenation of the agent's
// registered AddExtraPrompt fragments, composed by Airlock at run
// dispatch. The agent appends this to its sync-cached system prompt.
ExtraSystemPrompt string `json:"extraSystemPrompt,omitempty"`
// CallerAccess is the resolved per-(agent, user) access level for the
// triggering caller. agentsdk uses it to gate which conn_/mcp_/topic_/
// storage_ JS bindings (and registered tools) are exposed to the run.
// Airlock sets this from trigger.ResolveAgentAccess. For trusted server
// triggers (webhooks, crons) Airlock sends AccessAdmin.
CallerAccess Access `json:"callerAccess,omitempty"`
// ForceCompact tells the agent to skip the thinking loop and run a
// user-triggered compaction instead. Message is ignored when set. The
// agent loads conversation history, asks the model to summarize it,
// persists the summary via the SessionStore's Compact method, and emits
// a short text-delta describing the outcome.
ForceCompact bool `json:"forceCompact,omitempty"`
}
PromptInput is the request body for POST /prompt.
type ProxyRequest ¶
type ProxyRequest struct {
Method string `json:"method"`
Path string `json:"path"`
Body string `json:"body,omitempty"`
}
ProxyRequest is the body for POST /api/agent/proxy/{slug}.
type Route ¶
type Route struct {
Method string // "GET", "POST", ...
Path string // e.g. "/spotify"
Handler RouteHandlerFunc // required
Access Access // required: AccessAdmin, AccessUser, or AccessPublic
Description string
}
Route is the self-contained declaration registered via agent.RegisterRoute. Custom HTTP routes served by the agent and proxied by Airlock via subdomain routing. The (Method, Path) pair must be unique per agent.
type RouteDef ¶
type RouteDef struct {
Path string `json:"path"`
Method string `json:"method"`
Access Access `json:"access"`
Description string `json:"description,omitempty"`
}
RouteDef is a custom HTTP route definition sent during sync.
type RouteHandlerFunc ¶
RouteHandlerFunc handles custom HTTP routes registered via RegisterRoute.
type RunCompleteRequest ¶
type RunCompleteRequest struct {
RunID string `json:"runId"`
// Status is "success" | "error" | "suspended" | "timeout" | "tool_errors".
Status string `json:"status"`
Error string `json:"error,omitempty"`
// ErrorKind is set when Status == "error" and disambiguates platform
// vs agent failure for the UI. Empty otherwise.
ErrorKind string `json:"errorKind,omitempty"`
PanicTrace string `json:"panicTrace,omitempty"`
Actions json.RawMessage `json:"actions"`
Logs []LogEntry `json:"logs,omitempty"`
Checkpoint json.RawMessage `json:"checkpoint,omitempty"`
}
RunCompleteRequest is the body for POST /api/agent/run/complete.
type Storage ¶
type Storage struct {
Slug string
Read Access // gates Get/Stat/List + the public route; default AccessUser
Write Access // gates Put/Delete/Copy/CopyTo; default AccessUser
Description string // shown in the system prompt's storage zones section
}
Storage is the self-contained declaration registered via agent.RegisterStorage. Each zone owns an S3 prefix ("{Slug}/") and a JS binding (storage_{slug}); AccessInternal axes are reachable only from builder Go code and never surface in run_js. The framework auto-registers a reserved zone "tmp" at Read=Write=AccessUser; builder calls with Slug="tmp" silently no-op (returning the framework handle) so frameworks and builders share the same scratch area without conflict.
Read and Write are independent — "Read: AccessUser, Write: AccessAdmin" (admin-curated, user-readable) and "Read: AccessAdmin, Write: AccessUser" (user-fed inbox processed only by admins) are both valid. The JS `storage_{slug}` object exposes Get/Stat/List only when Read satisfies the caller, and Put/Delete/Copy only when Write does.
type StorageDef ¶
type StorageDef struct {
Slug string `json:"slug"`
Read Access `json:"read"`
Write Access `json:"write"`
Description string `json:"description"`
}
StorageDef is the wire format sent in SyncRequest.
type StorageHandle ¶
type StorageHandle struct {
// contains filtered or unexported fields
}
StorageHandle is a compile-time binding to a registered Storage zone. All keys passed to its methods are relative to the zone's prefix; the handle prepends "{slug}/" before talking to Airlock. List returns keys stripped of the prefix as well, so callers see relative paths.
func (*StorageHandle) Copy ¶
func (h *StorageHandle) Copy(ctx context.Context, src, dst string) error
Copy server-side-copies a file within this zone. Both keys are relative.
func (*StorageHandle) CopyTo ¶
func (h *StorageHandle) CopyTo(ctx context.Context, src string, dstZone *StorageHandle, dst string) error
CopyTo server-side-copies a file from this zone into another zone. dstKey is relative to dstZone; src is relative to this zone. Builders compose move = CopyTo + src.Delete.
func (*StorageHandle) Delete ¶
func (h *StorageHandle) Delete(ctx context.Context, key string) error
Delete removes the file at `key` (relative to this zone). Idempotent — missing files do not error.
func (*StorageHandle) Get ¶
func (h *StorageHandle) Get(ctx context.Context, key string) (io.ReadCloser, error)
Get returns a reader over the file at `key` (relative to this zone). The caller must Close the returned ReadCloser.
func (*StorageHandle) List ¶
func (h *StorageHandle) List(ctx context.Context, prefix string) ([]StoredFile, error)
List enumerates files under `prefix` (relative to this zone). Returned StoredFile.Key values are also relative.
func (*StorageHandle) Put ¶
func (h *StorageHandle) Put(ctx context.Context, key string, data io.Reader, contentType string) error
Put writes a file at `key` (relative to this zone) with the given Content-Type. data is fully read; large bodies are streamed.
func (*StorageHandle) ReadAccess ¶
func (h *StorageHandle) ReadAccess() Access
ReadAccess returns the zone's required level for reads.
func (*StorageHandle) Ref ¶
func (h *StorageHandle) Ref(key string) StorageRef
Ref returns a typed StorageRef for `key` in this zone. This is the only public way to construct a StorageRef — builder code that returns file references from tool Out structs goes through here, so a ref can never claim a zone that the handle doesn't represent.
func (*StorageHandle) Slug ¶
func (h *StorageHandle) Slug() string
Slug returns the zone's slug. Useful when constructing public URLs (storage.airlock.example.com/storage/{agentID}/{slug}/{key}).
func (*StorageHandle) Stat ¶
func (h *StorageHandle) Stat(ctx context.Context, key string) (StoredFile, error)
Stat returns metadata for `key` (relative to this zone). The returned StoredFile.Key is also relative.
func (*StorageHandle) URL ¶
func (h *StorageHandle) URL(key string) string
URL returns the URL at which the given key is fetchable on the agent's subdomain. Whether a request to that URL succeeds depends on the zone's Read level and the caller's auth state:
- AccessPublic: served unauthenticated.
- AccessUser: requires a valid agent-subdomain session cookie + agent membership; the proxy redirects through the login flow when the cookie is absent (so a click in chat triggers sign-in and lands back on the file).
- AccessAdmin: same, but requires admin role on the agent.
- AccessInternal: the proxy 404s the URL — internal zones are builder-Go only. URL still composes a string so callers don't get silent empty hrefs, but a warning is logged so the mistake is visible.
Re-resolves on the next sync if the agent's slug or the configured domain changes.
func (*StorageHandle) WriteAccess ¶
func (h *StorageHandle) WriteAccess() Access
WriteAccess returns the zone's required level for writes.
type StorageRef ¶
type StorageRef struct {
// contains filtered or unexported fields
}
StorageRef is a typed reference to a file in a registered Storage zone. The fields are unexported so refs can only come from a *StorageHandle — either via handle.Ref(key), or by JSON-unmarshaling a wire-format {"zone": "...", "key": "..."} that the framework hands back (e.g. httpRequest savedTo, generateImage result, builder tool returns).
Use it as the field type on builder Out structs so the LLM sees an unambiguous {zone, key} shape:
type FetchOut struct {
File agentsdk.StorageRef `json:"file"`
}
The corresponding JS binding is `storage_<zone>` — JS code reads the referenced file with storage_X.get(ref) (the binding validates the ref's zone matches its own slug).
func (StorageRef) Key ¶
func (r StorageRef) Key() string
Key returns the file key relative to the zone.
func (StorageRef) MarshalJSON ¶
func (r StorageRef) MarshalJSON() ([]byte, error)
MarshalJSON encodes the ref as {"zone":"...","key":"..."}.
func (StorageRef) String ¶
func (r StorageRef) String() string
String returns the composed "zone/key" form, useful for logging.
func (*StorageRef) UnmarshalJSON ¶
func (r *StorageRef) UnmarshalJSON(data []byte) error
UnmarshalJSON decodes {"zone":"...","key":"..."}. The framework trusts the input here — validation happens at use time (when a JS binding receives a ref, or when builder code looks the zone up).
type StoredFile ¶
type StoredFile struct {
Key string `json:"key"`
Size int64 `json:"size"`
ContentType string `json:"contentType"`
LastModified time.Time `json:"lastModified"`
}
StoredFile describes a file in agent storage.
type SyncRequest ¶
type SyncRequest struct {
Version string `json:"version"`
Description string `json:"description,omitempty"`
Tools []ToolDef `json:"tools,omitempty"`
Webhooks []WebhookDef `json:"webhooks"`
Crons []CronDef `json:"crons"`
Routes []RouteDef `json:"routes,omitempty"`
Topics []TopicDef `json:"topics,omitempty"`
MCPServers []MCPDef `json:"mcpServers,omitempty"`
Storages []StorageDef `json:"storages,omitempty"`
ExtraPrompts []ExtraPromptDef `json:"extraPrompts,omitempty"`
ModelSlots []ModelSlotDef `json:"modelSlots,omitempty"`
}
SyncRequest is the body for PUT /api/agent/sync.
type SyncResponse ¶
type SyncResponse struct {
SystemPrompt string `json:"systemPrompt"`
MCPAuthStatus []MCPAuthStatus `json:"mcpAuthStatus,omitempty"`
// MCPSchemas carries discovered tool schemas per MCP server slug.
// Airlock populates these from its server-side discovery cache so the
// agent's VM can install one typed JS method per tool on each
// `mcp_{slug}` object — no per-run discovery round-trips.
MCPSchemas map[string][]MCPToolSchema `json:"mcpSchemas,omitempty"`
// PublicStorageBase is the URL prefix at which storage zones are reachable
// on the agent's subdomain, ending without a trailing slash;
// *StorageHandle.URL appends "/{slug}/{key}". Of the form
// https://{slug}.{agentDomain}/__air/storage. The proxy enforces the
// zone's Read access at fetch time — public zones serve unauthenticated,
// user/admin zones require subdomain login (redirect-on-missing-cookie).
PublicStorageBase string `json:"publicStorageBase,omitempty"`
}
SyncResponse is the response from PUT /api/agent/sync.
type Tool ¶
type Tool[In any, Out any] struct { Name string Description string Execute func(ctx context.Context, input In) (Out, error) Access Access InputExamples []In }
Tool is the declarative description of a typed, schema-bearing capability the LLM can invoke via run_js. In and Out are Go structs whose JSON schemas are generated at registration time and rendered as TypeScript signatures in the system prompt. Execute receives the unmarshaled In and returns Out — the wrapper handles JSON boundaries on both sides.
Construct with a pointer literal:
agent.RegisterTool(&agentsdk.Tool[SearchIn, SearchOut]{
Name: "search",
Description: "Search the web.",
Execute: doSearch,
Access: agentsdk.AccessUser,
})
type ToolDef ¶
type ToolDef struct {
Name string `json:"name"`
Description string `json:"description"`
Access Access `json:"access"`
InputSchema json.RawMessage `json:"inputSchema,omitempty"`
OutputSchema json.RawMessage `json:"outputSchema,omitempty"`
InputExamples []json.RawMessage `json:"inputExamples,omitempty"`
}
ToolDef describes a registered tool sent during sync. Carries the JSON schemas for input and output so Airlock can render TypeScript signatures in the system prompt and surface them in the UI.
type Topic ¶
type Topic struct {
Slug string
Description string
Access Access // who may subscribe via topic_{slug}.subscribe(); default AccessUser
}
Topic is the self-contained declaration registered via agent.RegisterTopic. Conversations subscribe to a topic via topic_{slug}.subscribe() in run_js; builders publish via the *TopicHandle returned by RegisterTopic.
type TopicDef ¶
type TopicDef struct {
Slug string `json:"slug"`
Description string `json:"description"`
Access Access `json:"access"`
}
TopicDef is the wire format sent in SyncRequest.
type TopicHandle ¶
type TopicHandle struct {
// contains filtered or unexported fields
}
TopicHandle is a compile-time binding to a registered topic. Returned by Agent.RegisterTopic; used for type-safe publishing.
func (*TopicHandle) Publish ¶
func (h *TopicHandle) Publish(ctx context.Context, parts []DisplayPart) error
Publish sends display parts to all conversations subscribed to this topic.
type Webhook ¶
type Webhook struct {
Path string // unique per agent
Handler WebhookHandlerFunc // required
Verify string // "hmac" | "token" | "none" (default: "none")
Header string // header carrying the signature/token (hmac/token modes)
Timeout time.Duration // max execution time (default: 2 min)
Description string
Access Access // who may invoke; default AccessUser
}
Webhook is the self-contained declaration registered via agent.RegisterWebhook. Agents serve incoming HTTP at /webhook/{Path} on their container.
type WebhookDef ¶
type WebhookDef struct {
Path string `json:"path"`
Verify string `json:"verify"`
Header string `json:"header,omitempty"`
TimeoutMs int64 `json:"timeoutMs"`
Description string `json:"description,omitempty"`
}
WebhookDef is a webhook definition sent during sync.
type WebhookHandlerFunc ¶
type WebhookHandlerFunc func(ctx context.Context, data []byte, ew *EventWriter) error
WebhookHandlerFunc handles incoming webhook requests. Pass ctx to any agent.X(ctx, ...) call the body makes.
Source Files
¶
- access.go
- agent.go
- agentsdk.go
- background.go
- busbridge.go
- client.go
- connection.go
- context.go
- conversation_vm.go
- db.go
- eventwriter.go
- extra_prompt.go
- lazy_run.go
- mcp.go
- migrate.go
- model_slot.go
- prompt.go
- provider.go
- recording.go
- register.go
- run.go
- search.go
- sensitive.go
- serve.go
- session_store.go
- solagent.go
- storage.go
- sync.go
- testing.go
- tool.go
- tools.go
- topic.go
- types.go
- vm.go
- vm_media.go
Directories
¶
| Path | Synopsis |
|---|---|
|
Package tsrender produces the TypeScript .d.ts blocks that Airlock embeds into the agent system prompt: typed signatures for registered tools, and per-server `declare const mcp_{slug}: {...}` namespaces for MCP tools.
|
Package tsrender produces the TypeScript .d.ts blocks that Airlock embeds into the agent system prompt: typed signatures for registered tools, and per-server `declare const mcp_{slug}: {...}` namespaces for MCP tools. |