@nxisai/agent-harness 0.2.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.
Files changed (126) hide show
  1. package/README.md +434 -0
  2. package/dist/a2ui/cards.d.ts +55 -0
  3. package/dist/a2ui/cards.d.ts.map +1 -0
  4. package/dist/a2ui/cards.js +133 -0
  5. package/dist/a2ui/cards.js.map +1 -0
  6. package/dist/a2ui/emit.d.ts +33 -0
  7. package/dist/a2ui/emit.d.ts.map +1 -0
  8. package/dist/a2ui/emit.js +116 -0
  9. package/dist/a2ui/emit.js.map +1 -0
  10. package/dist/a2ui/form.d.ts +20 -0
  11. package/dist/a2ui/form.d.ts.map +1 -0
  12. package/dist/a2ui/form.js +92 -0
  13. package/dist/a2ui/form.js.map +1 -0
  14. package/dist/a2ui/host.d.ts +34 -0
  15. package/dist/a2ui/host.d.ts.map +1 -0
  16. package/dist/a2ui/host.js +47 -0
  17. package/dist/a2ui/host.js.map +1 -0
  18. package/dist/a2ui/index.d.ts +23 -0
  19. package/dist/a2ui/index.d.ts.map +1 -0
  20. package/dist/a2ui/index.js +20 -0
  21. package/dist/a2ui/index.js.map +1 -0
  22. package/dist/a2ui/stepper.d.ts +26 -0
  23. package/dist/a2ui/stepper.d.ts.map +1 -0
  24. package/dist/a2ui/stepper.js +162 -0
  25. package/dist/a2ui/stepper.js.map +1 -0
  26. package/dist/a2ui/theme.d.ts +21 -0
  27. package/dist/a2ui/theme.d.ts.map +1 -0
  28. package/dist/a2ui/theme.js +134 -0
  29. package/dist/a2ui/theme.js.map +1 -0
  30. package/dist/a2ui/to-v09.d.ts +31 -0
  31. package/dist/a2ui/to-v09.d.ts.map +1 -0
  32. package/dist/a2ui/to-v09.js +104 -0
  33. package/dist/a2ui/to-v09.js.map +1 -0
  34. package/dist/engine.d.ts +209 -0
  35. package/dist/engine.d.ts.map +1 -0
  36. package/dist/engine.js +505 -0
  37. package/dist/engine.js.map +1 -0
  38. package/dist/harness/harness.d.ts +284 -0
  39. package/dist/harness/harness.d.ts.map +1 -0
  40. package/dist/harness/harness.js +568 -0
  41. package/dist/harness/harness.js.map +1 -0
  42. package/dist/harness/plan.d.ts +32 -0
  43. package/dist/harness/plan.d.ts.map +1 -0
  44. package/dist/harness/plan.js +68 -0
  45. package/dist/harness/plan.js.map +1 -0
  46. package/dist/harness/policy.d.ts +49 -0
  47. package/dist/harness/policy.d.ts.map +1 -0
  48. package/dist/harness/policy.js +34 -0
  49. package/dist/harness/policy.js.map +1 -0
  50. package/dist/harness/renderer.d.ts +163 -0
  51. package/dist/harness/renderer.d.ts.map +1 -0
  52. package/dist/harness/renderer.js +12 -0
  53. package/dist/harness/renderer.js.map +1 -0
  54. package/dist/harness/router/coordinator.d.ts +120 -0
  55. package/dist/harness/router/coordinator.d.ts.map +1 -0
  56. package/dist/harness/router/coordinator.js +145 -0
  57. package/dist/harness/router/coordinator.js.map +1 -0
  58. package/dist/harness/router/rules.d.ts +48 -0
  59. package/dist/harness/router/rules.d.ts.map +1 -0
  60. package/dist/harness/router/rules.js +38 -0
  61. package/dist/harness/router/rules.js.map +1 -0
  62. package/dist/harness/slots.d.ts +73 -0
  63. package/dist/harness/slots.d.ts.map +1 -0
  64. package/dist/harness/slots.js +68 -0
  65. package/dist/harness/slots.js.map +1 -0
  66. package/dist/harness/tools/bridge.d.ts +71 -0
  67. package/dist/harness/tools/bridge.d.ts.map +1 -0
  68. package/dist/harness/tools/bridge.js +271 -0
  69. package/dist/harness/tools/bridge.js.map +1 -0
  70. package/dist/harness/tools/client.d.ts +11 -0
  71. package/dist/harness/tools/client.d.ts.map +1 -0
  72. package/dist/harness/tools/client.js +21 -0
  73. package/dist/harness/tools/client.js.map +1 -0
  74. package/dist/harness/tools/discovery.d.ts +13 -0
  75. package/dist/harness/tools/discovery.d.ts.map +1 -0
  76. package/dist/harness/tools/discovery.js +43 -0
  77. package/dist/harness/tools/discovery.js.map +1 -0
  78. package/dist/harness/tools/local-context.d.ts +38 -0
  79. package/dist/harness/tools/local-context.d.ts.map +1 -0
  80. package/dist/harness/tools/local-context.js +55 -0
  81. package/dist/harness/tools/local-context.js.map +1 -0
  82. package/dist/harness/tools/schema.d.ts +52 -0
  83. package/dist/harness/tools/schema.d.ts.map +1 -0
  84. package/dist/harness/tools/schema.js +175 -0
  85. package/dist/harness/tools/schema.js.map +1 -0
  86. package/dist/harness/tools/source.d.ts +65 -0
  87. package/dist/harness/tools/source.d.ts.map +1 -0
  88. package/dist/harness/tools/source.js +89 -0
  89. package/dist/harness/tools/source.js.map +1 -0
  90. package/dist/harness/tools/webmcp.d.ts +50 -0
  91. package/dist/harness/tools/webmcp.d.ts.map +1 -0
  92. package/dist/harness/tools/webmcp.js +114 -0
  93. package/dist/harness/tools/webmcp.js.map +1 -0
  94. package/dist/index.d.ts +49 -0
  95. package/dist/index.d.ts.map +1 -0
  96. package/dist/index.js +38 -0
  97. package/dist/index.js.map +1 -0
  98. package/dist/providers/types.d.ts +123 -0
  99. package/dist/providers/types.d.ts.map +1 -0
  100. package/dist/providers/types.js +2 -0
  101. package/dist/providers/types.js.map +1 -0
  102. package/dist/types.d.ts +223 -0
  103. package/dist/types.d.ts.map +1 -0
  104. package/dist/types.js +8 -0
  105. package/dist/types.js.map +1 -0
  106. package/dist/ui/agent-fullscreen.d.ts +41 -0
  107. package/dist/ui/agent-fullscreen.d.ts.map +1 -0
  108. package/dist/ui/agent-fullscreen.js +2821 -0
  109. package/dist/ui/agent-fullscreen.js.map +1 -0
  110. package/dist/ui/config.d.ts +88 -0
  111. package/dist/ui/config.d.ts.map +1 -0
  112. package/dist/ui/config.js +96 -0
  113. package/dist/ui/config.js.map +1 -0
  114. package/dist/ui/index.d.ts +22 -0
  115. package/dist/ui/index.d.ts.map +1 -0
  116. package/dist/ui/index.js +19 -0
  117. package/dist/ui/index.js.map +1 -0
  118. package/dist/ui/tailwind.generated.d.ts +2 -0
  119. package/dist/ui/tailwind.generated.d.ts.map +1 -0
  120. package/dist/ui/tailwind.generated.js +3 -0
  121. package/dist/ui/tailwind.generated.js.map +1 -0
  122. package/dist/webmcp-contract.d.ts +57 -0
  123. package/dist/webmcp-contract.d.ts.map +1 -0
  124. package/dist/webmcp-contract.js +11 -0
  125. package/dist/webmcp-contract.js.map +1 -0
  126. package/package.json +39 -0
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Resolves a site's MCP server from its `.well-known` catalogs.
3
+ *
4
+ * Reads `/.well-known/ai-catalog.json` (falling back to `catalog.json`),
5
+ * follows an entry's URL to the server card, and extracts the Streamable HTTP
6
+ * endpoint, its auth header, and the tools available without a key.
7
+ *
8
+ * @module
9
+ */
10
+ import type { McpServerInfo } from '../../types.js';
11
+ /** Discover the remote MCP server: card URL → endpoint, auth, public tools. */
12
+ export declare function discoverMcpServer(): Promise<McpServerInfo>;
13
+ //# sourceMappingURL=discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../../src/harness/tools/discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAe,aAAa,EAAc,MAAM,gBAAgB,CAAC;AAuB7E,+EAA+E;AAC/E,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,aAAa,CAAC,CAoBhE"}
@@ -0,0 +1,43 @@
1
+ async function fetchJson(url) {
2
+ const res = await fetch(url, { headers: { Accept: 'application/json' } });
3
+ if (!res.ok)
4
+ throw new Error(`GET ${url} → ${res.status}`);
5
+ return (await res.json());
6
+ }
7
+ /** Find the server-card URL by reading the well-known catalogs in order. */
8
+ async function resolveServerCardUrl() {
9
+ const catalogs = ['/.well-known/ai-catalog.json', '/.well-known/catalog.json'];
10
+ for (const path of catalogs) {
11
+ try {
12
+ const catalog = await fetchJson(path);
13
+ const entry = catalog.entries?.find((e) => !!e.url);
14
+ if (entry?.url)
15
+ return entry.url;
16
+ }
17
+ catch {
18
+ /* try the next catalog */
19
+ }
20
+ }
21
+ throw new Error('No MCP server-card URL found in .well-known catalogs');
22
+ }
23
+ /** Discover the remote MCP server: card URL → endpoint, auth, public tools. */
24
+ export async function discoverMcpServer() {
25
+ const cardUrl = await resolveServerCardUrl();
26
+ const card = await fetchJson(cardUrl);
27
+ const remote = card.remotes?.find((r) => r.type === 'streamable-http') ?? card.remotes?.[0];
28
+ if (!remote?.url)
29
+ throw new Error(`Server card at ${cardUrl} has no remote endpoint URL`);
30
+ const authHeader = remote.headers?.[0];
31
+ const meta = card._meta ?? {};
32
+ const publicTools = meta['ai.nxis/publicTools'] ?? [];
33
+ return {
34
+ endpoint: remote.url,
35
+ authHeaderName: authHeader?.name,
36
+ authRequired: authHeader?.isRequired ?? false,
37
+ publicTools,
38
+ protocolVersions: remote.supportedProtocolVersions ?? [],
39
+ cardUrl,
40
+ title: card.title,
41
+ };
42
+ }
43
+ //# sourceMappingURL=discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../../src/harness/tools/discovery.ts"],"names":[],"mappings":"AAWA,KAAK,UAAU,SAAS,CAAI,GAAW;IACrC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE,EAAE,CAAC,CAAC;IAC1E,IAAI,CAAC,GAAG,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,OAAO,GAAG,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IAC3D,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAM,CAAC;AACjC,CAAC;AAED,4EAA4E;AAC5E,KAAK,UAAU,oBAAoB;IACjC,MAAM,QAAQ,GAAG,CAAC,8BAA8B,EAAE,2BAA2B,CAAC,CAAC;IAC/E,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,SAAS,CAAc,IAAI,CAAC,CAAC;YACnD,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YACpD,IAAI,KAAK,EAAE,GAAG;gBAAE,OAAO,KAAK,CAAC,GAAG,CAAC;QACnC,CAAC;QAAC,MAAM,CAAC;YACP,0BAA0B;QAC5B,CAAC;IACH,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;AAC1E,CAAC;AAED,+EAA+E;AAC/E,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,MAAM,OAAO,GAAG,MAAM,oBAAoB,EAAE,CAAC;IAC7C,MAAM,IAAI,GAAG,MAAM,SAAS,CAAa,OAAO,CAAC,CAAC;IAElD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,iBAAiB,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;IAC5F,IAAI,CAAC,MAAM,EAAE,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,OAAO,6BAA6B,CAAC,CAAC;IAE1F,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;IACvC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;IAC9B,MAAM,WAAW,GAAI,IAAI,CAAC,qBAAqB,CAA0B,IAAI,EAAE,CAAC;IAEhF,OAAO;QACL,QAAQ,EAAE,MAAM,CAAC,GAAG;QACpB,cAAc,EAAE,UAAU,EAAE,IAAI;QAChC,YAAY,EAAE,UAAU,EAAE,UAAU,IAAI,KAAK;QAC7C,WAAW;QACX,gBAAgB,EAAE,MAAM,CAAC,yBAAyB,IAAI,EAAE;QACxD,OAAO;QACP,KAAK,EAAE,IAAI,CAAC,KAAK;KAClB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * A minimal WebMCP registry, for pages that have none of their own.
3
+ *
4
+ * `document.modelContext` is normally installed by a page script or a browser
5
+ * extension. Where neither is present, discovered remote tools would have
6
+ * nowhere to be registered, and a site with a working MCP server would still
7
+ * offer the agent no tools.
8
+ *
9
+ * Implements only register, list and execute. It does not expose the page's own
10
+ * forms, which come from the page's own script.
11
+ *
12
+ * @module
13
+ */
14
+ import type { ModelContext, ModelContextTool, ModelContextToolInfo, ModelContextToolResponse } from '../../types.js';
15
+ /** Set on the instance so a later, real provider can be told apart from ours. */
16
+ export declare const LOCAL_CONTEXT_FLAG = "__nxisLocalModelContext";
17
+ /**
18
+ * A minimal in-memory tool registry implementing {@link ModelContext}.
19
+ *
20
+ * Installed by {@link ensureModelContext} on pages that have no registry of
21
+ * their own, so that discovered remote tools have somewhere to live.
22
+ */
23
+ export declare class LocalModelContext extends EventTarget implements ModelContext {
24
+ readonly [LOCAL_CONTEXT_FLAG] = true;
25
+ private readonly _tools;
26
+ registerTool(tool: ModelContextTool): void;
27
+ getTools(): Promise<ModelContextToolInfo[]>;
28
+ executeTool(nameOrTool: string | object, input?: string | Record<string, unknown> | null): Promise<ModelContextToolResponse>;
29
+ }
30
+ /**
31
+ * Install a {@link LocalModelContext} on `document` if the page has no registry.
32
+ *
33
+ * Never replaces an existing provider, which owns the page's own action tools.
34
+ *
35
+ * @returns The page's registry, whether pre-existing or newly installed.
36
+ */
37
+ export declare function ensureModelContext(): ModelContext;
38
+ //# sourceMappingURL=local-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-context.d.ts","sourceRoot":"","sources":["../../../src/harness/tools/local-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EACV,YAAY,EACZ,gBAAgB,EAChB,oBAAoB,EACpB,wBAAwB,EACzB,MAAM,gBAAgB,CAAC;AAExB,iFAAiF;AACjF,eAAO,MAAM,kBAAkB,4BAA4B,CAAC;AAE5D;;;;;GAKG;AACH,qBAAa,iBAAkB,SAAQ,WAAY,YAAW,YAAY;IACxE,QAAQ,CAAC,CAAC,kBAAkB,CAAC,QAAQ;IACrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuC;IAE9D,YAAY,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI;IAM1C,QAAQ,IAAI,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAWrC,WAAW,CACf,UAAU,EAAE,MAAM,GAAG,MAAM,EAC3B,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAC9C,OAAO,CAAC,wBAAwB,CAAC;CAUrC;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,IAAI,YAAY,CAMjD"}
@@ -0,0 +1,55 @@
1
+ var _a;
2
+ /** Set on the instance so a later, real provider can be told apart from ours. */
3
+ export const LOCAL_CONTEXT_FLAG = '__nxisLocalModelContext';
4
+ /**
5
+ * A minimal in-memory tool registry implementing {@link ModelContext}.
6
+ *
7
+ * Installed by {@link ensureModelContext} on pages that have no registry of
8
+ * their own, so that discovered remote tools have somewhere to live.
9
+ */
10
+ export class LocalModelContext extends EventTarget {
11
+ constructor() {
12
+ super(...arguments);
13
+ this[_a] = true;
14
+ this._tools = new Map();
15
+ }
16
+ registerTool(tool) {
17
+ this._tools.set(tool.name, tool);
18
+ // Tool discovery listens for this rather than polling to its timeout.
19
+ this.dispatchEvent(new Event('toolchange'));
20
+ }
21
+ getTools() {
22
+ return Promise.resolve([...this._tools.values()].map((t) => ({
23
+ name: t.name,
24
+ description: t.description,
25
+ inputSchema: t.inputSchema,
26
+ annotations: t.annotations,
27
+ })));
28
+ }
29
+ async executeTool(nameOrTool, input) {
30
+ const name = typeof nameOrTool === 'string' ? nameOrTool : nameOrTool.name;
31
+ const tool = this._tools.get(name);
32
+ if (!tool) {
33
+ return { content: [{ type: 'text', text: `Unknown tool: ${name}` }], isError: true };
34
+ }
35
+ const args = typeof input === 'string' ? JSON.parse(input || '{}') : input ?? {};
36
+ return tool.execute(args);
37
+ }
38
+ }
39
+ _a = LOCAL_CONTEXT_FLAG;
40
+ /**
41
+ * Install a {@link LocalModelContext} on `document` if the page has no registry.
42
+ *
43
+ * Never replaces an existing provider, which owns the page's own action tools.
44
+ *
45
+ * @returns The page's registry, whether pre-existing or newly installed.
46
+ */
47
+ export function ensureModelContext() {
48
+ const existing = document.modelContext ?? navigator.modelContext ?? null;
49
+ if (existing)
50
+ return existing;
51
+ const local = new LocalModelContext();
52
+ document.modelContext = local;
53
+ return local;
54
+ }
55
+ //# sourceMappingURL=local-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-context.js","sourceRoot":"","sources":["../../../src/harness/tools/local-context.ts"],"names":[],"mappings":";AAoBA,iFAAiF;AACjF,MAAM,CAAC,MAAM,kBAAkB,GAAG,yBAAyB,CAAC;AAE5D;;;;;GAKG;AACH,MAAM,OAAO,iBAAkB,SAAQ,WAAW;IAAlD;;QACW,QAAoB,GAAG,IAAI,CAAC;QACpB,WAAM,GAAG,IAAI,GAAG,EAA4B,CAAC;IAgChE,CAAC;IA9BC,YAAY,CAAC,IAAsB;QACjC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACjC,sEAAsE;QACtE,IAAI,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC;IAC9C,CAAC;IAED,QAAQ;QACN,OAAO,OAAO,CAAC,OAAO,CACpB,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACpC,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,WAAW,EAAE,CAAC,CAAC,WAAW;YAC1B,WAAW,EAAE,CAAC,CAAC,WAAW;YAC1B,WAAW,EAAE,CAAC,CAAC,WAAW;SAC3B,CAAC,CAAC,CACJ,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,WAAW,CACf,UAA2B,EAC3B,KAA+C;QAE/C,MAAM,IAAI,GAAG,OAAO,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAE,UAA+B,CAAC,IAAI,CAAC;QACjG,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,IAAI,EAAE,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACvF,CAAC;QACD,MAAM,IAAI,GACR,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,IAAI,CAA6B,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACnG,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;CACF;KAjCW,kBAAkB;AAmC9B;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB;IAChC,MAAM,QAAQ,GAAG,QAAQ,CAAC,YAAY,IAAI,SAAS,CAAC,YAAY,IAAI,IAAI,CAAC;IACzE,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC9B,MAAM,KAAK,GAAG,IAAI,iBAAiB,EAAE,CAAC;IACtC,QAAQ,CAAC,YAAY,GAAG,KAAK,CAAC;IAC9B,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Reading a tool's JSON Schema, and reconciling model output against it.
3
+ *
4
+ * Model-agnostic: these helpers work the same whichever provider produced the
5
+ * arguments, so they sit with the harness rather than behind
6
+ * {@link ModelProvider}.
7
+ *
8
+ * @module
9
+ */
10
+ import type { JsonSchema, ModelContextToolInfo, ModelContextToolResponse } from '../../types.js';
11
+ /**
12
+ * Read a tool's input schema, whichever key and form it arrives in.
13
+ *
14
+ * Accepts every alias on {@link ModelContextToolInfo}, parses a schema supplied
15
+ * as a JSON string, merges in any required fields the page's own markup
16
+ * declares, and gives every node a `type` so a chat template that formats types
17
+ * cannot fail on an untyped one.
18
+ *
19
+ * @param tool - The tool as reported by discovery.
20
+ * @returns The normalised schema, or an empty object when there is none.
21
+ */
22
+ export declare function toolSchema(tool: ModelContextToolInfo): JsonSchema;
23
+ /**
24
+ * Which of a tool's required fields have no usable value.
25
+ *
26
+ * @param tool - The tool whose schema declares the requirements.
27
+ * @param args - The arguments so far.
28
+ * @returns Required field names that are absent, null, or blank.
29
+ */
30
+ export declare function missingRequired(tool: ModelContextToolInfo, args: Record<string, unknown> | undefined): string[];
31
+ /**
32
+ * Map a model's argument keys onto the schema's real property names.
33
+ *
34
+ * Models paraphrase field names. Keys are matched exactly first, then
35
+ * case- and punctuation-insensitively, then by prefix, then by shared word.
36
+ * Values matching an enum are snapped to the enum's own casing. A key with no
37
+ * plausible match is passed through unchanged.
38
+ *
39
+ * @param args - The arguments the model supplied.
40
+ * @param schema - The tool's normalised schema.
41
+ * @returns The arguments rekeyed to schema property names.
42
+ */
43
+ export declare function reconcileArgs(args: Record<string, unknown> | undefined, schema: JsonSchema): Record<string, unknown>;
44
+ /**
45
+ * Flatten a tool response to text.
46
+ *
47
+ * @param res - The response, a plain string, or nothing.
48
+ * @returns The response's text blocks joined, or its JSON form when it carries
49
+ * no text. Empty for a null or undefined response.
50
+ */
51
+ export declare function extractResult(res: ModelContextToolResponse | string | null | undefined): string;
52
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/harness/tools/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EACV,UAAU,EACV,oBAAoB,EACpB,wBAAwB,EACzB,MAAM,gBAAgB,CAAC;AAExB;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,oBAAoB,GAAG,UAAU,CAsBjE;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,oBAAoB,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,MAAM,EAAE,CAM/G;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EACzC,MAAM,EAAE,UAAU,GACjB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAkCzB;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,wBAAwB,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAc/F"}
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Read a tool's input schema, whichever key and form it arrives in.
3
+ *
4
+ * Accepts every alias on {@link ModelContextToolInfo}, parses a schema supplied
5
+ * as a JSON string, merges in any required fields the page's own markup
6
+ * declares, and gives every node a `type` so a chat template that formats types
7
+ * cannot fail on an untyped one.
8
+ *
9
+ * @param tool - The tool as reported by discovery.
10
+ * @returns The normalised schema, or an empty object when there is none.
11
+ */
12
+ export function toolSchema(tool) {
13
+ let raw = tool && (tool.inputSchema ?? tool.input_schema ?? tool.parameters ?? tool.schema);
14
+ if (typeof raw === 'string') {
15
+ try {
16
+ raw = JSON.parse(raw);
17
+ }
18
+ catch {
19
+ raw = undefined;
20
+ }
21
+ }
22
+ const schema = raw && typeof raw === 'object' ? raw : {};
23
+ // The page's own markup is authoritative about what is required: a backend
24
+ // schema may omit fields the rendered form still demands.
25
+ const props = schema.properties ? Object.keys(schema.properties) : [];
26
+ if (props.length) {
27
+ const domReq = _domRequired(props);
28
+ if (domReq.length)
29
+ schema.required = [...new Set([...(schema.required || []), ...domReq])];
30
+ }
31
+ // Some schemas declare properties with no `type`. Gemma's tool chat template
32
+ // applies `| upper` to each parameter type and throws on an undefined one, so
33
+ // every node is given a type before prompt building.
34
+ return _normalizeSchema(schema, true);
35
+ }
36
+ /**
37
+ * Which of a tool's required fields have no usable value.
38
+ *
39
+ * @param tool - The tool whose schema declares the requirements.
40
+ * @param args - The arguments so far.
41
+ * @returns Required field names that are absent, null, or blank.
42
+ */
43
+ export function missingRequired(tool, args) {
44
+ const required = toolSchema(tool).required || [];
45
+ return required.filter((k) => {
46
+ const v = args ? args[k] : undefined;
47
+ return v === undefined || v === null || (typeof v === 'string' && v.trim() === '');
48
+ });
49
+ }
50
+ /**
51
+ * Map a model's argument keys onto the schema's real property names.
52
+ *
53
+ * Models paraphrase field names. Keys are matched exactly first, then
54
+ * case- and punctuation-insensitively, then by prefix, then by shared word.
55
+ * Values matching an enum are snapped to the enum's own casing. A key with no
56
+ * plausible match is passed through unchanged.
57
+ *
58
+ * @param args - The arguments the model supplied.
59
+ * @param schema - The tool's normalised schema.
60
+ * @returns The arguments rekeyed to schema property names.
61
+ */
62
+ export function reconcileArgs(args, schema) {
63
+ const props = schema && schema.properties ? Object.keys(schema.properties) : [];
64
+ if (!props.length || !args)
65
+ return args || {};
66
+ const norm = (s) => String(s).toLowerCase().replace(/[^a-z0-9]/g, '');
67
+ const toks = (s) => String(s)
68
+ .toLowerCase()
69
+ .split(/[^a-z0-9]+/)
70
+ .filter(Boolean);
71
+ const out = {};
72
+ for (const [key, value] of Object.entries(args)) {
73
+ if (props.includes(key)) {
74
+ out[key] = _snapEnum(value, schema.properties[key]);
75
+ continue;
76
+ }
77
+ const nk = norm(key);
78
+ let best = props.find((p) => norm(p) === nk);
79
+ if (!best)
80
+ best = props.find((p) => nk.startsWith(norm(p)) || norm(p).startsWith(nk));
81
+ if (!best) {
82
+ const ktoks = new Set(toks(key));
83
+ let bestScore = 0;
84
+ for (const p of props) {
85
+ const score = toks(p).filter((t) => ktoks.has(t)).length;
86
+ if (score > bestScore) {
87
+ bestScore = score;
88
+ best = p;
89
+ }
90
+ }
91
+ if (bestScore === 0)
92
+ best = undefined;
93
+ }
94
+ const targetKey = best || key;
95
+ out[targetKey] = _snapEnum(value, schema.properties[targetKey]);
96
+ }
97
+ return out;
98
+ }
99
+ /**
100
+ * Flatten a tool response to text.
101
+ *
102
+ * @param res - The response, a plain string, or nothing.
103
+ * @returns The response's text blocks joined, or its JSON form when it carries
104
+ * no text. Empty for a null or undefined response.
105
+ */
106
+ export function extractResult(res) {
107
+ if (res == null)
108
+ return '';
109
+ if (typeof res === 'string')
110
+ return res;
111
+ if (Array.isArray(res.content)) {
112
+ return res.content
113
+ .map((c) => (c && c.text) || '')
114
+ .filter(Boolean)
115
+ .join('\n');
116
+ }
117
+ try {
118
+ return JSON.stringify(res);
119
+ }
120
+ catch {
121
+ return String(res);
122
+ }
123
+ }
124
+ // ── internals ───────────────────────────────────────────────────────────────
125
+ /**
126
+ * Give every schema node a `type`, which the chat template requires.
127
+ *
128
+ * Nodes with properties become `object`, nodes with items become `array`, and
129
+ * remaining leaves become `string`. Mutates and returns the schema.
130
+ */
131
+ function _normalizeSchema(schema, isRoot = false) {
132
+ if (!schema || typeof schema !== 'object')
133
+ return schema;
134
+ if (schema.properties && typeof schema.properties === 'object') {
135
+ if (!schema.type)
136
+ schema.type = 'object';
137
+ for (const key of Object.keys(schema.properties))
138
+ _normalizeSchema(schema.properties[key]);
139
+ }
140
+ if (schema.items && typeof schema.items === 'object') {
141
+ if (!schema.type)
142
+ schema.type = 'array';
143
+ _normalizeSchema(schema.items);
144
+ }
145
+ if (!schema.type)
146
+ schema.type = isRoot ? 'object' : 'string';
147
+ if (isRoot && schema.type === 'object' && !schema.properties)
148
+ schema.properties = {};
149
+ return schema;
150
+ }
151
+ /** Which of these property names the page's own markup marks required. */
152
+ function _domRequired(propNames) {
153
+ const out = [];
154
+ for (const name of propNames) {
155
+ let el = null;
156
+ try {
157
+ el = document.querySelector(`[name="${CSS.escape(name)}"]`);
158
+ }
159
+ catch {
160
+ // Not a usable selector.
161
+ }
162
+ if (el && (el.required || el.hasAttribute('data-required')))
163
+ out.push(name);
164
+ }
165
+ return out;
166
+ }
167
+ /** Correct a value's casing to match its schema's enum, when one matches. */
168
+ function _snapEnum(value, propSchema) {
169
+ const enumVals = propSchema && (propSchema.enum || (propSchema.items && propSchema.items.enum));
170
+ if (!enumVals || typeof value !== 'string' || enumVals.includes(value))
171
+ return value;
172
+ const ci = enumVals.find((e) => String(e).toLowerCase() === value.toLowerCase());
173
+ return ci !== undefined ? ci : value;
174
+ }
175
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/harness/tools/schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Assembles the page's toolset from both of its sources.
3
+ *
4
+ * Tools come from two places: those registered on the page itself, and those
5
+ * from a remote MCP server discovered through `.well-known` and bridged in.
6
+ * Both end up in `document.modelContext`, so the harness discovers them with a
7
+ * single call and treats them alike, distinguishing only read from write via
8
+ * each tool's annotations.
9
+ *
10
+ * {@link connectTools} is awaited rather than run as a load-time side effect,
11
+ * so a caller knows when the toolset is complete.
12
+ *
13
+ * @module
14
+ */
15
+ import { registerRemoteTools, type BridgeOptions } from './bridge.js';
16
+ import { connectMcp } from './client.js';
17
+ import { discoverMcpServer } from './discovery.js';
18
+ import type { ModelContext } from '../../types.js';
19
+ /** The outcome of {@link connectTools}. */
20
+ export interface ConnectResult {
21
+ /** The registry the tools were registered into, or null if none was found. */
22
+ modelContext: ModelContext | null;
23
+ /** Remote tool names bridged in. Empty when discovery failed or was skipped. */
24
+ remoteTools: string[];
25
+ /** Why remote tools are absent, when they are. Never fatal. */
26
+ warning?: string;
27
+ }
28
+ /**
29
+ * Wait for a WebMCP provider to appear on the page.
30
+ *
31
+ * @param timeout - How long to wait, in milliseconds.
32
+ * @returns The model context, or null if none appears in time.
33
+ */
34
+ export declare function waitForModelContext(timeout?: number): Promise<ModelContext | null>;
35
+ /** Options for {@link connectTools}. */
36
+ export interface ConnectOptions {
37
+ /** How long to wait for a WebMCP provider before falling back. */
38
+ timeout?: number;
39
+ /**
40
+ * Register into a local registry when the page has no WebMCP provider.
41
+ *
42
+ * Defaults to true, so a working MCP server still yields tools on a page with
43
+ * no WebMCP implementation. Pass false to require a real provider.
44
+ */
45
+ fallback?: boolean;
46
+ /** Override which of the server's tools are bridged in. */
47
+ accept?: BridgeOptions['accept'];
48
+ }
49
+ /**
50
+ * Wait for a tool registry, then bridge in a remote MCP server's tools.
51
+ *
52
+ * Every remote failure is caught and reported as
53
+ * {@link ConnectResult.warning}: discovery, CORS and network problems leave the
54
+ * page's own tools working, and a site with no MCP server is an ordinary case
55
+ * rather than an error.
56
+ *
57
+ * @param apiKey - Key for the remote server's private tools. Falls back to
58
+ * `window.__NXIS_CONFIG__.mcp_api_key`. Public tools need none.
59
+ * @param opts - Timeout, local-registry fallback, and a tool filter.
60
+ * @returns The registry, the remote tools bridged in, and any warning.
61
+ */
62
+ export declare function connectTools(apiKey?: string, opts?: ConnectOptions): Promise<ConnectResult>;
63
+ export { discoverMcpServer, connectMcp, registerRemoteTools };
64
+ export { ensureModelContext, LocalModelContext } from './local-context.js';
65
+ //# sourceMappingURL=source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../../src/harness/tools/source.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,mBAAmB,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAEtE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAKnD,2CAA2C;AAC3C,MAAM,WAAW,aAAa;IAC5B,8EAA8E;IAC9E,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,gFAAgF;IAChF,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,+DAA+D;IAC/D,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAOD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,SAAmB,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAgB5F;AAED,wCAAwC;AACxC,MAAM,WAAW,cAAc;IAC7B,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;CAClC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,YAAY,CAChC,MAAM,CAAC,EAAE,MAAM,EACf,IAAI,GAAE,cAAmB,GACxB,OAAO,CAAC,aAAa,CAAC,CAyBxB;AAED,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,mBAAmB,EAAE,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Assembles the page's toolset from both of its sources.
3
+ *
4
+ * Tools come from two places: those registered on the page itself, and those
5
+ * from a remote MCP server discovered through `.well-known` and bridged in.
6
+ * Both end up in `document.modelContext`, so the harness discovers them with a
7
+ * single call and treats them alike, distinguishing only read from write via
8
+ * each tool's annotations.
9
+ *
10
+ * {@link connectTools} is awaited rather than run as a load-time side effect,
11
+ * so a caller knows when the toolset is complete.
12
+ *
13
+ * @module
14
+ */
15
+ import { registerRemoteTools } from './bridge.js';
16
+ import { ensureModelContext } from './local-context.js';
17
+ import { connectMcp } from './client.js';
18
+ import { discoverMcpServer } from './discovery.js';
19
+ const READY_TIMEOUT_MS = 20000;
20
+ const POLL_INTERVAL_MS = 200;
21
+ /** The page's model context, from either of the two places it may appear. */
22
+ function getModelContext() {
23
+ return document.modelContext ?? navigator.modelContext ?? null;
24
+ }
25
+ /**
26
+ * Wait for a WebMCP provider to appear on the page.
27
+ *
28
+ * @param timeout - How long to wait, in milliseconds.
29
+ * @returns The model context, or null if none appears in time.
30
+ */
31
+ export function waitForModelContext(timeout = READY_TIMEOUT_MS) {
32
+ const immediate = getModelContext();
33
+ if (immediate)
34
+ return Promise.resolve(immediate);
35
+ return new Promise((resolve) => {
36
+ const started = Date.now();
37
+ const iv = setInterval(() => {
38
+ const mc = getModelContext();
39
+ if (mc) {
40
+ clearInterval(iv);
41
+ resolve(mc);
42
+ }
43
+ else if (Date.now() - started > timeout) {
44
+ clearInterval(iv);
45
+ resolve(null);
46
+ }
47
+ }, POLL_INTERVAL_MS);
48
+ });
49
+ }
50
+ /**
51
+ * Wait for a tool registry, then bridge in a remote MCP server's tools.
52
+ *
53
+ * Every remote failure is caught and reported as
54
+ * {@link ConnectResult.warning}: discovery, CORS and network problems leave the
55
+ * page's own tools working, and a site with no MCP server is an ordinary case
56
+ * rather than an error.
57
+ *
58
+ * @param apiKey - Key for the remote server's private tools. Falls back to
59
+ * `window.__NXIS_CONFIG__.mcp_api_key`. Public tools need none.
60
+ * @param opts - Timeout, local-registry fallback, and a tool filter.
61
+ * @returns The registry, the remote tools bridged in, and any warning.
62
+ */
63
+ export async function connectTools(apiKey, opts = {}) {
64
+ const waited = await waitForModelContext(opts.timeout ?? READY_TIMEOUT_MS);
65
+ const mc = waited ?? (opts.fallback === false ? null : ensureModelContext());
66
+ if (!mc) {
67
+ return {
68
+ modelContext: null,
69
+ remoteTools: [],
70
+ warning: 'WebMCP (document.modelContext) unavailable — no tools registered.',
71
+ };
72
+ }
73
+ try {
74
+ const info = await discoverMcpServer();
75
+ const client = await connectMcp(info, apiKey ?? window.__NXIS_CONFIG__?.mcp_api_key);
76
+ const remoteTools = await registerRemoteTools(client, mc, info, { accept: opts.accept });
77
+ return { modelContext: mc, remoteTools };
78
+ }
79
+ catch (err) {
80
+ return {
81
+ modelContext: mc,
82
+ remoteTools: [],
83
+ warning: `remote tool bootstrap failed — on-page tools still work: ${String(err?.message || err)}`,
84
+ };
85
+ }
86
+ }
87
+ export { discoverMcpServer, connectMcp, registerRemoteTools };
88
+ export { ensureModelContext, LocalModelContext } from './local-context.js';
89
+ //# sourceMappingURL=source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source.js","sourceRoot":"","sources":["../../../src/harness/tools/source.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,mBAAmB,EAAsB,MAAM,aAAa,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAGnD,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAC/B,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAY7B,6EAA6E;AAC7E,SAAS,eAAe;IACtB,OAAO,QAAQ,CAAC,YAAY,IAAI,SAAS,CAAC,YAAY,IAAI,IAAI,CAAC;AACjE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAO,GAAG,gBAAgB;IAC5D,MAAM,SAAS,GAAG,eAAe,EAAE,CAAC;IACpC,IAAI,SAAS;QAAE,OAAO,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACjD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC3B,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE;YAC1B,MAAM,EAAE,GAAG,eAAe,EAAE,CAAC;YAC7B,IAAI,EAAE,EAAE,CAAC;gBACP,aAAa,CAAC,EAAE,CAAC,CAAC;gBAClB,OAAO,CAAC,EAAE,CAAC,CAAC;YACd,CAAC;iBAAM,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,GAAG,OAAO,EAAE,CAAC;gBAC1C,aAAa,CAAC,EAAE,CAAC,CAAC;gBAClB,OAAO,CAAC,IAAI,CAAC,CAAC;YAChB,CAAC;QACH,CAAC,EAAE,gBAAgB,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;AACL,CAAC;AAiBD;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,MAAe,EACf,OAAuB,EAAE;IAEzB,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,IAAI,CAAC,OAAO,IAAI,gBAAgB,CAAC,CAAC;IAC3E,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,kBAAkB,EAAE,CAAC,CAAC;IAC7E,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,OAAO;YACL,YAAY,EAAE,IAAI;YAClB,WAAW,EAAE,EAAE;YACf,OAAO,EAAE,mEAAmE;SAC7E,CAAC;IACJ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,iBAAiB,EAAE,CAAC;QACvC,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,MAAM,IAAI,MAAM,CAAC,eAAe,EAAE,WAAW,CAAC,CAAC;QACrF,MAAM,WAAW,GAAG,MAAM,mBAAmB,CAAC,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QACzF,OAAO,EAAE,YAAY,EAAE,EAAE,EAAE,WAAW,EAAE,CAAC;IAC3C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,YAAY,EAAE,EAAE;YAChB,WAAW,EAAE,EAAE;YACf,OAAO,EAAE,4DAA4D,MAAM,CACxE,GAAa,EAAE,OAAO,IAAI,GAAG,CAC/B,EAAE;SACJ,CAAC;IACJ,CAAC;AACH,CAAC;AAED,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,mBAAmB,EAAE,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,50 @@
1
+ import type { ModelContext, ModelContextToolInfo, ModelContextToolResponse } from '../../types.js';
2
+ /**
3
+ * The default tool source, backed by the page's `document.modelContext`.
4
+ *
5
+ * Supply an instance as {@link HarnessOptions.toolSource}, or substitute any
6
+ * object with the same shape to draw tools from somewhere else.
7
+ */
8
+ export declare class WebMcpTools {
9
+ /**
10
+ * The page's model context.
11
+ *
12
+ * @returns The context, or null on a page where WebMCP is not present.
13
+ */
14
+ modelContext(): ModelContext | null;
15
+ /**
16
+ * Wait for tools to appear on a model context.
17
+ *
18
+ * Tools register asynchronously, so a context can be present but empty for a
19
+ * short time after page load. Polls, and also listens for `toolchange`.
20
+ *
21
+ * @param mc - The context to watch.
22
+ * @param signal - Abort to stop waiting early. Resolves empty when aborted.
23
+ * @returns The registered tools, or an empty array if none appear within
24
+ * {@link TOOLS_TIMEOUT_MS}.
25
+ */
26
+ waitForTools(mc: ModelContext, signal?: AbortSignal): Promise<ModelContextToolInfo[]>;
27
+ /**
28
+ * Every tool registered on the page.
29
+ *
30
+ * @param signal - Abort to stop waiting for tools to appear.
31
+ * @returns The registered tools, or an empty array when WebMCP is absent,
32
+ * discovery fails, or the wait is aborted.
33
+ */
34
+ discoverTools(signal?: AbortSignal): Promise<ModelContextToolInfo[]>;
35
+ /**
36
+ * Call a tool.
37
+ *
38
+ * Handles both the native calling convention (a registered tool object and a
39
+ * JSON string) and the polyfill's (a name and an object), trying the native
40
+ * form first and falling back when the context rejects it.
41
+ *
42
+ * @param toolObj - The tool as reported by discovery, or null to call by name.
43
+ * @param name - The tool's name, used for the fallback call.
44
+ * @param args - The arguments to send.
45
+ * @returns The tool's response.
46
+ * @throws If WebMCP is not available, or the tool itself throws.
47
+ */
48
+ execTool(toolObj: ModelContextToolInfo | null, name: string, args: Record<string, unknown>): Promise<ModelContextToolResponse>;
49
+ }
50
+ //# sourceMappingURL=webmcp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webmcp.d.ts","sourceRoot":"","sources":["../../../src/harness/tools/webmcp.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,YAAY,EACZ,oBAAoB,EACpB,wBAAwB,EACzB,MAAM,gBAAgB,CAAC;AAExB;;;;;GAKG;AACH,qBAAa,WAAW;IACtB;;;;OAIG;IACH,YAAY,IAAI,YAAY,GAAG,IAAI;IAInC;;;;;;;;;;OAUG;IACH,YAAY,CAAC,EAAE,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IA2BrF;;;;;;OAMG;IACG,aAAa,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAU1E;;;;;;;;;;;;OAYG;IACG,QAAQ,CACZ,OAAO,EAAE,oBAAoB,GAAG,IAAI,EACpC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,wBAAwB,CAAC;CAcrC"}