agents 0.30.1 → 0.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/{agent-routing-CDbpVjYq.d.ts → agent-routing-vVMA7m8Y.d.ts} +69 -608
- package/dist/agent-routing.d.ts +1 -1
- package/dist/agent-tool-types.d.ts +1 -1
- package/dist/{agent-tools-C8DH8Yii.d.ts → agent-tools-gGXXkf1z.d.ts} +2 -2
- package/dist/agent-tools.d.ts +1 -1
- package/dist/agent-tools.js +0 -1
- package/dist/agent-tools.js.map +1 -1
- package/dist/{ai-iXw0uOGj.d.ts → ai-CDn3Abax.d.ts} +30 -4
- package/dist/{ai-sdk-DRPh2rRa.js → ai-sdk-Kon40i0q.js} +2 -36
- package/dist/ai-sdk-Kon40i0q.js.map +1 -0
- package/dist/browser/ai.d.ts +1 -1
- package/dist/browser/ai.js +16 -3
- package/dist/browser/ai.js.map +1 -1
- package/dist/browser/index.d.ts +64 -16
- package/dist/browser/index.js +4 -4
- package/dist/browser/tools/ai-sdk.d.ts +7 -5
- package/dist/browser/tools/ai-sdk.js +4 -4
- package/dist/browser/tools/ai-sdk.js.map +1 -1
- package/dist/browser/tools/pi.d.ts +9 -15
- package/dist/browser/tools/pi.js +6 -14
- package/dist/browser/tools/pi.js.map +1 -1
- package/dist/browser/tools/tanstack-ai.d.ts +48 -25
- package/dist/browser/tools/tanstack-ai.js +8 -4
- package/dist/browser/tools/tanstack-ai.js.map +1 -1
- package/dist/{browser-DccPw_wW.js → browser-1eUbPvC2.js} +413 -14
- package/dist/browser-1eUbPvC2.js.map +1 -0
- package/dist/{browser-DlXhSAdf.d.ts → browser-D9RNpJuT.d.ts} +254 -20
- package/dist/browser-tool-BhjCcNVE.d.ts +71 -0
- package/dist/browser-tool-DRan7Lk6.js +497 -0
- package/dist/browser-tool-DRan7Lk6.js.map +1 -0
- package/dist/capability-id-B3J8Nok_.js +13 -0
- package/dist/capability-id-B3J8Nok_.js.map +1 -0
- package/dist/catalog-BpOejOsE.js +239 -0
- package/dist/catalog-BpOejOsE.js.map +1 -0
- package/dist/catalog-BpiVV1OF.d.ts +173 -0
- package/dist/chat/index.d.ts +2 -2
- package/dist/chat-sdk/index.d.ts +3 -3
- package/dist/chat-sdk/index.js +1 -1
- package/dist/client-4OlMIJx-.js.map +1 -1
- package/dist/{client-BnYbNT3z.js → client-DMWujQJ1.js} +68 -244
- package/dist/client-DMWujQJ1.js.map +1 -0
- package/dist/{client-C27CtRZr.d.ts → client-eSfgYvd3.d.ts} +9 -7
- package/dist/client.d.ts +1 -1
- package/dist/{cloudflare-Dzvc7V2N.js → cloudflare-CUUm_9q9.js} +26 -4
- package/dist/cloudflare-CUUm_9q9.js.map +1 -0
- package/dist/{connector-DAXBOIIi.js → connector-CM-uuxKM.js} +96 -8
- package/dist/connector-CM-uuxKM.js.map +1 -0
- package/dist/{connector-20DJ6p4k.d.ts → connector-DZ71EjE-.d.ts} +109 -9
- package/dist/{do-oauth-client-provider-DfsUcpc3.d.ts → do-oauth-client-provider-DtNqv7oj.d.ts} +26 -2
- package/dist/{index-YSKgfgg9.d.ts → emitter-BJZtCVjQ.d.ts} +6 -140
- package/dist/emitter-DPOVcCln.js +15 -0
- package/dist/emitter-DPOVcCln.js.map +1 -0
- package/dist/experimental/channels/web/index.js +1 -1
- package/dist/experimental/webmcp.js +1 -1
- package/dist/{handler-stateless-Bly_nSH3.js → handler-stateless-B5hU3dxK.js} +35 -2
- package/dist/handler-stateless-B5hU3dxK.js.map +1 -0
- package/dist/{handler-stateless-DxYpJ_XF.d.ts → handler-stateless-C90kD5_R.d.ts} +3 -47
- package/dist/harness/container/index.d.ts +15 -15
- package/dist/harness/container/index.js +0 -1
- package/dist/harness/container/index.js.map +1 -1
- package/dist/harness/container/runtime/index.js +2 -2
- package/dist/harness/opencode/index.js +0 -1
- package/dist/harness/opencode/index.js.map +1 -1
- package/dist/harness/pi/index.d.ts +15 -7
- package/dist/harness/pi/index.js +74 -151
- package/dist/harness/pi/index.js.map +1 -1
- package/dist/harness/think/index.d.ts +2 -1
- package/dist/{images-xaDv2Fqe.js → images-CfuRCjwq.js} +1 -5
- package/dist/images-CfuRCjwq.js.map +1 -0
- package/dist/{index-DCxk3OSJ.d.ts → index-8k4qsX1T.d.ts} +2 -28
- package/dist/index.d.ts +15 -16
- package/dist/index.js +3 -3
- package/dist/internal-hosts-Kfp5A392.d.ts +230 -0
- package/dist/internal-kmw70xwR.js.map +1 -1
- package/dist/invoker-BC1SZ3q1.js +26 -0
- package/dist/invoker-BC1SZ3q1.js.map +1 -0
- package/dist/invoker-DoLFPJZV.d.ts +21 -0
- package/dist/markdown-BZ-VLtA1.js +86 -0
- package/dist/markdown-BZ-VLtA1.js.map +1 -0
- package/dist/mcp/client/do-oauth-client-provider.d.ts +4 -2
- package/dist/mcp/client/do-oauth-client-provider.js +15 -1
- package/dist/mcp/client/do-oauth-client-provider.js.map +1 -1
- package/dist/mcp/client/index.d.ts +15 -1
- package/dist/mcp/client/index.js +2 -2
- package/dist/mcp/client/x402.d.ts +7 -5
- package/dist/mcp/client/x402.js +34 -1
- package/dist/mcp/client/x402.js.map +1 -1
- package/dist/mcp/index.d.ts +561 -27
- package/dist/mcp/index.js +180 -3
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/server/index.d.ts +1 -1
- package/dist/mcp/server/index.js +1 -1
- package/dist/models/ai-sdk/index.d.ts +2 -2
- package/dist/models/ai-sdk/index.js +1 -1
- package/dist/models/opencode/index.d.ts +2 -2
- package/dist/models/opencode/index.js +1 -1
- package/dist/models/pi-ai/index.d.ts +3 -28
- package/dist/models/pi-ai/index.js +160 -18
- package/dist/models/pi-ai/index.js.map +1 -1
- package/dist/observability/ai/index.js +1 -2
- package/dist/observability/ai/index.js.map +1 -1
- package/dist/observability/index.d.ts +170 -9
- package/dist/observability/index.js +386 -11
- package/dist/observability/index.js.map +1 -1
- package/dist/protocol-BEgrJYC5.d.ts +29 -29
- package/dist/react.d.ts +2 -2
- package/dist/resource-B59OV2a2.js +325 -0
- package/dist/resource-B59OV2a2.js.map +1 -0
- package/dist/routing/index.d.ts +1 -1
- package/dist/script-CFDLTk5b.d.ts +91 -0
- package/dist/script-workspace-BpdAYq1R.d.ts +41 -0
- package/dist/serializable.d.ts +1 -1
- package/dist/{session-store-yvwq1f9x.js → session-7CDgVE0z.js} +455 -33
- package/dist/session-7CDgVE0z.js.map +1 -0
- package/dist/{session-store-_IK6dV-w.d.ts → session-store-B7Ca-u1t.d.ts} +8 -1
- package/dist/settings-Dk2il2Hf.js.map +1 -1
- package/dist/skill-DRBcIBjC.d.ts +221 -0
- package/dist/skills/index.d.ts +275 -36
- package/dist/skills/index.js +265 -1534
- package/dist/skills/index.js.map +1 -1
- package/dist/skills/runner.d.ts +37 -0
- package/dist/skills/runner.js +912 -0
- package/dist/skills/runner.js.map +1 -0
- package/dist/skills/tools/ai-sdk.d.ts +36 -0
- package/dist/skills/tools/ai-sdk.js +94 -0
- package/dist/skills/tools/ai-sdk.js.map +1 -0
- package/dist/source-9RQzlEhM.d.ts +112 -0
- package/dist/{src-DfLzdwlK.js → src-DoGNJ4Ud.js} +21 -6
- package/dist/src-DoGNJ4Ud.js.map +1 -0
- package/dist/sub-routing.d.ts +12 -12
- package/dist/tool-CTp72Jb_.d.ts +10 -10
- package/dist/tool-CxKsvxjm.js.map +1 -1
- package/dist/tool-DkT_DJBm.js.map +1 -1
- package/dist/tool-DoVberpN.d.ts +22 -22
- package/dist/tool-helpers-BI7ifO2S.js +255 -0
- package/dist/tool-helpers-BI7ifO2S.js.map +1 -0
- package/dist/{transport-CPh7YGiw.d.ts → transport-5moD2pW5.d.ts} +1 -43
- package/dist/types-D2naO3rA.d.ts +49 -0
- package/dist/vite.d.ts +2 -2
- package/dist/vite.js +10 -258
- package/dist/vite.js.map +1 -1
- package/dist/voice/index.d.ts +1 -1
- package/dist/websockets/index.js +1 -1
- package/dist/{websockets-CyoeosdO.js → websockets-C6SJtWCJ.js} +1 -2
- package/dist/{websockets-CyoeosdO.js.map → websockets-C6SJtWCJ.js.map} +1 -1
- package/dist/workflow-types.d.ts +1 -1
- package/dist/workflows.d.ts +1 -1
- package/dist/workflows.js +0 -1
- package/dist/workflows.js.map +1 -1
- package/docs/browse-the-web.md +247 -413
- package/docs/harnesses/pi.md +36 -30
- package/docs/index.md +4 -4
- package/docs/mcp-client.md +25 -1
- package/docs/mcp-servers.md +26 -7
- package/docs/models-pi-ai.md +9 -11
- package/docs/models.md +1 -8
- package/docs/observability.md +5 -3
- package/docs/securing-mcp-servers.md +113 -302
- package/package.json +31 -17
- package/dist/ai-sdk-DRPh2rRa.js.map +0 -1
- package/dist/browser-DccPw_wW.js.map +0 -1
- package/dist/browser-tool-B1mhifin.js +0 -616
- package/dist/browser-tool-B1mhifin.js.map +0 -1
- package/dist/browser-tool-Cxjk5sgG.d.ts +0 -92
- package/dist/client-BnYbNT3z.js.map +0 -1
- package/dist/cloudflare-Dzvc7V2N.js.map +0 -1
- package/dist/connector-DAXBOIIi.js.map +0 -1
- package/dist/handler-stateless-Bly_nSH3.js.map +0 -1
- package/dist/images-xaDv2Fqe.js.map +0 -1
- package/dist/index-iv9FTXX9.d.ts +0 -311
- package/dist/invoker-CG0_p_Wq.d.ts +0 -20
- package/dist/invoker-CHMnoxIA.js +0 -57
- package/dist/invoker-CHMnoxIA.js.map +0 -1
- package/dist/session-store-yvwq1f9x.js.map +0 -1
- package/dist/skills/compile.d.ts +0 -40
- package/dist/skills/compile.js +0 -65
- package/dist/skills/compile.js.map +0 -1
- package/dist/src-DfLzdwlK.js.map +0 -1
- package/dist/tool-helpers-O5BDVEAY.js +0 -58
- package/dist/tool-helpers-O5BDVEAY.js.map +0 -1
- package/skills-module.d.ts +0 -22
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["dcUnsubscribe"],"sources":["../../src/observability/index.ts"],"sourcesContent":["import {\n subscribe as dcSubscribe,\n unsubscribe as dcUnsubscribe\n} from \"node:diagnostics_channel\";\nimport type { AgentObservabilityEvent } from \"./agent\";\nimport type { MCPObservabilityEvent } from \"./mcp\";\nimport { publishDiagnosticsEvent } from \"./diagnostics\";\nexport { channels } from \"./diagnostics\";\n\n/**\n * Union of all observability event types from different domains\n */\nexport type ObservabilityEvent =\n | AgentObservabilityEvent\n | MCPObservabilityEvent;\n\nexport interface Observability {\n /**\n * Emit an event for the Agent's observability implementation to handle.\n * @param event - The event to emit\n */\n emit(event: ObservabilityEvent): void;\n}\n\n/**\n * Channel keys whose diagnostics channel name differs from `agents:${key}`.\n * Keep this in sync with {@link channels} for any camelCase key that maps to a\n * snake_case diagnostics channel.\n */\nconst CHANNEL_DIAGNOSTIC_NAME_OVERRIDES: Partial<Record<string, string>> = {\n agentTool: \"agents:agent_tool\"\n};\n\n/**\n * The default observability implementation.\n *\n * Publishes events to diagnostics_channel. Events are silent unless\n * a subscriber is registered or a Tail Worker is attached.\n */\nexport const genericObservability: Observability = {\n emit(event) {\n publishDiagnosticsEvent(event);\n }\n};\n\n/**\n * Maps each channel key to the observability events it carries.\n */\nexport type ChannelEventMap = {\n state: Extract<ObservabilityEvent, { type: `state:${string}` }>;\n rpc: Extract<ObservabilityEvent, { type: \"rpc\" | `rpc:${string}` }>;\n message: Extract<\n ObservabilityEvent,\n {\n type:\n | `message:${string}`\n | `tool:${string}`\n | `submission:${string}`\n | `action:${string}`;\n }\n >;\n chat: Exclude<\n Extract<ObservabilityEvent, { type: `chat:${string}` }>,\n { type: `chat:transcript:${string}` }\n >;\n transcript: Extract<\n ObservabilityEvent,\n { type: `transcript:${string}` | `chat:transcript:${string}` }\n >;\n fiber: Extract<ObservabilityEvent, { type: `fiber:${string}` }>;\n agentTool: Extract<ObservabilityEvent, { type: `agent_tool:${string}` }>;\n schedule: Extract<\n ObservabilityEvent,\n { type: `schedule:${string}` | `queue:${string}` }\n >;\n lifecycle: Extract<\n ObservabilityEvent,\n { type: \"connect\" | \"disconnect\" | \"destroy\" }\n >;\n workflow: Extract<ObservabilityEvent, { type: `workflow:${string}` }>;\n mcp: Extract<ObservabilityEvent, { type: `mcp:${string}` }>;\n email: Extract<ObservabilityEvent, { type: `email:${string}` }>;\n channel: Extract<\n ObservabilityEvent,\n { type: `channel:${string}` | `notice:${string}` }\n >;\n};\n\n/**\n * Subscribe to a typed observability channel.\n *\n * ```ts\n * import { subscribe } from \"agents/observability\";\n *\n * const unsub = subscribe(\"rpc\", (event) => {\n * console.log(event.payload.method); // fully typed\n * });\n * ```\n *\n * @returns A function that unsubscribes the callback.\n */\nexport function subscribe<K extends keyof ChannelEventMap>(\n channelKey: K,\n callback: (event: ChannelEventMap[K]) => void\n): () => void {\n const name =\n CHANNEL_DIAGNOSTIC_NAME_OVERRIDES[channelKey] ?? `agents:${channelKey}`;\n const handler = (message: unknown, _name: string | symbol) =>\n callback(message as ChannelEventMap[K]);\n dcSubscribe(name, handler);\n return () => dcUnsubscribe(name, handler);\n}\n"],"mappings":";;;;;;;;AA6BA,MAAM,oCAAqE,EACzE,WAAW,oBACb;;;;;;;AAQA,MAAa,uBAAsC,EACjD,KAAK,OAAO;CACV,wBAAwB,KAAK;AAC/B,EACF;;;;;;;;;;;;;;AA0DA,SAAgB,UACd,YACA,UACY;CACZ,MAAM,OACJ,kCAAkC,eAAe,UAAU;CAC7D,MAAM,WAAW,SAAkB,UACjC,SAAS,OAA6B;CACxC,YAAY,MAAM,OAAO;CACzB,aAAaA,YAAc,MAAM,OAAO;AAC1C"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["dcUnsubscribe"],"sources":["../../src/observability/otel/bridge.ts","../../src/observability/otel/register.ts","../../src/observability/otel/index.ts","../../src/observability/index.ts"],"sourcesContent":["/**\n * The OpenTelemetry API on Workers native tracing.\n *\n * Every recording OTel span is a native span. Native tracing has no manual\n * parent wiring: a span's parent is whatever native span is active (in the\n * async context) when it opens, and a span can only be active inside the\n * callback that opened it. The bridge works within that:\n *\n * - Every span opens with `tracing.startActiveSpan`, so it is native-active for\n * at least a moment. Inside that moment the bridge captures an async-context\n * snapshot: a way back into \"this span is the active native parent\".\n * - `startActiveSpan` runs the caller's function inside the native callback.\n * - `startSpan` returns from the native callback at once (the span stays open\n * and inactive, as OTel requires). When the span later becomes active through\n * `context.with(trace.setSpan(ctx, span), fn)` — the pattern the MCP SDK and\n * other instrumentation use — `fn` runs inside the snapshot, so platform\n * spans (fetch, KV, D1, Durable Objects) and child spans nest under it.\n * - A span is only opened where its native parent is the span the caller asked\n * for. Anything native tracing cannot represent faithfully (remote parents,\n * new roots, explicit start times, parents from another request) returns a\n * non-recording span instead of a span under a substitute parent.\n */\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport {\n createContextKey,\n diag,\n INVALID_SPAN_CONTEXT,\n isSpanContextValid,\n ROOT_CONTEXT,\n SpanStatusCode,\n trace\n} from \"@opentelemetry/api\";\nimport type {\n Attributes,\n Context,\n ContextManager,\n Exception,\n Link,\n Span,\n SpanContext,\n SpanOptions,\n SpanStatus,\n TimeInput,\n Tracer,\n TracerProvider\n} from \"@opentelemetry/api\";\nimport type {\n NativeException,\n NativeSpan,\n NativeTracing\n} from \"../tracing/native\";\n\n/**\n * Runs `fn` in a captured async context (`AsyncLocalStorage.snapshot()`),\n * which includes the native active span.\n */\nexport type ContextSnapshot = <R>(fn: () => R) => R;\n\nexport type BridgeRuntime = {\n readonly tracing: NativeTracing;\n /** Captures the current async context. Defaults to `AsyncLocalStorage.snapshot`. */\n readonly snapshot?: () => ContextSnapshot;\n};\n\n/** The OTel components one bridge registers. */\nexport type OpenTelemetryBridge = {\n readonly contextManager: ContextManager;\n readonly tracerProvider: TracerProvider;\n};\n\nconst reported = new Set<string>();\n\n/**\n * Marks a context taken where no native span was visible. Durable Object\n * constructors and `blockConcurrencyWhile` callbacks report no active span,\n * yet native spans opened there still parent to the request; at module scope\n * they record nothing. Either way the runtime, not the bridge, picks.\n */\nconst AMBIENT = createContextKey(\"agents: ambient native span\");\n\n/**\n * Reports a dropped or refused feature once per isolate through OTel's `diag`\n * logger. Messages name the feature only, never span names or values.\n */\nfunction unsupported(feature: string): void {\n if (reported.has(feature)) {\n return;\n }\n reported.add(feature);\n diag.warn(\n `agents/observability: ${feature} cannot be represented by Workers tracing.`\n );\n}\n\n/** Telemetry must never replace the application's result or error. */\nfunction safely(write: () => void, feature: string): void {\n try {\n write();\n } catch {\n unsupported(`${feature} (the runtime rejected the value)`);\n }\n}\n\ntype Scope = {\n /** The OTel context set by `context.with`. */\n readonly context: Context;\n /** The native active span when that context was set. */\n readonly native: NativeSpan | undefined;\n};\n\nclass Bridge implements OpenTelemetryBridge {\n readonly contextManager: WorkersContextManager;\n readonly tracerProvider: TracerProvider;\n /** One OTel wrapper per native span, so identity comparisons hold. */\n readonly #spans = new WeakMap<NativeSpan, WorkersSpan>();\n readonly #tracer: Tracer;\n readonly #snapshot: () => ContextSnapshot;\n\n constructor(\n readonly native: NativeTracing,\n snapshot: () => ContextSnapshot\n ) {\n this.#snapshot = snapshot;\n this.contextManager = new WorkersContextManager(this).enable();\n this.#tracer = new WorkersTracer(this);\n const tracer = this.#tracer;\n this.tracerProvider = { getTracer: () => tracer };\n }\n\n /** The OTel span for a native span the bridge did not open (root, agent spans). */\n wrap(native: NativeSpan): WorkersSpan {\n let span = this.#spans.get(native);\n if (span === undefined) {\n span = new WorkersSpan(this, native, undefined);\n this.#spans.set(native, span);\n }\n return span;\n }\n\n /**\n * Opens a native span where `placement` says, seeds its attributes, and\n * calls `body` while it is the active native span.\n */\n open<T>(\n name: string,\n attributes: Attributes | undefined,\n placement: OpenPlacement,\n body: (span: WorkersSpan) => T\n ): T {\n const start = () =>\n this.native.startActiveSpan(name, (native) => {\n const span = new WorkersSpan(this, native, this.#snapshot());\n this.#spans.set(native, span);\n if (attributes !== undefined) {\n span.setAttributes(attributes);\n }\n return body(span);\n });\n return placement.in === undefined ? start() : placement.in(start);\n }\n\n /**\n * Decides whether a span can open natively under the requested parent, and\n * from which async context.\n */\n place(options: SpanOptions, parentContext: Context): Placement {\n const parent = options.root ? undefined : trace.getSpan(parentContext);\n const current = this.native.getActiveSpan();\n const refuse = (feature: string): Placement => {\n unsupported(feature);\n const ids = parent?.spanContext();\n return {\n refused:\n ids !== undefined && isSpanContextValid(ids)\n ? ids\n : INVALID_SPAN_CONTEXT\n };\n };\n\n if (current === undefined) {\n // No visible native span (see AMBIENT): let native tracing choose the\n // parent, unless the caller asked for something specific.\n return parent === undefined &&\n !options.root &&\n options.startTime === undefined &&\n parentContext.getValue(AMBIENT) === true\n ? { in: undefined }\n : refuse(\"Spans outside a request\");\n }\n if (parent === undefined) {\n return refuse(\"Root spans and spans without a parent\");\n }\n if (!(parent instanceof WorkersSpan) || parent.bridge !== this) {\n return refuse(\"Spans under remote or foreign parents\");\n }\n if (options.startTime !== undefined) {\n return refuse(\"Explicit span start timestamps\");\n }\n if (options.links !== undefined && options.links.length > 0) {\n unsupported(\"Span links (dropped)\");\n }\n // Workers spans have no kind. Instrumentation (MCP CLIENT/SERVER spans,\n // HTTP client spans) is still recorded; the kind is not.\n if (parent.native === current) {\n return { in: undefined };\n }\n const reentry = parent.reentry(current);\n return reentry === undefined\n ? refuse(\"Spans under a parent from another request or scope\")\n : { in: reentry };\n }\n\n /** Runs `fn` with `context` as the OTel context and `native` as its native span. */\n run<T>(context: Context, native: NativeSpan | undefined, fn: () => T): T {\n return this.contextManager.run({ context, native }, fn);\n }\n}\n\ntype OpenPlacement = {\n /** Where to open: `undefined` for the current context, else a snapshot. */\n readonly in: ContextSnapshot | undefined;\n};\ntype Placement = OpenPlacement | { readonly refused: SpanContext };\n\nclass WorkersSpan implements Span {\n readonly #traceId: string | undefined;\n\n constructor(\n readonly bridge: Bridge,\n readonly native: NativeSpan,\n /** The async context in which `native` is active; only for spans the bridge opened. */\n readonly snapshot: ContextSnapshot | undefined\n ) {\n this.#traceId = snapshot === undefined ? undefined : traceIdOf(native);\n }\n\n /**\n * The snapshot to re-enter so this span is the active native parent again,\n * or `undefined` when that would cross into another request.\n */\n reentry(current: NativeSpan): ContextSnapshot | undefined {\n if (this.snapshot === undefined) {\n return undefined;\n }\n const currentTraceId = traceIdOf(current);\n if (\n this.#traceId !== undefined &&\n currentTraceId !== undefined &&\n this.#traceId !== currentTraceId\n ) {\n return undefined;\n }\n return this.snapshot;\n }\n\n spanContext(): SpanContext {\n let ids: SpanContext | undefined;\n safely(() => {\n ids = this.native.spanContext?.();\n }, \"Span context\");\n if (ids === undefined) {\n return INVALID_SPAN_CONTEXT;\n }\n const { traceId, spanId, traceFlags } = ids;\n return { traceId, spanId, traceFlags };\n }\n\n isRecording(): boolean {\n return this.native.isTraced;\n }\n\n setAttribute(key: string, value: unknown): this {\n if (key === \"\" || value === undefined || !this.native.isTraced) {\n return this;\n }\n if (\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n safely(() => this.native.setAttribute(key, value), \"Attribute\");\n } else {\n // OTel array attributes are typed values. JSON text under an array-typed\n // key would mislead backends, so drop rather than serialize.\n unsupported(\"Array and non-scalar attribute values (dropped)\");\n }\n return this;\n }\n\n setAttributes(attributes: Attributes): this {\n for (const [key, value] of Object.entries(attributes)) {\n this.setAttribute(key, value);\n }\n return this;\n }\n\n setStatus(status: SpanStatus): this {\n // The runtime applies OTel's status rules (Ok is final, Unset has no\n // effect, the message is kept only with Error). Unset needs no call.\n if (\n status.code !== SpanStatusCode.OK &&\n status.code !== SpanStatusCode.ERROR\n ) {\n return this;\n }\n const setStatus = this.native.setStatus;\n if (setStatus === undefined) {\n unsupported(\"Span status on this runtime version\");\n return this;\n }\n safely(\n () =>\n setStatus.call(\n this.native,\n status.code === SpanStatusCode.ERROR\n ? status.message === undefined\n ? { code: \"error\" }\n : { code: \"error\", message: status.message }\n : { code: \"ok\" }\n ),\n \"Span status\"\n );\n return this;\n }\n\n updateName(name: string): this {\n const updateName = this.native.updateName;\n if (updateName === undefined) {\n unsupported(\"Span renames on this runtime version\");\n return this;\n }\n safely(() => updateName.call(this.native, name), \"Span rename\");\n return this;\n }\n\n recordException(exception: Exception, time?: TimeInput): void {\n if (time !== undefined) {\n unsupported(\"Explicit exception timestamps (recorded at runtime time)\");\n }\n safely(\n () => this.native.recordException(exception as NativeException),\n \"Exception\"\n );\n }\n\n end(endTime?: TimeInput): void {\n if (endTime !== undefined) {\n unsupported(\"Explicit end timestamps (ended at runtime time)\");\n }\n safely(() => this.native.end(), \"Span end\");\n }\n\n addEvent(\n _name: string,\n _attributesOrStartTime?: Attributes | TimeInput,\n _startTime?: TimeInput\n ): this {\n unsupported(\"Span events other than exceptions (dropped)\");\n return this;\n }\n\n addLink(_link: Link): this {\n unsupported(\"Span links (dropped)\");\n return this;\n }\n\n addLinks(links: Link[]): this {\n if (links.length > 0) {\n unsupported(\"Span links (dropped)\");\n }\n return this;\n }\n}\n\nfunction traceIdOf(native: NativeSpan): string | undefined {\n try {\n const traceId = native.spanContext?.().traceId;\n return traceId === undefined || /^0+$/.test(traceId) ? undefined : traceId;\n } catch {\n return undefined;\n }\n}\n\nclass WorkersTracer implements Tracer {\n constructor(private readonly bridge: Bridge) {}\n\n startSpan(\n name: string,\n options: SpanOptions = {},\n parentContext: Context = this.bridge.contextManager.active()\n ): Span {\n const placement = this.bridge.place(options, parentContext);\n if (\"refused\" in placement) {\n return trace.wrapSpanContext(placement.refused);\n }\n return this.bridge.open(\n name,\n options.attributes,\n placement,\n (span) => span\n );\n }\n\n startActiveSpan<F extends (span: Span) => unknown>(\n name: string,\n fn: F\n ): ReturnType<F>;\n startActiveSpan<F extends (span: Span) => unknown>(\n name: string,\n options: SpanOptions,\n fn: F\n ): ReturnType<F>;\n startActiveSpan<F extends (span: Span) => unknown>(\n name: string,\n options: SpanOptions,\n context: Context,\n fn: F\n ): ReturnType<F>;\n startActiveSpan<F extends (span: Span) => unknown>(\n name: string,\n optionsOrFn: SpanOptions | F,\n contextOrFn?: Context | F,\n maybeFn?: F\n ): ReturnType<F> {\n const options = typeof optionsOrFn === \"function\" ? {} : optionsOrFn;\n const parentContext =\n typeof contextOrFn === \"object\"\n ? contextOrFn\n : this.bridge.contextManager.active();\n const fn =\n typeof optionsOrFn === \"function\"\n ? optionsOrFn\n : typeof contextOrFn === \"function\"\n ? contextOrFn\n : maybeFn;\n if (fn === undefined) {\n throw new TypeError(\"startActiveSpan requires a callback\");\n }\n\n const placement = this.bridge.place(options, parentContext);\n if (\"refused\" in placement) {\n const span = trace.wrapSpanContext(placement.refused);\n return this.bridge.contextManager.with(\n trace.setSpan(parentContext, span),\n () => fn(span)\n ) as ReturnType<F>;\n }\n // The caller owns `end()`, as with any OTel tracer.\n return this.bridge.open(name, options.attributes, placement, (span) =>\n this.bridge.run(trace.setSpan(parentContext, span), span.native, () =>\n fn(span)\n )\n ) as ReturnType<F>;\n }\n}\n\nclass WorkersContextManager implements ContextManager {\n #storage: AsyncLocalStorage<Scope> | undefined;\n\n constructor(private readonly bridge: Bridge) {}\n\n active(): Context {\n const storage = this.#storage;\n if (storage === undefined) {\n return ROOT_CONTEXT;\n }\n const scope = storage.getStore();\n const native = this.bridge.native.getActiveSpan();\n // An explicit OTel context wins until code enters a new native span\n // (an Agents SDK span, `tracing.enterSpan`, ...), which then becomes the\n // active span while the rest of the context (baggage, values) carries on.\n if (scope !== undefined && scope.native === native) {\n return scope.context;\n }\n if (native === undefined) {\n return scope?.context ?? ROOT_CONTEXT.setValue(AMBIENT, true);\n }\n return trace.setSpan(\n scope?.context ?? ROOT_CONTEXT,\n this.bridge.wrap(native)\n );\n }\n\n with<A extends unknown[], F extends (...args: A) => ReturnType<F>>(\n context: Context,\n fn: F,\n thisArg?: ThisParameterType<F>,\n ...args: A\n ): ReturnType<F> {\n const call = () => fn.apply(thisArg, args);\n if (this.#storage === undefined) {\n return call();\n }\n const current = this.bridge.native.getActiveSpan();\n const span = trace.getSpan(context);\n if (\n span instanceof WorkersSpan &&\n span.bridge === this.bridge &&\n current !== undefined &&\n span.native !== current\n ) {\n // Make the span the active native parent again (see the module note).\n const reentry = span.reentry(current);\n if (reentry !== undefined) {\n return reentry(() => this.run({ context, native: span.native }, call));\n }\n unsupported(\"Activating a span from another request or scope\");\n }\n return this.run({ context, native: current }, call);\n }\n\n /** INTERNAL: runs `fn` in `scope` without native activation. */\n run<T>(scope: Scope, fn: () => T): T {\n const storage = this.#storage;\n return storage === undefined ? fn() : storage.run(scope, fn);\n }\n\n bind<T>(context: Context, target: T): T {\n if (typeof target !== \"function\") {\n unsupported(\"context.bind on non-functions (left unchanged)\");\n return target;\n }\n const manager = this;\n const callable = target as (...args: unknown[]) => unknown;\n return function (this: unknown, ...args: unknown[]) {\n return manager.with(context, () => callable.apply(this, args));\n } as T;\n }\n\n enable(): this {\n this.#storage ??= new AsyncLocalStorage<Scope>();\n return this;\n }\n\n /** Workers has no `AsyncLocalStorage.disable()`; drop access to old scopes instead. */\n disable(): this {\n this.#storage = undefined;\n return this;\n }\n}\n\n/** Creates (but does not register) the OTel components for native tracing. */\nexport function createOpenTelemetryBridge(\n runtime: BridgeRuntime\n): OpenTelemetryBridge {\n return new Bridge(\n runtime.tracing,\n runtime.snapshot ?? (() => AsyncLocalStorage.snapshot())\n );\n}\n","import { context, diag, trace } from \"@opentelemetry/api\";\nimport type { OpenTelemetryBridge } from \"./bridge\";\n\n/** Where `@opentelemetry/api` 1.x keeps its global registrations. */\nconst OTEL_GLOBAL = Symbol.for(\"opentelemetry.js.api.1\");\n\ntype OtelGlobal = {\n readonly version?: string;\n readonly context?: unknown;\n readonly trace?: unknown;\n};\n\n/** What happened when the bridge was offered to the global OTel API. */\nexport type RegistrationOutcome =\n | \"registered\"\n | \"already-registered\"\n | \"deferred\";\n\nfunction otelGlobal(): OtelGlobal | undefined {\n return (globalThis as Record<symbol, OtelGlobal | undefined>)[OTEL_GLOBAL];\n}\n\n/** The provider behind the global proxy, when the proxy exposes it. */\nfunction delegateOf(provider: unknown): unknown {\n const proxy = provider as { getDelegate?: () => unknown } | null | undefined;\n return typeof proxy?.getDelegate === \"function\"\n ? proxy.getDelegate()\n : provider;\n}\n\n/**\n * Registers `bridge` as the global OTel context manager and tracer provider.\n *\n * - Idempotent while the bridge is registered.\n * - Steps aside (`\"deferred\"`) when both globals are already registered by\n * someone else: an OTel SDK the application set up, or the Workers runtime\n * once it registers the OTel API natively. The existing setup keeps working.\n * - Throws when only one of the two is registered, or the registry belongs to\n * an incompatible `@opentelemetry/api` copy: either would leave OTel spans\n * silently detached from native tracing.\n */\nexport function registerBridge(\n bridge: OpenTelemetryBridge\n): RegistrationOutcome {\n const registry = otelGlobal();\n const contextOwner = registry?.context;\n const traceOwner = registry?.trace;\n const ownsContext = contextOwner === bridge.contextManager;\n const ownsTrace =\n traceOwner !== undefined &&\n delegateOf(traceOwner) === bridge.tracerProvider;\n\n if (ownsContext && ownsTrace) {\n return \"already-registered\";\n }\n if (\n contextOwner !== undefined &&\n traceOwner !== undefined &&\n !ownsContext &&\n !ownsTrace\n ) {\n diag.info(\n \"agents/observability: OpenTelemetry is already registered; experimental_registerOpenTelemetry() left it in place.\"\n );\n return \"deferred\";\n }\n if (contextOwner !== undefined || traceOwner !== undefined) {\n throw new Error(\n `experimental_registerOpenTelemetry(): an OpenTelemetry ${contextOwner === undefined ? \"tracer provider\" : \"context manager\"} is already registered without its ${contextOwner === undefined ? \"context manager\" : \"tracer provider\"}. Remove the partial OpenTelemetry setup, or register both before calling experimental_registerOpenTelemetry().`\n );\n }\n\n if (!context.setGlobalContextManager(bridge.contextManager)) {\n throw incompatible(registry?.version);\n }\n bridge.contextManager.enable();\n if (!trace.setGlobalTracerProvider(bridge.tracerProvider)) {\n // Roll back only the manager installed above.\n context.disable();\n throw incompatible(registry?.version);\n }\n return \"registered\";\n}\n\nfunction incompatible(version: string | undefined): Error {\n return new Error(\n `experimental_registerOpenTelemetry(): the global OpenTelemetry API rejected the registration${version === undefined ? \"\" : ` (globals were created by @opentelemetry/api ${version})`}. Install a single version of @opentelemetry/api.`\n );\n}\n","import { diag } from \"@opentelemetry/api\";\nimport { nativeTracing } from \"../tracing/cloudflare\";\nimport { createOpenTelemetryBridge } from \"./bridge\";\nimport type { OpenTelemetryBridge } from \"./bridge\";\nimport { registerBridge } from \"./register\";\n\nlet bridge: OpenTelemetryBridge | undefined;\n\n/**\n * Connects the OpenTelemetry API (`@opentelemetry/api`) to Workers tracing.\n * Call once at module scope:\n *\n * ```ts\n * import { experimental_registerOpenTelemetry } from \"agents/observability\";\n *\n * experimental_registerOpenTelemetry();\n * ```\n *\n * Afterwards, libraries instrumented with the OpenTelemetry API (the MCP SDK,\n * AI SDK telemetry, your own `trace.getTracer(...)` spans) record native\n * Workers spans. They nest with the Agents SDK's spans and the automatic\n * fetch, KV, D1 and Durable Object spans, and export through\n * `observability.traces.destinations`. Enable `observability.traces` in your\n * Wrangler configuration for anything to be recorded.\n *\n * Safe to call more than once. When OpenTelemetry is already fully registered,\n * by your own SDK setup or natively by the Workers runtime, this leaves it in\n * place and does nothing. Throws when only part of an OpenTelemetry setup is\n * registered.\n *\n * @experimental Undocumented and subject to change: a temporary bridge until\n * Workers supports the OpenTelemetry API natively. See\n * `design/rfc-opentelemetry-bridge.md` for what it records and refuses.\n */\nexport function experimental_registerOpenTelemetry(): void {\n if (nativeTracing === undefined) {\n diag.warn(\n \"agents/observability: this runtime has no native tracing; experimental_registerOpenTelemetry() did nothing.\"\n );\n return;\n }\n bridge ??= createOpenTelemetryBridge({ tracing: nativeTracing });\n registerBridge(bridge);\n}\n","import {\n subscribe as dcSubscribe,\n unsubscribe as dcUnsubscribe\n} from \"node:diagnostics_channel\";\nimport type { ObservabilityEvent } from \"./emitter\";\nexport { channels } from \"./diagnostics\";\nexport { genericObservability } from \"./emitter\";\nexport type { Observability, ObservabilityEvent } from \"./emitter\";\nexport { experimental_registerOpenTelemetry } from \"./otel\";\n\n/**\n * Channel keys whose diagnostics channel name differs from `agents:${key}`.\n * Keep this in sync with {@link channels} for any camelCase key that maps to a\n * snake_case diagnostics channel.\n */\nconst CHANNEL_DIAGNOSTIC_NAME_OVERRIDES: Partial<Record<string, string>> = {\n agentTool: \"agents:agent_tool\"\n};\n\n/**\n * Maps each channel key to the observability events it carries.\n */\nexport type ChannelEventMap = {\n state: Extract<ObservabilityEvent, { type: `state:${string}` }>;\n rpc: Extract<ObservabilityEvent, { type: \"rpc\" | `rpc:${string}` }>;\n message: Extract<\n ObservabilityEvent,\n {\n type:\n | `message:${string}`\n | `tool:${string}`\n | `submission:${string}`\n | `action:${string}`;\n }\n >;\n chat: Exclude<\n Extract<ObservabilityEvent, { type: `chat:${string}` }>,\n { type: `chat:transcript:${string}` }\n >;\n transcript: Extract<\n ObservabilityEvent,\n { type: `transcript:${string}` | `chat:transcript:${string}` }\n >;\n fiber: Extract<ObservabilityEvent, { type: `fiber:${string}` }>;\n agentTool: Extract<ObservabilityEvent, { type: `agent_tool:${string}` }>;\n schedule: Extract<\n ObservabilityEvent,\n { type: `schedule:${string}` | `queue:${string}` }\n >;\n lifecycle: Extract<\n ObservabilityEvent,\n { type: \"connect\" | \"disconnect\" | \"destroy\" }\n >;\n workflow: Extract<ObservabilityEvent, { type: `workflow:${string}` }>;\n mcp: Extract<ObservabilityEvent, { type: `mcp:${string}` }>;\n email: Extract<ObservabilityEvent, { type: `email:${string}` }>;\n channel: Extract<\n ObservabilityEvent,\n { type: `channel:${string}` | `notice:${string}` }\n >;\n};\n\n/**\n * Subscribe to a typed observability channel.\n *\n * ```ts\n * import { subscribe } from \"agents/observability\";\n *\n * const unsub = subscribe(\"rpc\", (event) => {\n * console.log(event.payload.method); // fully typed\n * });\n * ```\n *\n * @returns A function that unsubscribes the callback.\n */\nexport function subscribe<K extends keyof ChannelEventMap>(\n channelKey: K,\n callback: (event: ChannelEventMap[K]) => void\n): () => void {\n const name =\n CHANNEL_DIAGNOSTIC_NAME_OVERRIDES[channelKey] ?? `agents:${channelKey}`;\n const handler = (message: unknown, _name: string | symbol) =>\n callback(message as ChannelEventMap[K]);\n dcSubscribe(name, handler);\n return () => dcUnsubscribe(name, handler);\n}\n"],"mappings":"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"}
|
|
@@ -109,35 +109,35 @@ type ContainerMessage = {
|
|
|
109
109
|
};
|
|
110
110
|
/** What an adapter reports while it runs. */
|
|
111
111
|
type ContainerEvent =
|
|
112
|
-
/** Live text for an assistant message that is still being written. */
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
112
|
+
| /** Live text for an assistant message that is still being written. */ {
|
|
113
|
+
readonly type: "text-delta";
|
|
114
|
+
readonly messageId: string;
|
|
115
|
+
readonly delta: string;
|
|
116
|
+
} /** Live reasoning for an assistant message that is still being written. */
|
|
117
|
+
| {
|
|
118
|
+
readonly type: "reasoning-delta";
|
|
119
|
+
readonly messageId: string;
|
|
120
|
+
readonly delta: string;
|
|
121
|
+
} /** A finished or updated transcript message. Stored. */
|
|
122
|
+
| {
|
|
123
|
+
readonly type: "message";
|
|
124
|
+
readonly message: ContainerMessage;
|
|
125
|
+
} /** Token and cost figures the adapter reports, as the adapter counts them. */
|
|
126
|
+
| {
|
|
127
|
+
readonly type: "usage";
|
|
128
|
+
readonly inputTokens?: number;
|
|
129
|
+
readonly outputTokens?: number;
|
|
130
|
+
readonly costUsd?: number;
|
|
131
|
+
} /** A diagnostic line. */
|
|
132
|
+
| {
|
|
133
|
+
readonly type: "log";
|
|
134
|
+
readonly level: "info" | "warn" | "error";
|
|
135
|
+
readonly message: string;
|
|
136
|
+
} /** Anything adapter-specific, passed through untouched. */
|
|
137
|
+
| {
|
|
138
|
+
readonly type: "raw";
|
|
139
|
+
readonly value: JsonValue;
|
|
140
|
+
};
|
|
141
141
|
/** How an operation ended, as the daemon reports it. */
|
|
142
142
|
type ContainerOutcome =
|
|
143
143
|
| {
|
package/dist/react.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
C as MCPServersState,
|
|
3
3
|
J as AgentToolRunPart,
|
|
4
4
|
Y as AgentToolRunState
|
|
5
|
-
} from "./agent-routing-
|
|
5
|
+
} from "./agent-routing-vVMA7m8Y.js";
|
|
6
6
|
import { ClientParameters } from "./serializable.js";
|
|
7
7
|
import { t as AgentTransport } from "./transport-protocol-ZTew5Wso.js";
|
|
8
8
|
import {
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
p as RequiredAgentMethods,
|
|
16
16
|
s as AgentStub,
|
|
17
17
|
v as createStubProxy
|
|
18
|
-
} from "./client-
|
|
18
|
+
} from "./client-eSfgYvd3.js";
|
|
19
19
|
import { PartySocket } from "partysocket";
|
|
20
20
|
import { usePartySocket } from "partysocket/react";
|
|
21
21
|
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
//#region src/skills/result.ts
|
|
2
|
+
/** @internal Wrap a success value. */
|
|
3
|
+
function ok(value) {
|
|
4
|
+
return {
|
|
5
|
+
ok: true,
|
|
6
|
+
value
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
/** @internal Wrap an expected error. */
|
|
10
|
+
function err(error) {
|
|
11
|
+
return {
|
|
12
|
+
ok: false,
|
|
13
|
+
error
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
//#region src/skills/skill.ts
|
|
18
|
+
/**
|
|
19
|
+
* A `SKILL.md` that breaks an Agent Skills rule. Returned as the error of a
|
|
20
|
+
* failed parse, or as a warning when the skill loads anyway.
|
|
21
|
+
*/
|
|
22
|
+
var SkillParseError = class extends Error {
|
|
23
|
+
/**
|
|
24
|
+
* @param code - Which rule the skill broke.
|
|
25
|
+
* @param message - Human-readable explanation, safe to show to a model.
|
|
26
|
+
* @param options - The underlying cause, such as a YAML syntax error.
|
|
27
|
+
*/
|
|
28
|
+
constructor(code, message, options) {
|
|
29
|
+
super(message, options);
|
|
30
|
+
this.code = code;
|
|
31
|
+
this._tag = "SkillParseError";
|
|
32
|
+
this.name = "SkillParseError";
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
const NAME_MAX_LENGTH = 64;
|
|
36
|
+
const DESCRIPTION_MAX_LENGTH = 1024;
|
|
37
|
+
const COMPATIBILITY_MAX_LENGTH = 500;
|
|
38
|
+
const NAME_CHARACTERS = /^[\p{L}\p{N}-]+$/u;
|
|
39
|
+
const UNSAFE_NAME_CHARACTERS = /[/\\\u0000-\u001f\u007f]/;
|
|
40
|
+
const SPEC_FIELDS = /* @__PURE__ */ new Set([
|
|
41
|
+
"name",
|
|
42
|
+
"description",
|
|
43
|
+
"license",
|
|
44
|
+
"compatibility",
|
|
45
|
+
"metadata",
|
|
46
|
+
"allowed-tools"
|
|
47
|
+
]);
|
|
48
|
+
/**
|
|
49
|
+
* Parse a skill name against the Agent Skills spec.
|
|
50
|
+
*
|
|
51
|
+
* The name is NFKC-normalized first. It must be 1-64 characters of
|
|
52
|
+
* lowercase letters, digits, and hyphens, must not start or end with a
|
|
53
|
+
* hyphen, and must not contain `--`.
|
|
54
|
+
*
|
|
55
|
+
* @param input - The candidate name.
|
|
56
|
+
* @returns The branded name, or `SkillParseError` with code `invalid-name`.
|
|
57
|
+
*/
|
|
58
|
+
function parseSkillName(input) {
|
|
59
|
+
const name = input.normalize("NFKC");
|
|
60
|
+
const problem = specNameProblem(name);
|
|
61
|
+
if (problem !== null) return err(new SkillParseError("invalid-name", `Invalid skill name "${input}": ${problem}.`));
|
|
62
|
+
return ok(name);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* @internal Build a skill from already-decoded frontmatter. Sources that do
|
|
66
|
+
* not start from a `SKILL.md` string (such as manifests) use this so every
|
|
67
|
+
* skill passes the same rules.
|
|
68
|
+
*/
|
|
69
|
+
function parseSkillFrontmatter(data, body, options = {}) {
|
|
70
|
+
if (!isRecord(data)) return err(new SkillParseError("invalid-frontmatter", "SKILL.md frontmatter must be a YAML mapping."));
|
|
71
|
+
const warnings = [];
|
|
72
|
+
let failure;
|
|
73
|
+
function take(field) {
|
|
74
|
+
if ("fatal" in field) {
|
|
75
|
+
failure ??= field.fatal;
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
for (const problem of field.problems ?? []) warnings.push(problem);
|
|
79
|
+
return field.value;
|
|
80
|
+
}
|
|
81
|
+
const name = take(parseName(data.name, options.directory));
|
|
82
|
+
const description = take(parseDescription(data.description));
|
|
83
|
+
const license = take(parseLicense(data.license));
|
|
84
|
+
const compatibility = take(parseCompatibility(data.compatibility));
|
|
85
|
+
const metadata = take(parseMetadata(data.metadata));
|
|
86
|
+
const allowedTools = take(parseAllowedTools(data["allowed-tools"]));
|
|
87
|
+
if (failure || name === void 0 || description === void 0 || metadata === void 0 || allowedTools === void 0) return err(failure ?? new SkillParseError("invalid-frontmatter", "Invalid frontmatter."));
|
|
88
|
+
const extraFields = {};
|
|
89
|
+
for (const [key, value] of Object.entries(data)) if (!SPEC_FIELDS.has(key)) extraFields[key] = value;
|
|
90
|
+
return {
|
|
91
|
+
ok: true,
|
|
92
|
+
value: {
|
|
93
|
+
name,
|
|
94
|
+
description,
|
|
95
|
+
...license === void 0 ? {} : { license },
|
|
96
|
+
...compatibility === void 0 ? {} : { compatibility },
|
|
97
|
+
metadata,
|
|
98
|
+
allowedTools,
|
|
99
|
+
extraFields,
|
|
100
|
+
body
|
|
101
|
+
},
|
|
102
|
+
warnings
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Whether a model may activate this skill on its own. Skills opt out with
|
|
107
|
+
* `disable-model-invocation: true`, as a top-level field or in `metadata`.
|
|
108
|
+
*
|
|
109
|
+
* @param skill - The parsed skill.
|
|
110
|
+
* @returns `false` when the skill disables model invocation.
|
|
111
|
+
*/
|
|
112
|
+
function isModelInvocable(skill) {
|
|
113
|
+
return skill.extraFields["disable-model-invocation"] !== true && skill.metadata["disable-model-invocation"] !== "true";
|
|
114
|
+
}
|
|
115
|
+
/** Why a name breaks the spec format, or `null` when it follows it. */
|
|
116
|
+
function specNameProblem(name) {
|
|
117
|
+
if (name.length === 0) return "it must not be empty";
|
|
118
|
+
if ([...name].length > NAME_MAX_LENGTH) return `it must be at most ${NAME_MAX_LENGTH} characters`;
|
|
119
|
+
if (name !== name.toLowerCase()) return "it must be lowercase";
|
|
120
|
+
if (!NAME_CHARACTERS.test(name)) return "it may only contain letters, digits, and hyphens";
|
|
121
|
+
if (name.startsWith("-") || name.endsWith("-")) return "it must not start or end with a hyphen";
|
|
122
|
+
if (name.includes("--")) return "it must not contain consecutive hyphens";
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
/** Whether a name is usable as a directory, enum value, and path segment. */
|
|
126
|
+
function isSafeName(name) {
|
|
127
|
+
return name.length > 0 && name === name.trim() && name !== "." && name !== ".." && !UNSAFE_NAME_CHARACTERS.test(name);
|
|
128
|
+
}
|
|
129
|
+
function parseName(value, directory) {
|
|
130
|
+
const fallback = (value === void 0 || value === null) && directory ? directory : void 0;
|
|
131
|
+
const declared = typeof value === "string" ? value : fallback;
|
|
132
|
+
if (declared === void 0) return { fatal: new SkillParseError("invalid-name", "SKILL.md frontmatter must set `name` to a string.") };
|
|
133
|
+
const name = declared.trim().normalize("NFKC");
|
|
134
|
+
if (!isSafeName(name)) return { fatal: new SkillParseError("invalid-name", `Invalid skill name "${declared}": it must be a single path segment without slashes or control characters.`) };
|
|
135
|
+
const accepted = name;
|
|
136
|
+
const problems = [];
|
|
137
|
+
if (fallback) problems.push(new SkillParseError("invalid-name", `SKILL.md frontmatter has no \`name\`; using its directory "${fallback}".`));
|
|
138
|
+
else {
|
|
139
|
+
const formatProblem = declared !== declared.trim() ? "it must not start or end with whitespace" : specNameProblem(name);
|
|
140
|
+
if (formatProblem !== null) problems.push(new SkillParseError("invalid-name", `Invalid skill name "${declared}": ${formatProblem}.`));
|
|
141
|
+
if (directory !== void 0 && directory.normalize("NFKC") !== name) problems.push(new SkillParseError("name-mismatch", `Skill name "${name}" must match its directory "${directory}".`));
|
|
142
|
+
}
|
|
143
|
+
return problems.length === 0 ? { value: accepted } : {
|
|
144
|
+
value: accepted,
|
|
145
|
+
problems
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
function parseDescription(value) {
|
|
149
|
+
const description = typeof value === "string" ? value.trim() : "";
|
|
150
|
+
if (description.length === 0) return { fatal: new SkillParseError("invalid-description", "SKILL.md frontmatter must set `description` to a non-empty string.") };
|
|
151
|
+
if ([...description].length > DESCRIPTION_MAX_LENGTH) return {
|
|
152
|
+
value: description,
|
|
153
|
+
problems: [new SkillParseError("invalid-description", `Skill description must be at most ${DESCRIPTION_MAX_LENGTH} characters.`)]
|
|
154
|
+
};
|
|
155
|
+
return { value: description };
|
|
156
|
+
}
|
|
157
|
+
function parseLicense(value) {
|
|
158
|
+
if (value === void 0 || value === null) return { value: void 0 };
|
|
159
|
+
if (typeof value !== "string" || value.trim().length === 0) return {
|
|
160
|
+
value: void 0,
|
|
161
|
+
problems: [new SkillParseError("invalid-license", "Skill `license` must be a non-empty string.")]
|
|
162
|
+
};
|
|
163
|
+
return { value: value.trim() };
|
|
164
|
+
}
|
|
165
|
+
function parseCompatibility(value) {
|
|
166
|
+
if (value === void 0 || value === null) return { value: void 0 };
|
|
167
|
+
const compatibility = typeof value === "string" ? value.trim() : "";
|
|
168
|
+
if (compatibility.length === 0 || [...compatibility].length > COMPATIBILITY_MAX_LENGTH) return {
|
|
169
|
+
value: compatibility.length === 0 ? void 0 : compatibility,
|
|
170
|
+
problems: [new SkillParseError("invalid-compatibility", `Skill \`compatibility\` must be 1-${COMPATIBILITY_MAX_LENGTH} characters.`)]
|
|
171
|
+
};
|
|
172
|
+
return { value: compatibility };
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* The spec defines `metadata` as a string-to-string map. YAML turns
|
|
176
|
+
* unquoted values such as `version: 1.0` into numbers, so scalar values are
|
|
177
|
+
* converted to strings rather than rejected. Nested values break the rule
|
|
178
|
+
* and are dropped.
|
|
179
|
+
*/
|
|
180
|
+
function parseMetadata(value) {
|
|
181
|
+
if (value === void 0 || value === null) return { value: {} };
|
|
182
|
+
if (!isRecord(value)) return {
|
|
183
|
+
value: {},
|
|
184
|
+
problems: [new SkillParseError("invalid-metadata", "Skill `metadata` must be a mapping of string keys to string values.")]
|
|
185
|
+
};
|
|
186
|
+
const metadata = {};
|
|
187
|
+
let problem;
|
|
188
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
189
|
+
if (typeof entry !== "string" && typeof entry !== "number" && typeof entry !== "boolean") {
|
|
190
|
+
problem ??= new SkillParseError("invalid-metadata", `Skill \`metadata.${key}\` must be a string.`);
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
metadata[key] = String(entry);
|
|
194
|
+
}
|
|
195
|
+
return problem ? {
|
|
196
|
+
value: metadata,
|
|
197
|
+
problems: [problem]
|
|
198
|
+
} : { value: metadata };
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* The spec defines `allowed-tools` as a space-separated string. A YAML list
|
|
202
|
+
* of strings is also accepted, since some clients write it that way.
|
|
203
|
+
*/
|
|
204
|
+
function parseAllowedTools(value) {
|
|
205
|
+
if (value === void 0 || value === null) return { value: [] };
|
|
206
|
+
if (typeof value === "string") return { value: value.split(/\s+/).filter((tool) => tool.length > 0) };
|
|
207
|
+
if (Array.isArray(value) && value.every((tool) => typeof tool === "string")) return { value: value.map((tool) => tool.trim()).filter(Boolean) };
|
|
208
|
+
return {
|
|
209
|
+
value: [],
|
|
210
|
+
problems: [new SkillParseError("invalid-allowed-tools", "Skill `allowed-tools` must be a space-separated string.")]
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
function isRecord(value) {
|
|
214
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
215
|
+
}
|
|
216
|
+
//#endregion
|
|
217
|
+
//#region src/skills/resource.ts
|
|
218
|
+
/** A resource path that is absolute, escapes the skill, or is malformed. */
|
|
219
|
+
var InvalidSkillResourcePathError = class extends Error {
|
|
220
|
+
/** @param path - The rejected path. */
|
|
221
|
+
constructor(path) {
|
|
222
|
+
super(`Skill resource path must be a normalized relative path inside the skill: ${path}`);
|
|
223
|
+
this.path = path;
|
|
224
|
+
this._tag = "InvalidSkillResourcePathError";
|
|
225
|
+
this.name = "InvalidSkillResourcePathError";
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
/**
|
|
229
|
+
* Parse a path to a file inside a skill directory.
|
|
230
|
+
*
|
|
231
|
+
* @param path - Candidate path relative to the skill root.
|
|
232
|
+
* @returns The branded path, or `InvalidSkillResourcePathError` when it is
|
|
233
|
+
* empty, absolute, contains `.`/`..`/empty segments or NUL, or names
|
|
234
|
+
* `SKILL.md` itself.
|
|
235
|
+
*/
|
|
236
|
+
function parseSkillResourcePath(path) {
|
|
237
|
+
if (path.length === 0 || path.startsWith("/") || path.includes("\0") || path.includes("\\") || path === "SKILL.md" || path.split("/").some((part) => part === "" || part === "." || part === "..")) return err(new InvalidSkillResourcePathError(path));
|
|
238
|
+
return ok(path);
|
|
239
|
+
}
|
|
240
|
+
const TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
241
|
+
"",
|
|
242
|
+
".bash",
|
|
243
|
+
".css",
|
|
244
|
+
".csv",
|
|
245
|
+
".html",
|
|
246
|
+
".js",
|
|
247
|
+
".json",
|
|
248
|
+
".jsx",
|
|
249
|
+
".md",
|
|
250
|
+
".mdx",
|
|
251
|
+
".mjs",
|
|
252
|
+
".py",
|
|
253
|
+
".sh",
|
|
254
|
+
".svg",
|
|
255
|
+
".toml",
|
|
256
|
+
".ts",
|
|
257
|
+
".tsx",
|
|
258
|
+
".txt",
|
|
259
|
+
".xml",
|
|
260
|
+
".yaml",
|
|
261
|
+
".yml"
|
|
262
|
+
]);
|
|
263
|
+
const MIME_TYPES = /* @__PURE__ */ new Map([
|
|
264
|
+
[".css", "text/css"],
|
|
265
|
+
[".csv", "text/csv"],
|
|
266
|
+
[".gif", "image/gif"],
|
|
267
|
+
[".html", "text/html"],
|
|
268
|
+
[".jpeg", "image/jpeg"],
|
|
269
|
+
[".jpg", "image/jpeg"],
|
|
270
|
+
[".js", "text/javascript"],
|
|
271
|
+
[".json", "application/json"],
|
|
272
|
+
[".md", "text/markdown"],
|
|
273
|
+
[".mjs", "text/javascript"],
|
|
274
|
+
[".pdf", "application/pdf"],
|
|
275
|
+
[".png", "image/png"],
|
|
276
|
+
[".py", "text/x-python"],
|
|
277
|
+
[".sh", "text/x-shellscript"],
|
|
278
|
+
[".svg", "image/svg+xml"],
|
|
279
|
+
[".txt", "text/plain"],
|
|
280
|
+
[".webp", "image/webp"],
|
|
281
|
+
[".xml", "application/xml"],
|
|
282
|
+
[".yaml", "application/yaml"],
|
|
283
|
+
[".yml", "application/yaml"]
|
|
284
|
+
]);
|
|
285
|
+
/** Directories and files never treated as skill resources. */
|
|
286
|
+
const IGNORED_SEGMENTS = /* @__PURE__ */ new Set([
|
|
287
|
+
".git",
|
|
288
|
+
"node_modules",
|
|
289
|
+
".DS_Store"
|
|
290
|
+
]);
|
|
291
|
+
/** @internal Lowercased extension including the dot, or `""`. */
|
|
292
|
+
function extensionOf(path) {
|
|
293
|
+
const file = path.split("/").at(-1) ?? path;
|
|
294
|
+
const index = file.lastIndexOf(".");
|
|
295
|
+
return index <= 0 ? "" : file.slice(index).toLowerCase();
|
|
296
|
+
}
|
|
297
|
+
/** @internal Whether a skill-relative path is tooling noise, not content. */
|
|
298
|
+
function isIgnoredSkillPath(path) {
|
|
299
|
+
return path.split("/").some((part) => IGNORED_SEGMENTS.has(part));
|
|
300
|
+
}
|
|
301
|
+
/** @internal Describe a resource from its path alone. */
|
|
302
|
+
function describeSkillResource(path, size) {
|
|
303
|
+
const root = path.split("/", 1)[0];
|
|
304
|
+
const kind = root === "scripts" ? "script" : root === "references" ? "reference" : root === "assets" ? "asset" : "file";
|
|
305
|
+
const extension = extensionOf(path);
|
|
306
|
+
const mimeType = MIME_TYPES.get(extension);
|
|
307
|
+
return {
|
|
308
|
+
path,
|
|
309
|
+
kind,
|
|
310
|
+
encoding: TEXT_EXTENSIONS.has(extension) ? "text" : "base64",
|
|
311
|
+
...mimeType === void 0 ? {} : { mimeType },
|
|
312
|
+
...size === void 0 ? {} : { size }
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
/** @internal Encode file bytes the way {@link SkillResource} expects. */
|
|
316
|
+
function encodeSkillResourceContent(bytes, encoding) {
|
|
317
|
+
if (encoding === "text") return new TextDecoder().decode(bytes);
|
|
318
|
+
const parts = [];
|
|
319
|
+
for (let offset = 0; offset < bytes.byteLength; offset += 32768) parts.push(String.fromCharCode(...bytes.subarray(offset, offset + 32768)));
|
|
320
|
+
return btoa(parts.join(""));
|
|
321
|
+
}
|
|
322
|
+
//#endregion
|
|
323
|
+
export { isIgnoredSkillPath as a, isModelInvocable as c, err as d, ok as f, extensionOf as i, parseSkillFrontmatter as l, describeSkillResource as n, parseSkillResourcePath as o, encodeSkillResourceContent as r, SkillParseError as s, InvalidSkillResourcePathError as t, parseSkillName as u };
|
|
324
|
+
|
|
325
|
+
//# sourceMappingURL=resource-B59OV2a2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource-B59OV2a2.js","names":[],"sources":["../src/skills/result.ts","../src/skills/skill.ts","../src/skills/resource.ts"],"sourcesContent":["/**\n * The outcome of a skills operation that can fail in an expected way.\n *\n * Skill parsing and source I/O return failures as values instead of throwing,\n * so a broken `SKILL.md` or an unreachable bucket never takes down the agent.\n *\n * @template T - The success value.\n * @template E - The expected error.\n */\nexport type SkillResult<T, E extends Error> =\n | { readonly ok: true; readonly value: T }\n | { readonly ok: false; readonly error: E };\n\n/** @internal Wrap a success value. */\nexport function ok<T>(value: T): { readonly ok: true; readonly value: T } {\n return { ok: true, value };\n}\n\n/** @internal Wrap an expected error. */\nexport function err<E extends Error>(\n error: E\n): { readonly ok: false; readonly error: E } {\n return { ok: false, error };\n}\n","import { err, ok, type SkillResult } from \"./result\";\n\n/**\n * The Agent Skills `Skill` type and its frontmatter rules. `SKILL.md`\n * text parsing lives in `./markdown` so code that only handles parsed\n * skills does not load the YAML parser.\n *\n * The rules come from https://agentskills.io/specification, applied the way\n * the spec's guide for agents recommends\n * (https://agentskills.io/client-implementation/adding-skills-support):\n * a skill that breaks a rule still loads, and each broken rule is returned\n * as a warning. Only a skill that cannot be used is rejected: no\n * description, no usable name, or frontmatter that is not YAML.\n *\n * A skill that follows the spec parses with no warnings, so authoring tools\n * check `warnings.length === 0` before storing a skill.\n *\n * Frontmatter keys the spec does not define are kept in\n * {@link Skill.extraFields}.\n *\n * @module\n */\n\ndeclare const skillNameBrand: unique symbol;\n\n/**\n * A skill name the parser accepted. It is always a single safe path segment\n * (no `/`, `\\`, NUL, or control characters, and not `.` or `..`), so it can\n * name a directory, a tool enum value, and a qualified resource path. A name\n * from {@link parseSkillName}, or from a parse with no warnings, also follows\n * the spec format.\n */\nexport type SkillName = string & { readonly [skillNameBrand]: true };\n\n/** Why a `SKILL.md` or skill field broke a rule. */\nexport type SkillParseErrorCode =\n | \"missing-frontmatter\"\n | \"invalid-yaml\"\n | \"invalid-frontmatter\"\n | \"invalid-name\"\n | \"name-mismatch\"\n | \"invalid-description\"\n | \"invalid-license\"\n | \"invalid-compatibility\"\n | \"invalid-metadata\"\n | \"invalid-allowed-tools\";\n\n/**\n * A `SKILL.md` that breaks an Agent Skills rule. Returned as the error of a\n * failed parse, or as a warning when the skill loads anyway.\n */\nexport class SkillParseError extends Error {\n /** Stable tag for narrowing. */\n readonly _tag = \"SkillParseError\" as const;\n\n /**\n * @param code - Which rule the skill broke.\n * @param message - Human-readable explanation, safe to show to a model.\n * @param options - The underlying cause, such as a YAML syntax error.\n */\n constructor(\n readonly code: SkillParseErrorCode,\n message: string,\n options?: { cause?: unknown }\n ) {\n super(message, options);\n this.name = \"SkillParseError\";\n }\n}\n\n/** A parsed Agent Skill: its frontmatter and Markdown instructions. */\nexport interface Skill {\n /** The skill's name. */\n readonly name: SkillName;\n /** What the skill does and when to use it. */\n readonly description: string;\n /** License name or a reference to a bundled license file. */\n readonly license?: string;\n /** Environment requirements. */\n readonly compatibility?: string;\n /** String key-value metadata. Empty when the skill declares none. */\n readonly metadata: Readonly<Record<string, string>>;\n /** Pre-approved tools from `allowed-tools`. Experimental in the spec. */\n readonly allowedTools: readonly string[];\n /** Frontmatter keys the spec does not define, kept verbatim. */\n readonly extraFields: Readonly<Record<string, unknown>>;\n /** Markdown instructions after the frontmatter. */\n readonly body: string;\n}\n\n/** Options for {@link parseSkill}. */\nexport interface ParseSkillOptions {\n /**\n * Name of the directory that holds this `SKILL.md`. The spec requires the\n * skill's `name` to match it; a mismatch is a warning. A missing `name`\n * falls back to the directory, with a warning.\n */\n readonly directory?: string;\n}\n\n/** The outcome of parsing a skill. */\nexport type SkillParseResult =\n | {\n readonly ok: true;\n /** The parsed skill. */\n readonly value: Skill;\n /**\n * Spec rules the skill breaks but was loaded anyway. Empty for a\n * skill that follows the spec.\n */\n readonly warnings: readonly SkillParseError[];\n }\n | { readonly ok: false; readonly error: SkillParseError };\n\nconst NAME_MAX_LENGTH = 64;\nconst DESCRIPTION_MAX_LENGTH = 1024;\nconst COMPATIBILITY_MAX_LENGTH = 500;\nconst NAME_CHARACTERS = /^[\\p{L}\\p{N}-]+$/u;\n// oxlint-disable-next-line no-control-regex -- Rejects control characters in names.\nconst UNSAFE_NAME_CHARACTERS = /[/\\\\\\u0000-\\u001f\\u007f]/;\nconst SPEC_FIELDS = new Set([\n \"name\",\n \"description\",\n \"license\",\n \"compatibility\",\n \"metadata\",\n \"allowed-tools\"\n]);\n\n/**\n * Parse a skill name against the Agent Skills spec.\n *\n * The name is NFKC-normalized first. It must be 1-64 characters of\n * lowercase letters, digits, and hyphens, must not start or end with a\n * hyphen, and must not contain `--`.\n *\n * @param input - The candidate name.\n * @returns The branded name, or `SkillParseError` with code `invalid-name`.\n */\nexport function parseSkillName(\n input: string\n): SkillResult<SkillName, SkillParseError> {\n const name = input.normalize(\"NFKC\");\n const problem = specNameProblem(name);\n if (problem !== null) {\n return err(\n new SkillParseError(\n \"invalid-name\",\n `Invalid skill name \"${input}\": ${problem}.`\n )\n );\n }\n // SAFETY: specNameProblem checked every rule the spec format requires,\n // and the spec format is a subset of the safe-segment rule.\n return ok(name as SkillName);\n}\n\n/** A field value, plus the rules it broke when the parse kept it. */\ntype Field<T> =\n | { readonly value: T; readonly problems?: readonly SkillParseError[] }\n | { readonly fatal: SkillParseError };\n\n/**\n * @internal Build a skill from already-decoded frontmatter. Sources that do\n * not start from a `SKILL.md` string (such as manifests) use this so every\n * skill passes the same rules.\n */\nexport function parseSkillFrontmatter(\n data: unknown,\n body: string,\n options: ParseSkillOptions = {}\n): SkillParseResult {\n if (!isRecord(data)) {\n return err(\n new SkillParseError(\n \"invalid-frontmatter\",\n \"SKILL.md frontmatter must be a YAML mapping.\"\n )\n );\n }\n\n const warnings: SkillParseError[] = [];\n let failure: SkillParseError | undefined;\n function take<T>(field: Field<T>): T | undefined {\n if (\"fatal\" in field) {\n failure ??= field.fatal;\n return undefined;\n }\n for (const problem of field.problems ?? []) {\n warnings.push(problem);\n }\n return field.value;\n }\n\n const name = take(parseName(data.name, options.directory));\n const description = take(parseDescription(data.description));\n const license = take(parseLicense(data.license));\n const compatibility = take(parseCompatibility(data.compatibility));\n const metadata = take(parseMetadata(data.metadata));\n const allowedTools = take(parseAllowedTools(data[\"allowed-tools\"]));\n if (\n failure ||\n name === undefined ||\n description === undefined ||\n metadata === undefined ||\n allowedTools === undefined\n ) {\n return err(\n failure ??\n new SkillParseError(\"invalid-frontmatter\", \"Invalid frontmatter.\")\n );\n }\n\n const extraFields: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(data)) {\n if (!SPEC_FIELDS.has(key)) extraFields[key] = value;\n }\n\n return {\n ok: true,\n value: {\n name,\n description,\n ...(license === undefined ? {} : { license }),\n ...(compatibility === undefined ? {} : { compatibility }),\n metadata,\n allowedTools,\n extraFields,\n body\n },\n warnings\n };\n}\n\n/**\n * Whether a model may activate this skill on its own. Skills opt out with\n * `disable-model-invocation: true`, as a top-level field or in `metadata`.\n *\n * @param skill - The parsed skill.\n * @returns `false` when the skill disables model invocation.\n */\nexport function isModelInvocable(skill: Skill): boolean {\n return (\n skill.extraFields[\"disable-model-invocation\"] !== true &&\n skill.metadata[\"disable-model-invocation\"] !== \"true\"\n );\n}\n\n/** Why a name breaks the spec format, or `null` when it follows it. */\nfunction specNameProblem(name: string): string | null {\n if (name.length === 0) return \"it must not be empty\";\n if ([...name].length > NAME_MAX_LENGTH) {\n return `it must be at most ${NAME_MAX_LENGTH} characters`;\n }\n if (name !== name.toLowerCase()) return \"it must be lowercase\";\n if (!NAME_CHARACTERS.test(name)) {\n return \"it may only contain letters, digits, and hyphens\";\n }\n if (name.startsWith(\"-\") || name.endsWith(\"-\")) {\n return \"it must not start or end with a hyphen\";\n }\n if (name.includes(\"--\")) return \"it must not contain consecutive hyphens\";\n return null;\n}\n\n/** Whether a name is usable as a directory, enum value, and path segment. */\nfunction isSafeName(name: string): boolean {\n return (\n name.length > 0 &&\n name === name.trim() &&\n name !== \".\" &&\n name !== \"..\" &&\n !UNSAFE_NAME_CHARACTERS.test(name)\n );\n}\n\nfunction parseName(\n value: unknown,\n directory: string | undefined\n): Field<SkillName> {\n const fallback =\n (value === undefined || value === null) && directory\n ? directory\n : undefined;\n const declared = typeof value === \"string\" ? value : fallback;\n if (declared === undefined) {\n return {\n fatal: new SkillParseError(\n \"invalid-name\",\n \"SKILL.md frontmatter must set `name` to a string.\"\n )\n };\n }\n // Padding is a format problem, not something to fix silently: it is\n // trimmed and reported.\n const name = declared.trim().normalize(\"NFKC\");\n if (!isSafeName(name)) {\n return {\n fatal: new SkillParseError(\n \"invalid-name\",\n `Invalid skill name \"${declared}\": it must be a single path segment without slashes or control characters.`\n )\n };\n }\n // SAFETY: isSafeName checked the guarantees every SkillName carries. Spec\n // format problems are reported below, and a strict parse fails on them.\n const accepted = name as SkillName;\n\n const problems: SkillParseError[] = [];\n if (fallback) {\n problems.push(\n new SkillParseError(\n \"invalid-name\",\n `SKILL.md frontmatter has no \\`name\\`; using its directory \"${fallback}\".`\n )\n );\n } else {\n const formatProblem =\n declared !== declared.trim()\n ? \"it must not start or end with whitespace\"\n : specNameProblem(name);\n if (formatProblem !== null) {\n problems.push(\n new SkillParseError(\n \"invalid-name\",\n `Invalid skill name \"${declared}\": ${formatProblem}.`\n )\n );\n }\n // Checked independently of the format, so a source reports every rule\n // a name breaks.\n if (directory !== undefined && directory.normalize(\"NFKC\") !== name) {\n problems.push(\n new SkillParseError(\n \"name-mismatch\",\n `Skill name \"${name}\" must match its directory \"${directory}\".`\n )\n );\n }\n }\n return problems.length === 0\n ? { value: accepted }\n : { value: accepted, problems };\n}\n\nfunction parseDescription(value: unknown): Field<string> {\n const description = typeof value === \"string\" ? value.trim() : \"\";\n if (description.length === 0) {\n return {\n fatal: new SkillParseError(\n \"invalid-description\",\n \"SKILL.md frontmatter must set `description` to a non-empty string.\"\n )\n };\n }\n if ([...description].length > DESCRIPTION_MAX_LENGTH) {\n return {\n value: description,\n problems: [\n new SkillParseError(\n \"invalid-description\",\n `Skill description must be at most ${DESCRIPTION_MAX_LENGTH} characters.`\n )\n ]\n };\n }\n return { value: description };\n}\n\nfunction parseLicense(value: unknown): Field<string | undefined> {\n if (value === undefined || value === null) return { value: undefined };\n if (typeof value !== \"string\" || value.trim().length === 0) {\n return {\n value: undefined,\n problems: [\n new SkillParseError(\n \"invalid-license\",\n \"Skill `license` must be a non-empty string.\"\n )\n ]\n };\n }\n return { value: value.trim() };\n}\n\nfunction parseCompatibility(value: unknown): Field<string | undefined> {\n if (value === undefined || value === null) return { value: undefined };\n const compatibility = typeof value === \"string\" ? value.trim() : \"\";\n if (\n compatibility.length === 0 ||\n [...compatibility].length > COMPATIBILITY_MAX_LENGTH\n ) {\n return {\n value: compatibility.length === 0 ? undefined : compatibility,\n problems: [\n new SkillParseError(\n \"invalid-compatibility\",\n `Skill \\`compatibility\\` must be 1-${COMPATIBILITY_MAX_LENGTH} characters.`\n )\n ]\n };\n }\n return { value: compatibility };\n}\n\n/**\n * The spec defines `metadata` as a string-to-string map. YAML turns\n * unquoted values such as `version: 1.0` into numbers, so scalar values are\n * converted to strings rather than rejected. Nested values break the rule\n * and are dropped.\n */\nfunction parseMetadata(\n value: unknown\n): Field<Readonly<Record<string, string>>> {\n if (value === undefined || value === null) return { value: {} };\n if (!isRecord(value)) {\n return {\n value: {},\n problems: [\n new SkillParseError(\n \"invalid-metadata\",\n \"Skill `metadata` must be a mapping of string keys to string values.\"\n )\n ]\n };\n }\n const metadata: Record<string, string> = {};\n let problem: SkillParseError | undefined;\n for (const [key, entry] of Object.entries(value)) {\n if (\n typeof entry !== \"string\" &&\n typeof entry !== \"number\" &&\n typeof entry !== \"boolean\"\n ) {\n problem ??= new SkillParseError(\n \"invalid-metadata\",\n `Skill \\`metadata.${key}\\` must be a string.`\n );\n continue;\n }\n metadata[key] = String(entry);\n }\n return problem\n ? { value: metadata, problems: [problem] }\n : { value: metadata };\n}\n\n/**\n * The spec defines `allowed-tools` as a space-separated string. A YAML list\n * of strings is also accepted, since some clients write it that way.\n */\nfunction parseAllowedTools(value: unknown): Field<readonly string[]> {\n if (value === undefined || value === null) return { value: [] };\n if (typeof value === \"string\") {\n return { value: value.split(/\\s+/).filter((tool) => tool.length > 0) };\n }\n if (\n Array.isArray(value) &&\n value.every((tool): tool is string => typeof tool === \"string\")\n ) {\n return { value: value.map((tool) => tool.trim()).filter(Boolean) };\n }\n return {\n value: [],\n problems: [\n new SkillParseError(\n \"invalid-allowed-tools\",\n \"Skill `allowed-tools` must be a space-separated string.\"\n )\n ]\n };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n","import { err, ok, type SkillResult } from \"./result\";\n\ndeclare const skillResourcePathBrand: unique symbol;\n\n/**\n * A normalized path to a file inside a skill directory, relative to the\n * skill root (for example `references/style-guide.md`). Construct one with\n * {@link parseSkillResourcePath}.\n */\nexport type SkillResourcePath = string & {\n readonly [skillResourcePathBrand]: true;\n};\n\n/**\n * What a skill file is for, from the spec's directory conventions:\n * `scripts/`, `references/`, and `assets/`. Anything else is a `file`.\n */\nexport type SkillResourceKind = \"script\" | \"reference\" | \"asset\" | \"file\";\n\n/** A file bundled with a skill, without its content. */\nexport interface SkillResourceInfo {\n /** Path relative to the skill directory. */\n readonly path: SkillResourcePath;\n /** Role inferred from the top-level directory. */\n readonly kind: SkillResourceKind;\n /** How {@link SkillResource.content} is encoded. */\n readonly encoding: \"text\" | \"base64\";\n /** MIME type, when the extension maps to a known one. */\n readonly mimeType?: string;\n /** Size in bytes, when the source knows it without reading the file. */\n readonly size?: number;\n}\n\n/** A file bundled with a skill, with its content. */\nexport interface SkillResource extends SkillResourceInfo {\n /** UTF-8 text, or base64 for binary files. */\n readonly content: string;\n}\n\n/** A resource path that is absolute, escapes the skill, or is malformed. */\nexport class InvalidSkillResourcePathError extends Error {\n /** Stable tag for narrowing. */\n readonly _tag = \"InvalidSkillResourcePathError\" as const;\n\n /** @param path - The rejected path. */\n constructor(readonly path: string) {\n super(\n `Skill resource path must be a normalized relative path inside the skill: ${path}`\n );\n this.name = \"InvalidSkillResourcePathError\";\n }\n}\n\n/**\n * Parse a path to a file inside a skill directory.\n *\n * @param path - Candidate path relative to the skill root.\n * @returns The branded path, or `InvalidSkillResourcePathError` when it is\n * empty, absolute, contains `.`/`..`/empty segments or NUL, or names\n * `SKILL.md` itself.\n */\nexport function parseSkillResourcePath(\n path: string\n): SkillResult<SkillResourcePath, InvalidSkillResourcePathError> {\n if (\n path.length === 0 ||\n path.startsWith(\"/\") ||\n path.includes(\"\\0\") ||\n path.includes(\"\\\\\") ||\n path === \"SKILL.md\" ||\n path.split(\"/\").some((part) => part === \"\" || part === \".\" || part === \"..\")\n ) {\n return err(new InvalidSkillResourcePathError(path));\n }\n // SAFETY: every rule the SkillResourcePath brand promises was checked above.\n return ok(path as SkillResourcePath);\n}\n\nconst TEXT_EXTENSIONS = new Set([\n \"\",\n \".bash\",\n \".css\",\n \".csv\",\n \".html\",\n \".js\",\n \".json\",\n \".jsx\",\n \".md\",\n \".mdx\",\n \".mjs\",\n \".py\",\n \".sh\",\n \".svg\",\n \".toml\",\n \".ts\",\n \".tsx\",\n \".txt\",\n \".xml\",\n \".yaml\",\n \".yml\"\n]);\n\nconst MIME_TYPES = new Map([\n [\".css\", \"text/css\"],\n [\".csv\", \"text/csv\"],\n [\".gif\", \"image/gif\"],\n [\".html\", \"text/html\"],\n [\".jpeg\", \"image/jpeg\"],\n [\".jpg\", \"image/jpeg\"],\n [\".js\", \"text/javascript\"],\n [\".json\", \"application/json\"],\n [\".md\", \"text/markdown\"],\n [\".mjs\", \"text/javascript\"],\n [\".pdf\", \"application/pdf\"],\n [\".png\", \"image/png\"],\n [\".py\", \"text/x-python\"],\n [\".sh\", \"text/x-shellscript\"],\n [\".svg\", \"image/svg+xml\"],\n [\".txt\", \"text/plain\"],\n [\".webp\", \"image/webp\"],\n [\".xml\", \"application/xml\"],\n [\".yaml\", \"application/yaml\"],\n [\".yml\", \"application/yaml\"]\n]);\n\n/** Directories and files never treated as skill resources. */\nconst IGNORED_SEGMENTS = new Set([\".git\", \"node_modules\", \".DS_Store\"]);\n\n/** @internal Lowercased extension including the dot, or `\"\"`. */\nexport function extensionOf(path: string): string {\n const file = path.split(\"/\").at(-1) ?? path;\n const index = file.lastIndexOf(\".\");\n return index <= 0 ? \"\" : file.slice(index).toLowerCase();\n}\n\n/** @internal Whether a skill-relative path is tooling noise, not content. */\nexport function isIgnoredSkillPath(path: string): boolean {\n return path.split(\"/\").some((part) => IGNORED_SEGMENTS.has(part));\n}\n\n/** @internal Describe a resource from its path alone. */\nexport function describeSkillResource(\n path: SkillResourcePath,\n size?: number\n): SkillResourceInfo {\n const root = path.split(\"/\", 1)[0];\n const kind: SkillResourceKind =\n root === \"scripts\"\n ? \"script\"\n : root === \"references\"\n ? \"reference\"\n : root === \"assets\"\n ? \"asset\"\n : \"file\";\n const extension = extensionOf(path);\n const mimeType = MIME_TYPES.get(extension);\n return {\n path,\n kind,\n encoding: TEXT_EXTENSIONS.has(extension) ? \"text\" : \"base64\",\n ...(mimeType === undefined ? {} : { mimeType }),\n ...(size === undefined ? {} : { size })\n };\n}\n\n/** @internal Encode file bytes the way {@link SkillResource} expects. */\nexport function encodeSkillResourceContent(\n bytes: Uint8Array,\n encoding: \"text\" | \"base64\"\n): string {\n if (encoding === \"text\") return new TextDecoder().decode(bytes);\n const parts: string[] = [];\n for (let offset = 0; offset < bytes.byteLength; offset += 0x8000) {\n parts.push(String.fromCharCode(...bytes.subarray(offset, offset + 0x8000)));\n }\n return btoa(parts.join(\"\"));\n}\n"],"mappings":"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"}
|
package/dist/routing/index.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
n as AgentOptions,
|
|
11
11
|
r as RoutingRetryOptions,
|
|
12
12
|
t as AgentGetOptions
|
|
13
|
-
} from "../agent-routing-
|
|
13
|
+
} from "../agent-routing-vVMA7m8Y.js";
|
|
14
14
|
|
|
15
15
|
//#region src/routing/routed-agents.d.ts
|
|
16
16
|
/** A public entry in an {@link RoutedAgents}. */
|