@illuma-ai/agents 1.4.0-alpha.3 → 1.4.0-alpha.4
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/dist/cjs/providers/tools-server/ToolsServerCapabilityProvider.cjs +4 -0
- package/dist/cjs/providers/tools-server/ToolsServerCapabilityProvider.cjs.map +1 -1
- package/dist/cjs/providers/types.cjs.map +1 -1
- package/dist/cjs/tools/artifacts/schema.cjs +30 -7
- package/dist/cjs/tools/artifacts/schema.cjs.map +1 -1
- package/dist/cjs/tools/artifacts/tool.cjs +8 -2
- package/dist/cjs/tools/artifacts/tool.cjs.map +1 -1
- package/dist/esm/providers/tools-server/ToolsServerCapabilityProvider.mjs +4 -0
- package/dist/esm/providers/tools-server/ToolsServerCapabilityProvider.mjs.map +1 -1
- package/dist/esm/providers/types.mjs.map +1 -1
- package/dist/esm/tools/artifacts/schema.mjs +30 -7
- package/dist/esm/tools/artifacts/schema.mjs.map +1 -1
- package/dist/esm/tools/artifacts/tool.mjs +8 -2
- package/dist/esm/tools/artifacts/tool.mjs.map +1 -1
- package/dist/types/providers/types.d.ts +14 -0
- package/package.json +1 -1
- package/src/providers/tools-server/ToolsServerCapabilityProvider.ts +8 -0
- package/src/providers/types.ts +17 -0
- package/src/tools/artifacts/__tests__/tool.test.ts +31 -15
- package/src/tools/artifacts/schema.ts +36 -13
- package/src/tools/artifacts/tool.ts +28 -16
- package/src/tools/artifacts/types.ts +18 -5
|
@@ -113,6 +113,10 @@ function normalizeEntry(entry) {
|
|
|
113
113
|
icon: entry.icon,
|
|
114
114
|
category: entry.category,
|
|
115
115
|
tags: entry.tags,
|
|
116
|
+
// Governance — hosts use these to gate UI/role/environment.
|
|
117
|
+
hidden: entry.hidden,
|
|
118
|
+
admin: entry.admin,
|
|
119
|
+
env: entry.env,
|
|
116
120
|
},
|
|
117
121
|
};
|
|
118
122
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToolsServerCapabilityProvider.cjs","sources":["../../../../src/providers/tools-server/ToolsServerCapabilityProvider.ts"],"sourcesContent":["/**\n * ToolsServerCapabilityProvider — capabilities sourced from a tools-server\n * HTTP endpoint.\n *\n * Fetches the manifest via GET /manifest, builds proxy StructuredTools via\n * POST /execute/:tool. Manifest is cached (TTL-configurable) so repeated\n * init cycles don't refetch.\n *\n * See docs/architecture-capability-layer.md for the design rationale.\n */\n\nimport type { AxiosInstance } from 'axios';\nimport type { StructuredToolInterface } from '@langchain/core/tools';\nimport {\n CapabilityKind,\n type Capability,\n type CapabilityFilter,\n type CapabilityProvider,\n type CredentialMap,\n} from '@/providers/types';\nimport {\n createHttpClient,\n type HttpClientConfig,\n assertOk,\n} from '@/utils/httpClient';\nimport {\n ManifestCache,\n filterToCacheKey,\n applyFilter,\n} from '@/utils/toolManifest';\nimport { buildProxyTool } from '@/tools/proxyTool';\n\n/** Configuration for ToolsServerCapabilityProvider. */\nexport interface ToolsServerConfig {\n /** Tools-server base URL (e.g., https://tools.illuma.ai or http://localhost:3500). */\n baseUrl: string;\n /** API key sent as x-api-key header on all requests. Required. */\n apiKey: string;\n /** Optional override for manifest path. Defaults to `/manifest`. */\n manifestPath?: string;\n /** Optional override for execute path template. Defaults to `/execute/:name`. */\n executePath?: string;\n /** Request timeout in ms. Defaults to 30_000. */\n timeoutMs?: number;\n /** Manifest cache TTL in ms. 0 disables. Defaults to 60_000 (1 min). */\n manifestTtlMs?: number;\n /** Optional pre-built axios instance (for testing). */\n client?: AxiosInstance;\n /** Optional proxy override (defaults to process.env.PROXY). */\n proxy?: string | null;\n}\n\n/**\n * Shape of a single entry from tools-server's /manifest response.\n *\n * Matches the tools-server ManifestToolEntry type. We define our own here\n * to avoid cross-package coupling — the shape is a stable HTTP contract.\n */\ninterface ToolsServerManifestEntry {\n pluginKey: string;\n name: string;\n description: string;\n icon?: string;\n authConfig?: Array<{\n authField: string;\n label?: string;\n description?: string;\n source?: string;\n required?: boolean;\n prod?: boolean;\n admin?: boolean;\n hide?: boolean;\n }>;\n /** Input schema as JSON Schema (tools-server emits `schema`). */\n schema?: unknown;\n /** Legacy alias accepted for backwards compatibility. */\n jsonSchema?: unknown;\n category?: string;\n tags?: string[];\n toolkit?: string;\n endpoint?: string;\n}\n\nexport class ToolsServerCapabilityProvider implements CapabilityProvider {\n readonly providerId: string;\n private readonly client: AxiosInstance;\n private readonly manifestPath: string;\n private readonly executePath: string;\n private readonly cache: ManifestCache;\n\n constructor(private readonly config: ToolsServerConfig) {\n const {\n baseUrl,\n apiKey,\n manifestPath = '/manifest',\n executePath = '/execute/:name',\n timeoutMs = 30_000,\n manifestTtlMs = 60_000,\n client,\n proxy,\n } = config;\n\n if (!baseUrl) {\n throw new Error('ToolsServerCapabilityProvider: baseUrl is required');\n }\n if (!apiKey) {\n throw new Error('ToolsServerCapabilityProvider: apiKey is required');\n }\n\n this.providerId = `tools-server:${baseUrl}`;\n this.manifestPath = manifestPath;\n this.executePath = executePath;\n this.cache = new ManifestCache({ ttlMs: manifestTtlMs });\n\n if (client) {\n this.client = client;\n } else {\n const httpConfig: HttpClientConfig = {\n baseURL: baseUrl,\n apiKey,\n timeoutMs,\n proxy,\n };\n this.client = createHttpClient(httpConfig);\n }\n }\n\n async fetchManifest(filter?: CapabilityFilter): Promise<Capability[]> {\n const cacheKey = filterToCacheKey(filter);\n const cached = this.cache.get(cacheKey);\n if (cached) {\n // DEBUG: cache hit (remove after stabilization)\n // eslint-disable-next-line no-console\n console.debug(\n `[${this.providerId}] manifest cache hit — ${cached.length} caps`\n );\n return cached;\n }\n\n // DEBUG\n // eslint-disable-next-line no-console\n console.debug(\n `[${this.providerId}] fetching manifest from ${this.manifestPath}`\n );\n\n const res = await this.client.get<ToolsServerManifestEntry[]>(\n this.manifestPath\n );\n assertOk(res.status, this.manifestPath, res.data);\n\n const entries = Array.isArray(res.data) ? res.data : [];\n const capabilities: Capability[] = entries.map((entry) =>\n normalizeEntry(entry)\n );\n\n // Apply filter before caching the full list separately so unfiltered\n // refetches don't re-hit the network.\n const fullCacheKey = filterToCacheKey();\n this.cache.set(fullCacheKey, capabilities);\n\n const filtered = applyFilter(capabilities, filter);\n if (cacheKey !== fullCacheKey) {\n this.cache.set(cacheKey, filtered);\n }\n\n // DEBUG\n // eslint-disable-next-line no-console\n console.debug(\n `[${this.providerId}] manifest loaded — ${capabilities.length} caps, ${filtered.length} after filter`\n );\n\n return filtered;\n }\n\n async createRunnables(\n capabilities: Capability[],\n credentials: CredentialMap\n ): Promise<StructuredToolInterface[]> {\n return capabilities.map((cap) =>\n buildProxyTool(cap, credentials, {\n client: this.client,\n executePath: this.executePath,\n })\n );\n }\n\n /** Force a manifest refresh on next fetchManifest call. */\n invalidateCache(): void {\n this.cache.clear();\n }\n}\n\n/**\n * Translate a raw tools-server manifest entry into a typed Capability.\n * Defensive — tools-server may add fields; we pull only what we need.\n */\nfunction normalizeEntry(entry: ToolsServerManifestEntry): Capability {\n return {\n kind: CapabilityKind.TOOL,\n name: entry.pluginKey,\n description: entry.description ?? '',\n schema: entry.schema ?? entry.jsonSchema,\n authConfig: (entry.authConfig ?? []).map((ac) => ({\n authField: ac.authField,\n label: ac.label,\n description: ac.description,\n required: ac.required,\n prod: ac.prod,\n admin: ac.admin,\n hide: ac.hide,\n // Source is a string in wire format; downstream consumers coerce to AuthSource.\n source: ac.source as Capability['authConfig'][number]['source'],\n })),\n metadata: {\n icon: entry.icon,\n category: entry.category,\n tags: entry.tags,\n },\n };\n}\n"],"names":["ManifestCache","createHttpClient","filterToCacheKey","assertOk","applyFilter","buildProxyTool","CapabilityKind"],"mappings":";;;;;;;AAAA;;;;;;;;;AASG;MA0EU,6BAA6B,CAAA;AAOX,IAAA,MAAA;AANpB,IAAA,UAAU;AACF,IAAA,MAAM;AACN,IAAA,YAAY;AACZ,IAAA,WAAW;AACX,IAAA,KAAK;AAEtB,IAAA,WAAA,CAA6B,MAAyB,EAAA;QAAzB,IAAA,CAAA,MAAM,GAAN,MAAM;QACjC,MAAM,EACJ,OAAO,EACP,MAAM,EACN,YAAY,GAAG,WAAW,EAC1B,WAAW,GAAG,gBAAgB,EAC9B,SAAS,GAAG,MAAM,EAClB,aAAa,GAAG,MAAM,EACtB,MAAM,EACN,KAAK,GACN,GAAG,MAAM;QAEV,IAAI,CAAC,OAAO,EAAE;AACZ,YAAA,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC;QACvE;QACA,IAAI,CAAC,MAAM,EAAE;AACX,YAAA,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC;QACtE;AAEA,QAAA,IAAI,CAAC,UAAU,GAAG,CAAA,aAAA,EAAgB,OAAO,EAAE;AAC3C,QAAA,IAAI,CAAC,YAAY,GAAG,YAAY;AAChC,QAAA,IAAI,CAAC,WAAW,GAAG,WAAW;AAC9B,QAAA,IAAI,CAAC,KAAK,GAAG,IAAIA,0BAAa,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;QAExD,IAAI,MAAM,EAAE;AACV,YAAA,IAAI,CAAC,MAAM,GAAG,MAAM;QACtB;aAAO;AACL,YAAA,MAAM,UAAU,GAAqB;AACnC,gBAAA,OAAO,EAAE,OAAO;gBAChB,MAAM;gBACN,SAAS;gBACT,KAAK;aACN;AACD,YAAA,IAAI,CAAC,MAAM,GAAGC,2BAAgB,CAAC,UAAU,CAAC;QAC5C;IACF;IAEA,MAAM,aAAa,CAAC,MAAyB,EAAA;AAC3C,QAAA,MAAM,QAAQ,GAAGC,6BAAgB,CAAC,MAAM,CAAC;QACzC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC;QACvC,IAAI,MAAM,EAAE;;;AAGV,YAAA,OAAO,CAAC,KAAK,CACX,CAAA,CAAA,EAAI,IAAI,CAAC,UAAU,CAAA,uBAAA,EAA0B,MAAM,CAAC,MAAM,CAAA,KAAA,CAAO,CAClE;AACD,YAAA,OAAO,MAAM;QACf;;;AAIA,QAAA,OAAO,CAAC,KAAK,CACX,CAAA,CAAA,EAAI,IAAI,CAAC,UAAU,CAAA,yBAAA,EAA4B,IAAI,CAAC,YAAY,CAAA,CAAE,CACnE;AAED,QAAA,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAC/B,IAAI,CAAC,YAAY,CAClB;AACD,QAAAC,mBAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,GAAG,CAAC,IAAI,CAAC;QAEjD,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,IAAI,GAAG,EAAE;AACvD,QAAA,MAAM,YAAY,GAAiB,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,KACnD,cAAc,CAAC,KAAK,CAAC,CACtB;;;AAID,QAAA,MAAM,YAAY,GAAGD,6BAAgB,EAAE;QACvC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,EAAE,YAAY,CAAC;QAE1C,MAAM,QAAQ,GAAGE,wBAAW,CAAC,YAAY,EAAE,MAAM,CAAC;AAClD,QAAA,IAAI,QAAQ,KAAK,YAAY,EAAE;YAC7B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC;QACpC;;;AAIA,QAAA,OAAO,CAAC,KAAK,CACX,CAAA,CAAA,EAAI,IAAI,CAAC,UAAU,CAAA,oBAAA,EAAuB,YAAY,CAAC,MAAM,CAAA,OAAA,EAAU,QAAQ,CAAC,MAAM,CAAA,aAAA,CAAe,CACtG;AAED,QAAA,OAAO,QAAQ;IACjB;AAEA,IAAA,MAAM,eAAe,CACnB,YAA0B,EAC1B,WAA0B,EAAA;AAE1B,QAAA,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC,GAAG,KAC1BC,wBAAc,CAAC,GAAG,EAAE,WAAW,EAAE;YAC/B,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,WAAW,EAAE,IAAI,CAAC,WAAW;AAC9B,SAAA,CAAC,CACH;IACH;;IAGA,eAAe,GAAA;AACb,QAAA,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE;IACpB;AACD;AAED;;;AAGG;AACH,SAAS,cAAc,CAAC,KAA+B,EAAA;IACrD,OAAO;QACL,IAAI,EAAEC,oBAAc,CAAC,IAAI;QACzB,IAAI,EAAE,KAAK,CAAC,SAAS;AACrB,QAAA,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,EAAE;AACpC,QAAA,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,UAAU;AACxC,QAAA,UAAU,EAAE,CAAC,KAAK,CAAC,UAAU,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC,EAAE,MAAM;YAChD,SAAS,EAAE,EAAE,CAAC,SAAS;YACvB,KAAK,EAAE,EAAE,CAAC,KAAK;YACf,WAAW,EAAE,EAAE,CAAC,WAAW;YAC3B,QAAQ,EAAE,EAAE,CAAC,QAAQ;YACrB,IAAI,EAAE,EAAE,CAAC,IAAI;YACb,KAAK,EAAE,EAAE,CAAC,KAAK;YACf,IAAI,EAAE,EAAE,CAAC,IAAI;;YAEb,MAAM,EAAE,EAAE,CAAC,MAAoD;AAChE,SAAA,CAAC,CAAC;AACH,QAAA,QAAQ,EAAE;YACR,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,IAAI,EAAE,KAAK,CAAC,IAAI;AACjB,SAAA;KACF;AACH;;;;"}
|
|
1
|
+
{"version":3,"file":"ToolsServerCapabilityProvider.cjs","sources":["../../../../src/providers/tools-server/ToolsServerCapabilityProvider.ts"],"sourcesContent":["/**\n * ToolsServerCapabilityProvider — capabilities sourced from a tools-server\n * HTTP endpoint.\n *\n * Fetches the manifest via GET /manifest, builds proxy StructuredTools via\n * POST /execute/:tool. Manifest is cached (TTL-configurable) so repeated\n * init cycles don't refetch.\n *\n * See docs/architecture-capability-layer.md for the design rationale.\n */\n\nimport type { AxiosInstance } from 'axios';\nimport type { StructuredToolInterface } from '@langchain/core/tools';\nimport {\n CapabilityKind,\n type Capability,\n type CapabilityFilter,\n type CapabilityProvider,\n type CredentialMap,\n} from '@/providers/types';\nimport {\n createHttpClient,\n type HttpClientConfig,\n assertOk,\n} from '@/utils/httpClient';\nimport {\n ManifestCache,\n filterToCacheKey,\n applyFilter,\n} from '@/utils/toolManifest';\nimport { buildProxyTool } from '@/tools/proxyTool';\n\n/** Configuration for ToolsServerCapabilityProvider. */\nexport interface ToolsServerConfig {\n /** Tools-server base URL (e.g., https://tools.illuma.ai or http://localhost:3500). */\n baseUrl: string;\n /** API key sent as x-api-key header on all requests. Required. */\n apiKey: string;\n /** Optional override for manifest path. Defaults to `/manifest`. */\n manifestPath?: string;\n /** Optional override for execute path template. Defaults to `/execute/:name`. */\n executePath?: string;\n /** Request timeout in ms. Defaults to 30_000. */\n timeoutMs?: number;\n /** Manifest cache TTL in ms. 0 disables. Defaults to 60_000 (1 min). */\n manifestTtlMs?: number;\n /** Optional pre-built axios instance (for testing). */\n client?: AxiosInstance;\n /** Optional proxy override (defaults to process.env.PROXY). */\n proxy?: string | null;\n}\n\n/**\n * Shape of a single entry from tools-server's /manifest response.\n *\n * Matches the tools-server ManifestToolEntry type. We define our own here\n * to avoid cross-package coupling — the shape is a stable HTTP contract.\n */\ninterface ToolsServerManifestEntry {\n pluginKey: string;\n name: string;\n description: string;\n icon?: string;\n authConfig?: Array<{\n authField: string;\n label?: string;\n description?: string;\n source?: string;\n required?: boolean;\n prod?: boolean;\n admin?: boolean;\n hide?: boolean;\n }>;\n /** Input schema as JSON Schema (tools-server emits `schema`). */\n schema?: unknown;\n /** Legacy alias accepted for backwards compatibility. */\n jsonSchema?: unknown;\n category?: string;\n tags?: string[];\n toolkit?: string;\n endpoint?: string;\n /** Governance flags forwarded by tools-server getManifest(). */\n hidden?: boolean;\n admin?: boolean;\n env?: Array<'development' | 'production' | 'test' | 'staging'>;\n}\n\nexport class ToolsServerCapabilityProvider implements CapabilityProvider {\n readonly providerId: string;\n private readonly client: AxiosInstance;\n private readonly manifestPath: string;\n private readonly executePath: string;\n private readonly cache: ManifestCache;\n\n constructor(private readonly config: ToolsServerConfig) {\n const {\n baseUrl,\n apiKey,\n manifestPath = '/manifest',\n executePath = '/execute/:name',\n timeoutMs = 30_000,\n manifestTtlMs = 60_000,\n client,\n proxy,\n } = config;\n\n if (!baseUrl) {\n throw new Error('ToolsServerCapabilityProvider: baseUrl is required');\n }\n if (!apiKey) {\n throw new Error('ToolsServerCapabilityProvider: apiKey is required');\n }\n\n this.providerId = `tools-server:${baseUrl}`;\n this.manifestPath = manifestPath;\n this.executePath = executePath;\n this.cache = new ManifestCache({ ttlMs: manifestTtlMs });\n\n if (client) {\n this.client = client;\n } else {\n const httpConfig: HttpClientConfig = {\n baseURL: baseUrl,\n apiKey,\n timeoutMs,\n proxy,\n };\n this.client = createHttpClient(httpConfig);\n }\n }\n\n async fetchManifest(filter?: CapabilityFilter): Promise<Capability[]> {\n const cacheKey = filterToCacheKey(filter);\n const cached = this.cache.get(cacheKey);\n if (cached) {\n // DEBUG: cache hit (remove after stabilization)\n // eslint-disable-next-line no-console\n console.debug(\n `[${this.providerId}] manifest cache hit — ${cached.length} caps`\n );\n return cached;\n }\n\n // DEBUG\n // eslint-disable-next-line no-console\n console.debug(\n `[${this.providerId}] fetching manifest from ${this.manifestPath}`\n );\n\n const res = await this.client.get<ToolsServerManifestEntry[]>(\n this.manifestPath\n );\n assertOk(res.status, this.manifestPath, res.data);\n\n const entries = Array.isArray(res.data) ? res.data : [];\n const capabilities: Capability[] = entries.map((entry) =>\n normalizeEntry(entry)\n );\n\n // Apply filter before caching the full list separately so unfiltered\n // refetches don't re-hit the network.\n const fullCacheKey = filterToCacheKey();\n this.cache.set(fullCacheKey, capabilities);\n\n const filtered = applyFilter(capabilities, filter);\n if (cacheKey !== fullCacheKey) {\n this.cache.set(cacheKey, filtered);\n }\n\n // DEBUG\n // eslint-disable-next-line no-console\n console.debug(\n `[${this.providerId}] manifest loaded — ${capabilities.length} caps, ${filtered.length} after filter`\n );\n\n return filtered;\n }\n\n async createRunnables(\n capabilities: Capability[],\n credentials: CredentialMap\n ): Promise<StructuredToolInterface[]> {\n return capabilities.map((cap) =>\n buildProxyTool(cap, credentials, {\n client: this.client,\n executePath: this.executePath,\n })\n );\n }\n\n /** Force a manifest refresh on next fetchManifest call. */\n invalidateCache(): void {\n this.cache.clear();\n }\n}\n\n/**\n * Translate a raw tools-server manifest entry into a typed Capability.\n * Defensive — tools-server may add fields; we pull only what we need.\n */\nfunction normalizeEntry(entry: ToolsServerManifestEntry): Capability {\n return {\n kind: CapabilityKind.TOOL,\n name: entry.pluginKey,\n description: entry.description ?? '',\n schema: entry.schema ?? entry.jsonSchema,\n authConfig: (entry.authConfig ?? []).map((ac) => ({\n authField: ac.authField,\n label: ac.label,\n description: ac.description,\n required: ac.required,\n prod: ac.prod,\n admin: ac.admin,\n hide: ac.hide,\n // Source is a string in wire format; downstream consumers coerce to AuthSource.\n source: ac.source as Capability['authConfig'][number]['source'],\n })),\n metadata: {\n icon: entry.icon,\n category: entry.category,\n tags: entry.tags,\n // Governance — hosts use these to gate UI/role/environment.\n hidden: entry.hidden,\n admin: entry.admin,\n env: entry.env,\n },\n };\n}\n"],"names":["ManifestCache","createHttpClient","filterToCacheKey","assertOk","applyFilter","buildProxyTool","CapabilityKind"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.cjs","sources":["../../../src/providers/types.ts"],"sourcesContent":["/**\n * CapabilityProvider types — the abstraction that lets agents consume tools,\n * skills, and MCP-backed capabilities through a single interface regardless\n * of where they come from.\n *\n * Design principles:\n * 1. Source-agnostic — providers are distinguished by WHERE they come from\n * (tools-server, skill store, MCP server), not by the backend service\n * any individual tool calls.\n * 2. Credential-agnostic — providers receive a flat credentialMap from the\n * host; they don't know about user settings, databases, OAuth flows.\n * 3. Extension-ready — the shape reserves slots for upcoming patterns\n * (skills injectedMessages, ToolCall.auth/expires_at, skill sessions)\n * so when those land we don't refactor the core.\n */\n\nimport type { StructuredToolInterface } from '@langchain/core/tools';\n\n/**\n * Kind of capability. Today only TOOL is implemented; SKILL and MCP are\n * reserved — SkillCapabilityProvider + MCPCapabilityProvider will populate\n * them in later phases. Keeping the enum from day one prevents a breaking\n * change when those ship.\n */\nexport enum CapabilityKind {\n TOOL = 'tool',\n SKILL = 'skill',\n MCP = 'mcp',\n /**\n * Remote agent reachable over the A2A (Agent-to-Agent) protocol.\n * The library's `A2ACapabilityProvider` is a client for this kind —\n * invoking an A2A capability sends a JSON-RPC `tasks/send` to the\n * remote agent's endpoint.\n */\n A2A = 'a2a',\n}\n\n/**\n * Where an auth credential comes from. Used by hosts to decide whether to\n * forward the credential per-request or let the capability provider resolve\n * it from its own environment.\n */\nexport enum AuthSource {\n /** Resolved by the capability provider itself from its environment. Host never sends. */\n SERVER = 'server',\n /** User-configured value stored in the host's credential store. Host forwards per-request. */\n USER = 'user',\n /** Active OAuth/session token. Host forwards per-request from active session. */\n FORWARDED = 'forwarded',\n}\n\n/**\n * One entry in a capability's auth config. Describes a single credential\n * the capability needs. The `source` field tells the host how to resolve\n * the value; the `prod`/`admin`/`hide` flags control UI visibility.\n */\nexport interface AuthConfigEntry {\n /** Environment-variable-style name (e.g., \"OPENAI_API_KEY\"). Stable identifier. */\n authField: string;\n /** Human-readable label for UI. */\n label?: string;\n /** Optional description of how to obtain the credential. */\n description?: string;\n /** Where the value comes from. Defaults to USER if unspecified. */\n source?: AuthSource;\n /** True if the credential is required for the capability to function. */\n required?: boolean;\n /** Platform-managed in production — never prompt user. */\n prod?: boolean;\n /** Only admins can configure. */\n admin?: boolean;\n /** Never show in any UI (used when source === SERVER). */\n hide?: boolean;\n}\n\n/**\n * Arbitrary metadata attached to a capability. Extension point.\n *\n * Fields prefixed with \"Reserved for\" are not populated today but exist in\n * the type so upstream patterns (skills, auth expiration, sessions) can\n * drop in without a schema migration.\n */\nexport interface CapabilityMetadata {\n /** Icon URL or path relative to the provider's static asset root. */\n icon?: string;\n /** Category for UI grouping (e.g., \"search\", \"image\", \"finance\"). */\n category?: string;\n /** Free-form tags for filtering / search. */\n tags?: string[];\n\n // --- Reserved for upstream patterns (not populated today) ---\n\n /** Reserved for upstream `fix/auth-events` — auth mode declared by tool. */\n auth?: string;\n /** Reserved for upstream `fix/auth-events` — Unix timestamp for token expiration. */\n expires_at?: number;\n /** Reserved for upstream skills — capability returns injected messages on execute. */\n injectedMessages?: boolean;\n /** Reserved for upstream skills — capability consumes ToolSessionMap state. */\n sessionAware?: boolean;\n}\n\n/**\n * A single capability — a tool, skill, or MCP-backed operation that an agent\n * can invoke. The shape mirrors common plugin-manifest conventions so the\n * same entry can round-trip between an upstream catalog and a host registry.\n */\nexport interface Capability {\n /** What kind of capability this is. Controls how it's invoked downstream. */\n kind: CapabilityKind;\n /**\n * Stable unique identifier. For tools this is the pluginKey\n * (e.g., \"dalle\", \"wikipedia\"). For skills this is the skill's `name`.\n * Used everywhere the capability is referenced.\n */\n name: string;\n /** Human-readable description for the LLM and UI. */\n description: string;\n /**\n * Input schema as JSON Schema. For tools this comes from the Zod schema\n * passed through `zodToJsonSchema`. Optional for capabilities with no\n * input (e.g., parameter-less skills).\n */\n schema?: unknown;\n /** Credential requirements. */\n authConfig: AuthConfigEntry[];\n /** Extension metadata. See CapabilityMetadata. */\n metadata: CapabilityMetadata;\n}\n\n/** Filter for fetchManifest. All fields optional; missing = no filter. */\nexport interface CapabilityFilter {\n kind?: CapabilityKind;\n tags?: string[];\n /** Restrict to capabilities whose `name` is in this list. */\n names?: string[];\n}\n\n/**\n * A flat credential map: authField → value.\n *\n * The host is responsible for resolving values (from env vars, user\n * settings, OAuth sessions, etc.) before passing to the provider. The\n * provider does not inspect the origin — it just forwards to the tool.\n */\nexport type CredentialMap = Record<string, string>;\n\n/**\n * The core interface. All concrete providers implement this.\n *\n * Providers are identified by `providerId` for logging/debug. They fetch\n * their own manifest and build LangChain-compatible runnables from it.\n *\n * Lifetime: a provider may be instantiated once at startup (e.g., tools-\n * server pointing at a stable URL) or per-user (e.g., MCP with per-user\n * OAuth). The interface is agnostic.\n */\nexport interface CapabilityProvider {\n /** Stable identifier for this provider instance (e.g., \"tools-server:https://...\"). */\n readonly providerId: string;\n\n /**\n * Return the list of capabilities this provider exposes.\n *\n * Implementations may cache the manifest — the contract is that the\n * returned list reflects the provider's current view of available\n * capabilities.\n *\n * @param filter optional filter to scope the result\n */\n fetchManifest(filter?: CapabilityFilter): Promise<Capability[]>;\n\n /**\n * Build LangChain StructuredTools from a set of capabilities using the\n * caller-supplied credentials.\n *\n * Called at agent init. The returned tools are bound to the LLM and\n * invoked during the graph's tool-calling loop.\n *\n * @param capabilities the subset of capabilities the agent wants to use\n * @param credentials credential values keyed by authField\n */\n createRunnables(\n capabilities: Capability[],\n credentials: CredentialMap\n ): Promise<StructuredToolInterface[]>;\n}\n"],"names":["CapabilityKind","AuthSource"],"mappings":";;AAAA;;;;;;;;;;;;;;AAcG;AAIH;;;;;AAKG;AACSA;AAAZ,CAAA,UAAY,cAAc,EAAA;AACxB,IAAA,cAAA,CAAA,MAAA,CAAA,GAAA,MAAa;AACb,IAAA,cAAA,CAAA,OAAA,CAAA,GAAA,OAAe;AACf,IAAA,cAAA,CAAA,KAAA,CAAA,GAAA,KAAW;AACX;;;;;AAKG;AACH,IAAA,cAAA,CAAA,KAAA,CAAA,GAAA,KAAW;AACb,CAAC,EAXWA,sBAAc,KAAdA,sBAAc,GAAA,EAAA,CAAA,CAAA;AAa1B;;;;AAIG;AACSC;AAAZ,CAAA,UAAY,UAAU,EAAA;;AAEpB,IAAA,UAAA,CAAA,QAAA,CAAA,GAAA,QAAiB;;AAEjB,IAAA,UAAA,CAAA,MAAA,CAAA,GAAA,MAAa;;AAEb,IAAA,UAAA,CAAA,WAAA,CAAA,GAAA,WAAuB;AACzB,CAAC,EAPWA,kBAAU,KAAVA,kBAAU,GAAA,EAAA,CAAA,CAAA;;"}
|
|
1
|
+
{"version":3,"file":"types.cjs","sources":["../../../src/providers/types.ts"],"sourcesContent":["/**\n * CapabilityProvider types — the abstraction that lets agents consume tools,\n * skills, and MCP-backed capabilities through a single interface regardless\n * of where they come from.\n *\n * Design principles:\n * 1. Source-agnostic — providers are distinguished by WHERE they come from\n * (tools-server, skill store, MCP server), not by the backend service\n * any individual tool calls.\n * 2. Credential-agnostic — providers receive a flat credentialMap from the\n * host; they don't know about user settings, databases, OAuth flows.\n * 3. Extension-ready — the shape reserves slots for upcoming patterns\n * (skills injectedMessages, ToolCall.auth/expires_at, skill sessions)\n * so when those land we don't refactor the core.\n */\n\nimport type { StructuredToolInterface } from '@langchain/core/tools';\n\n/**\n * Kind of capability. Today only TOOL is implemented; SKILL and MCP are\n * reserved — SkillCapabilityProvider + MCPCapabilityProvider will populate\n * them in later phases. Keeping the enum from day one prevents a breaking\n * change when those ship.\n */\nexport enum CapabilityKind {\n TOOL = 'tool',\n SKILL = 'skill',\n MCP = 'mcp',\n /**\n * Remote agent reachable over the A2A (Agent-to-Agent) protocol.\n * The library's `A2ACapabilityProvider` is a client for this kind —\n * invoking an A2A capability sends a JSON-RPC `tasks/send` to the\n * remote agent's endpoint.\n */\n A2A = 'a2a',\n}\n\n/**\n * Where an auth credential comes from. Used by hosts to decide whether to\n * forward the credential per-request or let the capability provider resolve\n * it from its own environment.\n */\nexport enum AuthSource {\n /** Resolved by the capability provider itself from its environment. Host never sends. */\n SERVER = 'server',\n /** User-configured value stored in the host's credential store. Host forwards per-request. */\n USER = 'user',\n /** Active OAuth/session token. Host forwards per-request from active session. */\n FORWARDED = 'forwarded',\n}\n\n/**\n * One entry in a capability's auth config. Describes a single credential\n * the capability needs. The `source` field tells the host how to resolve\n * the value; the `prod`/`admin`/`hide` flags control UI visibility.\n */\nexport interface AuthConfigEntry {\n /** Environment-variable-style name (e.g., \"OPENAI_API_KEY\"). Stable identifier. */\n authField: string;\n /** Human-readable label for UI. */\n label?: string;\n /** Optional description of how to obtain the credential. */\n description?: string;\n /** Where the value comes from. Defaults to USER if unspecified. */\n source?: AuthSource;\n /** True if the credential is required for the capability to function. */\n required?: boolean;\n /** Platform-managed in production — never prompt user. */\n prod?: boolean;\n /** Only admins can configure. */\n admin?: boolean;\n /** Never show in any UI (used when source === SERVER). */\n hide?: boolean;\n}\n\n/**\n * Arbitrary metadata attached to a capability. Extension point.\n *\n * Fields prefixed with \"Reserved for\" are not populated today but exist in\n * the type so upstream patterns (skills, auth expiration, sessions) can\n * drop in without a schema migration.\n */\nexport interface CapabilityMetadata {\n /** Icon URL or path relative to the provider's static asset root. */\n icon?: string;\n /** Category for UI grouping (e.g., \"search\", \"image\", \"finance\"). */\n category?: string;\n /** Free-form tags for filtering / search. */\n tags?: string[];\n\n // --- Governance flags ------------------------------------------------\n\n /**\n * When true, hosts omit this capability from user-facing pickers\n * (Agent Builder, tool dropdown). Still invokable when a saved agent\n * references it by name.\n */\n hidden?: boolean;\n /** When true, only admin-role users can enable or invoke this capability. */\n admin?: boolean;\n /**\n * Deployment-stage restriction. When set, hosts whose deployment stage\n * isn't in the array should hide the capability (e.g., a prod host\n * shouldn't surface a tool with `env: ['development']`).\n */\n env?: Array<'development' | 'production' | 'test' | 'staging'>;\n\n // --- Reserved for upstream patterns (not populated today) ---\n\n /** Reserved for upstream `fix/auth-events` — auth mode declared by tool. */\n auth?: string;\n /** Reserved for upstream `fix/auth-events` — Unix timestamp for token expiration. */\n expires_at?: number;\n /** Reserved for upstream skills — capability returns injected messages on execute. */\n injectedMessages?: boolean;\n /** Reserved for upstream skills — capability consumes ToolSessionMap state. */\n sessionAware?: boolean;\n}\n\n/**\n * A single capability — a tool, skill, or MCP-backed operation that an agent\n * can invoke. The shape mirrors common plugin-manifest conventions so the\n * same entry can round-trip between an upstream catalog and a host registry.\n */\nexport interface Capability {\n /** What kind of capability this is. Controls how it's invoked downstream. */\n kind: CapabilityKind;\n /**\n * Stable unique identifier. For tools this is the pluginKey\n * (e.g., \"dalle\", \"wikipedia\"). For skills this is the skill's `name`.\n * Used everywhere the capability is referenced.\n */\n name: string;\n /** Human-readable description for the LLM and UI. */\n description: string;\n /**\n * Input schema as JSON Schema. For tools this comes from the Zod schema\n * passed through `zodToJsonSchema`. Optional for capabilities with no\n * input (e.g., parameter-less skills).\n */\n schema?: unknown;\n /** Credential requirements. */\n authConfig: AuthConfigEntry[];\n /** Extension metadata. See CapabilityMetadata. */\n metadata: CapabilityMetadata;\n}\n\n/** Filter for fetchManifest. All fields optional; missing = no filter. */\nexport interface CapabilityFilter {\n kind?: CapabilityKind;\n tags?: string[];\n /** Restrict to capabilities whose `name` is in this list. */\n names?: string[];\n}\n\n/**\n * A flat credential map: authField → value.\n *\n * The host is responsible for resolving values (from env vars, user\n * settings, OAuth sessions, etc.) before passing to the provider. The\n * provider does not inspect the origin — it just forwards to the tool.\n */\nexport type CredentialMap = Record<string, string>;\n\n/**\n * The core interface. All concrete providers implement this.\n *\n * Providers are identified by `providerId` for logging/debug. They fetch\n * their own manifest and build LangChain-compatible runnables from it.\n *\n * Lifetime: a provider may be instantiated once at startup (e.g., tools-\n * server pointing at a stable URL) or per-user (e.g., MCP with per-user\n * OAuth). The interface is agnostic.\n */\nexport interface CapabilityProvider {\n /** Stable identifier for this provider instance (e.g., \"tools-server:https://...\"). */\n readonly providerId: string;\n\n /**\n * Return the list of capabilities this provider exposes.\n *\n * Implementations may cache the manifest — the contract is that the\n * returned list reflects the provider's current view of available\n * capabilities.\n *\n * @param filter optional filter to scope the result\n */\n fetchManifest(filter?: CapabilityFilter): Promise<Capability[]>;\n\n /**\n * Build LangChain StructuredTools from a set of capabilities using the\n * caller-supplied credentials.\n *\n * Called at agent init. The returned tools are bound to the LLM and\n * invoked during the graph's tool-calling loop.\n *\n * @param capabilities the subset of capabilities the agent wants to use\n * @param credentials credential values keyed by authField\n */\n createRunnables(\n capabilities: Capability[],\n credentials: CredentialMap\n ): Promise<StructuredToolInterface[]>;\n}\n"],"names":["CapabilityKind","AuthSource"],"mappings":";;AAAA;;;;;;;;;;;;;;AAcG;AAIH;;;;;AAKG;AACSA;AAAZ,CAAA,UAAY,cAAc,EAAA;AACxB,IAAA,cAAA,CAAA,MAAA,CAAA,GAAA,MAAa;AACb,IAAA,cAAA,CAAA,OAAA,CAAA,GAAA,OAAe;AACf,IAAA,cAAA,CAAA,KAAA,CAAA,GAAA,KAAW;AACX;;;;;AAKG;AACH,IAAA,cAAA,CAAA,KAAA,CAAA,GAAA,KAAW;AACb,CAAC,EAXWA,sBAAc,KAAdA,sBAAc,GAAA,EAAA,CAAA,CAAA;AAa1B;;;;AAIG;AACSC;AAAZ,CAAA,UAAY,UAAU,EAAA;;AAEpB,IAAA,UAAA,CAAA,QAAA,CAAA,GAAA,QAAiB;;AAEjB,IAAA,UAAA,CAAA,MAAA,CAAA,GAAA,MAAa;;AAEb,IAAA,UAAA,CAAA,WAAA,CAAA,GAAA,WAAuB;AACzB,CAAC,EAPWA,kBAAU,KAAVA,kBAAU,GAAA,EAAA,CAAA,CAAA;;"}
|
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
var zod = require('zod');
|
|
4
4
|
|
|
5
|
-
const ARTIFACT_WRITE_ACTIONS = [
|
|
5
|
+
const ARTIFACT_WRITE_ACTIONS = [
|
|
6
|
+
'write',
|
|
7
|
+
'edit',
|
|
8
|
+
'verify',
|
|
9
|
+
'delete',
|
|
10
|
+
];
|
|
6
11
|
const CONTENT_READ_ACTIONS = ['read', 'search', 'list', 'info'];
|
|
7
12
|
const artifactToolSchema = zod.z.object({
|
|
8
13
|
action: zod.z
|
|
@@ -26,7 +31,10 @@ const artifactToolSchema = zod.z.object({
|
|
|
26
31
|
.string()
|
|
27
32
|
.optional()
|
|
28
33
|
.describe('Exact string to find and replace (required for edit).'),
|
|
29
|
-
new_str: zod.z
|
|
34
|
+
new_str: zod.z
|
|
35
|
+
.string()
|
|
36
|
+
.optional()
|
|
37
|
+
.describe('Replacement string (required for edit).'),
|
|
30
38
|
replace_all: zod.z
|
|
31
39
|
.boolean()
|
|
32
40
|
.optional()
|
|
@@ -44,12 +52,27 @@ const contentReaderSchema = zod.z.object({
|
|
|
44
52
|
start_line: zod.z.number().optional().describe('1-based start line for reading.'),
|
|
45
53
|
end_line: zod.z.number().optional().describe('1-based end line (inclusive).'),
|
|
46
54
|
// search
|
|
47
|
-
pattern: zod.z
|
|
48
|
-
|
|
49
|
-
|
|
55
|
+
pattern: zod.z
|
|
56
|
+
.string()
|
|
57
|
+
.optional()
|
|
58
|
+
.describe('Regex pattern (required for search).'),
|
|
59
|
+
flags: zod.z
|
|
60
|
+
.string()
|
|
61
|
+
.optional()
|
|
62
|
+
.describe('Regex flags (e.g., "i" for case-insensitive).'),
|
|
63
|
+
context: zod.z
|
|
64
|
+
.number()
|
|
65
|
+
.optional()
|
|
66
|
+
.describe('Lines of context around each match.'),
|
|
50
67
|
// shared pagination
|
|
51
|
-
offset: zod.z
|
|
52
|
-
|
|
68
|
+
offset: zod.z
|
|
69
|
+
.number()
|
|
70
|
+
.optional()
|
|
71
|
+
.describe('Offset for read or search pagination.'),
|
|
72
|
+
limit: zod.z
|
|
73
|
+
.number()
|
|
74
|
+
.optional()
|
|
75
|
+
.describe('Max lines (read) or matches (search).'),
|
|
53
76
|
});
|
|
54
77
|
const ARTIFACT_TOOL_NAME = 'artifact_tool';
|
|
55
78
|
const CONTENT_READER_NAME = 'content_reader';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.cjs","sources":["../../../../src/tools/artifacts/schema.ts"],"sourcesContent":["import { z } from 'zod';\n\nexport const ARTIFACT_WRITE_ACTIONS = ['write'
|
|
1
|
+
{"version":3,"file":"schema.cjs","sources":["../../../../src/tools/artifacts/schema.ts"],"sourcesContent":["import { z } from 'zod';\n\nexport const ARTIFACT_WRITE_ACTIONS = [\n 'write',\n 'edit',\n 'verify',\n 'delete',\n] as const;\nexport const CONTENT_READ_ACTIONS = ['read', 'search', 'list', 'info'] as const;\n\nexport const artifactToolSchema = z.object({\n action: z\n .enum(ARTIFACT_WRITE_ACTIONS)\n .describe(\n 'Authoring action: write (create/overwrite), edit (str_replace), verify (syntax check), delete (remove).'\n ),\n content_id: z\n .string()\n .optional()\n .describe(\n 'ID of the artifact entry. Required for edit/verify/delete; optional for write (supply to overwrite an existing entry).'\n ),\n\n // write\n content: z\n .string()\n .optional()\n .describe('Full file content (required for write action).'),\n name: z\n .string()\n .optional()\n .describe(\n 'Filename for the new entry (required when creating). MUST include the correct file extension — the extension drives the preview template.'\n ),\n\n // edit (str_replace)\n old_str: z\n .string()\n .optional()\n .describe('Exact string to find and replace (required for edit).'),\n new_str: z\n .string()\n .optional()\n .describe('Replacement string (required for edit).'),\n replace_all: z\n .boolean()\n .optional()\n .describe(\n 'edit: when true, replaces every occurrence of old_str. When false (default) and old_str matches more than one location, the edit is refused.'\n ),\n});\n\nexport const contentReaderSchema = z.object({\n action: z\n .enum(CONTENT_READ_ACTIONS)\n .describe(\n 'Read-only action: read (lines), search (regex), list (all entries), info (metadata).'\n ),\n content_id: z\n .string()\n .optional()\n .describe(\n 'ID of the content entry. Required for read/search/info. Omit for list.'\n ),\n\n // read pagination\n start_line: z.number().optional().describe('1-based start line for reading.'),\n end_line: z.number().optional().describe('1-based end line (inclusive).'),\n\n // search\n pattern: z\n .string()\n .optional()\n .describe('Regex pattern (required for search).'),\n flags: z\n .string()\n .optional()\n .describe('Regex flags (e.g., \"i\" for case-insensitive).'),\n context: z\n .number()\n .optional()\n .describe('Lines of context around each match.'),\n\n // shared pagination\n offset: z\n .number()\n .optional()\n .describe('Offset for read or search pagination.'),\n limit: z\n .number()\n .optional()\n .describe('Max lines (read) or matches (search).'),\n});\n\nexport const ARTIFACT_TOOL_NAME = 'artifact_tool';\nexport const CONTENT_READER_NAME = 'content_reader';\n\nexport type ArtifactToolInput = z.infer<typeof artifactToolSchema>;\nexport type ContentReaderInput = z.infer<typeof contentReaderSchema>;\n"],"names":["z"],"mappings":";;;;AAEO,MAAM,sBAAsB,GAAG;IACpC,OAAO;IACP,MAAM;IACN,QAAQ;IACR,QAAQ;;AAEH,MAAM,oBAAoB,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM;AAE9D,MAAM,kBAAkB,GAAGA,KAAC,CAAC,MAAM,CAAC;AACzC,IAAA,MAAM,EAAEA;SACL,IAAI,CAAC,sBAAsB;SAC3B,QAAQ,CACP,yGAAyG,CAC1G;AACH,IAAA,UAAU,EAAEA;AACT,SAAA,MAAM;AACN,SAAA,QAAQ;SACR,QAAQ,CACP,wHAAwH,CACzH;;AAGH,IAAA,OAAO,EAAEA;AACN,SAAA,MAAM;AACN,SAAA,QAAQ;SACR,QAAQ,CAAC,gDAAgD,CAAC;AAC7D,IAAA,IAAI,EAAEA;AACH,SAAA,MAAM;AACN,SAAA,QAAQ;SACR,QAAQ,CACP,2IAA2I,CAC5I;;AAGH,IAAA,OAAO,EAAEA;AACN,SAAA,MAAM;AACN,SAAA,QAAQ;SACR,QAAQ,CAAC,uDAAuD,CAAC;AACpE,IAAA,OAAO,EAAEA;AACN,SAAA,MAAM;AACN,SAAA,QAAQ;SACR,QAAQ,CAAC,yCAAyC,CAAC;AACtD,IAAA,WAAW,EAAEA;AACV,SAAA,OAAO;AACP,SAAA,QAAQ;SACR,QAAQ,CACP,8IAA8I,CAC/I;AACJ,CAAA;AAEM,MAAM,mBAAmB,GAAGA,KAAC,CAAC,MAAM,CAAC;AAC1C,IAAA,MAAM,EAAEA;SACL,IAAI,CAAC,oBAAoB;SACzB,QAAQ,CACP,sFAAsF,CACvF;AACH,IAAA,UAAU,EAAEA;AACT,SAAA,MAAM;AACN,SAAA,QAAQ;SACR,QAAQ,CACP,wEAAwE,CACzE;;AAGH,IAAA,UAAU,EAAEA,KAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,iCAAiC,CAAC;AAC7E,IAAA,QAAQ,EAAEA,KAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;;AAGzE,IAAA,OAAO,EAAEA;AACN,SAAA,MAAM;AACN,SAAA,QAAQ;SACR,QAAQ,CAAC,sCAAsC,CAAC;AACnD,IAAA,KAAK,EAAEA;AACJ,SAAA,MAAM;AACN,SAAA,QAAQ;SACR,QAAQ,CAAC,+CAA+C,CAAC;AAC5D,IAAA,OAAO,EAAEA;AACN,SAAA,MAAM;AACN,SAAA,QAAQ;SACR,QAAQ,CAAC,qCAAqC,CAAC;;AAGlD,IAAA,MAAM,EAAEA;AACL,SAAA,MAAM;AACN,SAAA,QAAQ;SACR,QAAQ,CAAC,uCAAuC,CAAC;AACpD,IAAA,KAAK,EAAEA;AACJ,SAAA,MAAM;AACN,SAAA,QAAQ;SACR,QAAQ,CAAC,uCAAuC,CAAC;AACrD,CAAA;AAEM,MAAM,kBAAkB,GAAG;AAC3B,MAAM,mBAAmB,GAAG;;;;;;;;;"}
|
|
@@ -106,7 +106,10 @@ function createArtifactTool(config) {
|
|
|
106
106
|
return await handlers.delete(args, scope);
|
|
107
107
|
}
|
|
108
108
|
default:
|
|
109
|
-
return [
|
|
109
|
+
return [
|
|
110
|
+
`Unknown action: ${input.action}`,
|
|
111
|
+
{},
|
|
112
|
+
];
|
|
110
113
|
}
|
|
111
114
|
}
|
|
112
115
|
catch (err) {
|
|
@@ -183,7 +186,10 @@ function createContentReaderTool(config) {
|
|
|
183
186
|
return await handlers.info(args, scope);
|
|
184
187
|
}
|
|
185
188
|
default:
|
|
186
|
-
return [
|
|
189
|
+
return [
|
|
190
|
+
`Unknown action: ${input.action}`,
|
|
191
|
+
{},
|
|
192
|
+
];
|
|
187
193
|
}
|
|
188
194
|
}
|
|
189
195
|
catch (err) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool.cjs","sources":["../../../../src/tools/artifacts/tool.ts"],"sourcesContent":["/**\n * artifact_tool + content_reader library factories.\n *\n * The library owns the LangChain wiring (schema, description, response\n * shape) and the action dispatch; the runtime supplies a handler bundle\n * matching the `ArtifactWriteHandlers` / `ContentReadHandlers` interface.\n *\n * This keeps 800+ LOC of host-specific handler logic (S3 adapters, file\n * model CRUD, syntax checkers, line utils) out of the library while\n * still centralizing the tool surface every runtime shares.\n */\n\nimport { tool, DynamicStructuredTool } from '@langchain/core/tools';\nimport {\n artifactToolSchema,\n contentReaderSchema,\n ARTIFACT_TOOL_NAME,\n CONTENT_READER_NAME,\n} from './schema';\nimport type {\n ArtifactToolConfig,\n ContentReaderToolConfig,\n ArtifactToolScope,\n ArtifactToolResult,\n WriteArgs,\n EditArgs,\n VerifyArgs,\n DeleteArgs,\n ReadArgs,\n SearchArgs,\n ListArgs,\n InfoArgs,\n ContentIdResolver,\n} from './types';\n\nconst DEFAULT_ARTIFACT_DESCRIPTION = `Author content artifacts that render live in the host's preview panel — this tool does NOT produce downloadable files (use execute_code for those).\n\nActions:\n- write: Create a new artifact. Write a COMPLETE file in one call. The \\`name\\` field MUST include the file extension — it routes the preview (.tsx, .html, .mmd, .svg, .csv, .json, .dot, .md, .drawio).\n- verify: Check an artifact for syntax errors. REQUIRED as the next step after every write/edit on code files — do not render until verify passes.\n- edit: Surgical string replacement — provide old_str (exact match) and new_str. Works on all file types.\n- delete: Remove an artifact and its backing file.\n\nArtifacts are persisted by the host. No manual save needed.`;\n\nconst DEFAULT_CONTENT_READER_DESCRIPTION = `Read and navigate stored content — artifacts authored by artifact_tool, large tool results auto-cached by the host, uploaded file attachments, and code blocks.\n\nRead-only surface. Use write/edit tools (artifact_tool, execute_code) to mutate.\n\nActions:\n- read: Return line ranges from a specific content_id.\n- search: Regex search across a specific content_id with paginated matches.\n- list: Enumerate every content entry currently stored.\n- info: Metadata (size, kind, creation time) for a specific content_id.`;\n\n/**\n * Optional content_id self-healing — if the runtime supplies a resolver,\n * we pre-resolve the ID on every action that takes one so nicknames\n * (e.g., \"Dashboard\") map to canonical IDs.\n */\nasync function resolveContentIdIfPresent(\n resolver: ContentIdResolver | undefined,\n id: string | undefined,\n scope: ArtifactToolScope,\n logger?: { debug: (msg: string) => void },\n): Promise<string | undefined> {\n if (!resolver || !id) return id;\n const out = await resolver.resolve(id, scope);\n if (!out) return id;\n if (out.resolvedId !== id) {\n logger?.debug(\n `[artifact] resolved \"${id}\" → \"${out.resolvedId}\"${out.resolvedName ? ` (\"${out.resolvedName}\")` : ''}`,\n );\n }\n return out.resolvedId;\n}\n\n// ─── Writer tool (artifact_tool) ─────────────────────────────────────────\n\nexport function createArtifactTool(\n config: ArtifactToolConfig,\n): DynamicStructuredTool {\n const { handlers, getScope, resolver, logger, descriptionOverride } = config;\n\n return tool(\n async (rawInput, runnableConfig): Promise<ArtifactToolResult> => {\n const scope = getScope(runnableConfig);\n if (!scope) {\n logger?.warn('[artifact_tool] no scope resolved from runnableConfig');\n return ['Error: No conversation context available', {}];\n }\n\n const input = rawInput as {\n action: 'write' | 'edit' | 'verify' | 'delete';\n content_id?: string;\n content?: string;\n name?: string;\n old_str?: string;\n new_str?: string;\n replace_all?: boolean;\n };\n\n const resolvedContentId = await resolveContentIdIfPresent(\n resolver,\n input.content_id,\n scope,\n logger,\n );\n\n const started = Date.now();\n try {\n switch (input.action) {\n case 'write': {\n const args: WriteArgs = {\n action: 'write',\n content_id: resolvedContentId,\n content: input.content ?? '',\n name: input.name,\n };\n if (!args.content) return ['Error: write requires content', {}];\n return await handlers.write(args, scope);\n }\n case 'edit': {\n if (!resolvedContentId) return ['Error: edit requires content_id', {}];\n const args: EditArgs = {\n action: 'edit',\n content_id: resolvedContentId,\n old_str: input.old_str ?? '',\n new_str: input.new_str ?? '',\n replace_all: input.replace_all,\n };\n if (!args.old_str) return ['Error: edit requires old_str', {}];\n return await handlers.edit(args, scope);\n }\n case 'verify': {\n if (!resolvedContentId) return ['Error: verify requires content_id', {}];\n const args: VerifyArgs = {\n action: 'verify',\n content_id: resolvedContentId,\n };\n return await handlers.verify(args, scope);\n }\n case 'delete': {\n if (!resolvedContentId) return ['Error: delete requires content_id', {}];\n const args: DeleteArgs = {\n action: 'delete',\n content_id: resolvedContentId,\n };\n return await handlers.delete(args, scope);\n }\n default:\n return [`Unknown action: ${(input as { action: string }).action}`, {}];\n }\n } catch (err) {\n const e = err instanceof Error ? err : new Error(String(err));\n logger?.error('[artifact_tool] handler threw', {\n action: input.action,\n contentId: resolvedContentId,\n error: e.message,\n elapsed: `${Date.now() - started}ms`,\n });\n return [`Error: ${e.message}`, {}];\n }\n },\n {\n name: ARTIFACT_TOOL_NAME,\n responseFormat: 'content_and_artifact',\n description: descriptionOverride ?? DEFAULT_ARTIFACT_DESCRIPTION,\n schema: artifactToolSchema,\n },\n );\n}\n\n// ─── Reader tool (content_reader) ────────────────────────────────────────\n\nexport function createContentReaderTool(\n config: ContentReaderToolConfig,\n): DynamicStructuredTool {\n const { handlers, getScope, resolver, logger, descriptionOverride } = config;\n\n return tool(\n async (rawInput, runnableConfig): Promise<ArtifactToolResult> => {\n const scope = getScope(runnableConfig);\n if (!scope) {\n logger?.warn('[content_reader] no scope resolved from runnableConfig');\n return ['Error: No conversation context available', {}];\n }\n\n const input = rawInput as {\n action: 'read' | 'search' | 'list' | 'info';\n content_id?: string;\n start_line?: number;\n end_line?: number;\n pattern?: string;\n flags?: string;\n context?: number;\n offset?: number;\n limit?: number;\n };\n\n const resolvedContentId = await resolveContentIdIfPresent(\n resolver,\n input.content_id,\n scope,\n logger,\n );\n\n const started = Date.now();\n try {\n switch (input.action) {\n case 'read': {\n if (!resolvedContentId) return ['Error: read requires content_id', {}];\n const args: ReadArgs = {\n action: 'read',\n content_id: resolvedContentId,\n start_line: input.start_line,\n end_line: input.end_line,\n offset: input.offset,\n limit: input.limit,\n };\n return await handlers.read(args, scope);\n }\n case 'search': {\n if (!resolvedContentId) return ['Error: search requires content_id', {}];\n if (!input.pattern) return ['Error: search requires pattern', {}];\n const args: SearchArgs = {\n action: 'search',\n content_id: resolvedContentId,\n pattern: input.pattern,\n flags: input.flags,\n context: input.context,\n offset: input.offset,\n limit: input.limit,\n };\n return await handlers.search(args, scope);\n }\n case 'list': {\n const args: ListArgs = { action: 'list' };\n return await handlers.list(args, scope);\n }\n case 'info': {\n if (!resolvedContentId) return ['Error: info requires content_id', {}];\n const args: InfoArgs = {\n action: 'info',\n content_id: resolvedContentId,\n };\n return await handlers.info(args, scope);\n }\n default:\n return [`Unknown action: ${(input as { action: string }).action}`, {}];\n }\n } catch (err) {\n const e = err instanceof Error ? err : new Error(String(err));\n logger?.error('[content_reader] handler threw', {\n action: input.action,\n contentId: resolvedContentId,\n error: e.message,\n elapsed: `${Date.now() - started}ms`,\n });\n return [`Error: ${e.message}`, {}];\n }\n },\n {\n name: CONTENT_READER_NAME,\n responseFormat: 'content_and_artifact',\n description: descriptionOverride ?? DEFAULT_CONTENT_READER_DESCRIPTION,\n schema: contentReaderSchema,\n },\n );\n}\n\nexport {\n ARTIFACT_TOOL_NAME,\n CONTENT_READER_NAME,\n ARTIFACT_WRITE_ACTIONS,\n CONTENT_READ_ACTIONS,\n} from './schema';\n"],"names":["tool","ARTIFACT_TOOL_NAME","artifactToolSchema","CONTENT_READER_NAME","contentReaderSchema"],"mappings":";;;;;AAAA;;;;;;;;;;AAUG;AAyBH,MAAM,4BAA4B,GAAG,CAAA;;;;;;;;4DAQuB;AAE5D,MAAM,kCAAkC,GAAG,CAAA;;;;;;;;wEAQ6B;AAExE;;;;AAIG;AACH,eAAe,yBAAyB,CACtC,QAAuC,EACvC,EAAsB,EACtB,KAAwB,EACxB,MAAyC,EAAA;AAEzC,IAAA,IAAI,CAAC,QAAQ,IAAI,CAAC,EAAE;AAAE,QAAA,OAAO,EAAE;IAC/B,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,EAAE,EAAE,KAAK,CAAC;AAC7C,IAAA,IAAI,CAAC,GAAG;AAAE,QAAA,OAAO,EAAE;AACnB,IAAA,IAAI,GAAG,CAAC,UAAU,KAAK,EAAE,EAAE;QACzB,MAAM,EAAE,KAAK,CACX,CAAA,qBAAA,EAAwB,EAAE,CAAA,KAAA,EAAQ,GAAG,CAAC,UAAU,CAAA,CAAA,EAAI,GAAG,CAAC,YAAY,GAAG,CAAA,GAAA,EAAM,GAAG,CAAC,YAAY,CAAA,EAAA,CAAI,GAAG,EAAE,CAAA,CAAE,CACzG;IACH;IACA,OAAO,GAAG,CAAC,UAAU;AACvB;AAEA;AAEM,SAAU,kBAAkB,CAChC,MAA0B,EAAA;AAE1B,IAAA,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,mBAAmB,EAAE,GAAG,MAAM;IAE5E,OAAOA,UAAI,CACT,OAAO,QAAQ,EAAE,cAAc,KAAiC;AAC9D,QAAA,MAAM,KAAK,GAAG,QAAQ,CAAC,cAAc,CAAC;QACtC,IAAI,CAAC,KAAK,EAAE;AACV,YAAA,MAAM,EAAE,IAAI,CAAC,uDAAuD,CAAC;AACrE,YAAA,OAAO,CAAC,0CAA0C,EAAE,EAAE,CAAC;QACzD;QAEA,MAAM,KAAK,GAAG,QAQb;AAED,QAAA,MAAM,iBAAiB,GAAG,MAAM,yBAAyB,CACvD,QAAQ,EACR,KAAK,CAAC,UAAU,EAChB,KAAK,EACL,MAAM,CACP;AAED,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE;AAC1B,QAAA,IAAI;AACF,YAAA,QAAQ,KAAK,CAAC,MAAM;gBAClB,KAAK,OAAO,EAAE;AACZ,oBAAA,MAAM,IAAI,GAAc;AACtB,wBAAA,MAAM,EAAE,OAAO;AACf,wBAAA,UAAU,EAAE,iBAAiB;AAC7B,wBAAA,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,EAAE;wBAC5B,IAAI,EAAE,KAAK,CAAC,IAAI;qBACjB;oBACD,IAAI,CAAC,IAAI,CAAC,OAAO;AAAE,wBAAA,OAAO,CAAC,+BAA+B,EAAE,EAAE,CAAC;oBAC/D,OAAO,MAAM,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC;gBAC1C;gBACA,KAAK,MAAM,EAAE;AACX,oBAAA,IAAI,CAAC,iBAAiB;AAAE,wBAAA,OAAO,CAAC,iCAAiC,EAAE,EAAE,CAAC;AACtE,oBAAA,MAAM,IAAI,GAAa;AACrB,wBAAA,MAAM,EAAE,MAAM;AACd,wBAAA,UAAU,EAAE,iBAAiB;AAC7B,wBAAA,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,EAAE;AAC5B,wBAAA,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,EAAE;wBAC5B,WAAW,EAAE,KAAK,CAAC,WAAW;qBAC/B;oBACD,IAAI,CAAC,IAAI,CAAC,OAAO;AAAE,wBAAA,OAAO,CAAC,8BAA8B,EAAE,EAAE,CAAC;oBAC9D,OAAO,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC;gBACzC;gBACA,KAAK,QAAQ,EAAE;AACb,oBAAA,IAAI,CAAC,iBAAiB;AAAE,wBAAA,OAAO,CAAC,mCAAmC,EAAE,EAAE,CAAC;AACxE,oBAAA,MAAM,IAAI,GAAe;AACvB,wBAAA,MAAM,EAAE,QAAQ;AAChB,wBAAA,UAAU,EAAE,iBAAiB;qBAC9B;oBACD,OAAO,MAAM,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC;gBAC3C;gBACA,KAAK,QAAQ,EAAE;AACb,oBAAA,IAAI,CAAC,iBAAiB;AAAE,wBAAA,OAAO,CAAC,mCAAmC,EAAE,EAAE,CAAC;AACxE,oBAAA,MAAM,IAAI,GAAe;AACvB,wBAAA,MAAM,EAAE,QAAQ;AAChB,wBAAA,UAAU,EAAE,iBAAiB;qBAC9B;oBACD,OAAO,MAAM,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC;gBAC3C;AACA,gBAAA;oBACE,OAAO,CAAC,mBAAoB,KAA4B,CAAC,MAAM,CAAA,CAAE,EAAE,EAAE,CAAC;;QAE5E;QAAE,OAAO,GAAG,EAAE;YACZ,MAAM,CAAC,GAAG,GAAG,YAAY,KAAK,GAAG,GAAG,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AAC7D,YAAA,MAAM,EAAE,KAAK,CAAC,+BAA+B,EAAE;gBAC7C,MAAM,EAAE,KAAK,CAAC,MAAM;AACpB,gBAAA,SAAS,EAAE,iBAAiB;gBAC5B,KAAK,EAAE,CAAC,CAAC,OAAO;gBAChB,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAA,EAAA,CAAI;AACrC,aAAA,CAAC;YACF,OAAO,CAAC,UAAU,CAAC,CAAC,OAAO,CAAA,CAAE,EAAE,EAAE,CAAC;QACpC;AACF,IAAA,CAAC,EACD;AACE,QAAA,IAAI,EAAEC,yBAAkB;AACxB,QAAA,cAAc,EAAE,sBAAsB;QACtC,WAAW,EAAE,mBAAmB,IAAI,4BAA4B;AAChE,QAAA,MAAM,EAAEC,yBAAkB;AAC3B,KAAA,CACF;AACH;AAEA;AAEM,SAAU,uBAAuB,CACrC,MAA+B,EAAA;AAE/B,IAAA,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,mBAAmB,EAAE,GAAG,MAAM;IAE5E,OAAOF,UAAI,CACT,OAAO,QAAQ,EAAE,cAAc,KAAiC;AAC9D,QAAA,MAAM,KAAK,GAAG,QAAQ,CAAC,cAAc,CAAC;QACtC,IAAI,CAAC,KAAK,EAAE;AACV,YAAA,MAAM,EAAE,IAAI,CAAC,wDAAwD,CAAC;AACtE,YAAA,OAAO,CAAC,0CAA0C,EAAE,EAAE,CAAC;QACzD;QAEA,MAAM,KAAK,GAAG,QAUb;AAED,QAAA,MAAM,iBAAiB,GAAG,MAAM,yBAAyB,CACvD,QAAQ,EACR,KAAK,CAAC,UAAU,EAChB,KAAK,EACL,MAAM,CACP;AAED,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE;AAC1B,QAAA,IAAI;AACF,YAAA,QAAQ,KAAK,CAAC,MAAM;gBAClB,KAAK,MAAM,EAAE;AACX,oBAAA,IAAI,CAAC,iBAAiB;AAAE,wBAAA,OAAO,CAAC,iCAAiC,EAAE,EAAE,CAAC;AACtE,oBAAA,MAAM,IAAI,GAAa;AACrB,wBAAA,MAAM,EAAE,MAAM;AACd,wBAAA,UAAU,EAAE,iBAAiB;wBAC7B,UAAU,EAAE,KAAK,CAAC,UAAU;wBAC5B,QAAQ,EAAE,KAAK,CAAC,QAAQ;wBACxB,MAAM,EAAE,KAAK,CAAC,MAAM;wBACpB,KAAK,EAAE,KAAK,CAAC,KAAK;qBACnB;oBACD,OAAO,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC;gBACzC;gBACA,KAAK,QAAQ,EAAE;AACb,oBAAA,IAAI,CAAC,iBAAiB;AAAE,wBAAA,OAAO,CAAC,mCAAmC,EAAE,EAAE,CAAC;oBACxE,IAAI,CAAC,KAAK,CAAC,OAAO;AAAE,wBAAA,OAAO,CAAC,gCAAgC,EAAE,EAAE,CAAC;AACjE,oBAAA,MAAM,IAAI,GAAe;AACvB,wBAAA,MAAM,EAAE,QAAQ;AAChB,wBAAA,UAAU,EAAE,iBAAiB;wBAC7B,OAAO,EAAE,KAAK,CAAC,OAAO;wBACtB,KAAK,EAAE,KAAK,CAAC,KAAK;wBAClB,OAAO,EAAE,KAAK,CAAC,OAAO;wBACtB,MAAM,EAAE,KAAK,CAAC,MAAM;wBACpB,KAAK,EAAE,KAAK,CAAC,KAAK;qBACnB;oBACD,OAAO,MAAM,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC;gBAC3C;gBACA,KAAK,MAAM,EAAE;AACX,oBAAA,MAAM,IAAI,GAAa,EAAE,MAAM,EAAE,MAAM,EAAE;oBACzC,OAAO,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC;gBACzC;gBACA,KAAK,MAAM,EAAE;AACX,oBAAA,IAAI,CAAC,iBAAiB;AAAE,wBAAA,OAAO,CAAC,iCAAiC,EAAE,EAAE,CAAC;AACtE,oBAAA,MAAM,IAAI,GAAa;AACrB,wBAAA,MAAM,EAAE,MAAM;AACd,wBAAA,UAAU,EAAE,iBAAiB;qBAC9B;oBACD,OAAO,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC;gBACzC;AACA,gBAAA;oBACE,OAAO,CAAC,mBAAoB,KAA4B,CAAC,MAAM,CAAA,CAAE,EAAE,EAAE,CAAC;;QAE5E;QAAE,OAAO,GAAG,EAAE;YACZ,MAAM,CAAC,GAAG,GAAG,YAAY,KAAK,GAAG,GAAG,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AAC7D,YAAA,MAAM,EAAE,KAAK,CAAC,gCAAgC,EAAE;gBAC9C,MAAM,EAAE,KAAK,CAAC,MAAM;AACpB,gBAAA,SAAS,EAAE,iBAAiB;gBAC5B,KAAK,EAAE,CAAC,CAAC,OAAO;gBAChB,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAA,EAAA,CAAI;AACrC,aAAA,CAAC;YACF,OAAO,CAAC,UAAU,CAAC,CAAC,OAAO,CAAA,CAAE,EAAE,EAAE,CAAC;QACpC;AACF,IAAA,CAAC,EACD;AACE,QAAA,IAAI,EAAEG,0BAAmB;AACzB,QAAA,cAAc,EAAE,sBAAsB;QACtC,WAAW,EAAE,mBAAmB,IAAI,kCAAkC;AACtE,QAAA,MAAM,EAAEC,0BAAmB;AAC5B,KAAA,CACF;AACH;;;;;;;;;"}
|
|
1
|
+
{"version":3,"file":"tool.cjs","sources":["../../../../src/tools/artifacts/tool.ts"],"sourcesContent":["/**\n * artifact_tool + content_reader library factories.\n *\n * The library owns the LangChain wiring (schema, description, response\n * shape) and the action dispatch; the runtime supplies a handler bundle\n * matching the `ArtifactWriteHandlers` / `ContentReadHandlers` interface.\n *\n * This keeps 800+ LOC of host-specific handler logic (S3 adapters, file\n * model CRUD, syntax checkers, line utils) out of the library while\n * still centralizing the tool surface every runtime shares.\n */\n\nimport { tool, DynamicStructuredTool } from '@langchain/core/tools';\nimport {\n artifactToolSchema,\n contentReaderSchema,\n ARTIFACT_TOOL_NAME,\n CONTENT_READER_NAME,\n} from './schema';\nimport type {\n ArtifactToolConfig,\n ContentReaderToolConfig,\n ArtifactToolScope,\n ArtifactToolResult,\n WriteArgs,\n EditArgs,\n VerifyArgs,\n DeleteArgs,\n ReadArgs,\n SearchArgs,\n ListArgs,\n InfoArgs,\n ContentIdResolver,\n} from './types';\n\nconst DEFAULT_ARTIFACT_DESCRIPTION = `Author content artifacts that render live in the host's preview panel — this tool does NOT produce downloadable files (use execute_code for those).\n\nActions:\n- write: Create a new artifact. Write a COMPLETE file in one call. The \\`name\\` field MUST include the file extension — it routes the preview (.tsx, .html, .mmd, .svg, .csv, .json, .dot, .md, .drawio).\n- verify: Check an artifact for syntax errors. REQUIRED as the next step after every write/edit on code files — do not render until verify passes.\n- edit: Surgical string replacement — provide old_str (exact match) and new_str. Works on all file types.\n- delete: Remove an artifact and its backing file.\n\nArtifacts are persisted by the host. No manual save needed.`;\n\nconst DEFAULT_CONTENT_READER_DESCRIPTION = `Read and navigate stored content — artifacts authored by artifact_tool, large tool results auto-cached by the host, uploaded file attachments, and code blocks.\n\nRead-only surface. Use write/edit tools (artifact_tool, execute_code) to mutate.\n\nActions:\n- read: Return line ranges from a specific content_id.\n- search: Regex search across a specific content_id with paginated matches.\n- list: Enumerate every content entry currently stored.\n- info: Metadata (size, kind, creation time) for a specific content_id.`;\n\n/**\n * Optional content_id self-healing — if the runtime supplies a resolver,\n * we pre-resolve the ID on every action that takes one so nicknames\n * (e.g., \"Dashboard\") map to canonical IDs.\n */\nasync function resolveContentIdIfPresent(\n resolver: ContentIdResolver | undefined,\n id: string | undefined,\n scope: ArtifactToolScope,\n logger?: { debug: (msg: string) => void }\n): Promise<string | undefined> {\n if (!resolver || !id) return id;\n const out = await resolver.resolve(id, scope);\n if (!out) return id;\n if (out.resolvedId !== id) {\n logger?.debug(\n `[artifact] resolved \"${id}\" → \"${out.resolvedId}\"${out.resolvedName ? ` (\"${out.resolvedName}\")` : ''}`\n );\n }\n return out.resolvedId;\n}\n\n// ─── Writer tool (artifact_tool) ─────────────────────────────────────────\n\nexport function createArtifactTool(\n config: ArtifactToolConfig\n): DynamicStructuredTool {\n const { handlers, getScope, resolver, logger, descriptionOverride } = config;\n\n return tool(\n async (rawInput, runnableConfig): Promise<ArtifactToolResult> => {\n const scope = getScope(runnableConfig);\n if (!scope) {\n logger?.warn('[artifact_tool] no scope resolved from runnableConfig');\n return ['Error: No conversation context available', {}];\n }\n\n const input = rawInput as {\n action: 'write' | 'edit' | 'verify' | 'delete';\n content_id?: string;\n content?: string;\n name?: string;\n old_str?: string;\n new_str?: string;\n replace_all?: boolean;\n };\n\n const resolvedContentId = await resolveContentIdIfPresent(\n resolver,\n input.content_id,\n scope,\n logger\n );\n\n const started = Date.now();\n try {\n switch (input.action) {\n case 'write': {\n const args: WriteArgs = {\n action: 'write',\n content_id: resolvedContentId,\n content: input.content ?? '',\n name: input.name,\n };\n if (!args.content) return ['Error: write requires content', {}];\n return await handlers.write(args, scope);\n }\n case 'edit': {\n if (!resolvedContentId)\n return ['Error: edit requires content_id', {}];\n const args: EditArgs = {\n action: 'edit',\n content_id: resolvedContentId,\n old_str: input.old_str ?? '',\n new_str: input.new_str ?? '',\n replace_all: input.replace_all,\n };\n if (!args.old_str) return ['Error: edit requires old_str', {}];\n return await handlers.edit(args, scope);\n }\n case 'verify': {\n if (!resolvedContentId)\n return ['Error: verify requires content_id', {}];\n const args: VerifyArgs = {\n action: 'verify',\n content_id: resolvedContentId,\n };\n return await handlers.verify(args, scope);\n }\n case 'delete': {\n if (!resolvedContentId)\n return ['Error: delete requires content_id', {}];\n const args: DeleteArgs = {\n action: 'delete',\n content_id: resolvedContentId,\n };\n return await handlers.delete(args, scope);\n }\n default:\n return [\n `Unknown action: ${(input as { action: string }).action}`,\n {},\n ];\n }\n } catch (err) {\n const e = err instanceof Error ? err : new Error(String(err));\n logger?.error('[artifact_tool] handler threw', {\n action: input.action,\n contentId: resolvedContentId,\n error: e.message,\n elapsed: `${Date.now() - started}ms`,\n });\n return [`Error: ${e.message}`, {}];\n }\n },\n {\n name: ARTIFACT_TOOL_NAME,\n responseFormat: 'content_and_artifact',\n description: descriptionOverride ?? DEFAULT_ARTIFACT_DESCRIPTION,\n schema: artifactToolSchema,\n }\n );\n}\n\n// ─── Reader tool (content_reader) ────────────────────────────────────────\n\nexport function createContentReaderTool(\n config: ContentReaderToolConfig\n): DynamicStructuredTool {\n const { handlers, getScope, resolver, logger, descriptionOverride } = config;\n\n return tool(\n async (rawInput, runnableConfig): Promise<ArtifactToolResult> => {\n const scope = getScope(runnableConfig);\n if (!scope) {\n logger?.warn('[content_reader] no scope resolved from runnableConfig');\n return ['Error: No conversation context available', {}];\n }\n\n const input = rawInput as {\n action: 'read' | 'search' | 'list' | 'info';\n content_id?: string;\n start_line?: number;\n end_line?: number;\n pattern?: string;\n flags?: string;\n context?: number;\n offset?: number;\n limit?: number;\n };\n\n const resolvedContentId = await resolveContentIdIfPresent(\n resolver,\n input.content_id,\n scope,\n logger\n );\n\n const started = Date.now();\n try {\n switch (input.action) {\n case 'read': {\n if (!resolvedContentId)\n return ['Error: read requires content_id', {}];\n const args: ReadArgs = {\n action: 'read',\n content_id: resolvedContentId,\n start_line: input.start_line,\n end_line: input.end_line,\n offset: input.offset,\n limit: input.limit,\n };\n return await handlers.read(args, scope);\n }\n case 'search': {\n if (!resolvedContentId)\n return ['Error: search requires content_id', {}];\n if (!input.pattern) return ['Error: search requires pattern', {}];\n const args: SearchArgs = {\n action: 'search',\n content_id: resolvedContentId,\n pattern: input.pattern,\n flags: input.flags,\n context: input.context,\n offset: input.offset,\n limit: input.limit,\n };\n return await handlers.search(args, scope);\n }\n case 'list': {\n const args: ListArgs = { action: 'list' };\n return await handlers.list(args, scope);\n }\n case 'info': {\n if (!resolvedContentId)\n return ['Error: info requires content_id', {}];\n const args: InfoArgs = {\n action: 'info',\n content_id: resolvedContentId,\n };\n return await handlers.info(args, scope);\n }\n default:\n return [\n `Unknown action: ${(input as { action: string }).action}`,\n {},\n ];\n }\n } catch (err) {\n const e = err instanceof Error ? err : new Error(String(err));\n logger?.error('[content_reader] handler threw', {\n action: input.action,\n contentId: resolvedContentId,\n error: e.message,\n elapsed: `${Date.now() - started}ms`,\n });\n return [`Error: ${e.message}`, {}];\n }\n },\n {\n name: CONTENT_READER_NAME,\n responseFormat: 'content_and_artifact',\n description: descriptionOverride ?? DEFAULT_CONTENT_READER_DESCRIPTION,\n schema: contentReaderSchema,\n }\n );\n}\n\nexport {\n ARTIFACT_TOOL_NAME,\n CONTENT_READER_NAME,\n ARTIFACT_WRITE_ACTIONS,\n CONTENT_READ_ACTIONS,\n} from './schema';\n"],"names":["tool","ARTIFACT_TOOL_NAME","artifactToolSchema","CONTENT_READER_NAME","contentReaderSchema"],"mappings":";;;;;AAAA;;;;;;;;;;AAUG;AAyBH,MAAM,4BAA4B,GAAG,CAAA;;;;;;;;4DAQuB;AAE5D,MAAM,kCAAkC,GAAG,CAAA;;;;;;;;wEAQ6B;AAExE;;;;AAIG;AACH,eAAe,yBAAyB,CACtC,QAAuC,EACvC,EAAsB,EACtB,KAAwB,EACxB,MAAyC,EAAA;AAEzC,IAAA,IAAI,CAAC,QAAQ,IAAI,CAAC,EAAE;AAAE,QAAA,OAAO,EAAE;IAC/B,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,EAAE,EAAE,KAAK,CAAC;AAC7C,IAAA,IAAI,CAAC,GAAG;AAAE,QAAA,OAAO,EAAE;AACnB,IAAA,IAAI,GAAG,CAAC,UAAU,KAAK,EAAE,EAAE;QACzB,MAAM,EAAE,KAAK,CACX,CAAA,qBAAA,EAAwB,EAAE,CAAA,KAAA,EAAQ,GAAG,CAAC,UAAU,CAAA,CAAA,EAAI,GAAG,CAAC,YAAY,GAAG,CAAA,GAAA,EAAM,GAAG,CAAC,YAAY,CAAA,EAAA,CAAI,GAAG,EAAE,CAAA,CAAE,CACzG;IACH;IACA,OAAO,GAAG,CAAC,UAAU;AACvB;AAEA;AAEM,SAAU,kBAAkB,CAChC,MAA0B,EAAA;AAE1B,IAAA,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,mBAAmB,EAAE,GAAG,MAAM;IAE5E,OAAOA,UAAI,CACT,OAAO,QAAQ,EAAE,cAAc,KAAiC;AAC9D,QAAA,MAAM,KAAK,GAAG,QAAQ,CAAC,cAAc,CAAC;QACtC,IAAI,CAAC,KAAK,EAAE;AACV,YAAA,MAAM,EAAE,IAAI,CAAC,uDAAuD,CAAC;AACrE,YAAA,OAAO,CAAC,0CAA0C,EAAE,EAAE,CAAC;QACzD;QAEA,MAAM,KAAK,GAAG,QAQb;AAED,QAAA,MAAM,iBAAiB,GAAG,MAAM,yBAAyB,CACvD,QAAQ,EACR,KAAK,CAAC,UAAU,EAChB,KAAK,EACL,MAAM,CACP;AAED,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE;AAC1B,QAAA,IAAI;AACF,YAAA,QAAQ,KAAK,CAAC,MAAM;gBAClB,KAAK,OAAO,EAAE;AACZ,oBAAA,MAAM,IAAI,GAAc;AACtB,wBAAA,MAAM,EAAE,OAAO;AACf,wBAAA,UAAU,EAAE,iBAAiB;AAC7B,wBAAA,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,EAAE;wBAC5B,IAAI,EAAE,KAAK,CAAC,IAAI;qBACjB;oBACD,IAAI,CAAC,IAAI,CAAC,OAAO;AAAE,wBAAA,OAAO,CAAC,+BAA+B,EAAE,EAAE,CAAC;oBAC/D,OAAO,MAAM,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC;gBAC1C;gBACA,KAAK,MAAM,EAAE;AACX,oBAAA,IAAI,CAAC,iBAAiB;AACpB,wBAAA,OAAO,CAAC,iCAAiC,EAAE,EAAE,CAAC;AAChD,oBAAA,MAAM,IAAI,GAAa;AACrB,wBAAA,MAAM,EAAE,MAAM;AACd,wBAAA,UAAU,EAAE,iBAAiB;AAC7B,wBAAA,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,EAAE;AAC5B,wBAAA,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,EAAE;wBAC5B,WAAW,EAAE,KAAK,CAAC,WAAW;qBAC/B;oBACD,IAAI,CAAC,IAAI,CAAC,OAAO;AAAE,wBAAA,OAAO,CAAC,8BAA8B,EAAE,EAAE,CAAC;oBAC9D,OAAO,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC;gBACzC;gBACA,KAAK,QAAQ,EAAE;AACb,oBAAA,IAAI,CAAC,iBAAiB;AACpB,wBAAA,OAAO,CAAC,mCAAmC,EAAE,EAAE,CAAC;AAClD,oBAAA,MAAM,IAAI,GAAe;AACvB,wBAAA,MAAM,EAAE,QAAQ;AAChB,wBAAA,UAAU,EAAE,iBAAiB;qBAC9B;oBACD,OAAO,MAAM,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC;gBAC3C;gBACA,KAAK,QAAQ,EAAE;AACb,oBAAA,IAAI,CAAC,iBAAiB;AACpB,wBAAA,OAAO,CAAC,mCAAmC,EAAE,EAAE,CAAC;AAClD,oBAAA,MAAM,IAAI,GAAe;AACvB,wBAAA,MAAM,EAAE,QAAQ;AAChB,wBAAA,UAAU,EAAE,iBAAiB;qBAC9B;oBACD,OAAO,MAAM,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC;gBAC3C;AACA,gBAAA;oBACE,OAAO;wBACL,CAAA,gBAAA,EAAoB,KAA4B,CAAC,MAAM,CAAA,CAAE;wBACzD,EAAE;qBACH;;QAEP;QAAE,OAAO,GAAG,EAAE;YACZ,MAAM,CAAC,GAAG,GAAG,YAAY,KAAK,GAAG,GAAG,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AAC7D,YAAA,MAAM,EAAE,KAAK,CAAC,+BAA+B,EAAE;gBAC7C,MAAM,EAAE,KAAK,CAAC,MAAM;AACpB,gBAAA,SAAS,EAAE,iBAAiB;gBAC5B,KAAK,EAAE,CAAC,CAAC,OAAO;gBAChB,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAA,EAAA,CAAI;AACrC,aAAA,CAAC;YACF,OAAO,CAAC,UAAU,CAAC,CAAC,OAAO,CAAA,CAAE,EAAE,EAAE,CAAC;QACpC;AACF,IAAA,CAAC,EACD;AACE,QAAA,IAAI,EAAEC,yBAAkB;AACxB,QAAA,cAAc,EAAE,sBAAsB;QACtC,WAAW,EAAE,mBAAmB,IAAI,4BAA4B;AAChE,QAAA,MAAM,EAAEC,yBAAkB;AAC3B,KAAA,CACF;AACH;AAEA;AAEM,SAAU,uBAAuB,CACrC,MAA+B,EAAA;AAE/B,IAAA,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,mBAAmB,EAAE,GAAG,MAAM;IAE5E,OAAOF,UAAI,CACT,OAAO,QAAQ,EAAE,cAAc,KAAiC;AAC9D,QAAA,MAAM,KAAK,GAAG,QAAQ,CAAC,cAAc,CAAC;QACtC,IAAI,CAAC,KAAK,EAAE;AACV,YAAA,MAAM,EAAE,IAAI,CAAC,wDAAwD,CAAC;AACtE,YAAA,OAAO,CAAC,0CAA0C,EAAE,EAAE,CAAC;QACzD;QAEA,MAAM,KAAK,GAAG,QAUb;AAED,QAAA,MAAM,iBAAiB,GAAG,MAAM,yBAAyB,CACvD,QAAQ,EACR,KAAK,CAAC,UAAU,EAChB,KAAK,EACL,MAAM,CACP;AAED,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE;AAC1B,QAAA,IAAI;AACF,YAAA,QAAQ,KAAK,CAAC,MAAM;gBAClB,KAAK,MAAM,EAAE;AACX,oBAAA,IAAI,CAAC,iBAAiB;AACpB,wBAAA,OAAO,CAAC,iCAAiC,EAAE,EAAE,CAAC;AAChD,oBAAA,MAAM,IAAI,GAAa;AACrB,wBAAA,MAAM,EAAE,MAAM;AACd,wBAAA,UAAU,EAAE,iBAAiB;wBAC7B,UAAU,EAAE,KAAK,CAAC,UAAU;wBAC5B,QAAQ,EAAE,KAAK,CAAC,QAAQ;wBACxB,MAAM,EAAE,KAAK,CAAC,MAAM;wBACpB,KAAK,EAAE,KAAK,CAAC,KAAK;qBACnB;oBACD,OAAO,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC;gBACzC;gBACA,KAAK,QAAQ,EAAE;AACb,oBAAA,IAAI,CAAC,iBAAiB;AACpB,wBAAA,OAAO,CAAC,mCAAmC,EAAE,EAAE,CAAC;oBAClD,IAAI,CAAC,KAAK,CAAC,OAAO;AAAE,wBAAA,OAAO,CAAC,gCAAgC,EAAE,EAAE,CAAC;AACjE,oBAAA,MAAM,IAAI,GAAe;AACvB,wBAAA,MAAM,EAAE,QAAQ;AAChB,wBAAA,UAAU,EAAE,iBAAiB;wBAC7B,OAAO,EAAE,KAAK,CAAC,OAAO;wBACtB,KAAK,EAAE,KAAK,CAAC,KAAK;wBAClB,OAAO,EAAE,KAAK,CAAC,OAAO;wBACtB,MAAM,EAAE,KAAK,CAAC,MAAM;wBACpB,KAAK,EAAE,KAAK,CAAC,KAAK;qBACnB;oBACD,OAAO,MAAM,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC;gBAC3C;gBACA,KAAK,MAAM,EAAE;AACX,oBAAA,MAAM,IAAI,GAAa,EAAE,MAAM,EAAE,MAAM,EAAE;oBACzC,OAAO,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC;gBACzC;gBACA,KAAK,MAAM,EAAE;AACX,oBAAA,IAAI,CAAC,iBAAiB;AACpB,wBAAA,OAAO,CAAC,iCAAiC,EAAE,EAAE,CAAC;AAChD,oBAAA,MAAM,IAAI,GAAa;AACrB,wBAAA,MAAM,EAAE,MAAM;AACd,wBAAA,UAAU,EAAE,iBAAiB;qBAC9B;oBACD,OAAO,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC;gBACzC;AACA,gBAAA;oBACE,OAAO;wBACL,CAAA,gBAAA,EAAoB,KAA4B,CAAC,MAAM,CAAA,CAAE;wBACzD,EAAE;qBACH;;QAEP;QAAE,OAAO,GAAG,EAAE;YACZ,MAAM,CAAC,GAAG,GAAG,YAAY,KAAK,GAAG,GAAG,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AAC7D,YAAA,MAAM,EAAE,KAAK,CAAC,gCAAgC,EAAE;gBAC9C,MAAM,EAAE,KAAK,CAAC,MAAM;AACpB,gBAAA,SAAS,EAAE,iBAAiB;gBAC5B,KAAK,EAAE,CAAC,CAAC,OAAO;gBAChB,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAA,EAAA,CAAI;AACrC,aAAA,CAAC;YACF,OAAO,CAAC,UAAU,CAAC,CAAC,OAAO,CAAA,CAAE,EAAE,EAAE,CAAC;QACpC;AACF,IAAA,CAAC,EACD;AACE,QAAA,IAAI,EAAEG,0BAAmB;AACzB,QAAA,cAAc,EAAE,sBAAsB;QACtC,WAAW,EAAE,mBAAmB,IAAI,kCAAkC;AACtE,QAAA,MAAM,EAAEC,0BAAmB;AAC5B,KAAA,CACF;AACH;;;;;;;;;"}
|
|
@@ -111,6 +111,10 @@ function normalizeEntry(entry) {
|
|
|
111
111
|
icon: entry.icon,
|
|
112
112
|
category: entry.category,
|
|
113
113
|
tags: entry.tags,
|
|
114
|
+
// Governance — hosts use these to gate UI/role/environment.
|
|
115
|
+
hidden: entry.hidden,
|
|
116
|
+
admin: entry.admin,
|
|
117
|
+
env: entry.env,
|
|
114
118
|
},
|
|
115
119
|
};
|
|
116
120
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToolsServerCapabilityProvider.mjs","sources":["../../../../src/providers/tools-server/ToolsServerCapabilityProvider.ts"],"sourcesContent":["/**\n * ToolsServerCapabilityProvider — capabilities sourced from a tools-server\n * HTTP endpoint.\n *\n * Fetches the manifest via GET /manifest, builds proxy StructuredTools via\n * POST /execute/:tool. Manifest is cached (TTL-configurable) so repeated\n * init cycles don't refetch.\n *\n * See docs/architecture-capability-layer.md for the design rationale.\n */\n\nimport type { AxiosInstance } from 'axios';\nimport type { StructuredToolInterface } from '@langchain/core/tools';\nimport {\n CapabilityKind,\n type Capability,\n type CapabilityFilter,\n type CapabilityProvider,\n type CredentialMap,\n} from '@/providers/types';\nimport {\n createHttpClient,\n type HttpClientConfig,\n assertOk,\n} from '@/utils/httpClient';\nimport {\n ManifestCache,\n filterToCacheKey,\n applyFilter,\n} from '@/utils/toolManifest';\nimport { buildProxyTool } from '@/tools/proxyTool';\n\n/** Configuration for ToolsServerCapabilityProvider. */\nexport interface ToolsServerConfig {\n /** Tools-server base URL (e.g., https://tools.illuma.ai or http://localhost:3500). */\n baseUrl: string;\n /** API key sent as x-api-key header on all requests. Required. */\n apiKey: string;\n /** Optional override for manifest path. Defaults to `/manifest`. */\n manifestPath?: string;\n /** Optional override for execute path template. Defaults to `/execute/:name`. */\n executePath?: string;\n /** Request timeout in ms. Defaults to 30_000. */\n timeoutMs?: number;\n /** Manifest cache TTL in ms. 0 disables. Defaults to 60_000 (1 min). */\n manifestTtlMs?: number;\n /** Optional pre-built axios instance (for testing). */\n client?: AxiosInstance;\n /** Optional proxy override (defaults to process.env.PROXY). */\n proxy?: string | null;\n}\n\n/**\n * Shape of a single entry from tools-server's /manifest response.\n *\n * Matches the tools-server ManifestToolEntry type. We define our own here\n * to avoid cross-package coupling — the shape is a stable HTTP contract.\n */\ninterface ToolsServerManifestEntry {\n pluginKey: string;\n name: string;\n description: string;\n icon?: string;\n authConfig?: Array<{\n authField: string;\n label?: string;\n description?: string;\n source?: string;\n required?: boolean;\n prod?: boolean;\n admin?: boolean;\n hide?: boolean;\n }>;\n /** Input schema as JSON Schema (tools-server emits `schema`). */\n schema?: unknown;\n /** Legacy alias accepted for backwards compatibility. */\n jsonSchema?: unknown;\n category?: string;\n tags?: string[];\n toolkit?: string;\n endpoint?: string;\n}\n\nexport class ToolsServerCapabilityProvider implements CapabilityProvider {\n readonly providerId: string;\n private readonly client: AxiosInstance;\n private readonly manifestPath: string;\n private readonly executePath: string;\n private readonly cache: ManifestCache;\n\n constructor(private readonly config: ToolsServerConfig) {\n const {\n baseUrl,\n apiKey,\n manifestPath = '/manifest',\n executePath = '/execute/:name',\n timeoutMs = 30_000,\n manifestTtlMs = 60_000,\n client,\n proxy,\n } = config;\n\n if (!baseUrl) {\n throw new Error('ToolsServerCapabilityProvider: baseUrl is required');\n }\n if (!apiKey) {\n throw new Error('ToolsServerCapabilityProvider: apiKey is required');\n }\n\n this.providerId = `tools-server:${baseUrl}`;\n this.manifestPath = manifestPath;\n this.executePath = executePath;\n this.cache = new ManifestCache({ ttlMs: manifestTtlMs });\n\n if (client) {\n this.client = client;\n } else {\n const httpConfig: HttpClientConfig = {\n baseURL: baseUrl,\n apiKey,\n timeoutMs,\n proxy,\n };\n this.client = createHttpClient(httpConfig);\n }\n }\n\n async fetchManifest(filter?: CapabilityFilter): Promise<Capability[]> {\n const cacheKey = filterToCacheKey(filter);\n const cached = this.cache.get(cacheKey);\n if (cached) {\n // DEBUG: cache hit (remove after stabilization)\n // eslint-disable-next-line no-console\n console.debug(\n `[${this.providerId}] manifest cache hit — ${cached.length} caps`\n );\n return cached;\n }\n\n // DEBUG\n // eslint-disable-next-line no-console\n console.debug(\n `[${this.providerId}] fetching manifest from ${this.manifestPath}`\n );\n\n const res = await this.client.get<ToolsServerManifestEntry[]>(\n this.manifestPath\n );\n assertOk(res.status, this.manifestPath, res.data);\n\n const entries = Array.isArray(res.data) ? res.data : [];\n const capabilities: Capability[] = entries.map((entry) =>\n normalizeEntry(entry)\n );\n\n // Apply filter before caching the full list separately so unfiltered\n // refetches don't re-hit the network.\n const fullCacheKey = filterToCacheKey();\n this.cache.set(fullCacheKey, capabilities);\n\n const filtered = applyFilter(capabilities, filter);\n if (cacheKey !== fullCacheKey) {\n this.cache.set(cacheKey, filtered);\n }\n\n // DEBUG\n // eslint-disable-next-line no-console\n console.debug(\n `[${this.providerId}] manifest loaded — ${capabilities.length} caps, ${filtered.length} after filter`\n );\n\n return filtered;\n }\n\n async createRunnables(\n capabilities: Capability[],\n credentials: CredentialMap\n ): Promise<StructuredToolInterface[]> {\n return capabilities.map((cap) =>\n buildProxyTool(cap, credentials, {\n client: this.client,\n executePath: this.executePath,\n })\n );\n }\n\n /** Force a manifest refresh on next fetchManifest call. */\n invalidateCache(): void {\n this.cache.clear();\n }\n}\n\n/**\n * Translate a raw tools-server manifest entry into a typed Capability.\n * Defensive — tools-server may add fields; we pull only what we need.\n */\nfunction normalizeEntry(entry: ToolsServerManifestEntry): Capability {\n return {\n kind: CapabilityKind.TOOL,\n name: entry.pluginKey,\n description: entry.description ?? '',\n schema: entry.schema ?? entry.jsonSchema,\n authConfig: (entry.authConfig ?? []).map((ac) => ({\n authField: ac.authField,\n label: ac.label,\n description: ac.description,\n required: ac.required,\n prod: ac.prod,\n admin: ac.admin,\n hide: ac.hide,\n // Source is a string in wire format; downstream consumers coerce to AuthSource.\n source: ac.source as Capability['authConfig'][number]['source'],\n })),\n metadata: {\n icon: entry.icon,\n category: entry.category,\n tags: entry.tags,\n },\n };\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ToolsServerCapabilityProvider.mjs","sources":["../../../../src/providers/tools-server/ToolsServerCapabilityProvider.ts"],"sourcesContent":["/**\n * ToolsServerCapabilityProvider — capabilities sourced from a tools-server\n * HTTP endpoint.\n *\n * Fetches the manifest via GET /manifest, builds proxy StructuredTools via\n * POST /execute/:tool. Manifest is cached (TTL-configurable) so repeated\n * init cycles don't refetch.\n *\n * See docs/architecture-capability-layer.md for the design rationale.\n */\n\nimport type { AxiosInstance } from 'axios';\nimport type { StructuredToolInterface } from '@langchain/core/tools';\nimport {\n CapabilityKind,\n type Capability,\n type CapabilityFilter,\n type CapabilityProvider,\n type CredentialMap,\n} from '@/providers/types';\nimport {\n createHttpClient,\n type HttpClientConfig,\n assertOk,\n} from '@/utils/httpClient';\nimport {\n ManifestCache,\n filterToCacheKey,\n applyFilter,\n} from '@/utils/toolManifest';\nimport { buildProxyTool } from '@/tools/proxyTool';\n\n/** Configuration for ToolsServerCapabilityProvider. */\nexport interface ToolsServerConfig {\n /** Tools-server base URL (e.g., https://tools.illuma.ai or http://localhost:3500). */\n baseUrl: string;\n /** API key sent as x-api-key header on all requests. Required. */\n apiKey: string;\n /** Optional override for manifest path. Defaults to `/manifest`. */\n manifestPath?: string;\n /** Optional override for execute path template. Defaults to `/execute/:name`. */\n executePath?: string;\n /** Request timeout in ms. Defaults to 30_000. */\n timeoutMs?: number;\n /** Manifest cache TTL in ms. 0 disables. Defaults to 60_000 (1 min). */\n manifestTtlMs?: number;\n /** Optional pre-built axios instance (for testing). */\n client?: AxiosInstance;\n /** Optional proxy override (defaults to process.env.PROXY). */\n proxy?: string | null;\n}\n\n/**\n * Shape of a single entry from tools-server's /manifest response.\n *\n * Matches the tools-server ManifestToolEntry type. We define our own here\n * to avoid cross-package coupling — the shape is a stable HTTP contract.\n */\ninterface ToolsServerManifestEntry {\n pluginKey: string;\n name: string;\n description: string;\n icon?: string;\n authConfig?: Array<{\n authField: string;\n label?: string;\n description?: string;\n source?: string;\n required?: boolean;\n prod?: boolean;\n admin?: boolean;\n hide?: boolean;\n }>;\n /** Input schema as JSON Schema (tools-server emits `schema`). */\n schema?: unknown;\n /** Legacy alias accepted for backwards compatibility. */\n jsonSchema?: unknown;\n category?: string;\n tags?: string[];\n toolkit?: string;\n endpoint?: string;\n /** Governance flags forwarded by tools-server getManifest(). */\n hidden?: boolean;\n admin?: boolean;\n env?: Array<'development' | 'production' | 'test' | 'staging'>;\n}\n\nexport class ToolsServerCapabilityProvider implements CapabilityProvider {\n readonly providerId: string;\n private readonly client: AxiosInstance;\n private readonly manifestPath: string;\n private readonly executePath: string;\n private readonly cache: ManifestCache;\n\n constructor(private readonly config: ToolsServerConfig) {\n const {\n baseUrl,\n apiKey,\n manifestPath = '/manifest',\n executePath = '/execute/:name',\n timeoutMs = 30_000,\n manifestTtlMs = 60_000,\n client,\n proxy,\n } = config;\n\n if (!baseUrl) {\n throw new Error('ToolsServerCapabilityProvider: baseUrl is required');\n }\n if (!apiKey) {\n throw new Error('ToolsServerCapabilityProvider: apiKey is required');\n }\n\n this.providerId = `tools-server:${baseUrl}`;\n this.manifestPath = manifestPath;\n this.executePath = executePath;\n this.cache = new ManifestCache({ ttlMs: manifestTtlMs });\n\n if (client) {\n this.client = client;\n } else {\n const httpConfig: HttpClientConfig = {\n baseURL: baseUrl,\n apiKey,\n timeoutMs,\n proxy,\n };\n this.client = createHttpClient(httpConfig);\n }\n }\n\n async fetchManifest(filter?: CapabilityFilter): Promise<Capability[]> {\n const cacheKey = filterToCacheKey(filter);\n const cached = this.cache.get(cacheKey);\n if (cached) {\n // DEBUG: cache hit (remove after stabilization)\n // eslint-disable-next-line no-console\n console.debug(\n `[${this.providerId}] manifest cache hit — ${cached.length} caps`\n );\n return cached;\n }\n\n // DEBUG\n // eslint-disable-next-line no-console\n console.debug(\n `[${this.providerId}] fetching manifest from ${this.manifestPath}`\n );\n\n const res = await this.client.get<ToolsServerManifestEntry[]>(\n this.manifestPath\n );\n assertOk(res.status, this.manifestPath, res.data);\n\n const entries = Array.isArray(res.data) ? res.data : [];\n const capabilities: Capability[] = entries.map((entry) =>\n normalizeEntry(entry)\n );\n\n // Apply filter before caching the full list separately so unfiltered\n // refetches don't re-hit the network.\n const fullCacheKey = filterToCacheKey();\n this.cache.set(fullCacheKey, capabilities);\n\n const filtered = applyFilter(capabilities, filter);\n if (cacheKey !== fullCacheKey) {\n this.cache.set(cacheKey, filtered);\n }\n\n // DEBUG\n // eslint-disable-next-line no-console\n console.debug(\n `[${this.providerId}] manifest loaded — ${capabilities.length} caps, ${filtered.length} after filter`\n );\n\n return filtered;\n }\n\n async createRunnables(\n capabilities: Capability[],\n credentials: CredentialMap\n ): Promise<StructuredToolInterface[]> {\n return capabilities.map((cap) =>\n buildProxyTool(cap, credentials, {\n client: this.client,\n executePath: this.executePath,\n })\n );\n }\n\n /** Force a manifest refresh on next fetchManifest call. */\n invalidateCache(): void {\n this.cache.clear();\n }\n}\n\n/**\n * Translate a raw tools-server manifest entry into a typed Capability.\n * Defensive — tools-server may add fields; we pull only what we need.\n */\nfunction normalizeEntry(entry: ToolsServerManifestEntry): Capability {\n return {\n kind: CapabilityKind.TOOL,\n name: entry.pluginKey,\n description: entry.description ?? '',\n schema: entry.schema ?? entry.jsonSchema,\n authConfig: (entry.authConfig ?? []).map((ac) => ({\n authField: ac.authField,\n label: ac.label,\n description: ac.description,\n required: ac.required,\n prod: ac.prod,\n admin: ac.admin,\n hide: ac.hide,\n // Source is a string in wire format; downstream consumers coerce to AuthSource.\n source: ac.source as Capability['authConfig'][number]['source'],\n })),\n metadata: {\n icon: entry.icon,\n category: entry.category,\n tags: entry.tags,\n // Governance — hosts use these to gate UI/role/environment.\n hidden: entry.hidden,\n admin: entry.admin,\n env: entry.env,\n },\n };\n}\n"],"names":[],"mappings":";;;;;AAAA;;;;;;;;;AASG;MA8EU,6BAA6B,CAAA;AAOX,IAAA,MAAA;AANpB,IAAA,UAAU;AACF,IAAA,MAAM;AACN,IAAA,YAAY;AACZ,IAAA,WAAW;AACX,IAAA,KAAK;AAEtB,IAAA,WAAA,CAA6B,MAAyB,EAAA;QAAzB,IAAA,CAAA,MAAM,GAAN,MAAM;QACjC,MAAM,EACJ,OAAO,EACP,MAAM,EACN,YAAY,GAAG,WAAW,EAC1B,WAAW,GAAG,gBAAgB,EAC9B,SAAS,GAAG,MAAM,EAClB,aAAa,GAAG,MAAM,EACtB,MAAM,EACN,KAAK,GACN,GAAG,MAAM;QAEV,IAAI,CAAC,OAAO,EAAE;AACZ,YAAA,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC;QACvE;QACA,IAAI,CAAC,MAAM,EAAE;AACX,YAAA,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC;QACtE;AAEA,QAAA,IAAI,CAAC,UAAU,GAAG,CAAA,aAAA,EAAgB,OAAO,EAAE;AAC3C,QAAA,IAAI,CAAC,YAAY,GAAG,YAAY;AAChC,QAAA,IAAI,CAAC,WAAW,GAAG,WAAW;AAC9B,QAAA,IAAI,CAAC,KAAK,GAAG,IAAI,aAAa,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;QAExD,IAAI,MAAM,EAAE;AACV,YAAA,IAAI,CAAC,MAAM,GAAG,MAAM;QACtB;aAAO;AACL,YAAA,MAAM,UAAU,GAAqB;AACnC,gBAAA,OAAO,EAAE,OAAO;gBAChB,MAAM;gBACN,SAAS;gBACT,KAAK;aACN;AACD,YAAA,IAAI,CAAC,MAAM,GAAG,gBAAgB,CAAC,UAAU,CAAC;QAC5C;IACF;IAEA,MAAM,aAAa,CAAC,MAAyB,EAAA;AAC3C,QAAA,MAAM,QAAQ,GAAG,gBAAgB,CAAC,MAAM,CAAC;QACzC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC;QACvC,IAAI,MAAM,EAAE;;;AAGV,YAAA,OAAO,CAAC,KAAK,CACX,CAAA,CAAA,EAAI,IAAI,CAAC,UAAU,CAAA,uBAAA,EAA0B,MAAM,CAAC,MAAM,CAAA,KAAA,CAAO,CAClE;AACD,YAAA,OAAO,MAAM;QACf;;;AAIA,QAAA,OAAO,CAAC,KAAK,CACX,CAAA,CAAA,EAAI,IAAI,CAAC,UAAU,CAAA,yBAAA,EAA4B,IAAI,CAAC,YAAY,CAAA,CAAE,CACnE;AAED,QAAA,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAC/B,IAAI,CAAC,YAAY,CAClB;AACD,QAAA,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,GAAG,CAAC,IAAI,CAAC;QAEjD,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,IAAI,GAAG,EAAE;AACvD,QAAA,MAAM,YAAY,GAAiB,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,KACnD,cAAc,CAAC,KAAK,CAAC,CACtB;;;AAID,QAAA,MAAM,YAAY,GAAG,gBAAgB,EAAE;QACvC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,EAAE,YAAY,CAAC;QAE1C,MAAM,QAAQ,GAAG,WAAW,CAAC,YAAY,EAAE,MAAM,CAAC;AAClD,QAAA,IAAI,QAAQ,KAAK,YAAY,EAAE;YAC7B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC;QACpC;;;AAIA,QAAA,OAAO,CAAC,KAAK,CACX,CAAA,CAAA,EAAI,IAAI,CAAC,UAAU,CAAA,oBAAA,EAAuB,YAAY,CAAC,MAAM,CAAA,OAAA,EAAU,QAAQ,CAAC,MAAM,CAAA,aAAA,CAAe,CACtG;AAED,QAAA,OAAO,QAAQ;IACjB;AAEA,IAAA,MAAM,eAAe,CACnB,YAA0B,EAC1B,WAA0B,EAAA;AAE1B,QAAA,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC,GAAG,KAC1B,cAAc,CAAC,GAAG,EAAE,WAAW,EAAE;YAC/B,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,WAAW,EAAE,IAAI,CAAC,WAAW;AAC9B,SAAA,CAAC,CACH;IACH;;IAGA,eAAe,GAAA;AACb,QAAA,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE;IACpB;AACD;AAED;;;AAGG;AACH,SAAS,cAAc,CAAC,KAA+B,EAAA;IACrD,OAAO;QACL,IAAI,EAAE,cAAc,CAAC,IAAI;QACzB,IAAI,EAAE,KAAK,CAAC,SAAS;AACrB,QAAA,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,EAAE;AACpC,QAAA,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,UAAU;AACxC,QAAA,UAAU,EAAE,CAAC,KAAK,CAAC,UAAU,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC,EAAE,MAAM;YAChD,SAAS,EAAE,EAAE,CAAC,SAAS;YACvB,KAAK,EAAE,EAAE,CAAC,KAAK;YACf,WAAW,EAAE,EAAE,CAAC,WAAW;YAC3B,QAAQ,EAAE,EAAE,CAAC,QAAQ;YACrB,IAAI,EAAE,EAAE,CAAC,IAAI;YACb,KAAK,EAAE,EAAE,CAAC,KAAK;YACf,IAAI,EAAE,EAAE,CAAC,IAAI;;YAEb,MAAM,EAAE,EAAE,CAAC,MAAoD;AAChE,SAAA,CAAC,CAAC;AACH,QAAA,QAAQ,EAAE;YACR,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,IAAI,EAAE,KAAK,CAAC,IAAI;;YAEhB,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,GAAG,EAAE,KAAK,CAAC,GAAG;AACf,SAAA;KACF;AACH;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.mjs","sources":["../../../src/providers/types.ts"],"sourcesContent":["/**\n * CapabilityProvider types — the abstraction that lets agents consume tools,\n * skills, and MCP-backed capabilities through a single interface regardless\n * of where they come from.\n *\n * Design principles:\n * 1. Source-agnostic — providers are distinguished by WHERE they come from\n * (tools-server, skill store, MCP server), not by the backend service\n * any individual tool calls.\n * 2. Credential-agnostic — providers receive a flat credentialMap from the\n * host; they don't know about user settings, databases, OAuth flows.\n * 3. Extension-ready — the shape reserves slots for upcoming patterns\n * (skills injectedMessages, ToolCall.auth/expires_at, skill sessions)\n * so when those land we don't refactor the core.\n */\n\nimport type { StructuredToolInterface } from '@langchain/core/tools';\n\n/**\n * Kind of capability. Today only TOOL is implemented; SKILL and MCP are\n * reserved — SkillCapabilityProvider + MCPCapabilityProvider will populate\n * them in later phases. Keeping the enum from day one prevents a breaking\n * change when those ship.\n */\nexport enum CapabilityKind {\n TOOL = 'tool',\n SKILL = 'skill',\n MCP = 'mcp',\n /**\n * Remote agent reachable over the A2A (Agent-to-Agent) protocol.\n * The library's `A2ACapabilityProvider` is a client for this kind —\n * invoking an A2A capability sends a JSON-RPC `tasks/send` to the\n * remote agent's endpoint.\n */\n A2A = 'a2a',\n}\n\n/**\n * Where an auth credential comes from. Used by hosts to decide whether to\n * forward the credential per-request or let the capability provider resolve\n * it from its own environment.\n */\nexport enum AuthSource {\n /** Resolved by the capability provider itself from its environment. Host never sends. */\n SERVER = 'server',\n /** User-configured value stored in the host's credential store. Host forwards per-request. */\n USER = 'user',\n /** Active OAuth/session token. Host forwards per-request from active session. */\n FORWARDED = 'forwarded',\n}\n\n/**\n * One entry in a capability's auth config. Describes a single credential\n * the capability needs. The `source` field tells the host how to resolve\n * the value; the `prod`/`admin`/`hide` flags control UI visibility.\n */\nexport interface AuthConfigEntry {\n /** Environment-variable-style name (e.g., \"OPENAI_API_KEY\"). Stable identifier. */\n authField: string;\n /** Human-readable label for UI. */\n label?: string;\n /** Optional description of how to obtain the credential. */\n description?: string;\n /** Where the value comes from. Defaults to USER if unspecified. */\n source?: AuthSource;\n /** True if the credential is required for the capability to function. */\n required?: boolean;\n /** Platform-managed in production — never prompt user. */\n prod?: boolean;\n /** Only admins can configure. */\n admin?: boolean;\n /** Never show in any UI (used when source === SERVER). */\n hide?: boolean;\n}\n\n/**\n * Arbitrary metadata attached to a capability. Extension point.\n *\n * Fields prefixed with \"Reserved for\" are not populated today but exist in\n * the type so upstream patterns (skills, auth expiration, sessions) can\n * drop in without a schema migration.\n */\nexport interface CapabilityMetadata {\n /** Icon URL or path relative to the provider's static asset root. */\n icon?: string;\n /** Category for UI grouping (e.g., \"search\", \"image\", \"finance\"). */\n category?: string;\n /** Free-form tags for filtering / search. */\n tags?: string[];\n\n // --- Reserved for upstream patterns (not populated today) ---\n\n /** Reserved for upstream `fix/auth-events` — auth mode declared by tool. */\n auth?: string;\n /** Reserved for upstream `fix/auth-events` — Unix timestamp for token expiration. */\n expires_at?: number;\n /** Reserved for upstream skills — capability returns injected messages on execute. */\n injectedMessages?: boolean;\n /** Reserved for upstream skills — capability consumes ToolSessionMap state. */\n sessionAware?: boolean;\n}\n\n/**\n * A single capability — a tool, skill, or MCP-backed operation that an agent\n * can invoke. The shape mirrors common plugin-manifest conventions so the\n * same entry can round-trip between an upstream catalog and a host registry.\n */\nexport interface Capability {\n /** What kind of capability this is. Controls how it's invoked downstream. */\n kind: CapabilityKind;\n /**\n * Stable unique identifier. For tools this is the pluginKey\n * (e.g., \"dalle\", \"wikipedia\"). For skills this is the skill's `name`.\n * Used everywhere the capability is referenced.\n */\n name: string;\n /** Human-readable description for the LLM and UI. */\n description: string;\n /**\n * Input schema as JSON Schema. For tools this comes from the Zod schema\n * passed through `zodToJsonSchema`. Optional for capabilities with no\n * input (e.g., parameter-less skills).\n */\n schema?: unknown;\n /** Credential requirements. */\n authConfig: AuthConfigEntry[];\n /** Extension metadata. See CapabilityMetadata. */\n metadata: CapabilityMetadata;\n}\n\n/** Filter for fetchManifest. All fields optional; missing = no filter. */\nexport interface CapabilityFilter {\n kind?: CapabilityKind;\n tags?: string[];\n /** Restrict to capabilities whose `name` is in this list. */\n names?: string[];\n}\n\n/**\n * A flat credential map: authField → value.\n *\n * The host is responsible for resolving values (from env vars, user\n * settings, OAuth sessions, etc.) before passing to the provider. The\n * provider does not inspect the origin — it just forwards to the tool.\n */\nexport type CredentialMap = Record<string, string>;\n\n/**\n * The core interface. All concrete providers implement this.\n *\n * Providers are identified by `providerId` for logging/debug. They fetch\n * their own manifest and build LangChain-compatible runnables from it.\n *\n * Lifetime: a provider may be instantiated once at startup (e.g., tools-\n * server pointing at a stable URL) or per-user (e.g., MCP with per-user\n * OAuth). The interface is agnostic.\n */\nexport interface CapabilityProvider {\n /** Stable identifier for this provider instance (e.g., \"tools-server:https://...\"). */\n readonly providerId: string;\n\n /**\n * Return the list of capabilities this provider exposes.\n *\n * Implementations may cache the manifest — the contract is that the\n * returned list reflects the provider's current view of available\n * capabilities.\n *\n * @param filter optional filter to scope the result\n */\n fetchManifest(filter?: CapabilityFilter): Promise<Capability[]>;\n\n /**\n * Build LangChain StructuredTools from a set of capabilities using the\n * caller-supplied credentials.\n *\n * Called at agent init. The returned tools are bound to the LLM and\n * invoked during the graph's tool-calling loop.\n *\n * @param capabilities the subset of capabilities the agent wants to use\n * @param credentials credential values keyed by authField\n */\n createRunnables(\n capabilities: Capability[],\n credentials: CredentialMap\n ): Promise<StructuredToolInterface[]>;\n}\n"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;AAcG;AAIH;;;;;AAKG;IACS;AAAZ,CAAA,UAAY,cAAc,EAAA;AACxB,IAAA,cAAA,CAAA,MAAA,CAAA,GAAA,MAAa;AACb,IAAA,cAAA,CAAA,OAAA,CAAA,GAAA,OAAe;AACf,IAAA,cAAA,CAAA,KAAA,CAAA,GAAA,KAAW;AACX;;;;;AAKG;AACH,IAAA,cAAA,CAAA,KAAA,CAAA,GAAA,KAAW;AACb,CAAC,EAXW,cAAc,KAAd,cAAc,GAAA,EAAA,CAAA,CAAA;AAa1B;;;;AAIG;IACS;AAAZ,CAAA,UAAY,UAAU,EAAA;;AAEpB,IAAA,UAAA,CAAA,QAAA,CAAA,GAAA,QAAiB;;AAEjB,IAAA,UAAA,CAAA,MAAA,CAAA,GAAA,MAAa;;AAEb,IAAA,UAAA,CAAA,WAAA,CAAA,GAAA,WAAuB;AACzB,CAAC,EAPW,UAAU,KAAV,UAAU,GAAA,EAAA,CAAA,CAAA;;;;"}
|
|
1
|
+
{"version":3,"file":"types.mjs","sources":["../../../src/providers/types.ts"],"sourcesContent":["/**\n * CapabilityProvider types — the abstraction that lets agents consume tools,\n * skills, and MCP-backed capabilities through a single interface regardless\n * of where they come from.\n *\n * Design principles:\n * 1. Source-agnostic — providers are distinguished by WHERE they come from\n * (tools-server, skill store, MCP server), not by the backend service\n * any individual tool calls.\n * 2. Credential-agnostic — providers receive a flat credentialMap from the\n * host; they don't know about user settings, databases, OAuth flows.\n * 3. Extension-ready — the shape reserves slots for upcoming patterns\n * (skills injectedMessages, ToolCall.auth/expires_at, skill sessions)\n * so when those land we don't refactor the core.\n */\n\nimport type { StructuredToolInterface } from '@langchain/core/tools';\n\n/**\n * Kind of capability. Today only TOOL is implemented; SKILL and MCP are\n * reserved — SkillCapabilityProvider + MCPCapabilityProvider will populate\n * them in later phases. Keeping the enum from day one prevents a breaking\n * change when those ship.\n */\nexport enum CapabilityKind {\n TOOL = 'tool',\n SKILL = 'skill',\n MCP = 'mcp',\n /**\n * Remote agent reachable over the A2A (Agent-to-Agent) protocol.\n * The library's `A2ACapabilityProvider` is a client for this kind —\n * invoking an A2A capability sends a JSON-RPC `tasks/send` to the\n * remote agent's endpoint.\n */\n A2A = 'a2a',\n}\n\n/**\n * Where an auth credential comes from. Used by hosts to decide whether to\n * forward the credential per-request or let the capability provider resolve\n * it from its own environment.\n */\nexport enum AuthSource {\n /** Resolved by the capability provider itself from its environment. Host never sends. */\n SERVER = 'server',\n /** User-configured value stored in the host's credential store. Host forwards per-request. */\n USER = 'user',\n /** Active OAuth/session token. Host forwards per-request from active session. */\n FORWARDED = 'forwarded',\n}\n\n/**\n * One entry in a capability's auth config. Describes a single credential\n * the capability needs. The `source` field tells the host how to resolve\n * the value; the `prod`/`admin`/`hide` flags control UI visibility.\n */\nexport interface AuthConfigEntry {\n /** Environment-variable-style name (e.g., \"OPENAI_API_KEY\"). Stable identifier. */\n authField: string;\n /** Human-readable label for UI. */\n label?: string;\n /** Optional description of how to obtain the credential. */\n description?: string;\n /** Where the value comes from. Defaults to USER if unspecified. */\n source?: AuthSource;\n /** True if the credential is required for the capability to function. */\n required?: boolean;\n /** Platform-managed in production — never prompt user. */\n prod?: boolean;\n /** Only admins can configure. */\n admin?: boolean;\n /** Never show in any UI (used when source === SERVER). */\n hide?: boolean;\n}\n\n/**\n * Arbitrary metadata attached to a capability. Extension point.\n *\n * Fields prefixed with \"Reserved for\" are not populated today but exist in\n * the type so upstream patterns (skills, auth expiration, sessions) can\n * drop in without a schema migration.\n */\nexport interface CapabilityMetadata {\n /** Icon URL or path relative to the provider's static asset root. */\n icon?: string;\n /** Category for UI grouping (e.g., \"search\", \"image\", \"finance\"). */\n category?: string;\n /** Free-form tags for filtering / search. */\n tags?: string[];\n\n // --- Governance flags ------------------------------------------------\n\n /**\n * When true, hosts omit this capability from user-facing pickers\n * (Agent Builder, tool dropdown). Still invokable when a saved agent\n * references it by name.\n */\n hidden?: boolean;\n /** When true, only admin-role users can enable or invoke this capability. */\n admin?: boolean;\n /**\n * Deployment-stage restriction. When set, hosts whose deployment stage\n * isn't in the array should hide the capability (e.g., a prod host\n * shouldn't surface a tool with `env: ['development']`).\n */\n env?: Array<'development' | 'production' | 'test' | 'staging'>;\n\n // --- Reserved for upstream patterns (not populated today) ---\n\n /** Reserved for upstream `fix/auth-events` — auth mode declared by tool. */\n auth?: string;\n /** Reserved for upstream `fix/auth-events` — Unix timestamp for token expiration. */\n expires_at?: number;\n /** Reserved for upstream skills — capability returns injected messages on execute. */\n injectedMessages?: boolean;\n /** Reserved for upstream skills — capability consumes ToolSessionMap state. */\n sessionAware?: boolean;\n}\n\n/**\n * A single capability — a tool, skill, or MCP-backed operation that an agent\n * can invoke. The shape mirrors common plugin-manifest conventions so the\n * same entry can round-trip between an upstream catalog and a host registry.\n */\nexport interface Capability {\n /** What kind of capability this is. Controls how it's invoked downstream. */\n kind: CapabilityKind;\n /**\n * Stable unique identifier. For tools this is the pluginKey\n * (e.g., \"dalle\", \"wikipedia\"). For skills this is the skill's `name`.\n * Used everywhere the capability is referenced.\n */\n name: string;\n /** Human-readable description for the LLM and UI. */\n description: string;\n /**\n * Input schema as JSON Schema. For tools this comes from the Zod schema\n * passed through `zodToJsonSchema`. Optional for capabilities with no\n * input (e.g., parameter-less skills).\n */\n schema?: unknown;\n /** Credential requirements. */\n authConfig: AuthConfigEntry[];\n /** Extension metadata. See CapabilityMetadata. */\n metadata: CapabilityMetadata;\n}\n\n/** Filter for fetchManifest. All fields optional; missing = no filter. */\nexport interface CapabilityFilter {\n kind?: CapabilityKind;\n tags?: string[];\n /** Restrict to capabilities whose `name` is in this list. */\n names?: string[];\n}\n\n/**\n * A flat credential map: authField → value.\n *\n * The host is responsible for resolving values (from env vars, user\n * settings, OAuth sessions, etc.) before passing to the provider. The\n * provider does not inspect the origin — it just forwards to the tool.\n */\nexport type CredentialMap = Record<string, string>;\n\n/**\n * The core interface. All concrete providers implement this.\n *\n * Providers are identified by `providerId` for logging/debug. They fetch\n * their own manifest and build LangChain-compatible runnables from it.\n *\n * Lifetime: a provider may be instantiated once at startup (e.g., tools-\n * server pointing at a stable URL) or per-user (e.g., MCP with per-user\n * OAuth). The interface is agnostic.\n */\nexport interface CapabilityProvider {\n /** Stable identifier for this provider instance (e.g., \"tools-server:https://...\"). */\n readonly providerId: string;\n\n /**\n * Return the list of capabilities this provider exposes.\n *\n * Implementations may cache the manifest — the contract is that the\n * returned list reflects the provider's current view of available\n * capabilities.\n *\n * @param filter optional filter to scope the result\n */\n fetchManifest(filter?: CapabilityFilter): Promise<Capability[]>;\n\n /**\n * Build LangChain StructuredTools from a set of capabilities using the\n * caller-supplied credentials.\n *\n * Called at agent init. The returned tools are bound to the LLM and\n * invoked during the graph's tool-calling loop.\n *\n * @param capabilities the subset of capabilities the agent wants to use\n * @param credentials credential values keyed by authField\n */\n createRunnables(\n capabilities: Capability[],\n credentials: CredentialMap\n ): Promise<StructuredToolInterface[]>;\n}\n"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;AAcG;AAIH;;;;;AAKG;IACS;AAAZ,CAAA,UAAY,cAAc,EAAA;AACxB,IAAA,cAAA,CAAA,MAAA,CAAA,GAAA,MAAa;AACb,IAAA,cAAA,CAAA,OAAA,CAAA,GAAA,OAAe;AACf,IAAA,cAAA,CAAA,KAAA,CAAA,GAAA,KAAW;AACX;;;;;AAKG;AACH,IAAA,cAAA,CAAA,KAAA,CAAA,GAAA,KAAW;AACb,CAAC,EAXW,cAAc,KAAd,cAAc,GAAA,EAAA,CAAA,CAAA;AAa1B;;;;AAIG;IACS;AAAZ,CAAA,UAAY,UAAU,EAAA;;AAEpB,IAAA,UAAA,CAAA,QAAA,CAAA,GAAA,QAAiB;;AAEjB,IAAA,UAAA,CAAA,MAAA,CAAA,GAAA,MAAa;;AAEb,IAAA,UAAA,CAAA,WAAA,CAAA,GAAA,WAAuB;AACzB,CAAC,EAPW,UAAU,KAAV,UAAU,GAAA,EAAA,CAAA,CAAA;;;;"}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
|
|
3
|
-
const ARTIFACT_WRITE_ACTIONS = [
|
|
3
|
+
const ARTIFACT_WRITE_ACTIONS = [
|
|
4
|
+
'write',
|
|
5
|
+
'edit',
|
|
6
|
+
'verify',
|
|
7
|
+
'delete',
|
|
8
|
+
];
|
|
4
9
|
const CONTENT_READ_ACTIONS = ['read', 'search', 'list', 'info'];
|
|
5
10
|
const artifactToolSchema = z.object({
|
|
6
11
|
action: z
|
|
@@ -24,7 +29,10 @@ const artifactToolSchema = z.object({
|
|
|
24
29
|
.string()
|
|
25
30
|
.optional()
|
|
26
31
|
.describe('Exact string to find and replace (required for edit).'),
|
|
27
|
-
new_str: z
|
|
32
|
+
new_str: z
|
|
33
|
+
.string()
|
|
34
|
+
.optional()
|
|
35
|
+
.describe('Replacement string (required for edit).'),
|
|
28
36
|
replace_all: z
|
|
29
37
|
.boolean()
|
|
30
38
|
.optional()
|
|
@@ -42,12 +50,27 @@ const contentReaderSchema = z.object({
|
|
|
42
50
|
start_line: z.number().optional().describe('1-based start line for reading.'),
|
|
43
51
|
end_line: z.number().optional().describe('1-based end line (inclusive).'),
|
|
44
52
|
// search
|
|
45
|
-
pattern: z
|
|
46
|
-
|
|
47
|
-
|
|
53
|
+
pattern: z
|
|
54
|
+
.string()
|
|
55
|
+
.optional()
|
|
56
|
+
.describe('Regex pattern (required for search).'),
|
|
57
|
+
flags: z
|
|
58
|
+
.string()
|
|
59
|
+
.optional()
|
|
60
|
+
.describe('Regex flags (e.g., "i" for case-insensitive).'),
|
|
61
|
+
context: z
|
|
62
|
+
.number()
|
|
63
|
+
.optional()
|
|
64
|
+
.describe('Lines of context around each match.'),
|
|
48
65
|
// shared pagination
|
|
49
|
-
offset: z
|
|
50
|
-
|
|
66
|
+
offset: z
|
|
67
|
+
.number()
|
|
68
|
+
.optional()
|
|
69
|
+
.describe('Offset for read or search pagination.'),
|
|
70
|
+
limit: z
|
|
71
|
+
.number()
|
|
72
|
+
.optional()
|
|
73
|
+
.describe('Max lines (read) or matches (search).'),
|
|
51
74
|
});
|
|
52
75
|
const ARTIFACT_TOOL_NAME = 'artifact_tool';
|
|
53
76
|
const CONTENT_READER_NAME = 'content_reader';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.mjs","sources":["../../../../src/tools/artifacts/schema.ts"],"sourcesContent":["import { z } from 'zod';\n\nexport const ARTIFACT_WRITE_ACTIONS = ['write'
|
|
1
|
+
{"version":3,"file":"schema.mjs","sources":["../../../../src/tools/artifacts/schema.ts"],"sourcesContent":["import { z } from 'zod';\n\nexport const ARTIFACT_WRITE_ACTIONS = [\n 'write',\n 'edit',\n 'verify',\n 'delete',\n] as const;\nexport const CONTENT_READ_ACTIONS = ['read', 'search', 'list', 'info'] as const;\n\nexport const artifactToolSchema = z.object({\n action: z\n .enum(ARTIFACT_WRITE_ACTIONS)\n .describe(\n 'Authoring action: write (create/overwrite), edit (str_replace), verify (syntax check), delete (remove).'\n ),\n content_id: z\n .string()\n .optional()\n .describe(\n 'ID of the artifact entry. Required for edit/verify/delete; optional for write (supply to overwrite an existing entry).'\n ),\n\n // write\n content: z\n .string()\n .optional()\n .describe('Full file content (required for write action).'),\n name: z\n .string()\n .optional()\n .describe(\n 'Filename for the new entry (required when creating). MUST include the correct file extension — the extension drives the preview template.'\n ),\n\n // edit (str_replace)\n old_str: z\n .string()\n .optional()\n .describe('Exact string to find and replace (required for edit).'),\n new_str: z\n .string()\n .optional()\n .describe('Replacement string (required for edit).'),\n replace_all: z\n .boolean()\n .optional()\n .describe(\n 'edit: when true, replaces every occurrence of old_str. When false (default) and old_str matches more than one location, the edit is refused.'\n ),\n});\n\nexport const contentReaderSchema = z.object({\n action: z\n .enum(CONTENT_READ_ACTIONS)\n .describe(\n 'Read-only action: read (lines), search (regex), list (all entries), info (metadata).'\n ),\n content_id: z\n .string()\n .optional()\n .describe(\n 'ID of the content entry. Required for read/search/info. Omit for list.'\n ),\n\n // read pagination\n start_line: z.number().optional().describe('1-based start line for reading.'),\n end_line: z.number().optional().describe('1-based end line (inclusive).'),\n\n // search\n pattern: z\n .string()\n .optional()\n .describe('Regex pattern (required for search).'),\n flags: z\n .string()\n .optional()\n .describe('Regex flags (e.g., \"i\" for case-insensitive).'),\n context: z\n .number()\n .optional()\n .describe('Lines of context around each match.'),\n\n // shared pagination\n offset: z\n .number()\n .optional()\n .describe('Offset for read or search pagination.'),\n limit: z\n .number()\n .optional()\n .describe('Max lines (read) or matches (search).'),\n});\n\nexport const ARTIFACT_TOOL_NAME = 'artifact_tool';\nexport const CONTENT_READER_NAME = 'content_reader';\n\nexport type ArtifactToolInput = z.infer<typeof artifactToolSchema>;\nexport type ContentReaderInput = z.infer<typeof contentReaderSchema>;\n"],"names":[],"mappings":";;AAEO,MAAM,sBAAsB,GAAG;IACpC,OAAO;IACP,MAAM;IACN,QAAQ;IACR,QAAQ;;AAEH,MAAM,oBAAoB,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM;AAE9D,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;AACzC,IAAA,MAAM,EAAE;SACL,IAAI,CAAC,sBAAsB;SAC3B,QAAQ,CACP,yGAAyG,CAC1G;AACH,IAAA,UAAU,EAAE;AACT,SAAA,MAAM;AACN,SAAA,QAAQ;SACR,QAAQ,CACP,wHAAwH,CACzH;;AAGH,IAAA,OAAO,EAAE;AACN,SAAA,MAAM;AACN,SAAA,QAAQ;SACR,QAAQ,CAAC,gDAAgD,CAAC;AAC7D,IAAA,IAAI,EAAE;AACH,SAAA,MAAM;AACN,SAAA,QAAQ;SACR,QAAQ,CACP,2IAA2I,CAC5I;;AAGH,IAAA,OAAO,EAAE;AACN,SAAA,MAAM;AACN,SAAA,QAAQ;SACR,QAAQ,CAAC,uDAAuD,CAAC;AACpE,IAAA,OAAO,EAAE;AACN,SAAA,MAAM;AACN,SAAA,QAAQ;SACR,QAAQ,CAAC,yCAAyC,CAAC;AACtD,IAAA,WAAW,EAAE;AACV,SAAA,OAAO;AACP,SAAA,QAAQ;SACR,QAAQ,CACP,8IAA8I,CAC/I;AACJ,CAAA;AAEM,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;AAC1C,IAAA,MAAM,EAAE;SACL,IAAI,CAAC,oBAAoB;SACzB,QAAQ,CACP,sFAAsF,CACvF;AACH,IAAA,UAAU,EAAE;AACT,SAAA,MAAM;AACN,SAAA,QAAQ;SACR,QAAQ,CACP,wEAAwE,CACzE;;AAGH,IAAA,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,iCAAiC,CAAC;AAC7E,IAAA,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;;AAGzE,IAAA,OAAO,EAAE;AACN,SAAA,MAAM;AACN,SAAA,QAAQ;SACR,QAAQ,CAAC,sCAAsC,CAAC;AACnD,IAAA,KAAK,EAAE;AACJ,SAAA,MAAM;AACN,SAAA,QAAQ;SACR,QAAQ,CAAC,+CAA+C,CAAC;AAC5D,IAAA,OAAO,EAAE;AACN,SAAA,MAAM;AACN,SAAA,QAAQ;SACR,QAAQ,CAAC,qCAAqC,CAAC;;AAGlD,IAAA,MAAM,EAAE;AACL,SAAA,MAAM;AACN,SAAA,QAAQ;SACR,QAAQ,CAAC,uCAAuC,CAAC;AACpD,IAAA,KAAK,EAAE;AACJ,SAAA,MAAM;AACN,SAAA,QAAQ;SACR,QAAQ,CAAC,uCAAuC,CAAC;AACrD,CAAA;AAEM,MAAM,kBAAkB,GAAG;AAC3B,MAAM,mBAAmB,GAAG;;;;"}
|
|
@@ -105,7 +105,10 @@ function createArtifactTool(config) {
|
|
|
105
105
|
return await handlers.delete(args, scope);
|
|
106
106
|
}
|
|
107
107
|
default:
|
|
108
|
-
return [
|
|
108
|
+
return [
|
|
109
|
+
`Unknown action: ${input.action}`,
|
|
110
|
+
{},
|
|
111
|
+
];
|
|
109
112
|
}
|
|
110
113
|
}
|
|
111
114
|
catch (err) {
|
|
@@ -182,7 +185,10 @@ function createContentReaderTool(config) {
|
|
|
182
185
|
return await handlers.info(args, scope);
|
|
183
186
|
}
|
|
184
187
|
default:
|
|
185
|
-
return [
|
|
188
|
+
return [
|
|
189
|
+
`Unknown action: ${input.action}`,
|
|
190
|
+
{},
|
|
191
|
+
];
|
|
186
192
|
}
|
|
187
193
|
}
|
|
188
194
|
catch (err) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool.mjs","sources":["../../../../src/tools/artifacts/tool.ts"],"sourcesContent":["/**\n * artifact_tool + content_reader library factories.\n *\n * The library owns the LangChain wiring (schema, description, response\n * shape) and the action dispatch; the runtime supplies a handler bundle\n * matching the `ArtifactWriteHandlers` / `ContentReadHandlers` interface.\n *\n * This keeps 800+ LOC of host-specific handler logic (S3 adapters, file\n * model CRUD, syntax checkers, line utils) out of the library while\n * still centralizing the tool surface every runtime shares.\n */\n\nimport { tool, DynamicStructuredTool } from '@langchain/core/tools';\nimport {\n artifactToolSchema,\n contentReaderSchema,\n ARTIFACT_TOOL_NAME,\n CONTENT_READER_NAME,\n} from './schema';\nimport type {\n ArtifactToolConfig,\n ContentReaderToolConfig,\n ArtifactToolScope,\n ArtifactToolResult,\n WriteArgs,\n EditArgs,\n VerifyArgs,\n DeleteArgs,\n ReadArgs,\n SearchArgs,\n ListArgs,\n InfoArgs,\n ContentIdResolver,\n} from './types';\n\nconst DEFAULT_ARTIFACT_DESCRIPTION = `Author content artifacts that render live in the host's preview panel — this tool does NOT produce downloadable files (use execute_code for those).\n\nActions:\n- write: Create a new artifact. Write a COMPLETE file in one call. The \\`name\\` field MUST include the file extension — it routes the preview (.tsx, .html, .mmd, .svg, .csv, .json, .dot, .md, .drawio).\n- verify: Check an artifact for syntax errors. REQUIRED as the next step after every write/edit on code files — do not render until verify passes.\n- edit: Surgical string replacement — provide old_str (exact match) and new_str. Works on all file types.\n- delete: Remove an artifact and its backing file.\n\nArtifacts are persisted by the host. No manual save needed.`;\n\nconst DEFAULT_CONTENT_READER_DESCRIPTION = `Read and navigate stored content — artifacts authored by artifact_tool, large tool results auto-cached by the host, uploaded file attachments, and code blocks.\n\nRead-only surface. Use write/edit tools (artifact_tool, execute_code) to mutate.\n\nActions:\n- read: Return line ranges from a specific content_id.\n- search: Regex search across a specific content_id with paginated matches.\n- list: Enumerate every content entry currently stored.\n- info: Metadata (size, kind, creation time) for a specific content_id.`;\n\n/**\n * Optional content_id self-healing — if the runtime supplies a resolver,\n * we pre-resolve the ID on every action that takes one so nicknames\n * (e.g., \"Dashboard\") map to canonical IDs.\n */\nasync function resolveContentIdIfPresent(\n resolver: ContentIdResolver | undefined,\n id: string | undefined,\n scope: ArtifactToolScope,\n logger?: { debug: (msg: string) => void },\n): Promise<string | undefined> {\n if (!resolver || !id) return id;\n const out = await resolver.resolve(id, scope);\n if (!out) return id;\n if (out.resolvedId !== id) {\n logger?.debug(\n `[artifact] resolved \"${id}\" → \"${out.resolvedId}\"${out.resolvedName ? ` (\"${out.resolvedName}\")` : ''}`,\n );\n }\n return out.resolvedId;\n}\n\n// ─── Writer tool (artifact_tool) ─────────────────────────────────────────\n\nexport function createArtifactTool(\n config: ArtifactToolConfig,\n): DynamicStructuredTool {\n const { handlers, getScope, resolver, logger, descriptionOverride } = config;\n\n return tool(\n async (rawInput, runnableConfig): Promise<ArtifactToolResult> => {\n const scope = getScope(runnableConfig);\n if (!scope) {\n logger?.warn('[artifact_tool] no scope resolved from runnableConfig');\n return ['Error: No conversation context available', {}];\n }\n\n const input = rawInput as {\n action: 'write' | 'edit' | 'verify' | 'delete';\n content_id?: string;\n content?: string;\n name?: string;\n old_str?: string;\n new_str?: string;\n replace_all?: boolean;\n };\n\n const resolvedContentId = await resolveContentIdIfPresent(\n resolver,\n input.content_id,\n scope,\n logger,\n );\n\n const started = Date.now();\n try {\n switch (input.action) {\n case 'write': {\n const args: WriteArgs = {\n action: 'write',\n content_id: resolvedContentId,\n content: input.content ?? '',\n name: input.name,\n };\n if (!args.content) return ['Error: write requires content', {}];\n return await handlers.write(args, scope);\n }\n case 'edit': {\n if (!resolvedContentId) return ['Error: edit requires content_id', {}];\n const args: EditArgs = {\n action: 'edit',\n content_id: resolvedContentId,\n old_str: input.old_str ?? '',\n new_str: input.new_str ?? '',\n replace_all: input.replace_all,\n };\n if (!args.old_str) return ['Error: edit requires old_str', {}];\n return await handlers.edit(args, scope);\n }\n case 'verify': {\n if (!resolvedContentId) return ['Error: verify requires content_id', {}];\n const args: VerifyArgs = {\n action: 'verify',\n content_id: resolvedContentId,\n };\n return await handlers.verify(args, scope);\n }\n case 'delete': {\n if (!resolvedContentId) return ['Error: delete requires content_id', {}];\n const args: DeleteArgs = {\n action: 'delete',\n content_id: resolvedContentId,\n };\n return await handlers.delete(args, scope);\n }\n default:\n return [`Unknown action: ${(input as { action: string }).action}`, {}];\n }\n } catch (err) {\n const e = err instanceof Error ? err : new Error(String(err));\n logger?.error('[artifact_tool] handler threw', {\n action: input.action,\n contentId: resolvedContentId,\n error: e.message,\n elapsed: `${Date.now() - started}ms`,\n });\n return [`Error: ${e.message}`, {}];\n }\n },\n {\n name: ARTIFACT_TOOL_NAME,\n responseFormat: 'content_and_artifact',\n description: descriptionOverride ?? DEFAULT_ARTIFACT_DESCRIPTION,\n schema: artifactToolSchema,\n },\n );\n}\n\n// ─── Reader tool (content_reader) ────────────────────────────────────────\n\nexport function createContentReaderTool(\n config: ContentReaderToolConfig,\n): DynamicStructuredTool {\n const { handlers, getScope, resolver, logger, descriptionOverride } = config;\n\n return tool(\n async (rawInput, runnableConfig): Promise<ArtifactToolResult> => {\n const scope = getScope(runnableConfig);\n if (!scope) {\n logger?.warn('[content_reader] no scope resolved from runnableConfig');\n return ['Error: No conversation context available', {}];\n }\n\n const input = rawInput as {\n action: 'read' | 'search' | 'list' | 'info';\n content_id?: string;\n start_line?: number;\n end_line?: number;\n pattern?: string;\n flags?: string;\n context?: number;\n offset?: number;\n limit?: number;\n };\n\n const resolvedContentId = await resolveContentIdIfPresent(\n resolver,\n input.content_id,\n scope,\n logger,\n );\n\n const started = Date.now();\n try {\n switch (input.action) {\n case 'read': {\n if (!resolvedContentId) return ['Error: read requires content_id', {}];\n const args: ReadArgs = {\n action: 'read',\n content_id: resolvedContentId,\n start_line: input.start_line,\n end_line: input.end_line,\n offset: input.offset,\n limit: input.limit,\n };\n return await handlers.read(args, scope);\n }\n case 'search': {\n if (!resolvedContentId) return ['Error: search requires content_id', {}];\n if (!input.pattern) return ['Error: search requires pattern', {}];\n const args: SearchArgs = {\n action: 'search',\n content_id: resolvedContentId,\n pattern: input.pattern,\n flags: input.flags,\n context: input.context,\n offset: input.offset,\n limit: input.limit,\n };\n return await handlers.search(args, scope);\n }\n case 'list': {\n const args: ListArgs = { action: 'list' };\n return await handlers.list(args, scope);\n }\n case 'info': {\n if (!resolvedContentId) return ['Error: info requires content_id', {}];\n const args: InfoArgs = {\n action: 'info',\n content_id: resolvedContentId,\n };\n return await handlers.info(args, scope);\n }\n default:\n return [`Unknown action: ${(input as { action: string }).action}`, {}];\n }\n } catch (err) {\n const e = err instanceof Error ? err : new Error(String(err));\n logger?.error('[content_reader] handler threw', {\n action: input.action,\n contentId: resolvedContentId,\n error: e.message,\n elapsed: `${Date.now() - started}ms`,\n });\n return [`Error: ${e.message}`, {}];\n }\n },\n {\n name: CONTENT_READER_NAME,\n responseFormat: 'content_and_artifact',\n description: descriptionOverride ?? DEFAULT_CONTENT_READER_DESCRIPTION,\n schema: contentReaderSchema,\n },\n );\n}\n\nexport {\n ARTIFACT_TOOL_NAME,\n CONTENT_READER_NAME,\n ARTIFACT_WRITE_ACTIONS,\n CONTENT_READ_ACTIONS,\n} from './schema';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tool.mjs","sources":["../../../../src/tools/artifacts/tool.ts"],"sourcesContent":["/**\n * artifact_tool + content_reader library factories.\n *\n * The library owns the LangChain wiring (schema, description, response\n * shape) and the action dispatch; the runtime supplies a handler bundle\n * matching the `ArtifactWriteHandlers` / `ContentReadHandlers` interface.\n *\n * This keeps 800+ LOC of host-specific handler logic (S3 adapters, file\n * model CRUD, syntax checkers, line utils) out of the library while\n * still centralizing the tool surface every runtime shares.\n */\n\nimport { tool, DynamicStructuredTool } from '@langchain/core/tools';\nimport {\n artifactToolSchema,\n contentReaderSchema,\n ARTIFACT_TOOL_NAME,\n CONTENT_READER_NAME,\n} from './schema';\nimport type {\n ArtifactToolConfig,\n ContentReaderToolConfig,\n ArtifactToolScope,\n ArtifactToolResult,\n WriteArgs,\n EditArgs,\n VerifyArgs,\n DeleteArgs,\n ReadArgs,\n SearchArgs,\n ListArgs,\n InfoArgs,\n ContentIdResolver,\n} from './types';\n\nconst DEFAULT_ARTIFACT_DESCRIPTION = `Author content artifacts that render live in the host's preview panel — this tool does NOT produce downloadable files (use execute_code for those).\n\nActions:\n- write: Create a new artifact. Write a COMPLETE file in one call. The \\`name\\` field MUST include the file extension — it routes the preview (.tsx, .html, .mmd, .svg, .csv, .json, .dot, .md, .drawio).\n- verify: Check an artifact for syntax errors. REQUIRED as the next step after every write/edit on code files — do not render until verify passes.\n- edit: Surgical string replacement — provide old_str (exact match) and new_str. Works on all file types.\n- delete: Remove an artifact and its backing file.\n\nArtifacts are persisted by the host. No manual save needed.`;\n\nconst DEFAULT_CONTENT_READER_DESCRIPTION = `Read and navigate stored content — artifacts authored by artifact_tool, large tool results auto-cached by the host, uploaded file attachments, and code blocks.\n\nRead-only surface. Use write/edit tools (artifact_tool, execute_code) to mutate.\n\nActions:\n- read: Return line ranges from a specific content_id.\n- search: Regex search across a specific content_id with paginated matches.\n- list: Enumerate every content entry currently stored.\n- info: Metadata (size, kind, creation time) for a specific content_id.`;\n\n/**\n * Optional content_id self-healing — if the runtime supplies a resolver,\n * we pre-resolve the ID on every action that takes one so nicknames\n * (e.g., \"Dashboard\") map to canonical IDs.\n */\nasync function resolveContentIdIfPresent(\n resolver: ContentIdResolver | undefined,\n id: string | undefined,\n scope: ArtifactToolScope,\n logger?: { debug: (msg: string) => void }\n): Promise<string | undefined> {\n if (!resolver || !id) return id;\n const out = await resolver.resolve(id, scope);\n if (!out) return id;\n if (out.resolvedId !== id) {\n logger?.debug(\n `[artifact] resolved \"${id}\" → \"${out.resolvedId}\"${out.resolvedName ? ` (\"${out.resolvedName}\")` : ''}`\n );\n }\n return out.resolvedId;\n}\n\n// ─── Writer tool (artifact_tool) ─────────────────────────────────────────\n\nexport function createArtifactTool(\n config: ArtifactToolConfig\n): DynamicStructuredTool {\n const { handlers, getScope, resolver, logger, descriptionOverride } = config;\n\n return tool(\n async (rawInput, runnableConfig): Promise<ArtifactToolResult> => {\n const scope = getScope(runnableConfig);\n if (!scope) {\n logger?.warn('[artifact_tool] no scope resolved from runnableConfig');\n return ['Error: No conversation context available', {}];\n }\n\n const input = rawInput as {\n action: 'write' | 'edit' | 'verify' | 'delete';\n content_id?: string;\n content?: string;\n name?: string;\n old_str?: string;\n new_str?: string;\n replace_all?: boolean;\n };\n\n const resolvedContentId = await resolveContentIdIfPresent(\n resolver,\n input.content_id,\n scope,\n logger\n );\n\n const started = Date.now();\n try {\n switch (input.action) {\n case 'write': {\n const args: WriteArgs = {\n action: 'write',\n content_id: resolvedContentId,\n content: input.content ?? '',\n name: input.name,\n };\n if (!args.content) return ['Error: write requires content', {}];\n return await handlers.write(args, scope);\n }\n case 'edit': {\n if (!resolvedContentId)\n return ['Error: edit requires content_id', {}];\n const args: EditArgs = {\n action: 'edit',\n content_id: resolvedContentId,\n old_str: input.old_str ?? '',\n new_str: input.new_str ?? '',\n replace_all: input.replace_all,\n };\n if (!args.old_str) return ['Error: edit requires old_str', {}];\n return await handlers.edit(args, scope);\n }\n case 'verify': {\n if (!resolvedContentId)\n return ['Error: verify requires content_id', {}];\n const args: VerifyArgs = {\n action: 'verify',\n content_id: resolvedContentId,\n };\n return await handlers.verify(args, scope);\n }\n case 'delete': {\n if (!resolvedContentId)\n return ['Error: delete requires content_id', {}];\n const args: DeleteArgs = {\n action: 'delete',\n content_id: resolvedContentId,\n };\n return await handlers.delete(args, scope);\n }\n default:\n return [\n `Unknown action: ${(input as { action: string }).action}`,\n {},\n ];\n }\n } catch (err) {\n const e = err instanceof Error ? err : new Error(String(err));\n logger?.error('[artifact_tool] handler threw', {\n action: input.action,\n contentId: resolvedContentId,\n error: e.message,\n elapsed: `${Date.now() - started}ms`,\n });\n return [`Error: ${e.message}`, {}];\n }\n },\n {\n name: ARTIFACT_TOOL_NAME,\n responseFormat: 'content_and_artifact',\n description: descriptionOverride ?? DEFAULT_ARTIFACT_DESCRIPTION,\n schema: artifactToolSchema,\n }\n );\n}\n\n// ─── Reader tool (content_reader) ────────────────────────────────────────\n\nexport function createContentReaderTool(\n config: ContentReaderToolConfig\n): DynamicStructuredTool {\n const { handlers, getScope, resolver, logger, descriptionOverride } = config;\n\n return tool(\n async (rawInput, runnableConfig): Promise<ArtifactToolResult> => {\n const scope = getScope(runnableConfig);\n if (!scope) {\n logger?.warn('[content_reader] no scope resolved from runnableConfig');\n return ['Error: No conversation context available', {}];\n }\n\n const input = rawInput as {\n action: 'read' | 'search' | 'list' | 'info';\n content_id?: string;\n start_line?: number;\n end_line?: number;\n pattern?: string;\n flags?: string;\n context?: number;\n offset?: number;\n limit?: number;\n };\n\n const resolvedContentId = await resolveContentIdIfPresent(\n resolver,\n input.content_id,\n scope,\n logger\n );\n\n const started = Date.now();\n try {\n switch (input.action) {\n case 'read': {\n if (!resolvedContentId)\n return ['Error: read requires content_id', {}];\n const args: ReadArgs = {\n action: 'read',\n content_id: resolvedContentId,\n start_line: input.start_line,\n end_line: input.end_line,\n offset: input.offset,\n limit: input.limit,\n };\n return await handlers.read(args, scope);\n }\n case 'search': {\n if (!resolvedContentId)\n return ['Error: search requires content_id', {}];\n if (!input.pattern) return ['Error: search requires pattern', {}];\n const args: SearchArgs = {\n action: 'search',\n content_id: resolvedContentId,\n pattern: input.pattern,\n flags: input.flags,\n context: input.context,\n offset: input.offset,\n limit: input.limit,\n };\n return await handlers.search(args, scope);\n }\n case 'list': {\n const args: ListArgs = { action: 'list' };\n return await handlers.list(args, scope);\n }\n case 'info': {\n if (!resolvedContentId)\n return ['Error: info requires content_id', {}];\n const args: InfoArgs = {\n action: 'info',\n content_id: resolvedContentId,\n };\n return await handlers.info(args, scope);\n }\n default:\n return [\n `Unknown action: ${(input as { action: string }).action}`,\n {},\n ];\n }\n } catch (err) {\n const e = err instanceof Error ? err : new Error(String(err));\n logger?.error('[content_reader] handler threw', {\n action: input.action,\n contentId: resolvedContentId,\n error: e.message,\n elapsed: `${Date.now() - started}ms`,\n });\n return [`Error: ${e.message}`, {}];\n }\n },\n {\n name: CONTENT_READER_NAME,\n responseFormat: 'content_and_artifact',\n description: descriptionOverride ?? DEFAULT_CONTENT_READER_DESCRIPTION,\n schema: contentReaderSchema,\n }\n );\n}\n\nexport {\n ARTIFACT_TOOL_NAME,\n CONTENT_READER_NAME,\n ARTIFACT_WRITE_ACTIONS,\n CONTENT_READ_ACTIONS,\n} from './schema';\n"],"names":[],"mappings":"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"}
|
|
@@ -82,6 +82,20 @@ export interface CapabilityMetadata {
|
|
|
82
82
|
category?: string;
|
|
83
83
|
/** Free-form tags for filtering / search. */
|
|
84
84
|
tags?: string[];
|
|
85
|
+
/**
|
|
86
|
+
* When true, hosts omit this capability from user-facing pickers
|
|
87
|
+
* (Agent Builder, tool dropdown). Still invokable when a saved agent
|
|
88
|
+
* references it by name.
|
|
89
|
+
*/
|
|
90
|
+
hidden?: boolean;
|
|
91
|
+
/** When true, only admin-role users can enable or invoke this capability. */
|
|
92
|
+
admin?: boolean;
|
|
93
|
+
/**
|
|
94
|
+
* Deployment-stage restriction. When set, hosts whose deployment stage
|
|
95
|
+
* isn't in the array should hide the capability (e.g., a prod host
|
|
96
|
+
* shouldn't surface a tool with `env: ['development']`).
|
|
97
|
+
*/
|
|
98
|
+
env?: Array<'development' | 'production' | 'test' | 'staging'>;
|
|
85
99
|
/** Reserved for upstream `fix/auth-events` — auth mode declared by tool. */
|
|
86
100
|
auth?: string;
|
|
87
101
|
/** Reserved for upstream `fix/auth-events` — Unix timestamp for token expiration. */
|
package/package.json
CHANGED
|
@@ -79,6 +79,10 @@ interface ToolsServerManifestEntry {
|
|
|
79
79
|
tags?: string[];
|
|
80
80
|
toolkit?: string;
|
|
81
81
|
endpoint?: string;
|
|
82
|
+
/** Governance flags forwarded by tools-server getManifest(). */
|
|
83
|
+
hidden?: boolean;
|
|
84
|
+
admin?: boolean;
|
|
85
|
+
env?: Array<'development' | 'production' | 'test' | 'staging'>;
|
|
82
86
|
}
|
|
83
87
|
|
|
84
88
|
export class ToolsServerCapabilityProvider implements CapabilityProvider {
|
|
@@ -215,6 +219,10 @@ function normalizeEntry(entry: ToolsServerManifestEntry): Capability {
|
|
|
215
219
|
icon: entry.icon,
|
|
216
220
|
category: entry.category,
|
|
217
221
|
tags: entry.tags,
|
|
222
|
+
// Governance — hosts use these to gate UI/role/environment.
|
|
223
|
+
hidden: entry.hidden,
|
|
224
|
+
admin: entry.admin,
|
|
225
|
+
env: entry.env,
|
|
218
226
|
},
|
|
219
227
|
};
|
|
220
228
|
}
|
package/src/providers/types.ts
CHANGED
|
@@ -88,6 +88,23 @@ export interface CapabilityMetadata {
|
|
|
88
88
|
/** Free-form tags for filtering / search. */
|
|
89
89
|
tags?: string[];
|
|
90
90
|
|
|
91
|
+
// --- Governance flags ------------------------------------------------
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* When true, hosts omit this capability from user-facing pickers
|
|
95
|
+
* (Agent Builder, tool dropdown). Still invokable when a saved agent
|
|
96
|
+
* references it by name.
|
|
97
|
+
*/
|
|
98
|
+
hidden?: boolean;
|
|
99
|
+
/** When true, only admin-role users can enable or invoke this capability. */
|
|
100
|
+
admin?: boolean;
|
|
101
|
+
/**
|
|
102
|
+
* Deployment-stage restriction. When set, hosts whose deployment stage
|
|
103
|
+
* isn't in the array should hide the capability (e.g., a prod host
|
|
104
|
+
* shouldn't surface a tool with `env: ['development']`).
|
|
105
|
+
*/
|
|
106
|
+
env?: Array<'development' | 'production' | 'test' | 'staging'>;
|
|
107
|
+
|
|
91
108
|
// --- Reserved for upstream patterns (not populated today) ---
|
|
92
109
|
|
|
93
110
|
/** Reserved for upstream `fix/auth-events` — auth mode declared by tool. */
|
|
@@ -10,10 +10,7 @@
|
|
|
10
10
|
* We verify each of those paths here with mock handlers.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import {
|
|
14
|
-
createArtifactTool,
|
|
15
|
-
createContentReaderTool,
|
|
16
|
-
} from '../tool';
|
|
13
|
+
import { createArtifactTool, createContentReaderTool } from '../tool';
|
|
17
14
|
import type {
|
|
18
15
|
ArtifactWriteHandlers,
|
|
19
16
|
ContentReadHandlers,
|
|
@@ -105,10 +102,14 @@ describe('createArtifactTool', () => {
|
|
|
105
102
|
await t.invoke({ action: 'write', content: 'hello', name: 'doc.md' });
|
|
106
103
|
expect(handlers.write).toHaveBeenCalledTimes(1);
|
|
107
104
|
expect(handlers._calls[0].args).toEqual(
|
|
108
|
-
expect.objectContaining({
|
|
105
|
+
expect.objectContaining({
|
|
106
|
+
action: 'write',
|
|
107
|
+
content: 'hello',
|
|
108
|
+
name: 'doc.md',
|
|
109
|
+
})
|
|
109
110
|
);
|
|
110
111
|
expect(handlers._calls[0].scope).toEqual(
|
|
111
|
-
expect.objectContaining({ conversationId: 'conv-1' })
|
|
112
|
+
expect.objectContaining({ conversationId: 'conv-1' })
|
|
112
113
|
);
|
|
113
114
|
});
|
|
114
115
|
|
|
@@ -131,17 +132,26 @@ describe('createArtifactTool', () => {
|
|
|
131
132
|
getScope: makeScope,
|
|
132
133
|
});
|
|
133
134
|
const e = await t.invoke({ action: 'edit', old_str: 'a', new_str: 'b' });
|
|
134
|
-
expect(String(Array.isArray(e) ? e[0] : e)).toMatch(
|
|
135
|
+
expect(String(Array.isArray(e) ? e[0] : e)).toMatch(
|
|
136
|
+
/edit requires content_id/i
|
|
137
|
+
);
|
|
135
138
|
const v = await t.invoke({ action: 'verify' });
|
|
136
|
-
expect(String(Array.isArray(v) ? v[0] : v)).toMatch(
|
|
139
|
+
expect(String(Array.isArray(v) ? v[0] : v)).toMatch(
|
|
140
|
+
/verify requires content_id/i
|
|
141
|
+
);
|
|
137
142
|
const d = await t.invoke({ action: 'delete' });
|
|
138
|
-
expect(String(Array.isArray(d) ? d[0] : d)).toMatch(
|
|
143
|
+
expect(String(Array.isArray(d) ? d[0] : d)).toMatch(
|
|
144
|
+
/delete requires content_id/i
|
|
145
|
+
);
|
|
139
146
|
});
|
|
140
147
|
|
|
141
148
|
it('applies the resolver before dispatching to handler', async () => {
|
|
142
149
|
const handlers = makeWriteHandlers();
|
|
143
150
|
const resolver: ContentIdResolver = {
|
|
144
|
-
resolve: jest.fn(async (id) => ({
|
|
151
|
+
resolve: jest.fn(async (id) => ({
|
|
152
|
+
resolvedId: `canonical:${id}`,
|
|
153
|
+
resolvedName: 'X',
|
|
154
|
+
})),
|
|
145
155
|
};
|
|
146
156
|
const t = createArtifactTool({
|
|
147
157
|
handlers,
|
|
@@ -155,7 +165,7 @@ describe('createArtifactTool', () => {
|
|
|
155
165
|
new_str: 'b',
|
|
156
166
|
});
|
|
157
167
|
expect(handlers._calls[0].args).toEqual(
|
|
158
|
-
expect.objectContaining({ content_id: 'canonical:nickname' })
|
|
168
|
+
expect.objectContaining({ content_id: 'canonical:nickname' })
|
|
159
169
|
);
|
|
160
170
|
});
|
|
161
171
|
|
|
@@ -202,11 +212,17 @@ describe('createContentReaderTool', () => {
|
|
|
202
212
|
getScope: makeScope,
|
|
203
213
|
});
|
|
204
214
|
const r = await t.invoke({ action: 'read' });
|
|
205
|
-
expect(String(Array.isArray(r) ? r[0] : r)).toMatch(
|
|
215
|
+
expect(String(Array.isArray(r) ? r[0] : r)).toMatch(
|
|
216
|
+
/read requires content_id/i
|
|
217
|
+
);
|
|
206
218
|
const i = await t.invoke({ action: 'info' });
|
|
207
|
-
expect(String(Array.isArray(i) ? i[0] : i)).toMatch(
|
|
219
|
+
expect(String(Array.isArray(i) ? i[0] : i)).toMatch(
|
|
220
|
+
/info requires content_id/i
|
|
221
|
+
);
|
|
208
222
|
const s = await t.invoke({ action: 'search', pattern: 'p' });
|
|
209
|
-
expect(String(Array.isArray(s) ? s[0] : s)).toMatch(
|
|
223
|
+
expect(String(Array.isArray(s) ? s[0] : s)).toMatch(
|
|
224
|
+
/search requires content_id/i
|
|
225
|
+
);
|
|
210
226
|
});
|
|
211
227
|
|
|
212
228
|
it('rejects search without pattern even when content_id is given', async () => {
|
|
@@ -237,7 +253,7 @@ describe('createContentReaderTool', () => {
|
|
|
237
253
|
content_id: 'c-1',
|
|
238
254
|
start_line: 10,
|
|
239
255
|
end_line: 50,
|
|
240
|
-
})
|
|
256
|
+
})
|
|
241
257
|
);
|
|
242
258
|
});
|
|
243
259
|
});
|
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
|
|
3
|
-
export const ARTIFACT_WRITE_ACTIONS = [
|
|
3
|
+
export const ARTIFACT_WRITE_ACTIONS = [
|
|
4
|
+
'write',
|
|
5
|
+
'edit',
|
|
6
|
+
'verify',
|
|
7
|
+
'delete',
|
|
8
|
+
] as const;
|
|
4
9
|
export const CONTENT_READ_ACTIONS = ['read', 'search', 'list', 'info'] as const;
|
|
5
10
|
|
|
6
11
|
export const artifactToolSchema = z.object({
|
|
7
12
|
action: z
|
|
8
13
|
.enum(ARTIFACT_WRITE_ACTIONS)
|
|
9
14
|
.describe(
|
|
10
|
-
'Authoring action: write (create/overwrite), edit (str_replace), verify (syntax check), delete (remove).'
|
|
15
|
+
'Authoring action: write (create/overwrite), edit (str_replace), verify (syntax check), delete (remove).'
|
|
11
16
|
),
|
|
12
17
|
content_id: z
|
|
13
18
|
.string()
|
|
14
19
|
.optional()
|
|
15
20
|
.describe(
|
|
16
|
-
'ID of the artifact entry. Required for edit/verify/delete; optional for write (supply to overwrite an existing entry).'
|
|
21
|
+
'ID of the artifact entry. Required for edit/verify/delete; optional for write (supply to overwrite an existing entry).'
|
|
17
22
|
),
|
|
18
23
|
|
|
19
24
|
// write
|
|
@@ -25,7 +30,7 @@ export const artifactToolSchema = z.object({
|
|
|
25
30
|
.string()
|
|
26
31
|
.optional()
|
|
27
32
|
.describe(
|
|
28
|
-
'Filename for the new entry (required when creating). MUST include the correct file extension — the extension drives the preview template.'
|
|
33
|
+
'Filename for the new entry (required when creating). MUST include the correct file extension — the extension drives the preview template.'
|
|
29
34
|
),
|
|
30
35
|
|
|
31
36
|
// edit (str_replace)
|
|
@@ -33,12 +38,15 @@ export const artifactToolSchema = z.object({
|
|
|
33
38
|
.string()
|
|
34
39
|
.optional()
|
|
35
40
|
.describe('Exact string to find and replace (required for edit).'),
|
|
36
|
-
new_str: z
|
|
41
|
+
new_str: z
|
|
42
|
+
.string()
|
|
43
|
+
.optional()
|
|
44
|
+
.describe('Replacement string (required for edit).'),
|
|
37
45
|
replace_all: z
|
|
38
46
|
.boolean()
|
|
39
47
|
.optional()
|
|
40
48
|
.describe(
|
|
41
|
-
'edit: when true, replaces every occurrence of old_str. When false (default) and old_str matches more than one location, the edit is refused.'
|
|
49
|
+
'edit: when true, replaces every occurrence of old_str. When false (default) and old_str matches more than one location, the edit is refused.'
|
|
42
50
|
),
|
|
43
51
|
});
|
|
44
52
|
|
|
@@ -46,13 +54,13 @@ export const contentReaderSchema = z.object({
|
|
|
46
54
|
action: z
|
|
47
55
|
.enum(CONTENT_READ_ACTIONS)
|
|
48
56
|
.describe(
|
|
49
|
-
'Read-only action: read (lines), search (regex), list (all entries), info (metadata).'
|
|
57
|
+
'Read-only action: read (lines), search (regex), list (all entries), info (metadata).'
|
|
50
58
|
),
|
|
51
59
|
content_id: z
|
|
52
60
|
.string()
|
|
53
61
|
.optional()
|
|
54
62
|
.describe(
|
|
55
|
-
'ID of the content entry. Required for read/search/info. Omit for list.'
|
|
63
|
+
'ID of the content entry. Required for read/search/info. Omit for list.'
|
|
56
64
|
),
|
|
57
65
|
|
|
58
66
|
// read pagination
|
|
@@ -60,13 +68,28 @@ export const contentReaderSchema = z.object({
|
|
|
60
68
|
end_line: z.number().optional().describe('1-based end line (inclusive).'),
|
|
61
69
|
|
|
62
70
|
// search
|
|
63
|
-
pattern: z
|
|
64
|
-
|
|
65
|
-
|
|
71
|
+
pattern: z
|
|
72
|
+
.string()
|
|
73
|
+
.optional()
|
|
74
|
+
.describe('Regex pattern (required for search).'),
|
|
75
|
+
flags: z
|
|
76
|
+
.string()
|
|
77
|
+
.optional()
|
|
78
|
+
.describe('Regex flags (e.g., "i" for case-insensitive).'),
|
|
79
|
+
context: z
|
|
80
|
+
.number()
|
|
81
|
+
.optional()
|
|
82
|
+
.describe('Lines of context around each match.'),
|
|
66
83
|
|
|
67
84
|
// shared pagination
|
|
68
|
-
offset: z
|
|
69
|
-
|
|
85
|
+
offset: z
|
|
86
|
+
.number()
|
|
87
|
+
.optional()
|
|
88
|
+
.describe('Offset for read or search pagination.'),
|
|
89
|
+
limit: z
|
|
90
|
+
.number()
|
|
91
|
+
.optional()
|
|
92
|
+
.describe('Max lines (read) or matches (search).'),
|
|
70
93
|
});
|
|
71
94
|
|
|
72
95
|
export const ARTIFACT_TOOL_NAME = 'artifact_tool';
|
|
@@ -62,14 +62,14 @@ async function resolveContentIdIfPresent(
|
|
|
62
62
|
resolver: ContentIdResolver | undefined,
|
|
63
63
|
id: string | undefined,
|
|
64
64
|
scope: ArtifactToolScope,
|
|
65
|
-
logger?: { debug: (msg: string) => void }
|
|
65
|
+
logger?: { debug: (msg: string) => void }
|
|
66
66
|
): Promise<string | undefined> {
|
|
67
67
|
if (!resolver || !id) return id;
|
|
68
68
|
const out = await resolver.resolve(id, scope);
|
|
69
69
|
if (!out) return id;
|
|
70
70
|
if (out.resolvedId !== id) {
|
|
71
71
|
logger?.debug(
|
|
72
|
-
`[artifact] resolved "${id}" → "${out.resolvedId}"${out.resolvedName ? ` ("${out.resolvedName}")` : ''}
|
|
72
|
+
`[artifact] resolved "${id}" → "${out.resolvedId}"${out.resolvedName ? ` ("${out.resolvedName}")` : ''}`
|
|
73
73
|
);
|
|
74
74
|
}
|
|
75
75
|
return out.resolvedId;
|
|
@@ -78,7 +78,7 @@ async function resolveContentIdIfPresent(
|
|
|
78
78
|
// ─── Writer tool (artifact_tool) ─────────────────────────────────────────
|
|
79
79
|
|
|
80
80
|
export function createArtifactTool(
|
|
81
|
-
config: ArtifactToolConfig
|
|
81
|
+
config: ArtifactToolConfig
|
|
82
82
|
): DynamicStructuredTool {
|
|
83
83
|
const { handlers, getScope, resolver, logger, descriptionOverride } = config;
|
|
84
84
|
|
|
@@ -104,7 +104,7 @@ export function createArtifactTool(
|
|
|
104
104
|
resolver,
|
|
105
105
|
input.content_id,
|
|
106
106
|
scope,
|
|
107
|
-
logger
|
|
107
|
+
logger
|
|
108
108
|
);
|
|
109
109
|
|
|
110
110
|
const started = Date.now();
|
|
@@ -121,7 +121,8 @@ export function createArtifactTool(
|
|
|
121
121
|
return await handlers.write(args, scope);
|
|
122
122
|
}
|
|
123
123
|
case 'edit': {
|
|
124
|
-
if (!resolvedContentId)
|
|
124
|
+
if (!resolvedContentId)
|
|
125
|
+
return ['Error: edit requires content_id', {}];
|
|
125
126
|
const args: EditArgs = {
|
|
126
127
|
action: 'edit',
|
|
127
128
|
content_id: resolvedContentId,
|
|
@@ -133,7 +134,8 @@ export function createArtifactTool(
|
|
|
133
134
|
return await handlers.edit(args, scope);
|
|
134
135
|
}
|
|
135
136
|
case 'verify': {
|
|
136
|
-
if (!resolvedContentId)
|
|
137
|
+
if (!resolvedContentId)
|
|
138
|
+
return ['Error: verify requires content_id', {}];
|
|
137
139
|
const args: VerifyArgs = {
|
|
138
140
|
action: 'verify',
|
|
139
141
|
content_id: resolvedContentId,
|
|
@@ -141,7 +143,8 @@ export function createArtifactTool(
|
|
|
141
143
|
return await handlers.verify(args, scope);
|
|
142
144
|
}
|
|
143
145
|
case 'delete': {
|
|
144
|
-
if (!resolvedContentId)
|
|
146
|
+
if (!resolvedContentId)
|
|
147
|
+
return ['Error: delete requires content_id', {}];
|
|
145
148
|
const args: DeleteArgs = {
|
|
146
149
|
action: 'delete',
|
|
147
150
|
content_id: resolvedContentId,
|
|
@@ -149,7 +152,10 @@ export function createArtifactTool(
|
|
|
149
152
|
return await handlers.delete(args, scope);
|
|
150
153
|
}
|
|
151
154
|
default:
|
|
152
|
-
return [
|
|
155
|
+
return [
|
|
156
|
+
`Unknown action: ${(input as { action: string }).action}`,
|
|
157
|
+
{},
|
|
158
|
+
];
|
|
153
159
|
}
|
|
154
160
|
} catch (err) {
|
|
155
161
|
const e = err instanceof Error ? err : new Error(String(err));
|
|
@@ -167,14 +173,14 @@ export function createArtifactTool(
|
|
|
167
173
|
responseFormat: 'content_and_artifact',
|
|
168
174
|
description: descriptionOverride ?? DEFAULT_ARTIFACT_DESCRIPTION,
|
|
169
175
|
schema: artifactToolSchema,
|
|
170
|
-
}
|
|
176
|
+
}
|
|
171
177
|
);
|
|
172
178
|
}
|
|
173
179
|
|
|
174
180
|
// ─── Reader tool (content_reader) ────────────────────────────────────────
|
|
175
181
|
|
|
176
182
|
export function createContentReaderTool(
|
|
177
|
-
config: ContentReaderToolConfig
|
|
183
|
+
config: ContentReaderToolConfig
|
|
178
184
|
): DynamicStructuredTool {
|
|
179
185
|
const { handlers, getScope, resolver, logger, descriptionOverride } = config;
|
|
180
186
|
|
|
@@ -202,14 +208,15 @@ export function createContentReaderTool(
|
|
|
202
208
|
resolver,
|
|
203
209
|
input.content_id,
|
|
204
210
|
scope,
|
|
205
|
-
logger
|
|
211
|
+
logger
|
|
206
212
|
);
|
|
207
213
|
|
|
208
214
|
const started = Date.now();
|
|
209
215
|
try {
|
|
210
216
|
switch (input.action) {
|
|
211
217
|
case 'read': {
|
|
212
|
-
if (!resolvedContentId)
|
|
218
|
+
if (!resolvedContentId)
|
|
219
|
+
return ['Error: read requires content_id', {}];
|
|
213
220
|
const args: ReadArgs = {
|
|
214
221
|
action: 'read',
|
|
215
222
|
content_id: resolvedContentId,
|
|
@@ -221,7 +228,8 @@ export function createContentReaderTool(
|
|
|
221
228
|
return await handlers.read(args, scope);
|
|
222
229
|
}
|
|
223
230
|
case 'search': {
|
|
224
|
-
if (!resolvedContentId)
|
|
231
|
+
if (!resolvedContentId)
|
|
232
|
+
return ['Error: search requires content_id', {}];
|
|
225
233
|
if (!input.pattern) return ['Error: search requires pattern', {}];
|
|
226
234
|
const args: SearchArgs = {
|
|
227
235
|
action: 'search',
|
|
@@ -239,7 +247,8 @@ export function createContentReaderTool(
|
|
|
239
247
|
return await handlers.list(args, scope);
|
|
240
248
|
}
|
|
241
249
|
case 'info': {
|
|
242
|
-
if (!resolvedContentId)
|
|
250
|
+
if (!resolvedContentId)
|
|
251
|
+
return ['Error: info requires content_id', {}];
|
|
243
252
|
const args: InfoArgs = {
|
|
244
253
|
action: 'info',
|
|
245
254
|
content_id: resolvedContentId,
|
|
@@ -247,7 +256,10 @@ export function createContentReaderTool(
|
|
|
247
256
|
return await handlers.info(args, scope);
|
|
248
257
|
}
|
|
249
258
|
default:
|
|
250
|
-
return [
|
|
259
|
+
return [
|
|
260
|
+
`Unknown action: ${(input as { action: string }).action}`,
|
|
261
|
+
{},
|
|
262
|
+
];
|
|
251
263
|
}
|
|
252
264
|
} catch (err) {
|
|
253
265
|
const e = err instanceof Error ? err : new Error(String(err));
|
|
@@ -265,7 +277,7 @@ export function createContentReaderTool(
|
|
|
265
277
|
responseFormat: 'content_and_artifact',
|
|
266
278
|
description: descriptionOverride ?? DEFAULT_CONTENT_READER_DESCRIPTION,
|
|
267
279
|
schema: contentReaderSchema,
|
|
268
|
-
}
|
|
280
|
+
}
|
|
269
281
|
);
|
|
270
282
|
}
|
|
271
283
|
|
|
@@ -83,7 +83,11 @@ export interface InfoArgs {
|
|
|
83
83
|
content_id: string;
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
export type ArtifactWriteAction =
|
|
86
|
+
export type ArtifactWriteAction =
|
|
87
|
+
| WriteArgs
|
|
88
|
+
| EditArgs
|
|
89
|
+
| VerifyArgs
|
|
90
|
+
| DeleteArgs;
|
|
87
91
|
export type ArtifactReadAction = ReadArgs | SearchArgs | ListArgs | InfoArgs;
|
|
88
92
|
|
|
89
93
|
// ─── Handler bundles ──────────────────────────────────────────────────────
|
|
@@ -92,14 +96,23 @@ export type ArtifactReadAction = ReadArgs | SearchArgs | ListArgs | InfoArgs;
|
|
|
92
96
|
export interface ArtifactWriteHandlers {
|
|
93
97
|
write(args: WriteArgs, scope: ArtifactToolScope): Promise<ArtifactToolResult>;
|
|
94
98
|
edit(args: EditArgs, scope: ArtifactToolScope): Promise<ArtifactToolResult>;
|
|
95
|
-
verify(
|
|
96
|
-
|
|
99
|
+
verify(
|
|
100
|
+
args: VerifyArgs,
|
|
101
|
+
scope: ArtifactToolScope
|
|
102
|
+
): Promise<ArtifactToolResult>;
|
|
103
|
+
delete(
|
|
104
|
+
args: DeleteArgs,
|
|
105
|
+
scope: ArtifactToolScope
|
|
106
|
+
): Promise<ArtifactToolResult>;
|
|
97
107
|
}
|
|
98
108
|
|
|
99
109
|
/** Reader-surface handlers — invoked by `content_reader`. */
|
|
100
110
|
export interface ContentReadHandlers {
|
|
101
111
|
read(args: ReadArgs, scope: ArtifactToolScope): Promise<ArtifactToolResult>;
|
|
102
|
-
search(
|
|
112
|
+
search(
|
|
113
|
+
args: SearchArgs,
|
|
114
|
+
scope: ArtifactToolScope
|
|
115
|
+
): Promise<ArtifactToolResult>;
|
|
103
116
|
list(args: ListArgs, scope: ArtifactToolScope): Promise<ArtifactToolResult>;
|
|
104
117
|
info(args: InfoArgs, scope: ArtifactToolScope): Promise<ArtifactToolResult>;
|
|
105
118
|
}
|
|
@@ -112,7 +125,7 @@ export interface ContentReadHandlers {
|
|
|
112
125
|
export interface ContentIdResolver {
|
|
113
126
|
resolve(
|
|
114
127
|
id: string,
|
|
115
|
-
scope: ArtifactToolScope
|
|
128
|
+
scope: ArtifactToolScope
|
|
116
129
|
): Promise<{ resolvedId: string; resolvedName?: string } | null>;
|
|
117
130
|
}
|
|
118
131
|
|