@iloveagents/foundry-agent 0.17.0 → 0.19.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.
@@ -24,22 +24,31 @@ export interface ClientToolEntry {
24
24
  }
25
25
  interface ClientToolRegistryState {
26
26
  globalTools: Map<string, ClientToolEntry>;
27
+ /** Tools the host page registered (replaced wholesale by `registerPageTools`). */
27
28
  pageTools: Map<string, ClientToolEntry>;
28
- /** Register a global tool (called once at app init) */
29
+ /** Tools contributed by components on the page (survive host re-registration). */
30
+ contributedTools: Map<string, ClientToolEntry>;
29
31
  registerGlobal: (tool: ClientToolEntry) => void;
30
- /** Register page-scoped tools (called by the host on mount) */
32
+ /** Replace the host page's tool catalogue (called by the host on navigation / capability change). */
31
33
  registerPageTools: (tools: ClientToolEntry[]) => void;
32
- /** Remove page-scoped tools (called by the host on unmount) */
34
+ /**
35
+ * Merge page-scoped tools by name, keeping the ones already registered —
36
+ * for components (a list, a panel) that contribute their own tools next
37
+ * to the page's. A contributed tool shadows a host tool of the same name
38
+ * while mounted. Pair with `removePageTools` on unmount.
39
+ */
40
+ addPageTools: (tools: ClientToolEntry[]) => void;
41
+ /** Drop contributed tools by name (a contributing component unmounted). */
42
+ removePageTools: (names: string[]) => void;
43
+ /** Every page-scoped tool: host tools, then contributed ones (which win by name). */
44
+ listPageTools: () => ClientToolEntry[];
45
+ /** Remove page-scoped tools — host and contributed (called by the host on unmount). */
33
46
  clearPageTools: () => void;
34
- /** Get all active tool schemas for the runner */
35
47
  getActiveSchemas: () => AGUITool[];
36
- /** Check if a tool name is registered */
37
48
  isRegistered: (name: string) => boolean;
38
- /** Execute a registered tool by name */
39
49
  executeTool: (name: string, argsJson: string) => Promise<string>;
40
50
  }
41
51
  export declare const clientToolRegistry: import("zustand/vanilla").StoreApi<ClientToolRegistryState>;
42
- /** Read-only registry view — what the runner consumes. */
43
52
  export interface ToolRegistry {
44
53
  isRegistered: (name: string) => boolean;
45
54
  executeTool: (name: string, argsJson: string) => Promise<string>;
@@ -2,6 +2,7 @@ import { createStore } from "zustand/vanilla";
2
2
  export const clientToolRegistry = createStore((set, get) => ({
3
3
  globalTools: new Map(),
4
4
  pageTools: new Map(),
5
+ contributedTools: new Map(),
5
6
  registerGlobal: (tool) => {
6
7
  const { globalTools } = get();
7
8
  const next = new Map(globalTools);
@@ -15,18 +16,41 @@ export const clientToolRegistry = createStore((set, get) => ({
15
16
  }
16
17
  set({ pageTools: next });
17
18
  },
19
+ addPageTools: (tools) => {
20
+ const next = new Map(get().contributedTools);
21
+ for (const tool of tools) {
22
+ next.set(tool.name, tool);
23
+ }
24
+ set({ contributedTools: next });
25
+ },
26
+ removePageTools: (names) => {
27
+ const { contributedTools } = get();
28
+ if (!names.some((name) => contributedTools.has(name)))
29
+ return;
30
+ const next = new Map(contributedTools);
31
+ for (const name of names) {
32
+ next.delete(name);
33
+ }
34
+ set({ contributedTools: next });
35
+ },
36
+ listPageTools: () => {
37
+ const { pageTools, contributedTools } = get();
38
+ const merged = new Map(pageTools);
39
+ for (const tool of contributedTools.values()) {
40
+ merged.set(tool.name, tool);
41
+ }
42
+ return Array.from(merged.values());
43
+ },
18
44
  clearPageTools: () => {
19
- set({ pageTools: new Map() });
45
+ set({ pageTools: new Map(), contributedTools: new Map() });
20
46
  },
21
47
  getActiveSchemas: () => {
22
- const { globalTools, pageTools } = get();
23
- // Merge: page tools override global tools with the same name
24
48
  const merged = new Map();
25
- for (const tool of globalTools.values()) {
49
+ for (const tool of get().globalTools.values()) {
26
50
  merged.set(tool.name, tool);
27
51
  }
28
- for (const tool of pageTools.values()) {
29
- merged.set(tool.name, tool); // page overrides global
52
+ for (const tool of get().listPageTools()) {
53
+ merged.set(tool.name, tool); // page overrides global, contributed overrides page
30
54
  }
31
55
  return Array.from(merged.values()).map((tool) => ({
32
56
  name: tool.name,
@@ -35,13 +59,12 @@ export const clientToolRegistry = createStore((set, get) => ({
35
59
  }));
36
60
  },
37
61
  isRegistered: (name) => {
38
- const { globalTools, pageTools } = get();
39
- return pageTools.has(name) || globalTools.has(name);
62
+ const { globalTools, pageTools, contributedTools } = get();
63
+ return contributedTools.has(name) || pageTools.has(name) || globalTools.has(name);
40
64
  },
41
65
  executeTool: async (name, argsJson) => {
42
- const { globalTools, pageTools } = get();
43
- // Page tools take precedence
44
- const tool = pageTools.get(name) ?? globalTools.get(name);
66
+ const { globalTools, pageTools, contributedTools } = get();
67
+ const tool = contributedTools.get(name) ?? pageTools.get(name) ?? globalTools.get(name);
45
68
  if (!tool) {
46
69
  return JSON.stringify({ error: `Unknown client tool: ${name}` });
47
70
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iloveagents/foundry-agent",
3
- "version": "0.17.0",
3
+ "version": "0.19.0",
4
4
  "license": "MIT",
5
5
  "description": "Cross-runtime AG-UI transport for Foundry UI — AGUIRunner protocol engine, vanilla zustand stores, optional MSAL auth subpath, service-fetch factory. Zero React, zero DOM.",
6
6
  "keywords": [