@illuma-ai/agents 1.3.1 → 1.4.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/graphs/Graph.cjs +3 -18
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/llm/openai/index.cjs +3 -0
- package/dist/cjs/llm/openai/index.cjs.map +1 -1
- package/dist/cjs/main.cjs +58 -0
- package/dist/cjs/main.cjs.map +1 -1
- package/dist/cjs/providers/a2a/A2ACapabilityProvider.cjs +288 -0
- package/dist/cjs/providers/a2a/A2ACapabilityProvider.cjs.map +1 -0
- package/dist/cjs/providers/a2a/client.cjs +92 -0
- package/dist/cjs/providers/a2a/client.cjs.map +1 -0
- package/dist/cjs/providers/a2a/config.cjs +38 -0
- package/dist/cjs/providers/a2a/config.cjs.map +1 -0
- package/dist/cjs/providers/capabilityNaming.cjs +43 -0
- package/dist/cjs/providers/capabilityNaming.cjs.map +1 -0
- package/dist/cjs/providers/composite/CompositeCapabilityProvider.cjs +80 -0
- package/dist/cjs/providers/composite/CompositeCapabilityProvider.cjs.map +1 -0
- package/dist/cjs/providers/mcp/MCPCapabilityProvider.cjs +244 -0
- package/dist/cjs/providers/mcp/MCPCapabilityProvider.cjs.map +1 -0
- package/dist/cjs/providers/mcp/config.cjs +42 -0
- package/dist/cjs/providers/mcp/config.cjs.map +1 -0
- package/dist/cjs/providers/mcp/transport.cjs +65 -0
- package/dist/cjs/providers/mcp/transport.cjs.map +1 -0
- package/dist/cjs/providers/tools-server/ToolsServerCapabilityProvider.cjs +121 -0
- package/dist/cjs/providers/tools-server/ToolsServerCapabilityProvider.cjs.map +1 -0
- package/dist/cjs/providers/types.cjs +51 -0
- package/dist/cjs/providers/types.cjs.map +1 -0
- package/dist/cjs/tools/ToolNode.cjs +3 -0
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/proxyTool.cjs +100 -0
- package/dist/cjs/tools/proxyTool.cjs.map +1 -0
- package/dist/cjs/utils/credentials.cjs +142 -0
- package/dist/cjs/utils/credentials.cjs.map +1 -0
- package/dist/cjs/utils/httpClient.cjs +74 -0
- package/dist/cjs/utils/httpClient.cjs.map +1 -0
- package/dist/cjs/utils/toolManifest.cjs +100 -0
- package/dist/cjs/utils/toolManifest.cjs.map +1 -0
- package/dist/esm/graphs/Graph.mjs +3 -18
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/llm/openai/index.mjs +3 -0
- package/dist/esm/llm/openai/index.mjs.map +1 -1
- package/dist/esm/main.mjs +14 -0
- package/dist/esm/main.mjs.map +1 -1
- package/dist/esm/providers/a2a/A2ACapabilityProvider.mjs +281 -0
- package/dist/esm/providers/a2a/A2ACapabilityProvider.mjs.map +1 -0
- package/dist/esm/providers/a2a/client.mjs +88 -0
- package/dist/esm/providers/a2a/client.mjs.map +1 -0
- package/dist/esm/providers/a2a/config.mjs +35 -0
- package/dist/esm/providers/a2a/config.mjs.map +1 -0
- package/dist/esm/providers/capabilityNaming.mjs +39 -0
- package/dist/esm/providers/capabilityNaming.mjs.map +1 -0
- package/dist/esm/providers/composite/CompositeCapabilityProvider.mjs +78 -0
- package/dist/esm/providers/composite/CompositeCapabilityProvider.mjs.map +1 -0
- package/dist/esm/providers/mcp/MCPCapabilityProvider.mjs +240 -0
- package/dist/esm/providers/mcp/MCPCapabilityProvider.mjs.map +1 -0
- package/dist/esm/providers/mcp/config.mjs +39 -0
- package/dist/esm/providers/mcp/config.mjs.map +1 -0
- package/dist/esm/providers/mcp/transport.mjs +63 -0
- package/dist/esm/providers/mcp/transport.mjs.map +1 -0
- package/dist/esm/providers/tools-server/ToolsServerCapabilityProvider.mjs +119 -0
- package/dist/esm/providers/tools-server/ToolsServerCapabilityProvider.mjs.map +1 -0
- package/dist/esm/providers/types.mjs +51 -0
- package/dist/esm/providers/types.mjs.map +1 -0
- package/dist/esm/tools/ToolNode.mjs +3 -0
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/proxyTool.mjs +98 -0
- package/dist/esm/tools/proxyTool.mjs.map +1 -0
- package/dist/esm/utils/credentials.mjs +135 -0
- package/dist/esm/utils/credentials.mjs.map +1 -0
- package/dist/esm/utils/httpClient.mjs +70 -0
- package/dist/esm/utils/httpClient.mjs.map +1 -0
- package/dist/esm/utils/toolManifest.mjs +96 -0
- package/dist/esm/utils/toolManifest.mjs.map +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/providers/a2a/A2ACapabilityProvider.d.ts +89 -0
- package/dist/types/providers/a2a/client.d.ts +47 -0
- package/dist/types/providers/a2a/config.d.ts +18 -0
- package/dist/types/providers/a2a/index.d.ts +6 -0
- package/dist/types/providers/a2a/types.d.ts +173 -0
- package/dist/types/providers/capabilityNaming.d.ts +25 -0
- package/dist/types/providers/composite/CompositeCapabilityProvider.d.ts +22 -0
- package/dist/types/providers/composite/index.d.ts +1 -0
- package/dist/types/providers/index.d.ts +13 -0
- package/dist/types/providers/mcp/MCPCapabilityProvider.d.ts +54 -0
- package/dist/types/providers/mcp/config.d.ts +20 -0
- package/dist/types/providers/mcp/index.d.ts +5 -0
- package/dist/types/providers/mcp/transport.d.ts +18 -0
- package/dist/types/providers/mcp/types.d.ts +112 -0
- package/dist/types/providers/tools-server/ToolsServerCapabilityProvider.d.ts +45 -0
- package/dist/types/providers/tools-server/index.d.ts +1 -0
- package/dist/types/providers/types.d.ts +170 -0
- package/dist/types/tools/proxyTool.d.ts +55 -0
- package/dist/types/types/stream.d.ts +10 -0
- package/dist/types/utils/credentials.d.ts +77 -0
- package/dist/types/utils/httpClient.d.ts +46 -0
- package/dist/types/utils/index.d.ts +3 -0
- package/dist/types/utils/toolManifest.d.ts +49 -0
- package/package.json +21 -1
- package/src/graphs/Graph.ts +0 -23
- package/src/index.ts +4 -0
- package/src/providers/__tests__/CompositeCapabilityProvider.test.ts +93 -0
- package/src/providers/__tests__/ToolsServerCapabilityProvider.integration.spec.ts +79 -0
- package/src/providers/__tests__/ToolsServerCapabilityProvider.test.ts +206 -0
- package/src/providers/__tests__/types.test.ts +64 -0
- package/src/providers/a2a/A2ACapabilityProvider.ts +384 -0
- package/src/providers/a2a/__tests__/A2ACapabilityProvider.integration.spec.ts +345 -0
- package/src/providers/a2a/__tests__/A2ACapabilityProvider.test.ts +460 -0
- package/src/providers/a2a/client.ts +115 -0
- package/src/providers/a2a/config.ts +40 -0
- package/src/providers/a2a/index.ts +29 -0
- package/src/providers/a2a/types.ts +191 -0
- package/src/providers/capabilityNaming.ts +42 -0
- package/src/providers/composite/CompositeCapabilityProvider.ts +112 -0
- package/src/providers/composite/index.ts +1 -0
- package/src/providers/index.ts +65 -0
- package/src/providers/mcp/MCPCapabilityProvider.ts +345 -0
- package/src/providers/mcp/__tests__/MCPCapabilityProvider.integration.spec.ts +386 -0
- package/src/providers/mcp/__tests__/MCPCapabilityProvider.test.ts +371 -0
- package/src/providers/mcp/config.ts +45 -0
- package/src/providers/mcp/index.ts +21 -0
- package/src/providers/mcp/transport.ts +76 -0
- package/src/providers/mcp/types.ts +139 -0
- package/src/providers/tools-server/ToolsServerCapabilityProvider.ts +220 -0
- package/src/providers/tools-server/index.ts +1 -0
- package/src/providers/types.ts +187 -0
- package/src/tools/proxyTool.ts +146 -0
- package/src/types/stream.ts +10 -0
- package/src/utils/__tests__/credentials.test.ts +130 -0
- package/src/utils/__tests__/errors.test.ts +6 -4
- package/src/utils/__tests__/httpClient.test.ts +75 -0
- package/src/utils/__tests__/toolManifest.test.ts +116 -0
- package/src/utils/credentials.ts +157 -0
- package/src/utils/httpClient.ts +92 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/toolManifest.ts +109 -0
- package/src/agents/AgentContext.js.map +0 -1
- package/src/agents/AgentContext.test.js.map +0 -1
- package/src/agents/__tests__/AgentContext.test.js.map +0 -1
- package/src/agents/__tests__/resolveStructuredOutputMode.test.js.map +0 -1
- package/src/common/enum.js.map +0 -1
- package/src/common/index.js.map +0 -1
- package/src/events.js.map +0 -1
- package/src/graphs/Graph.js.map +0 -1
- package/src/graphs/MultiAgentGraph.js.map +0 -1
- package/src/graphs/__tests__/structured-output.integration.test.js.map +0 -1
- package/src/graphs/__tests__/structured-output.test.js.map +0 -1
- package/src/graphs/contextManagement.e2e.test.js.map +0 -1
- package/src/graphs/contextManagement.test.js.map +0 -1
- package/src/graphs/handoffValidation.test.js.map +0 -1
- package/src/graphs/index.js.map +0 -1
- package/src/index.js.map +0 -1
- package/src/instrumentation.js.map +0 -1
- package/src/llm/anthropic/index.js.map +0 -1
- package/src/llm/anthropic/types.js.map +0 -1
- package/src/llm/anthropic/utils/message_inputs.js.map +0 -1
- package/src/llm/anthropic/utils/message_outputs.js.map +0 -1
- package/src/llm/anthropic/utils/output_parsers.js.map +0 -1
- package/src/llm/anthropic/utils/tools.js.map +0 -1
- package/src/llm/bedrock/__tests__/bedrock-caching.test.js.map +0 -1
- package/src/llm/bedrock/index.js.map +0 -1
- package/src/llm/bedrock/types.js.map +0 -1
- package/src/llm/bedrock/utils/index.js.map +0 -1
- package/src/llm/bedrock/utils/message_inputs.js.map +0 -1
- package/src/llm/bedrock/utils/message_outputs.js.map +0 -1
- package/src/llm/fake.js.map +0 -1
- package/src/llm/google/index.js.map +0 -1
- package/src/llm/google/types.js.map +0 -1
- package/src/llm/google/utils/common.js.map +0 -1
- package/src/llm/google/utils/tools.js.map +0 -1
- package/src/llm/google/utils/zod_to_genai_parameters.js.map +0 -1
- package/src/llm/openai/index.js.map +0 -1
- package/src/llm/openai/types.js.map +0 -1
- package/src/llm/openai/utils/index.js.map +0 -1
- package/src/llm/openai/utils/isReasoningModel.test.js.map +0 -1
- package/src/llm/openrouter/index.js.map +0 -1
- package/src/llm/openrouter/reasoning.test.js.map +0 -1
- package/src/llm/providers.js.map +0 -1
- package/src/llm/text.js.map +0 -1
- package/src/llm/vertexai/index.js.map +0 -1
- package/src/messages/__tests__/tools.test.js.map +0 -1
- package/src/messages/cache.js.map +0 -1
- package/src/messages/cache.test.js.map +0 -1
- package/src/messages/content.js.map +0 -1
- package/src/messages/content.test.js.map +0 -1
- package/src/messages/core.js.map +0 -1
- package/src/messages/ensureThinkingBlock.test.js.map +0 -1
- package/src/messages/format.js.map +0 -1
- package/src/messages/formatAgentMessages.test.js.map +0 -1
- package/src/messages/formatAgentMessages.tools.test.js.map +0 -1
- package/src/messages/formatMessage.test.js.map +0 -1
- package/src/messages/ids.js.map +0 -1
- package/src/messages/index.js.map +0 -1
- package/src/messages/labelContentByAgent.test.js.map +0 -1
- package/src/messages/prune.js.map +0 -1
- package/src/messages/reducer.js.map +0 -1
- package/src/messages/shiftIndexTokenCountMap.test.js.map +0 -1
- package/src/messages/summarize.js.map +0 -1
- package/src/messages/summarize.test.js.map +0 -1
- package/src/messages/tools.js.map +0 -1
- package/src/mockStream.js.map +0 -1
- package/src/prompts/collab.js.map +0 -1
- package/src/prompts/index.js.map +0 -1
- package/src/prompts/taskmanager.js.map +0 -1
- package/src/run.js.map +0 -1
- package/src/schemas/index.js.map +0 -1
- package/src/schemas/schema-preparation.test.js.map +0 -1
- package/src/schemas/validate.js.map +0 -1
- package/src/schemas/validate.test.js.map +0 -1
- package/src/scripts/abort.js.map +0 -1
- package/src/scripts/ant_web_search.js.map +0 -1
- package/src/scripts/ant_web_search_edge_case.js.map +0 -1
- package/src/scripts/ant_web_search_error_edge_case.js.map +0 -1
- package/src/scripts/args.js.map +0 -1
- package/src/scripts/bedrock-cache-debug.js.map +0 -1
- package/src/scripts/bedrock-content-aggregation-test.js.map +0 -1
- package/src/scripts/bedrock-merge-test.js.map +0 -1
- package/src/scripts/bedrock-parallel-tools-test.js.map +0 -1
- package/src/scripts/caching.js.map +0 -1
- package/src/scripts/cli.js.map +0 -1
- package/src/scripts/cli2.js.map +0 -1
- package/src/scripts/cli3.js.map +0 -1
- package/src/scripts/cli4.js.map +0 -1
- package/src/scripts/cli5.js.map +0 -1
- package/src/scripts/code_exec.js.map +0 -1
- package/src/scripts/code_exec_files.js.map +0 -1
- package/src/scripts/code_exec_multi_session.js.map +0 -1
- package/src/scripts/code_exec_ptc.js.map +0 -1
- package/src/scripts/code_exec_session.js.map +0 -1
- package/src/scripts/code_exec_simple.js.map +0 -1
- package/src/scripts/content.js.map +0 -1
- package/src/scripts/empty_input.js.map +0 -1
- package/src/scripts/handoff-test.js.map +0 -1
- package/src/scripts/image.js.map +0 -1
- package/src/scripts/memory.js.map +0 -1
- package/src/scripts/multi-agent-chain.js.map +0 -1
- package/src/scripts/multi-agent-conditional.js.map +0 -1
- package/src/scripts/multi-agent-document-review-chain.js.map +0 -1
- package/src/scripts/multi-agent-hybrid-flow.js.map +0 -1
- package/src/scripts/multi-agent-parallel-start.js.map +0 -1
- package/src/scripts/multi-agent-parallel.js.map +0 -1
- package/src/scripts/multi-agent-sequence.js.map +0 -1
- package/src/scripts/multi-agent-supervisor.js.map +0 -1
- package/src/scripts/multi-agent-test.js.map +0 -1
- package/src/scripts/parallel-asymmetric-tools-test.js.map +0 -1
- package/src/scripts/parallel-full-metadata-test.js.map +0 -1
- package/src/scripts/parallel-tools-test.js.map +0 -1
- package/src/scripts/programmatic_exec.js.map +0 -1
- package/src/scripts/programmatic_exec_agent.js.map +0 -1
- package/src/scripts/search.js.map +0 -1
- package/src/scripts/sequential-full-metadata-test.js.map +0 -1
- package/src/scripts/simple.js.map +0 -1
- package/src/scripts/single-agent-metadata-test.js.map +0 -1
- package/src/scripts/stream.js.map +0 -1
- package/src/scripts/test-custom-prompt-key.js.map +0 -1
- package/src/scripts/test-handoff-input.js.map +0 -1
- package/src/scripts/test-handoff-preamble.js.map +0 -1
- package/src/scripts/test-handoff-steering.js.map +0 -1
- package/src/scripts/test-multi-agent-list-handoff.js.map +0 -1
- package/src/scripts/test-parallel-agent-labeling.js.map +0 -1
- package/src/scripts/test-parallel-handoffs.js.map +0 -1
- package/src/scripts/test-thinking-handoff-bedrock.js.map +0 -1
- package/src/scripts/test-thinking-handoff.js.map +0 -1
- package/src/scripts/test-thinking-to-thinking-handoff-bedrock.js.map +0 -1
- package/src/scripts/test-tool-before-handoff-role-order.js.map +0 -1
- package/src/scripts/test-tools-before-handoff.js.map +0 -1
- package/src/scripts/test_code_api.js.map +0 -1
- package/src/scripts/thinking-bedrock.js.map +0 -1
- package/src/scripts/thinking-vertexai.js.map +0 -1
- package/src/scripts/thinking.js.map +0 -1
- package/src/scripts/tool_search.js.map +0 -1
- package/src/scripts/tools.js.map +0 -1
- package/src/specs/agent-handoffs-bedrock.integration.test.js.map +0 -1
- package/src/specs/agent-handoffs.test.js.map +0 -1
- package/src/specs/anthropic.simple.test.js.map +0 -1
- package/src/specs/azure.simple.test.js.map +0 -1
- package/src/specs/cache.simple.test.js.map +0 -1
- package/src/specs/custom-event-await.test.js.map +0 -1
- package/src/specs/deepseek.simple.test.js.map +0 -1
- package/src/specs/emergency-prune.test.js.map +0 -1
- package/src/specs/moonshot.simple.test.js.map +0 -1
- package/src/specs/observability.integration.test.js.map +0 -1
- package/src/specs/openai.simple.test.js.map +0 -1
- package/src/specs/openrouter.simple.test.js.map +0 -1
- package/src/specs/prune.test.js.map +0 -1
- package/src/specs/reasoning.test.js.map +0 -1
- package/src/specs/spec.utils.js.map +0 -1
- package/src/specs/thinking-handoff.test.js.map +0 -1
- package/src/specs/thinking-prune.test.js.map +0 -1
- package/src/specs/token-distribution-edge-case.test.js.map +0 -1
- package/src/specs/token-memoization.test.js.map +0 -1
- package/src/specs/tokens.test.js.map +0 -1
- package/src/specs/tool-error.test.js.map +0 -1
- package/src/splitStream.js.map +0 -1
- package/src/splitStream.test.js.map +0 -1
- package/src/stream.js.map +0 -1
- package/src/stream.test.js.map +0 -1
- package/src/test/mockTools.js.map +0 -1
- package/src/tools/BrowserTools.js.map +0 -1
- package/src/tools/Calculator.js.map +0 -1
- package/src/tools/Calculator.test.js.map +0 -1
- package/src/tools/CodeExecutor.js.map +0 -1
- package/src/tools/ProgrammaticToolCalling.js.map +0 -1
- package/src/tools/StreamingToolCallBuffer.js.map +0 -1
- package/src/tools/ToolNode.js.map +0 -1
- package/src/tools/ToolSearch.js.map +0 -1
- package/src/tools/__tests__/BrowserTools.test.js.map +0 -1
- package/src/tools/__tests__/ProgrammaticToolCalling.integration.test.js.map +0 -1
- package/src/tools/__tests__/ProgrammaticToolCalling.test.js.map +0 -1
- package/src/tools/__tests__/StreamingToolCallBuffer.test.js.map +0 -1
- package/src/tools/__tests__/ToolApproval.test.js.map +0 -1
- package/src/tools/__tests__/ToolNode.recovery.test.js.map +0 -1
- package/src/tools/__tests__/ToolNode.session.test.js.map +0 -1
- package/src/tools/__tests__/ToolSearch.integration.test.js.map +0 -1
- package/src/tools/__tests__/ToolSearch.test.js.map +0 -1
- package/src/tools/__tests__/handlers.test.js.map +0 -1
- package/src/tools/__tests__/truncation-recovery.integration.test.js.map +0 -1
- package/src/tools/handlers.js.map +0 -1
- package/src/tools/schema.js.map +0 -1
- package/src/tools/search/anthropic.js.map +0 -1
- package/src/tools/search/content.js.map +0 -1
- package/src/tools/search/content.test.js.map +0 -1
- package/src/tools/search/firecrawl.js.map +0 -1
- package/src/tools/search/format.js.map +0 -1
- package/src/tools/search/highlights.js.map +0 -1
- package/src/tools/search/index.js.map +0 -1
- package/src/tools/search/jina-reranker.test.js.map +0 -1
- package/src/tools/search/rerankers.js.map +0 -1
- package/src/tools/search/schema.js.map +0 -1
- package/src/tools/search/search.js.map +0 -1
- package/src/tools/search/serper-scraper.js.map +0 -1
- package/src/tools/search/test.js.map +0 -1
- package/src/tools/search/tool.js.map +0 -1
- package/src/tools/search/types.js.map +0 -1
- package/src/tools/search/utils.js.map +0 -1
- package/src/types/graph.js.map +0 -1
- package/src/types/graph.test.js.map +0 -1
- package/src/types/index.js.map +0 -1
- package/src/types/llm.js.map +0 -1
- package/src/types/messages.js.map +0 -1
- package/src/types/run.js.map +0 -1
- package/src/types/stream.js.map +0 -1
- package/src/types/tools.js.map +0 -1
- package/src/utils/contextAnalytics.js.map +0 -1
- package/src/utils/contextAnalytics.test.js.map +0 -1
- package/src/utils/events.js.map +0 -1
- package/src/utils/graph.js.map +0 -1
- package/src/utils/handlers.js.map +0 -1
- package/src/utils/index.js.map +0 -1
- package/src/utils/llm.js.map +0 -1
- package/src/utils/llmConfig.js.map +0 -1
- package/src/utils/logging.js.map +0 -1
- package/src/utils/misc.js.map +0 -1
- package/src/utils/run.js.map +0 -1
- package/src/utils/schema.js.map +0 -1
- package/src/utils/title.js.map +0 -1
- package/src/utils/tokens.js.map +0 -1
- package/src/utils/toonFormat.js.map +0 -1
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ToolsServerCapabilityProvider — capabilities sourced from a tools-server
|
|
3
|
+
* HTTP endpoint.
|
|
4
|
+
*
|
|
5
|
+
* Fetches the manifest via GET /manifest, builds proxy StructuredTools via
|
|
6
|
+
* POST /execute/:tool. Manifest is cached (TTL-configurable) so repeated
|
|
7
|
+
* init cycles don't refetch.
|
|
8
|
+
*
|
|
9
|
+
* See docs/architecture-capability-layer.md for the design rationale.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { AxiosInstance } from 'axios';
|
|
13
|
+
import type { StructuredToolInterface } from '@langchain/core/tools';
|
|
14
|
+
import {
|
|
15
|
+
CapabilityKind,
|
|
16
|
+
type Capability,
|
|
17
|
+
type CapabilityFilter,
|
|
18
|
+
type CapabilityProvider,
|
|
19
|
+
type CredentialMap,
|
|
20
|
+
} from '@/providers/types';
|
|
21
|
+
import {
|
|
22
|
+
createHttpClient,
|
|
23
|
+
type HttpClientConfig,
|
|
24
|
+
assertOk,
|
|
25
|
+
} from '@/utils/httpClient';
|
|
26
|
+
import {
|
|
27
|
+
ManifestCache,
|
|
28
|
+
filterToCacheKey,
|
|
29
|
+
applyFilter,
|
|
30
|
+
} from '@/utils/toolManifest';
|
|
31
|
+
import { buildProxyTool } from '@/tools/proxyTool';
|
|
32
|
+
|
|
33
|
+
/** Configuration for ToolsServerCapabilityProvider. */
|
|
34
|
+
export interface ToolsServerConfig {
|
|
35
|
+
/** Tools-server base URL (e.g., https://tools.illuma.ai or http://localhost:3500). */
|
|
36
|
+
baseUrl: string;
|
|
37
|
+
/** API key sent as x-api-key header on all requests. Required. */
|
|
38
|
+
apiKey: string;
|
|
39
|
+
/** Optional override for manifest path. Defaults to `/manifest`. */
|
|
40
|
+
manifestPath?: string;
|
|
41
|
+
/** Optional override for execute path template. Defaults to `/execute/:name`. */
|
|
42
|
+
executePath?: string;
|
|
43
|
+
/** Request timeout in ms. Defaults to 30_000. */
|
|
44
|
+
timeoutMs?: number;
|
|
45
|
+
/** Manifest cache TTL in ms. 0 disables. Defaults to 60_000 (1 min). */
|
|
46
|
+
manifestTtlMs?: number;
|
|
47
|
+
/** Optional pre-built axios instance (for testing). */
|
|
48
|
+
client?: AxiosInstance;
|
|
49
|
+
/** Optional proxy override (defaults to process.env.PROXY). */
|
|
50
|
+
proxy?: string | null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Shape of a single entry from tools-server's /manifest response.
|
|
55
|
+
*
|
|
56
|
+
* Matches the tools-server ManifestToolEntry type. We define our own here
|
|
57
|
+
* to avoid cross-package coupling — the shape is a stable HTTP contract.
|
|
58
|
+
*/
|
|
59
|
+
interface ToolsServerManifestEntry {
|
|
60
|
+
pluginKey: string;
|
|
61
|
+
name: string;
|
|
62
|
+
description: string;
|
|
63
|
+
icon?: string;
|
|
64
|
+
authConfig?: Array<{
|
|
65
|
+
authField: string;
|
|
66
|
+
label?: string;
|
|
67
|
+
description?: string;
|
|
68
|
+
source?: string;
|
|
69
|
+
required?: boolean;
|
|
70
|
+
prod?: boolean;
|
|
71
|
+
admin?: boolean;
|
|
72
|
+
hide?: boolean;
|
|
73
|
+
}>;
|
|
74
|
+
/** Input schema as JSON Schema (tools-server emits `schema`). */
|
|
75
|
+
schema?: unknown;
|
|
76
|
+
/** Legacy alias accepted for backwards compatibility. */
|
|
77
|
+
jsonSchema?: unknown;
|
|
78
|
+
category?: string;
|
|
79
|
+
tags?: string[];
|
|
80
|
+
toolkit?: string;
|
|
81
|
+
endpoint?: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export class ToolsServerCapabilityProvider implements CapabilityProvider {
|
|
85
|
+
readonly providerId: string;
|
|
86
|
+
private readonly client: AxiosInstance;
|
|
87
|
+
private readonly manifestPath: string;
|
|
88
|
+
private readonly executePath: string;
|
|
89
|
+
private readonly cache: ManifestCache;
|
|
90
|
+
|
|
91
|
+
constructor(private readonly config: ToolsServerConfig) {
|
|
92
|
+
const {
|
|
93
|
+
baseUrl,
|
|
94
|
+
apiKey,
|
|
95
|
+
manifestPath = '/manifest',
|
|
96
|
+
executePath = '/execute/:name',
|
|
97
|
+
timeoutMs = 30_000,
|
|
98
|
+
manifestTtlMs = 60_000,
|
|
99
|
+
client,
|
|
100
|
+
proxy,
|
|
101
|
+
} = config;
|
|
102
|
+
|
|
103
|
+
if (!baseUrl) {
|
|
104
|
+
throw new Error('ToolsServerCapabilityProvider: baseUrl is required');
|
|
105
|
+
}
|
|
106
|
+
if (!apiKey) {
|
|
107
|
+
throw new Error('ToolsServerCapabilityProvider: apiKey is required');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
this.providerId = `tools-server:${baseUrl}`;
|
|
111
|
+
this.manifestPath = manifestPath;
|
|
112
|
+
this.executePath = executePath;
|
|
113
|
+
this.cache = new ManifestCache({ ttlMs: manifestTtlMs });
|
|
114
|
+
|
|
115
|
+
if (client) {
|
|
116
|
+
this.client = client;
|
|
117
|
+
} else {
|
|
118
|
+
const httpConfig: HttpClientConfig = {
|
|
119
|
+
baseURL: baseUrl,
|
|
120
|
+
apiKey,
|
|
121
|
+
timeoutMs,
|
|
122
|
+
proxy,
|
|
123
|
+
};
|
|
124
|
+
this.client = createHttpClient(httpConfig);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async fetchManifest(filter?: CapabilityFilter): Promise<Capability[]> {
|
|
129
|
+
const cacheKey = filterToCacheKey(filter);
|
|
130
|
+
const cached = this.cache.get(cacheKey);
|
|
131
|
+
if (cached) {
|
|
132
|
+
// DEBUG: cache hit (remove after stabilization)
|
|
133
|
+
// eslint-disable-next-line no-console
|
|
134
|
+
console.debug(
|
|
135
|
+
`[${this.providerId}] manifest cache hit — ${cached.length} caps`
|
|
136
|
+
);
|
|
137
|
+
return cached;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// DEBUG
|
|
141
|
+
// eslint-disable-next-line no-console
|
|
142
|
+
console.debug(
|
|
143
|
+
`[${this.providerId}] fetching manifest from ${this.manifestPath}`
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
const res = await this.client.get<ToolsServerManifestEntry[]>(
|
|
147
|
+
this.manifestPath
|
|
148
|
+
);
|
|
149
|
+
assertOk(res.status, this.manifestPath, res.data);
|
|
150
|
+
|
|
151
|
+
const entries = Array.isArray(res.data) ? res.data : [];
|
|
152
|
+
const capabilities: Capability[] = entries.map((entry) =>
|
|
153
|
+
normalizeEntry(entry)
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
// Apply filter before caching the full list separately so unfiltered
|
|
157
|
+
// refetches don't re-hit the network.
|
|
158
|
+
const fullCacheKey = filterToCacheKey();
|
|
159
|
+
this.cache.set(fullCacheKey, capabilities);
|
|
160
|
+
|
|
161
|
+
const filtered = applyFilter(capabilities, filter);
|
|
162
|
+
if (cacheKey !== fullCacheKey) {
|
|
163
|
+
this.cache.set(cacheKey, filtered);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// DEBUG
|
|
167
|
+
// eslint-disable-next-line no-console
|
|
168
|
+
console.debug(
|
|
169
|
+
`[${this.providerId}] manifest loaded — ${capabilities.length} caps, ${filtered.length} after filter`
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
return filtered;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async createRunnables(
|
|
176
|
+
capabilities: Capability[],
|
|
177
|
+
credentials: CredentialMap
|
|
178
|
+
): Promise<StructuredToolInterface[]> {
|
|
179
|
+
return capabilities.map((cap) =>
|
|
180
|
+
buildProxyTool(cap, credentials, {
|
|
181
|
+
client: this.client,
|
|
182
|
+
executePath: this.executePath,
|
|
183
|
+
})
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/** Force a manifest refresh on next fetchManifest call. */
|
|
188
|
+
invalidateCache(): void {
|
|
189
|
+
this.cache.clear();
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Translate a raw tools-server manifest entry into a typed Capability.
|
|
195
|
+
* Defensive — tools-server may add fields; we pull only what we need.
|
|
196
|
+
*/
|
|
197
|
+
function normalizeEntry(entry: ToolsServerManifestEntry): Capability {
|
|
198
|
+
return {
|
|
199
|
+
kind: CapabilityKind.TOOL,
|
|
200
|
+
name: entry.pluginKey,
|
|
201
|
+
description: entry.description ?? '',
|
|
202
|
+
schema: entry.schema ?? entry.jsonSchema,
|
|
203
|
+
authConfig: (entry.authConfig ?? []).map((ac) => ({
|
|
204
|
+
authField: ac.authField,
|
|
205
|
+
label: ac.label,
|
|
206
|
+
description: ac.description,
|
|
207
|
+
required: ac.required,
|
|
208
|
+
prod: ac.prod,
|
|
209
|
+
admin: ac.admin,
|
|
210
|
+
hide: ac.hide,
|
|
211
|
+
// Source is a string in wire format; downstream consumers coerce to AuthSource.
|
|
212
|
+
source: ac.source as Capability['authConfig'][number]['source'],
|
|
213
|
+
})),
|
|
214
|
+
metadata: {
|
|
215
|
+
icon: entry.icon,
|
|
216
|
+
category: entry.category,
|
|
217
|
+
tags: entry.tags,
|
|
218
|
+
},
|
|
219
|
+
};
|
|
220
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './ToolsServerCapabilityProvider';
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CapabilityProvider types — the abstraction that lets agents consume tools,
|
|
3
|
+
* skills, and MCP-backed capabilities through a single interface regardless
|
|
4
|
+
* of where they come from.
|
|
5
|
+
*
|
|
6
|
+
* Design principles:
|
|
7
|
+
* 1. Source-agnostic — providers are distinguished by WHERE they come from
|
|
8
|
+
* (tools-server, skill store, MCP server), not by the backend service
|
|
9
|
+
* any individual tool calls.
|
|
10
|
+
* 2. Credential-agnostic — providers receive a flat credentialMap from the
|
|
11
|
+
* host; they don't know about user settings, databases, OAuth flows.
|
|
12
|
+
* 3. Extension-ready — the shape reserves slots for upcoming patterns
|
|
13
|
+
* (skills injectedMessages, ToolCall.auth/expires_at, skill sessions)
|
|
14
|
+
* so when those land we don't refactor the core.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import type { StructuredToolInterface } from '@langchain/core/tools';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Kind of capability. Today only TOOL is implemented; SKILL and MCP are
|
|
21
|
+
* reserved — SkillCapabilityProvider + MCPCapabilityProvider will populate
|
|
22
|
+
* them in later phases. Keeping the enum from day one prevents a breaking
|
|
23
|
+
* change when those ship.
|
|
24
|
+
*/
|
|
25
|
+
export enum CapabilityKind {
|
|
26
|
+
TOOL = 'tool',
|
|
27
|
+
SKILL = 'skill',
|
|
28
|
+
MCP = 'mcp',
|
|
29
|
+
/**
|
|
30
|
+
* Remote agent reachable over the A2A (Agent-to-Agent) protocol.
|
|
31
|
+
* The library's `A2ACapabilityProvider` is a client for this kind —
|
|
32
|
+
* invoking an A2A capability sends a JSON-RPC `tasks/send` to the
|
|
33
|
+
* remote agent's endpoint.
|
|
34
|
+
*/
|
|
35
|
+
A2A = 'a2a',
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Where an auth credential comes from. Used by hosts to decide whether to
|
|
40
|
+
* forward the credential per-request or let the capability provider resolve
|
|
41
|
+
* it from its own environment.
|
|
42
|
+
*/
|
|
43
|
+
export enum AuthSource {
|
|
44
|
+
/** Resolved by the capability provider itself from its environment. Host never sends. */
|
|
45
|
+
SERVER = 'server',
|
|
46
|
+
/** User-configured value stored in the host's credential store. Host forwards per-request. */
|
|
47
|
+
USER = 'user',
|
|
48
|
+
/** Active OAuth/session token. Host forwards per-request from active session. */
|
|
49
|
+
FORWARDED = 'forwarded',
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* One entry in a capability's auth config. Describes a single credential
|
|
54
|
+
* the capability needs. The `source` field tells the host how to resolve
|
|
55
|
+
* the value; the `prod`/`admin`/`hide` flags control UI visibility.
|
|
56
|
+
*/
|
|
57
|
+
export interface AuthConfigEntry {
|
|
58
|
+
/** Environment-variable-style name (e.g., "OPENAI_API_KEY"). Stable identifier. */
|
|
59
|
+
authField: string;
|
|
60
|
+
/** Human-readable label for UI. */
|
|
61
|
+
label?: string;
|
|
62
|
+
/** Optional description of how to obtain the credential. */
|
|
63
|
+
description?: string;
|
|
64
|
+
/** Where the value comes from. Defaults to USER if unspecified. */
|
|
65
|
+
source?: AuthSource;
|
|
66
|
+
/** True if the credential is required for the capability to function. */
|
|
67
|
+
required?: boolean;
|
|
68
|
+
/** Platform-managed in production — never prompt user. */
|
|
69
|
+
prod?: boolean;
|
|
70
|
+
/** Only admins can configure. */
|
|
71
|
+
admin?: boolean;
|
|
72
|
+
/** Never show in any UI (used when source === SERVER). */
|
|
73
|
+
hide?: boolean;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Arbitrary metadata attached to a capability. Extension point.
|
|
78
|
+
*
|
|
79
|
+
* Fields prefixed with "Reserved for" are not populated today but exist in
|
|
80
|
+
* the type so upstream patterns (skills, auth expiration, sessions) can
|
|
81
|
+
* drop in without a schema migration.
|
|
82
|
+
*/
|
|
83
|
+
export interface CapabilityMetadata {
|
|
84
|
+
/** Icon URL or path relative to the provider's static asset root. */
|
|
85
|
+
icon?: string;
|
|
86
|
+
/** Category for UI grouping (e.g., "search", "image", "finance"). */
|
|
87
|
+
category?: string;
|
|
88
|
+
/** Free-form tags for filtering / search. */
|
|
89
|
+
tags?: string[];
|
|
90
|
+
|
|
91
|
+
// --- Reserved for upstream patterns (not populated today) ---
|
|
92
|
+
|
|
93
|
+
/** Reserved for upstream `fix/auth-events` — auth mode declared by tool. */
|
|
94
|
+
auth?: string;
|
|
95
|
+
/** Reserved for upstream `fix/auth-events` — Unix timestamp for token expiration. */
|
|
96
|
+
expires_at?: number;
|
|
97
|
+
/** Reserved for upstream skills — capability returns injected messages on execute. */
|
|
98
|
+
injectedMessages?: boolean;
|
|
99
|
+
/** Reserved for upstream skills — capability consumes ToolSessionMap state. */
|
|
100
|
+
sessionAware?: boolean;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* A single capability — a tool, skill, or MCP-backed operation that an agent
|
|
105
|
+
* can invoke. The shape mirrors common plugin-manifest conventions so the
|
|
106
|
+
* same entry can round-trip between an upstream catalog and a host registry.
|
|
107
|
+
*/
|
|
108
|
+
export interface Capability {
|
|
109
|
+
/** What kind of capability this is. Controls how it's invoked downstream. */
|
|
110
|
+
kind: CapabilityKind;
|
|
111
|
+
/**
|
|
112
|
+
* Stable unique identifier. For tools this is the pluginKey
|
|
113
|
+
* (e.g., "dalle", "wikipedia"). For skills this is the skill's `name`.
|
|
114
|
+
* Used everywhere the capability is referenced.
|
|
115
|
+
*/
|
|
116
|
+
name: string;
|
|
117
|
+
/** Human-readable description for the LLM and UI. */
|
|
118
|
+
description: string;
|
|
119
|
+
/**
|
|
120
|
+
* Input schema as JSON Schema. For tools this comes from the Zod schema
|
|
121
|
+
* passed through `zodToJsonSchema`. Optional for capabilities with no
|
|
122
|
+
* input (e.g., parameter-less skills).
|
|
123
|
+
*/
|
|
124
|
+
schema?: unknown;
|
|
125
|
+
/** Credential requirements. */
|
|
126
|
+
authConfig: AuthConfigEntry[];
|
|
127
|
+
/** Extension metadata. See CapabilityMetadata. */
|
|
128
|
+
metadata: CapabilityMetadata;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** Filter for fetchManifest. All fields optional; missing = no filter. */
|
|
132
|
+
export interface CapabilityFilter {
|
|
133
|
+
kind?: CapabilityKind;
|
|
134
|
+
tags?: string[];
|
|
135
|
+
/** Restrict to capabilities whose `name` is in this list. */
|
|
136
|
+
names?: string[];
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* A flat credential map: authField → value.
|
|
141
|
+
*
|
|
142
|
+
* The host is responsible for resolving values (from env vars, user
|
|
143
|
+
* settings, OAuth sessions, etc.) before passing to the provider. The
|
|
144
|
+
* provider does not inspect the origin — it just forwards to the tool.
|
|
145
|
+
*/
|
|
146
|
+
export type CredentialMap = Record<string, string>;
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* The core interface. All concrete providers implement this.
|
|
150
|
+
*
|
|
151
|
+
* Providers are identified by `providerId` for logging/debug. They fetch
|
|
152
|
+
* their own manifest and build LangChain-compatible runnables from it.
|
|
153
|
+
*
|
|
154
|
+
* Lifetime: a provider may be instantiated once at startup (e.g., tools-
|
|
155
|
+
* server pointing at a stable URL) or per-user (e.g., MCP with per-user
|
|
156
|
+
* OAuth). The interface is agnostic.
|
|
157
|
+
*/
|
|
158
|
+
export interface CapabilityProvider {
|
|
159
|
+
/** Stable identifier for this provider instance (e.g., "tools-server:https://..."). */
|
|
160
|
+
readonly providerId: string;
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Return the list of capabilities this provider exposes.
|
|
164
|
+
*
|
|
165
|
+
* Implementations may cache the manifest — the contract is that the
|
|
166
|
+
* returned list reflects the provider's current view of available
|
|
167
|
+
* capabilities.
|
|
168
|
+
*
|
|
169
|
+
* @param filter optional filter to scope the result
|
|
170
|
+
*/
|
|
171
|
+
fetchManifest(filter?: CapabilityFilter): Promise<Capability[]>;
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Build LangChain StructuredTools from a set of capabilities using the
|
|
175
|
+
* caller-supplied credentials.
|
|
176
|
+
*
|
|
177
|
+
* Called at agent init. The returned tools are bound to the LLM and
|
|
178
|
+
* invoked during the graph's tool-calling loop.
|
|
179
|
+
*
|
|
180
|
+
* @param capabilities the subset of capabilities the agent wants to use
|
|
181
|
+
* @param credentials credential values keyed by authField
|
|
182
|
+
*/
|
|
183
|
+
createRunnables(
|
|
184
|
+
capabilities: Capability[],
|
|
185
|
+
credentials: CredentialMap
|
|
186
|
+
): Promise<StructuredToolInterface[]>;
|
|
187
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* proxyTool — wraps a Capability into a LangChain StructuredTool that
|
|
3
|
+
* dispatches execution to a remote backend (e.g., tools-server) over HTTP.
|
|
4
|
+
*
|
|
5
|
+
* The LLM sees this tool identically to a locally-implemented tool:
|
|
6
|
+
* - same name
|
|
7
|
+
* - same description
|
|
8
|
+
* - same input schema (JSON Schema)
|
|
9
|
+
* - same invoke(input) contract
|
|
10
|
+
*
|
|
11
|
+
* Under the hood, invoke() POSTs to the backend's execute endpoint with
|
|
12
|
+
* the input and a caller-supplied credential map. The backend returns
|
|
13
|
+
* { success, result, error, timing } which this wrapper unpacks.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import type { AxiosInstance } from 'axios';
|
|
17
|
+
import { tool, type StructuredToolInterface } from '@langchain/core/tools';
|
|
18
|
+
import type { Capability, CredentialMap } from '@/providers/types';
|
|
19
|
+
import { HttpError } from '@/utils/httpClient';
|
|
20
|
+
|
|
21
|
+
/** Shape of the backend's execute response. Matches tools-server. */
|
|
22
|
+
export interface ExecuteResponse {
|
|
23
|
+
success: boolean;
|
|
24
|
+
result?: unknown;
|
|
25
|
+
error?: string;
|
|
26
|
+
timing?: { durationMs: number };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Options passed to buildProxyTool. */
|
|
30
|
+
export interface ProxyToolOptions {
|
|
31
|
+
/** HTTP client configured with backend base URL + auth. */
|
|
32
|
+
client: AxiosInstance;
|
|
33
|
+
/**
|
|
34
|
+
* Path template for execution. The literal `:name` is replaced with the
|
|
35
|
+
* capability's name. Defaults to `/execute/:name` (tools-server convention).
|
|
36
|
+
*/
|
|
37
|
+
executePath?: string;
|
|
38
|
+
/**
|
|
39
|
+
* Optional callback invoked on every execution — used for metrics,
|
|
40
|
+
* telemetry, debug logging. Errors in the hook are swallowed.
|
|
41
|
+
*/
|
|
42
|
+
onExecute?: (ctx: ExecuteCallbackContext) => void;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface ExecuteCallbackContext {
|
|
46
|
+
capabilityName: string;
|
|
47
|
+
input: unknown;
|
|
48
|
+
response?: ExecuteResponse;
|
|
49
|
+
error?: Error;
|
|
50
|
+
durationMs: number;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Build a StructuredTool that proxies to a remote backend.
|
|
55
|
+
*
|
|
56
|
+
* The credentialMap is baked into the closure — callers that need
|
|
57
|
+
* per-invocation credential rotation should rebuild the tool.
|
|
58
|
+
*/
|
|
59
|
+
export function buildProxyTool(
|
|
60
|
+
capability: Capability,
|
|
61
|
+
credentials: CredentialMap,
|
|
62
|
+
options: ProxyToolOptions
|
|
63
|
+
): StructuredToolInterface {
|
|
64
|
+
const { client, executePath = '/execute/:name', onExecute } = options;
|
|
65
|
+
const url = executePath.replace(':name', encodeURIComponent(capability.name));
|
|
66
|
+
|
|
67
|
+
return tool(
|
|
68
|
+
async (input: unknown): Promise<string> => {
|
|
69
|
+
const startMs = Date.now();
|
|
70
|
+
const debugPrefix = `[proxyTool:${capability.name}]`;
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
// DEBUG: log (remove after POC stabilizes)
|
|
74
|
+
// eslint-disable-next-line no-console
|
|
75
|
+
console.debug(
|
|
76
|
+
`${debugPrefix} invoking — inputKeys=${input && typeof input === 'object' ? Object.keys(input as object).length : 0}`
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
const res = await client.post<ExecuteResponse>(url, {
|
|
80
|
+
input,
|
|
81
|
+
credentials,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const durationMs = Date.now() - startMs;
|
|
85
|
+
|
|
86
|
+
if (res.status < 200 || res.status >= 300) {
|
|
87
|
+
throw new HttpError(res.status, url, res.data);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const body = res.data;
|
|
91
|
+
if (onExecute) {
|
|
92
|
+
try {
|
|
93
|
+
onExecute({
|
|
94
|
+
capabilityName: capability.name,
|
|
95
|
+
input,
|
|
96
|
+
response: body,
|
|
97
|
+
durationMs,
|
|
98
|
+
});
|
|
99
|
+
} catch {
|
|
100
|
+
// hook errors are non-fatal
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (!body.success) {
|
|
105
|
+
// DEBUG
|
|
106
|
+
// eslint-disable-next-line no-console
|
|
107
|
+
console.debug(
|
|
108
|
+
`${debugPrefix} backend reported failure — ${body.error}`
|
|
109
|
+
);
|
|
110
|
+
throw new Error(body.error ?? 'Tool execution failed');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// LangChain tools typically return strings; stringify non-string results
|
|
114
|
+
if (typeof body.result === 'string') {
|
|
115
|
+
return body.result;
|
|
116
|
+
}
|
|
117
|
+
return JSON.stringify(body.result);
|
|
118
|
+
} catch (err) {
|
|
119
|
+
const durationMs = Date.now() - startMs;
|
|
120
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
121
|
+
if (onExecute) {
|
|
122
|
+
try {
|
|
123
|
+
onExecute({
|
|
124
|
+
capabilityName: capability.name,
|
|
125
|
+
input,
|
|
126
|
+
error,
|
|
127
|
+
durationMs,
|
|
128
|
+
});
|
|
129
|
+
} catch {
|
|
130
|
+
// hook errors are non-fatal
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
throw error;
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
name: capability.name,
|
|
138
|
+
description: capability.description,
|
|
139
|
+
schema: (capability.schema as object) ?? {
|
|
140
|
+
type: 'object',
|
|
141
|
+
properties: {},
|
|
142
|
+
},
|
|
143
|
+
responseFormat: 'content',
|
|
144
|
+
}
|
|
145
|
+
);
|
|
146
|
+
}
|
package/src/types/stream.ts
CHANGED
|
@@ -164,6 +164,16 @@ export type ToolCallsDetails = {
|
|
|
164
164
|
export type ToolCallDelta = {
|
|
165
165
|
type: StepTypes;
|
|
166
166
|
tool_calls?: ToolCallChunk[]; // #new
|
|
167
|
+
/**
|
|
168
|
+
* Auth URL for tool calls that require interactive authentication
|
|
169
|
+
* (typically OAuth-gated MCP tools). Hosts populate this on a delta
|
|
170
|
+
* dispatch when a tool invocation surfaces an auth challenge so the
|
|
171
|
+
* client can render an approval prompt without waiting for the call
|
|
172
|
+
* to complete.
|
|
173
|
+
*/
|
|
174
|
+
auth?: string;
|
|
175
|
+
/** Auth challenge expiration (UNIX seconds). Pairs with `auth`. */
|
|
176
|
+
expires_at?: number;
|
|
167
177
|
};
|
|
168
178
|
|
|
169
179
|
export type AgentToolCall =
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import {
|
|
2
|
+
mergeCredentials,
|
|
3
|
+
collectRequiredAuthFields,
|
|
4
|
+
filterForwardableCredentials,
|
|
5
|
+
findMissingCredentials,
|
|
6
|
+
credentialsFromEnv,
|
|
7
|
+
isForwardable,
|
|
8
|
+
CredentialOrigin,
|
|
9
|
+
} from '../credentials';
|
|
10
|
+
import { AuthSource, CapabilityKind, type Capability } from '@/providers/types';
|
|
11
|
+
|
|
12
|
+
const makeCap = (
|
|
13
|
+
name: string,
|
|
14
|
+
authFields: Array<[string, AuthSource?, boolean?]>
|
|
15
|
+
): Capability => ({
|
|
16
|
+
kind: CapabilityKind.TOOL,
|
|
17
|
+
name,
|
|
18
|
+
description: `${name} capability`,
|
|
19
|
+
authConfig: authFields.map(([authField, source, required]) => ({
|
|
20
|
+
authField,
|
|
21
|
+
source,
|
|
22
|
+
required,
|
|
23
|
+
})),
|
|
24
|
+
metadata: {},
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
describe('mergeCredentials', () => {
|
|
28
|
+
it('first layer wins on collision', () => {
|
|
29
|
+
const result = mergeCredentials(
|
|
30
|
+
{ origin: CredentialOrigin.RUNTIME, values: { KEY: 'runtime' } },
|
|
31
|
+
{
|
|
32
|
+
origin: CredentialOrigin.AGENT,
|
|
33
|
+
values: { KEY: 'agent', OTHER: 'agent' },
|
|
34
|
+
},
|
|
35
|
+
{ origin: CredentialOrigin.ENV, values: { KEY: 'env', THIRD: 'env' } }
|
|
36
|
+
);
|
|
37
|
+
expect(result.KEY).toBe('runtime');
|
|
38
|
+
expect(result.OTHER).toBe('agent');
|
|
39
|
+
expect(result.THIRD).toBe('env');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('skips empty/undefined/null values', () => {
|
|
43
|
+
const result = mergeCredentials(
|
|
44
|
+
{ origin: CredentialOrigin.RUNTIME, values: { KEY: '' } },
|
|
45
|
+
{ origin: CredentialOrigin.ENV, values: { KEY: 'fallback' } }
|
|
46
|
+
);
|
|
47
|
+
expect(result.KEY).toBe('fallback');
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('returns empty map when all layers empty', () => {
|
|
51
|
+
const result = mergeCredentials();
|
|
52
|
+
expect(result).toEqual({});
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
describe('collectRequiredAuthFields', () => {
|
|
57
|
+
it('unions auth fields across capabilities', () => {
|
|
58
|
+
const caps = [
|
|
59
|
+
makeCap('a', [['KEY_1'], ['KEY_2']]),
|
|
60
|
+
makeCap('b', [['KEY_2'], ['KEY_3']]),
|
|
61
|
+
];
|
|
62
|
+
const fields = collectRequiredAuthFields(caps);
|
|
63
|
+
expect(fields.sort()).toEqual(['KEY_1', 'KEY_2', 'KEY_3']);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
describe('filterForwardableCredentials', () => {
|
|
68
|
+
it('strips credentials whose source is SERVER', () => {
|
|
69
|
+
const caps = [
|
|
70
|
+
makeCap('x', [
|
|
71
|
+
['SERVER_KEY', AuthSource.SERVER],
|
|
72
|
+
['USER_KEY', AuthSource.USER],
|
|
73
|
+
]),
|
|
74
|
+
];
|
|
75
|
+
const filtered = filterForwardableCredentials(
|
|
76
|
+
{ SERVER_KEY: 'secret', USER_KEY: 'u1', UNRELATED: 'ok' },
|
|
77
|
+
caps
|
|
78
|
+
);
|
|
79
|
+
expect(filtered).toEqual({ USER_KEY: 'u1', UNRELATED: 'ok' });
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe('findMissingCredentials', () => {
|
|
84
|
+
it('flags missing required fields that are not server-resolved', () => {
|
|
85
|
+
const cap = makeCap('tool', [
|
|
86
|
+
['REQUIRED_USER', AuthSource.USER, true],
|
|
87
|
+
['OPTIONAL_USER', AuthSource.USER, false],
|
|
88
|
+
['SERVER_MANAGED', AuthSource.SERVER, true],
|
|
89
|
+
]);
|
|
90
|
+
const missing = findMissingCredentials(cap, {});
|
|
91
|
+
expect(missing).toEqual(['REQUIRED_USER']);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('returns empty when all required are present', () => {
|
|
95
|
+
const cap = makeCap('tool', [['KEY', AuthSource.USER, true]]);
|
|
96
|
+
expect(findMissingCredentials(cap, { KEY: 'val' })).toEqual([]);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
describe('credentialsFromEnv', () => {
|
|
101
|
+
it('reads only fields present in env', () => {
|
|
102
|
+
const layer = credentialsFromEnv(['A', 'B', 'C'], {
|
|
103
|
+
A: '1',
|
|
104
|
+
C: '3',
|
|
105
|
+
} as NodeJS.ProcessEnv);
|
|
106
|
+
expect(layer.values).toEqual({ A: '1', C: '3' });
|
|
107
|
+
expect(layer.origin).toBe(CredentialOrigin.ENV);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe('isForwardable', () => {
|
|
112
|
+
it('SERVER is not forwardable', () => {
|
|
113
|
+
expect(isForwardable({ authField: 'K', source: AuthSource.SERVER })).toBe(
|
|
114
|
+
false
|
|
115
|
+
);
|
|
116
|
+
});
|
|
117
|
+
it('USER is forwardable', () => {
|
|
118
|
+
expect(isForwardable({ authField: 'K', source: AuthSource.USER })).toBe(
|
|
119
|
+
true
|
|
120
|
+
);
|
|
121
|
+
});
|
|
122
|
+
it('FORWARDED is forwardable', () => {
|
|
123
|
+
expect(
|
|
124
|
+
isForwardable({ authField: 'K', source: AuthSource.FORWARDED })
|
|
125
|
+
).toBe(true);
|
|
126
|
+
});
|
|
127
|
+
it('defaults to forwardable when source is undefined', () => {
|
|
128
|
+
expect(isForwardable({ authField: 'K' })).toBe(true);
|
|
129
|
+
});
|
|
130
|
+
});
|