foldkit-agent-webmcp 0.7.2 → 0.8.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 CHANGED
@@ -129,7 +129,7 @@ boundary.
129
129
  Availability is Model-dependent, so the advertised WebMCP tool set may change as
130
130
  the application changes:
131
131
 
132
- ```ts
132
+ ```ts sketch
133
133
  RequestedDeleteTodo: {
134
134
  name: 'delete_todo',
135
135
  description: 'Delete the selected todo',
package/dist/index.d.mts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { Agent } from "foldkit-agent";
2
2
  import { Attribute, HtmlBuilder } from "foldkit/html";
3
- //#region src/webmcp.d.ts
4
3
  /**
5
4
  * The slice of Chrome's experimental WebMCP Imperative API this adapter uses.
6
5
  *
@@ -48,8 +47,6 @@ interface ModelContext {
48
47
  * a server, or in a browser with neither.
49
48
  */
50
49
  declare const pageModelContext: () => ModelContext | undefined;
51
- //#endregion
52
- //#region src/forms.d.ts
53
50
  /**
54
51
  * One capability drawn as a WebMCP declarative tool: a form whose `toolname`
55
52
  * and `tooldescription`, and whose fields' `name` and `toolparamdescription`,
@@ -79,8 +76,6 @@ declare const formTool: <ByName extends Record<string, unknown>, const Name exte
79
76
  }) => FormTool<Name, ByName[Name]>;
80
77
  /** Whether this browser draws forms as tools: its `SubmitEvent` says when an agent submitted. */
81
78
  declare const declarativeTools: () => boolean;
82
- //#endregion
83
- //#region src/register.d.ts
84
79
  /** A live WebMCP registration. */
85
80
  interface Registration {
86
81
  /** Re-reads availability from the current Model and reconciles registrations. */
@@ -139,6 +134,5 @@ declare const register: <Model, Context_, Principal, ByName, ByTag>(options: Reg
139
134
  declare namespace agentWebMcp_d_exports {
140
135
  export { FormTool, RegisterOptions, Registration, declarativeTools, formTool, pageModelContext, register };
141
136
  }
142
- //#endregion
143
137
  export { agentWebMcp_d_exports as AgentWebMcp, type ModelContext, type RegisterToolOptions, type ToolDescriptor, type ToolExecutionContext, type ToolResult };
144
138
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/webmcp.ts","../src/forms.ts","../src/register.ts","../src/agentWebMcp.ts"],"mappings":";;;;;;;;;;;UASiB;;WAEN,SAAS;;;UAIH;WACN,SAAS;aAAyB;aAAuB;;WACzD;;;UAIM;WACN;WACA;WACA,aAAa;WACb,UAAU,YAAY,SAAS,yBAAyB,QAAQ;;;;;;;;UAS1D;WACN,SAAS;;;UAIH;WACN,eACP,MAAM,gBACN,UAAU,+BACA;;;;;;;;cASD,wBAAuB;;;;;;;;;UCzCnB,SAAS,8BAA8B;WAC7C,MAAM;;WAEN,OAAO,SAAS,GAAG,YAAY,aAAa,cAAc,UAAU;;;;;WAKpE,QAAQ,SACf,WAAW,gBACX,GAAG,YAAY,aACZ,cAAc,UAAU;;WAEpB,MAAM;;;;;;;;cAkBJ,WACX,eAAe,+BACT,mBAAmB,iBAAe,YAE5B,MAAM,0BAA0B,cAAY,MAClD,MAAI;WACU;MACnB,SAAS,MAAM,OAAO;;cA0CZ;;;;UCrFI;;WAEN,eAAe;;WAEf;;WAEA,kBAAkB;;UAGZ,gBAAgB,OAAO,UAAU,WAAW,QAAQ;;WAE1D,OAAO,MAAM,aAAa,OAAO,UAAU,WAAW,QAAQ;;WAE9D,eAAe;;WAEf,SAAS;;;;;;WAMT;;WAEA;;;;;WAKA,YAAY;;;;;;WAMZ,QAAQ,cAAc,eAAe;;;;;;;;;;;;;;;;;;;;cAqBnC,WAAY,OAAO,UAAU,WAAW,QAAQ,OAAK,SACvD,gBAAgB,OAAO,UAAU,WAAW,QAAQ,WAC5D"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/webmcp.ts","../src/forms.ts","../src/register.ts","../src/agentWebMcp.ts"],"mappings":";;;;;;;;;;UASiB;;WAEN,SAAS;;;UAIH;WACN,SAAS;aAAyB;aAAuB;;WACzD;;;UAIM;WACN;WACA;WACA,aAAa;WACb,UAAU,YAAY,SAAS,yBAAyB,QAAQ;;;;;;;;UAS1D;WACN,SAAS;;;UAIH;WACN,eACP,MAAM,gBACN,UAAU,+BACA;;;;;;;;cASD,wBAAuB;;;;;;;UCzCnB,SAAS,8BAA8B;WAC7C,MAAM;;WAEN,OAAO,SAAS,GAAG,YAAY,aAAa,cAAc,UAAU;;;;;WAKpE,QAAQ,SACf,WAAW,gBACX,GAAG,YAAY,aACZ,cAAc,UAAU;;WAEpB,MAAM;;;;;;;;cAkBJ,WACX,eAAe,+BACT,mBAAmB,iBAAe,YAE5B,MAAM,0BAA0B,cAAY,MAClD,MAAI;WACU;MACnB,SAAS,MAAM,OAAO;;cA0CZ;;UCrFI;;WAEN,eAAe;;WAEf;;WAEA,kBAAkB;;UAGZ,gBAAgB,OAAO,UAAU,WAAW,QAAQ;;WAE1D,OAAO,MAAM,aAAa,OAAO,UAAU,WAAW,QAAQ;;WAE9D,eAAe;;WAEf,SAAS;;;;;;WAMT;;WAEA;;;;;WAKA,YAAY;;;;;;WAMZ,QAAQ,cAAc,eAAe;;;;;;;;;;;;;;;;;;;;cAqBnC,WAAY,OAAO,UAAU,WAAW,QAAQ,OAAK,SACvD,gBAAgB,OAAO,UAAU,WAAW,QAAQ,WAC5D"}
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
- import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
1
+ import { t as __exportAll } from "./rolldown-runtime-D8jQpDG7.mjs";
2
2
  import { Agent } from "foldkit-agent";
3
3
  import { Effect, Option } from "effect";
4
- //#region src/forms.ts
4
+ // src/forms.ts
5
5
  /** The description a property of the input's JSON Schema carries, if any. */
6
6
  const describedBy = (property) => typeof property === "object" && property !== null && "description" in property && typeof property.description === "string" ? Option.some(property.description) : Option.none();
7
7
  /**
@@ -88,8 +88,7 @@ const dispatchFor = (agent, invocationId) => async (name, input, signal) => {
88
88
  return textResult(`Capability "${name}" failed unexpectedly`, true);
89
89
  }
90
90
  };
91
- //#endregion
92
- //#region src/webmcp.ts
91
+ // src/webmcp.ts
93
92
  /**
94
93
  * The page's model context, when it has one: `document.modelContext`, where
95
94
  * the spec puts it, or else `navigator.modelContext`, the name Chromium used
@@ -102,8 +101,7 @@ const pageModelContext = () => {
102
101
  if (current !== void 0) return current;
103
102
  return typeof navigator === "undefined" ? void 0 : navigator.modelContext;
104
103
  };
105
- //#endregion
106
- //#region src/register.ts
104
+ // src/register.ts
107
105
  /**
108
106
  * Projects an agent contract into `document.modelContext.registerTool(...)`.
109
107
  *
@@ -213,15 +211,13 @@ const register = (options) => {
213
211
  registered: () => [...controllers.keys()]
214
212
  };
215
213
  };
216
- //#endregion
217
- //#region src/agentWebMcp.ts
214
+ // src/agentWebMcp.ts
218
215
  var agentWebMcp_exports = /* @__PURE__ */ __exportAll({
219
216
  declarativeTools: () => declarativeTools,
220
217
  formTool: () => formTool,
221
218
  pageModelContext: () => pageModelContext,
222
219
  register: () => register
223
220
  });
224
- //#endregion
225
221
  export { agentWebMcp_exports as AgentWebMcp };
226
222
 
227
223
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/forms.ts","../src/webmcp.ts","../src/register.ts","../src/agentWebMcp.ts"],"sourcesContent":["import { Agent } from 'foldkit-agent'\nimport { Effect, Option } from 'effect'\nimport type { Attribute, HtmlBuilder } from 'foldkit/html'\nimport type { ToolResult } from './webmcp.js'\n\n/**\n * One capability drawn as a WebMCP declarative tool: a form whose `toolname`\n * and `tooldescription`, and whose fields' `name` and `toolparamdescription`,\n * come from the agent contract, so the form and the registered tool cannot\n * disagree. `register({ forms })` answers its agent submissions.\n */\nexport interface FormTool<Name extends string = string, Input = unknown> {\n readonly name: Name\n /** The form's attributes: `toolname`, `tooldescription`, and `toolautosubmit` when asked. */\n readonly form: <Message>(h: HtmlBuilder<Message>) => ReadonlyArray<Attribute<Message>>\n /**\n * A field's attributes: `name`, the input's key, and `toolparamdescription`\n * when the input's Schema describes it.\n */\n readonly field: <Message>(\n key: keyof Input & string,\n h: HtmlBuilder<Message>,\n ) => ReadonlyArray<Attribute<Message>>\n /** The input's keys, which an agent's submission is read from. */\n readonly keys: ReadonlyArray<string>\n}\n\n/** The description a property of the input's JSON Schema carries, if any. */\nconst describedBy = (property: unknown): Option.Option<string> =>\n typeof property === 'object' &&\n property !== null &&\n 'description' in property &&\n typeof property.description === 'string'\n ? Option.some(property.description)\n : Option.none()\n\n/**\n * Draws the capability `name` of an agent contract as a declarative tool: see\n * the README's \"Forms as declarative tools\". It throws for a name the contract\n * does not expose, or whose input is not an object of fields, which no form\n * could fill.\n */\nexport const formTool = <\n ByName extends Record<string, unknown>,\n const Name extends keyof ByName & string,\n>(\n definition: Agent.Definition<any, any, any, ByName, any>,\n name: Name,\n options: { readonly autosubmit?: boolean } = {},\n): FormTool<Name, ByName[Name]> => {\n const descriptor = Agent.messages(definition).find(each => each.name === name)\n if (descriptor === undefined)\n throw new Error(`AgentWebMcp.formTool: the contract exposes no capability \"${name}\"`)\n const properties = descriptor.inputSchema['properties']\n if (\n descriptor.inputSchema['type'] !== 'object' ||\n typeof properties !== 'object' ||\n properties === null\n )\n throw new Error(\n `AgentWebMcp.formTool: \"${name}\" takes no object of fields, which no form can fill`,\n )\n const fields = new Map(\n Object.entries(properties).map(([key, property]) => [key, describedBy(property)] as const),\n )\n return {\n name,\n keys: [...fields.keys()],\n form: h => [\n h.Attribute('toolname', name),\n h.Attribute('tooldescription', descriptor.description),\n ...(options.autosubmit === true ? [h.Attribute('toolautosubmit', '')] : []),\n ],\n field: (key, h) => {\n const described = fields.get(key)\n if (described === undefined)\n throw new Error(`AgentWebMcp.formTool: \"${name}\" has no field \"${key}\"`)\n return [\n // An attribute, not `h.Name`, which Foldkit sets only in the browser:\n // a server-rendered form names its fields too.\n h.Attribute('name', key),\n ...Option.match(described, {\n onNone: () => [],\n onSome: description => [h.Attribute('toolparamdescription', description)],\n }),\n ]\n },\n }\n}\n\n/** Whether this browser draws forms as tools: its `SubmitEvent` says when an agent submitted. */\nexport const declarativeTools = (): boolean =>\n typeof SubmitEvent !== 'undefined' && 'agentInvoked' in SubmitEvent.prototype\n\n/**\n * Answers an agent's submission of a form tool on `root`: in the capture phase,\n * before the application's own submit handler, the form's fields named by the\n * input are dispatched as the capability through `dispatch`, and the result\n * goes back through `respondWith`. A person's submission is left alone.\n */\nexport const answerForms = (\n root: Document,\n forms: ReadonlyArray<FormTool>,\n dispatch: (name: string, input: unknown) => Promise<ToolResult>,\n): (() => void) => {\n const byName = new Map(forms.map(form => [form.name, form]))\n const onSubmit = (event: Event) => {\n // `agentInvoked` and `respondWith` are what a declarative WebMCP browser adds to the event.\n const form = event.target\n if (!('agentInvoked' in event) || event.agentInvoked !== true) return\n if (!(form instanceof HTMLFormElement) || !('respondWith' in event)) return\n const { respondWith } = event\n if (typeof respondWith !== 'function') return\n const tool = byName.get(form.getAttribute('toolname') ?? '')\n if (tool === undefined) return\n event.preventDefault()\n event.stopImmediatePropagation()\n // Text, as a form submits it; a field the input does not name is not read.\n const data = new FormData(form)\n const input: Record<string, string> = Object.create(null)\n for (const key of tool.keys) {\n const value = data.get(key)\n if (typeof value === 'string') input[key] = value\n }\n respondWith.call(event, dispatch(tool.name, input))\n }\n root.addEventListener('submit', onSubmit, { capture: true })\n return () => root.removeEventListener('submit', onSubmit, { capture: true })\n}\n\n/** Text a tool returns, which an agent reads. */\nconst textResult = (text: string, isError = false): ToolResult => ({\n content: [{ type: 'text', text }],\n isError,\n})\n\n/** Dispatches a capability for an agent, with the result as a tool returns it; it never rejects. */\nexport const dispatchFor =\n (agent: Agent.AgentRuntime<any, any, any, any, any>, invocationId: () => string) =>\n async (name: string, input: unknown, signal?: AbortSignal): Promise<ToolResult> => {\n try {\n // WebMCP hands the page a promise-returning callback, so this is the\n // edge where Effect meets the browser, not a run inside a service.\n const result = await Effect.runPromise(\n Effect.result(\n // The tool name and payload both come off the wire.\n agent.messages.dispatchUnknown(name, input, {\n id: invocationId(),\n transport: 'webmcp',\n signal,\n }),\n ),\n )\n // Every agent failure carries a message written for this audience.\n if (result._tag === 'Failure') return textResult(result.failure.message, true)\n // A declared completion contract has already resolved by the time\n // dispatch returns, so a failed completion is a failed tool call.\n const summary = Agent.summarize(result.success)\n return textResult(summary.text, !summary.ok)\n } catch {\n // `Effect.result` captures expected failures but not defects, and a\n // rejected tool promise is not something a calling agent can act on.\n // Report it as a tool error without leaking the application's internals.\n return textResult(`Capability \"${name}\" failed unexpectedly`, true)\n }\n }\n","/**\n * The slice of Chrome's experimental WebMCP Imperative API this adapter uses.\n *\n * These types are declared locally rather than imported: the API is still\n * experimental, and Foldkit should not be coupled to a browser proposal that is\n * still changing.\n */\n\n/** Metadata passed to a tool's `execute` function. */\nexport interface ToolExecutionContext {\n /** Cancellation for this invocation: is this call still wanted? */\n readonly signal?: AbortSignal | undefined\n}\n\n/** The value a WebMCP tool returns. */\nexport interface ToolResult {\n readonly content: ReadonlyArray<{ readonly type: 'text'; readonly text: string }>\n readonly isError?: boolean\n}\n\n/** A tool registration as accepted by `document.modelContext.registerTool`. */\nexport interface ToolDescriptor {\n readonly name: string\n readonly description: string\n readonly inputSchema: Record<string, unknown>\n readonly execute: (input: any, context: ToolExecutionContext) => Promise<ToolResult>\n}\n\n/**\n * Options accepted alongside a tool registration.\n *\n * The registration signal belongs here, not on the descriptor: aborting it is\n * how the documented API unregisters a tool.\n */\nexport interface RegisterToolOptions {\n readonly signal?: AbortSignal | undefined\n}\n\n/** The producer surface exposed on `document.modelContext`. */\nexport interface ModelContext {\n readonly registerTool: (\n tool: ToolDescriptor,\n options?: RegisterToolOptions,\n ) => void | Promise<unknown>\n}\n\n/**\n * The page's model context, when it has one: `document.modelContext`, where\n * the spec puts it, or else `navigator.modelContext`, the name Chromium used\n * before 150 and agent extensions that provide WebMCP still use. Undefined on\n * a server, or in a browser with neither.\n */\nexport const pageModelContext = (): ModelContext | undefined => {\n if (typeof document === 'undefined') return undefined\n const current = (document as unknown as { modelContext?: ModelContext }).modelContext\n if (current !== undefined) return current\n return typeof navigator === 'undefined'\n ? undefined\n : (navigator as unknown as { modelContext?: ModelContext }).modelContext\n}\n","import { Agent } from 'foldkit-agent'\nimport { Effect } from 'effect'\nimport { answerForms, declarativeTools, dispatchFor, type FormTool } from './forms.js'\nimport { type ModelContext, type ToolDescriptor, pageModelContext } from './webmcp.js'\n\n/** A live WebMCP registration. */\nexport interface Registration {\n /** Re-reads availability from the current Model and reconciles registrations. */\n readonly refresh: () => Promise<void>\n /** Unregisters every tool and stops following the Model. */\n readonly unregister: () => void\n /** The capability names currently registered with WebMCP. */\n readonly registered: () => ReadonlyArray<string>\n}\n\nexport interface RegisterOptions<Model, Context_, Principal, ByName, ByTag> {\n /** The agent contract bound to a live Foldkit Runtime. */\n readonly agent: Agent.AgentRuntime<Model, Context_, Principal, ByName, ByTag>\n /** Defaults to `pageModelContext()`: `document.modelContext`, or the older `navigator.modelContext`. */\n readonly modelContext?: ModelContext | undefined\n /** Unregisters everything when aborted. */\n readonly signal?: AbortSignal | undefined\n /**\n * Follow the live Model and reconcile registrations as `available(model)`\n * changes. Defaults to `true`, and is inert unless the host supports\n * subscription.\n */\n readonly followModel?: boolean | undefined\n /** Supplies an invocation id. Defaults to `crypto.randomUUID()`. */\n readonly invocationId?: (() => string) | undefined\n /**\n * Reports a failure from a reconcile that no caller is awaiting -- the\n * initial registration, or one triggered by a Model change.\n */\n readonly onError?: ((error: unknown) => void) | undefined\n /**\n * Capabilities the page draws as forms (`formTool`). An agent's submission\n * of one is answered as its tool call would be. In a browser that draws\n * forms as tools these are not registered too, as the form is the tool.\n */\n readonly forms?: ReadonlyArray<FormTool<keyof ByName & string>> | undefined\n}\n\n/**\n * Projects an agent contract into `document.modelContext.registerTool(...)`.\n *\n * Each currently available capability becomes one tool: the capability name\n * becomes the tool name, the variant description becomes the description, the\n * derived JSON Schema becomes `inputSchema`, and `execute` validates its input\n * and dispatches into the same live Foldkit Runtime the human is using.\n *\n * Tool availability is itself a projection of Model state. When\n * `available(model)` changes, registrations are reconciled: capabilities that\n * are gone have their registration signal aborted, and capabilities that have\n * appeared are registered.\n *\n * @example\n * ```ts\n * const registration = AgentWebMcp.register({ agent: agentRuntime })\n * ```\n */\nexport const register = <Model, Context_, Principal, ByName, ByTag>(\n options: RegisterOptions<Model, Context_, Principal, ByName, ByTag>,\n): Registration => {\n const modelContext = options.modelContext ?? pageModelContext()\n if (modelContext === undefined) {\n throw new Error(\n 'WebMCP is unavailable: no document.modelContext or navigator.modelContext. Pass an explicit modelContext to register().',\n )\n }\n\n const { agent } = options\n const dispatch = dispatchFor(agent, options.invocationId ?? Agent.newInvocationId)\n const forms = options.forms ?? []\n // Drawn as forms where the browser makes them tools, so registered only elsewhere.\n const asForms = new Set<string>(declarativeTools() ? forms.map(form => form.name) : [])\n const stopAnswering =\n forms.length === 0 || typeof document === 'undefined'\n ? () => {}\n : answerForms(document, forms, dispatch)\n\n /** One AbortController per registered tool: aborting it unregisters that tool. */\n const controllers = new Map<string, AbortController>()\n let disposed = false\n\n const toolFor = (\n name: string,\n description: string,\n inputSchema: Record<string, unknown>,\n ): { readonly controller: AbortController; readonly tool: ToolDescriptor } => {\n const controller = new AbortController()\n const execute = (input: unknown, context: { readonly signal?: AbortSignal | undefined }) =>\n dispatch(name, input, context.signal)\n return { controller, tool: { name, description, inputSchema, execute } }\n }\n\n const runReconcile = async (): Promise<void> => {\n if (disposed) return\n\n const available = await Effect.runPromise(agent.messages.available)\n const wanted = new Map(\n available.flatMap(descriptor =>\n asForms.has(descriptor.name) ? [] : [[descriptor.name, descriptor] as const],\n ),\n )\n\n // Unregister capabilities the Model no longer offers.\n for (const [name, controller] of [...controllers]) {\n if (!wanted.has(name)) {\n controller.abort()\n controllers.delete(name)\n }\n }\n\n // Register capabilities that have appeared.\n let failure: unknown\n for (const [name, descriptor] of wanted) {\n // unregister() can land while an await above is pending. Nothing more is\n // registered after that.\n if (disposed) return\n if (controllers.has(name)) continue\n\n const { controller, tool } = toolFor(name, descriptor.description, descriptor.inputSchema)\n\n try {\n // The signal goes in the options bag: aborting it is what unregisters\n // the tool.\n await modelContext.registerTool(tool, { signal: controller.signal })\n } catch (error) {\n // Nothing was registered, so nothing is recorded and nothing to abort.\n failure ??= error\n continue\n }\n\n // Disposal can also land while this registration is in flight, in which\n // case the tool is already registered and has to be taken back.\n if (disposed) {\n controller.abort()\n return\n }\n\n // Recorded only once the browser has accepted it.\n controllers.set(name, controller)\n }\n\n if (failure !== undefined) throw failure\n }\n\n /**\n * Reconciles are serialized.\n *\n * A capability is recorded only once the browser has accepted it, so two\n * overlapping reconciles would both see it as missing and register it twice.\n */\n let queue: Promise<void> = Promise.resolve()\n\n const reconcile = (): Promise<void> => {\n const next = queue.then(runReconcile, runReconcile)\n queue = next.then(\n () => {},\n () => {},\n )\n return next\n }\n\n let unsubscribe: () => void = () => {}\n\n const unregister = (): void => {\n disposed = true\n for (const controller of controllers.values()) controller.abort()\n controllers.clear()\n unsubscribe()\n stopAnswering()\n }\n\n /**\n * Reconciles without a caller to await the result. A rejection here would\n * otherwise become an unhandled rejection, so it is reported through\n * `onError` and the registration is left as it was.\n */\n const reconcileInBackground = (): void => {\n reconcile().catch(error => {\n options.onError?.(error)\n })\n }\n\n reconcileInBackground()\n\n if (options.followModel !== false) {\n unsubscribe = agent.subscribe(reconcileInBackground)\n }\n\n if (options.signal?.aborted === true) {\n // An already-aborted signal never fires its listener.\n unregister()\n } else {\n options.signal?.addEventListener('abort', unregister, { once: true })\n }\n\n return {\n refresh: reconcile,\n unregister,\n registered: () => [...controllers.keys()],\n }\n}\n","export { register, type RegisterOptions, type Registration } from './register.js'\nexport { pageModelContext } from './webmcp.js'\nexport { declarativeTools, formTool, type FormTool } from './forms.js'\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/forms.ts","../src/webmcp.ts","../src/register.ts","../src/agentWebMcp.ts"],"sourcesContent":["import { Agent } from 'foldkit-agent'\nimport { Effect, Option } from 'effect'\nimport type { Attribute, HtmlBuilder } from 'foldkit/html'\nimport type { ToolResult } from './webmcp.js'\n\n/**\n * One capability drawn as a WebMCP declarative tool: a form whose `toolname`\n * and `tooldescription`, and whose fields' `name` and `toolparamdescription`,\n * come from the agent contract, so the form and the registered tool cannot\n * disagree. `register({ forms })` answers its agent submissions.\n */\nexport interface FormTool<Name extends string = string, Input = unknown> {\n readonly name: Name\n /** The form's attributes: `toolname`, `tooldescription`, and `toolautosubmit` when asked. */\n readonly form: <Message>(h: HtmlBuilder<Message>) => ReadonlyArray<Attribute<Message>>\n /**\n * A field's attributes: `name`, the input's key, and `toolparamdescription`\n * when the input's Schema describes it.\n */\n readonly field: <Message>(\n key: keyof Input & string,\n h: HtmlBuilder<Message>,\n ) => ReadonlyArray<Attribute<Message>>\n /** The input's keys, which an agent's submission is read from. */\n readonly keys: ReadonlyArray<string>\n}\n\n/** The description a property of the input's JSON Schema carries, if any. */\nconst describedBy = (property: unknown): Option.Option<string> =>\n typeof property === 'object' &&\n property !== null &&\n 'description' in property &&\n typeof property.description === 'string'\n ? Option.some(property.description)\n : Option.none()\n\n/**\n * Draws the capability `name` of an agent contract as a declarative tool: see\n * the README's \"Forms as declarative tools\". It throws for a name the contract\n * does not expose, or whose input is not an object of fields, which no form\n * could fill.\n */\nexport const formTool = <\n ByName extends Record<string, unknown>,\n const Name extends keyof ByName & string,\n>(\n definition: Agent.Definition<any, any, any, ByName, any>,\n name: Name,\n options: { readonly autosubmit?: boolean } = {},\n): FormTool<Name, ByName[Name]> => {\n const descriptor = Agent.messages(definition).find(each => each.name === name)\n if (descriptor === undefined)\n throw new Error(`AgentWebMcp.formTool: the contract exposes no capability \"${name}\"`)\n const properties = descriptor.inputSchema['properties']\n if (\n descriptor.inputSchema['type'] !== 'object' ||\n typeof properties !== 'object' ||\n properties === null\n )\n throw new Error(\n `AgentWebMcp.formTool: \"${name}\" takes no object of fields, which no form can fill`,\n )\n const fields = new Map(\n Object.entries(properties).map(([key, property]) => [key, describedBy(property)] as const),\n )\n return {\n name,\n keys: [...fields.keys()],\n form: h => [\n h.Attribute('toolname', name),\n h.Attribute('tooldescription', descriptor.description),\n ...(options.autosubmit === true ? [h.Attribute('toolautosubmit', '')] : []),\n ],\n field: (key, h) => {\n const described = fields.get(key)\n if (described === undefined)\n throw new Error(`AgentWebMcp.formTool: \"${name}\" has no field \"${key}\"`)\n return [\n // An attribute, not `h.Name`, which Foldkit sets only in the browser:\n // a server-rendered form names its fields too.\n h.Attribute('name', key),\n ...Option.match(described, {\n onNone: () => [],\n onSome: description => [h.Attribute('toolparamdescription', description)],\n }),\n ]\n },\n }\n}\n\n/** Whether this browser draws forms as tools: its `SubmitEvent` says when an agent submitted. */\nexport const declarativeTools = (): boolean =>\n typeof SubmitEvent !== 'undefined' && 'agentInvoked' in SubmitEvent.prototype\n\n/**\n * Answers an agent's submission of a form tool on `root`: in the capture phase,\n * before the application's own submit handler, the form's fields named by the\n * input are dispatched as the capability through `dispatch`, and the result\n * goes back through `respondWith`. A person's submission is left alone.\n */\nexport const answerForms = (\n root: Document,\n forms: ReadonlyArray<FormTool>,\n dispatch: (name: string, input: unknown) => Promise<ToolResult>,\n): (() => void) => {\n const byName = new Map(forms.map(form => [form.name, form]))\n const onSubmit = (event: Event) => {\n // `agentInvoked` and `respondWith` are what a declarative WebMCP browser adds to the event.\n const form = event.target\n if (!('agentInvoked' in event) || event.agentInvoked !== true) return\n if (!(form instanceof HTMLFormElement) || !('respondWith' in event)) return\n const { respondWith } = event\n if (typeof respondWith !== 'function') return\n const tool = byName.get(form.getAttribute('toolname') ?? '')\n if (tool === undefined) return\n event.preventDefault()\n event.stopImmediatePropagation()\n // Text, as a form submits it; a field the input does not name is not read.\n const data = new FormData(form)\n const input: Record<string, string> = Object.create(null)\n for (const key of tool.keys) {\n const value = data.get(key)\n if (typeof value === 'string') input[key] = value\n }\n respondWith.call(event, dispatch(tool.name, input))\n }\n root.addEventListener('submit', onSubmit, { capture: true })\n return () => root.removeEventListener('submit', onSubmit, { capture: true })\n}\n\n/** Text a tool returns, which an agent reads. */\nconst textResult = (text: string, isError = false): ToolResult => ({\n content: [{ type: 'text', text }],\n isError,\n})\n\n/** Dispatches a capability for an agent, with the result as a tool returns it; it never rejects. */\nexport const dispatchFor =\n (agent: Agent.AgentRuntime<any, any, any, any, any>, invocationId: () => string) =>\n async (name: string, input: unknown, signal?: AbortSignal): Promise<ToolResult> => {\n try {\n // WebMCP hands the page a promise-returning callback, so this is the\n // edge where Effect meets the browser, not a run inside a service.\n const result = await Effect.runPromise(\n Effect.result(\n // The tool name and payload both come off the wire.\n agent.messages.dispatchUnknown(name, input, {\n id: invocationId(),\n transport: 'webmcp',\n signal,\n }),\n ),\n )\n // Every agent failure carries a message written for this audience.\n if (result._tag === 'Failure') return textResult(result.failure.message, true)\n // A declared completion contract has already resolved by the time\n // dispatch returns, so a failed completion is a failed tool call.\n const summary = Agent.summarize(result.success)\n return textResult(summary.text, !summary.ok)\n } catch {\n // `Effect.result` captures expected failures but not defects, and a\n // rejected tool promise is not something a calling agent can act on.\n // Report it as a tool error without leaking the application's internals.\n return textResult(`Capability \"${name}\" failed unexpectedly`, true)\n }\n }\n","/**\n * The slice of Chrome's experimental WebMCP Imperative API this adapter uses.\n *\n * These types are declared locally rather than imported: the API is still\n * experimental, and Foldkit should not be coupled to a browser proposal that is\n * still changing.\n */\n\n/** Metadata passed to a tool's `execute` function. */\nexport interface ToolExecutionContext {\n /** Cancellation for this invocation: is this call still wanted? */\n readonly signal?: AbortSignal | undefined\n}\n\n/** The value a WebMCP tool returns. */\nexport interface ToolResult {\n readonly content: ReadonlyArray<{ readonly type: 'text'; readonly text: string }>\n readonly isError?: boolean\n}\n\n/** A tool registration as accepted by `document.modelContext.registerTool`. */\nexport interface ToolDescriptor {\n readonly name: string\n readonly description: string\n readonly inputSchema: Record<string, unknown>\n readonly execute: (input: any, context: ToolExecutionContext) => Promise<ToolResult>\n}\n\n/**\n * Options accepted alongside a tool registration.\n *\n * The registration signal belongs here, not on the descriptor: aborting it is\n * how the documented API unregisters a tool.\n */\nexport interface RegisterToolOptions {\n readonly signal?: AbortSignal | undefined\n}\n\n/** The producer surface exposed on `document.modelContext`. */\nexport interface ModelContext {\n readonly registerTool: (\n tool: ToolDescriptor,\n options?: RegisterToolOptions,\n ) => void | Promise<unknown>\n}\n\n/**\n * The page's model context, when it has one: `document.modelContext`, where\n * the spec puts it, or else `navigator.modelContext`, the name Chromium used\n * before 150 and agent extensions that provide WebMCP still use. Undefined on\n * a server, or in a browser with neither.\n */\nexport const pageModelContext = (): ModelContext | undefined => {\n if (typeof document === 'undefined') return undefined\n const current = (document as unknown as { modelContext?: ModelContext }).modelContext\n if (current !== undefined) return current\n return typeof navigator === 'undefined'\n ? undefined\n : (navigator as unknown as { modelContext?: ModelContext }).modelContext\n}\n","import { Agent } from 'foldkit-agent'\nimport { Effect } from 'effect'\nimport { answerForms, declarativeTools, dispatchFor, type FormTool } from './forms.js'\nimport { type ModelContext, type ToolDescriptor, pageModelContext } from './webmcp.js'\n\n/** A live WebMCP registration. */\nexport interface Registration {\n /** Re-reads availability from the current Model and reconciles registrations. */\n readonly refresh: () => Promise<void>\n /** Unregisters every tool and stops following the Model. */\n readonly unregister: () => void\n /** The capability names currently registered with WebMCP. */\n readonly registered: () => ReadonlyArray<string>\n}\n\nexport interface RegisterOptions<Model, Context_, Principal, ByName, ByTag> {\n /** The agent contract bound to a live Foldkit Runtime. */\n readonly agent: Agent.AgentRuntime<Model, Context_, Principal, ByName, ByTag>\n /** Defaults to `pageModelContext()`: `document.modelContext`, or the older `navigator.modelContext`. */\n readonly modelContext?: ModelContext | undefined\n /** Unregisters everything when aborted. */\n readonly signal?: AbortSignal | undefined\n /**\n * Follow the live Model and reconcile registrations as `available(model)`\n * changes. Defaults to `true`, and is inert unless the host supports\n * subscription.\n */\n readonly followModel?: boolean | undefined\n /** Supplies an invocation id. Defaults to `crypto.randomUUID()`. */\n readonly invocationId?: (() => string) | undefined\n /**\n * Reports a failure from a reconcile that no caller is awaiting -- the\n * initial registration, or one triggered by a Model change.\n */\n readonly onError?: ((error: unknown) => void) | undefined\n /**\n * Capabilities the page draws as forms (`formTool`). An agent's submission\n * of one is answered as its tool call would be. In a browser that draws\n * forms as tools these are not registered too, as the form is the tool.\n */\n readonly forms?: ReadonlyArray<FormTool<keyof ByName & string>> | undefined\n}\n\n/**\n * Projects an agent contract into `document.modelContext.registerTool(...)`.\n *\n * Each currently available capability becomes one tool: the capability name\n * becomes the tool name, the variant description becomes the description, the\n * derived JSON Schema becomes `inputSchema`, and `execute` validates its input\n * and dispatches into the same live Foldkit Runtime the human is using.\n *\n * Tool availability is itself a projection of Model state. When\n * `available(model)` changes, registrations are reconciled: capabilities that\n * are gone have their registration signal aborted, and capabilities that have\n * appeared are registered.\n *\n * @example\n * ```ts\n * const registration = AgentWebMcp.register({ agent: agentRuntime })\n * ```\n */\nexport const register = <Model, Context_, Principal, ByName, ByTag>(\n options: RegisterOptions<Model, Context_, Principal, ByName, ByTag>,\n): Registration => {\n const modelContext = options.modelContext ?? pageModelContext()\n if (modelContext === undefined) {\n throw new Error(\n 'WebMCP is unavailable: no document.modelContext or navigator.modelContext. Pass an explicit modelContext to register().',\n )\n }\n\n const { agent } = options\n const dispatch = dispatchFor(agent, options.invocationId ?? Agent.newInvocationId)\n const forms = options.forms ?? []\n // Drawn as forms where the browser makes them tools, so registered only elsewhere.\n const asForms = new Set<string>(declarativeTools() ? forms.map(form => form.name) : [])\n const stopAnswering =\n forms.length === 0 || typeof document === 'undefined'\n ? () => {}\n : answerForms(document, forms, dispatch)\n\n /** One AbortController per registered tool: aborting it unregisters that tool. */\n const controllers = new Map<string, AbortController>()\n let disposed = false\n\n const toolFor = (\n name: string,\n description: string,\n inputSchema: Record<string, unknown>,\n ): { readonly controller: AbortController; readonly tool: ToolDescriptor } => {\n const controller = new AbortController()\n const execute = (input: unknown, context: { readonly signal?: AbortSignal | undefined }) =>\n dispatch(name, input, context.signal)\n return { controller, tool: { name, description, inputSchema, execute } }\n }\n\n const runReconcile = async (): Promise<void> => {\n if (disposed) return\n\n const available = await Effect.runPromise(agent.messages.available)\n const wanted = new Map(\n available.flatMap(descriptor =>\n asForms.has(descriptor.name) ? [] : [[descriptor.name, descriptor] as const],\n ),\n )\n\n // Unregister capabilities the Model no longer offers.\n for (const [name, controller] of [...controllers]) {\n if (!wanted.has(name)) {\n controller.abort()\n controllers.delete(name)\n }\n }\n\n // Register capabilities that have appeared.\n let failure: unknown\n for (const [name, descriptor] of wanted) {\n // unregister() can land while an await above is pending. Nothing more is\n // registered after that.\n if (disposed) return\n if (controllers.has(name)) continue\n\n const { controller, tool } = toolFor(name, descriptor.description, descriptor.inputSchema)\n\n try {\n // The signal goes in the options bag: aborting it is what unregisters\n // the tool.\n await modelContext.registerTool(tool, { signal: controller.signal })\n } catch (error) {\n // Nothing was registered, so nothing is recorded and nothing to abort.\n failure ??= error\n continue\n }\n\n // Disposal can also land while this registration is in flight, in which\n // case the tool is already registered and has to be taken back.\n if (disposed) {\n controller.abort()\n return\n }\n\n // Recorded only once the browser has accepted it.\n controllers.set(name, controller)\n }\n\n if (failure !== undefined) throw failure\n }\n\n /**\n * Reconciles are serialized.\n *\n * A capability is recorded only once the browser has accepted it, so two\n * overlapping reconciles would both see it as missing and register it twice.\n */\n let queue: Promise<void> = Promise.resolve()\n\n const reconcile = (): Promise<void> => {\n const next = queue.then(runReconcile, runReconcile)\n queue = next.then(\n () => {},\n () => {},\n )\n return next\n }\n\n let unsubscribe: () => void = () => {}\n\n const unregister = (): void => {\n disposed = true\n for (const controller of controllers.values()) controller.abort()\n controllers.clear()\n unsubscribe()\n stopAnswering()\n }\n\n /**\n * Reconciles without a caller to await the result. A rejection here would\n * otherwise become an unhandled rejection, so it is reported through\n * `onError` and the registration is left as it was.\n */\n const reconcileInBackground = (): void => {\n reconcile().catch(error => {\n options.onError?.(error)\n })\n }\n\n reconcileInBackground()\n\n if (options.followModel !== false) {\n unsubscribe = agent.subscribe(reconcileInBackground)\n }\n\n if (options.signal?.aborted === true) {\n // An already-aborted signal never fires its listener.\n unregister()\n } else {\n options.signal?.addEventListener('abort', unregister, { once: true })\n }\n\n return {\n refresh: reconcile,\n unregister,\n registered: () => [...controllers.keys()],\n }\n}\n","export { register, type RegisterOptions, type Registration } from './register.js'\nexport { pageModelContext } from './webmcp.js'\nexport { declarativeTools, formTool, type FormTool } from './forms.js'\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- //#region \0rolldown/runtime.js
1
+ // \0rolldown/runtime.js
2
2
  var __defProp = Object.defineProperty;
3
3
  var __exportAll = (all, no_symbols) => {
4
4
  let target = {};
@@ -9,5 +9,4 @@ var __exportAll = (all, no_symbols) => {
9
9
  if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
10
10
  return target;
11
11
  };
12
- //#endregion
13
12
  export { __exportAll as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foldkit-agent-webmcp",
3
- "version": "0.7.2",
3
+ "version": "0.8.0",
4
4
  "description": "WebMCP adapter for foldkit-agent. Projects exposed Foldkit Messages into document.modelContext tools.",
5
5
  "keywords": [
6
6
  "foldkit",
@@ -38,18 +38,18 @@
38
38
  "LICENSE"
39
39
  ],
40
40
  "peerDependencies": {
41
- "effect": "^4.0.0",
42
- "foldkit": "^0.169.0",
43
- "foldkit-agent": "^0.8.2"
41
+ "effect": "^4.1.0",
42
+ "foldkit": "^0.170.0",
43
+ "foldkit-agent": "^0.9.0"
44
44
  },
45
45
  "dependencies": {},
46
46
  "devDependencies": {
47
- "@effect/platform-browser": "^4.0.5",
48
- "effect": "^4.0.5",
49
- "foldkit": "0.169.0",
47
+ "@effect/platform-browser": "^4.1.0",
48
+ "effect": "^4.1.0",
49
+ "foldkit": "0.170.0",
50
50
  "tsdown": "^0.23.1",
51
51
  "typescript": "7.0.2",
52
- "foldkit-agent": "0.8.2"
52
+ "foldkit-agent": "0.9.0"
53
53
  },
54
54
  "scripts": {
55
55
  "build": "tsdown",