@google/gemini-cli-core 0.34.0-preview.3 → 0.35.0-nightly.20260314.3038fdce2
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/docs/changelogs/index.md +19 -0
- package/dist/docs/changelogs/latest.md +217 -191
- package/dist/docs/changelogs/preview.md +447 -184
- package/dist/docs/cli/model-routing.md +18 -1
- package/dist/docs/cli/model-steering.md +79 -0
- package/dist/docs/cli/plan-mode.md +99 -14
- package/dist/docs/cli/settings.md +14 -12
- package/dist/docs/cli/telemetry.md +45 -0
- package/dist/docs/cli/tutorials/plan-mode-steering.md +89 -0
- package/dist/docs/core/index.md +2 -0
- package/dist/docs/core/local-model-routing.md +193 -0
- package/dist/docs/reference/configuration.md +27 -3
- package/dist/docs/reference/keyboard-shortcuts.md +168 -90
- package/dist/docs/reference/policy-engine.md +30 -6
- package/dist/docs/resources/troubleshooting.md +15 -0
- package/dist/docs/sidebar.json +10 -0
- package/dist/docs/tools/shell.md +8 -0
- package/dist/google-gemini-cli-core-0.35.0-nightly.20260311.657f19c1f.tgz +0 -0
- package/dist/src/agents/a2a-client-manager.d.ts +11 -4
- package/dist/src/agents/a2a-client-manager.js +61 -34
- package/dist/src/agents/a2a-client-manager.js.map +1 -1
- package/dist/src/agents/a2a-client-manager.test.js +178 -115
- package/dist/src/agents/a2a-client-manager.test.js.map +1 -1
- package/dist/src/agents/a2aUtils.d.ts +4 -28
- package/dist/src/agents/a2aUtils.js +20 -181
- package/dist/src/agents/a2aUtils.js.map +1 -1
- package/dist/src/agents/a2aUtils.test.js +19 -106
- package/dist/src/agents/a2aUtils.test.js.map +1 -1
- package/dist/src/agents/agent-scheduler.d.ts +2 -0
- package/dist/src/agents/agent-scheduler.js +3 -2
- package/dist/src/agents/agent-scheduler.js.map +1 -1
- package/dist/src/agents/agent-scheduler.test.js +12 -3
- package/dist/src/agents/agent-scheduler.test.js.map +1 -1
- package/dist/src/agents/agentLoader.d.ts +2 -2
- package/dist/src/agents/agentLoader.js +15 -0
- package/dist/src/agents/agentLoader.js.map +1 -1
- package/dist/src/agents/auth-provider/factory.d.ts +2 -0
- package/dist/src/agents/auth-provider/factory.js +6 -3
- package/dist/src/agents/auth-provider/factory.js.map +1 -1
- package/dist/src/agents/auth-provider/google-credentials-provider.d.ts +26 -0
- package/dist/src/agents/auth-provider/google-credentials-provider.js +117 -0
- package/dist/src/agents/auth-provider/google-credentials-provider.js.map +1 -0
- package/dist/src/agents/auth-provider/google-credentials-provider.test.d.ts +6 -0
- package/dist/src/agents/auth-provider/google-credentials-provider.test.js +126 -0
- package/dist/src/agents/auth-provider/google-credentials-provider.test.js.map +1 -0
- package/dist/src/agents/browser/browserAgentFactory.js +11 -2
- package/dist/src/agents/browser/browserAgentFactory.js.map +1 -1
- package/dist/src/agents/browser/browserAgentInvocation.d.ts +4 -3
- package/dist/src/agents/browser/browserAgentInvocation.js +10 -4
- package/dist/src/agents/browser/browserAgentInvocation.js.map +1 -1
- package/dist/src/agents/browser/browserAgentInvocation.test.js +1 -0
- package/dist/src/agents/browser/browserAgentInvocation.test.js.map +1 -1
- package/dist/src/agents/browser/browserManager.d.ts +10 -0
- package/dist/src/agents/browser/browserManager.js +53 -8
- package/dist/src/agents/browser/browserManager.js.map +1 -1
- package/dist/src/agents/browser/inputBlocker.d.ts +51 -0
- package/dist/src/agents/browser/inputBlocker.js +234 -0
- package/dist/src/agents/browser/inputBlocker.js.map +1 -0
- package/dist/src/agents/browser/inputBlocker.test.d.ts +6 -0
- package/dist/src/agents/browser/inputBlocker.test.js +82 -0
- package/dist/src/agents/browser/inputBlocker.test.js.map +1 -0
- package/dist/src/agents/browser/mcpToolWrapper.d.ts +3 -2
- package/dist/src/agents/browser/mcpToolWrapper.js +49 -8
- package/dist/src/agents/browser/mcpToolWrapper.js.map +1 -1
- package/dist/src/agents/browser/mcpToolWrapper.test.js +51 -0
- package/dist/src/agents/browser/mcpToolWrapper.test.js.map +1 -1
- package/dist/src/agents/local-executor.d.ts +5 -4
- package/dist/src/agents/local-executor.js +30 -25
- package/dist/src/agents/local-executor.js.map +1 -1
- package/dist/src/agents/local-executor.test.js +269 -3
- package/dist/src/agents/local-executor.test.js.map +1 -1
- package/dist/src/agents/local-invocation.d.ts +4 -4
- package/dist/src/agents/local-invocation.js +12 -9
- package/dist/src/agents/local-invocation.js.map +1 -1
- package/dist/src/agents/local-invocation.test.js +19 -3
- package/dist/src/agents/local-invocation.test.js.map +1 -1
- package/dist/src/agents/registry.js +3 -2
- package/dist/src/agents/registry.js.map +1 -1
- package/dist/src/agents/registry.test.js +1 -0
- package/dist/src/agents/registry.test.js.map +1 -1
- package/dist/src/agents/remote-invocation.d.ts +0 -9
- package/dist/src/agents/remote-invocation.js +1 -28
- package/dist/src/agents/remote-invocation.js.map +1 -1
- package/dist/src/agents/remote-invocation.test.js +1 -0
- package/dist/src/agents/remote-invocation.test.js.map +1 -1
- package/dist/src/agents/subagent-tool-wrapper.d.ts +5 -4
- package/dist/src/agents/subagent-tool-wrapper.js +9 -5
- package/dist/src/agents/subagent-tool-wrapper.js.map +1 -1
- package/dist/src/agents/subagent-tool-wrapper.test.js +15 -1
- package/dist/src/agents/subagent-tool-wrapper.test.js.map +1 -1
- package/dist/src/agents/subagent-tool.d.ts +3 -3
- package/dist/src/agents/subagent-tool.js +16 -12
- package/dist/src/agents/subagent-tool.js.map +1 -1
- package/dist/src/agents/subagent-tool.test.js +13 -3
- package/dist/src/agents/subagent-tool.test.js.map +1 -1
- package/dist/src/code_assist/oauth2.js +0 -1
- package/dist/src/code_assist/oauth2.js.map +1 -1
- package/dist/src/code_assist/server.js +2 -2
- package/dist/src/code_assist/server.js.map +1 -1
- package/dist/src/code_assist/server.test.js +5 -1
- package/dist/src/code_assist/server.test.js.map +1 -1
- package/dist/src/code_assist/telemetry.d.ts +2 -2
- package/dist/src/code_assist/telemetry.js +5 -3
- package/dist/src/code_assist/telemetry.js.map +1 -1
- package/dist/src/code_assist/telemetry.test.js +14 -12
- package/dist/src/code_assist/telemetry.test.js.map +1 -1
- package/dist/src/code_assist/types.d.ts +14 -12
- package/dist/src/code_assist/types.js.map +1 -1
- package/dist/src/config/agent-loop-context.d.ts +3 -0
- package/dist/src/config/config.d.ts +75 -2
- package/dist/src/config/config.js +78 -11
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/config.test.js +170 -10
- package/dist/src/config/config.test.js.map +1 -1
- package/dist/src/config/models.d.ts +14 -0
- package/dist/src/config/models.js +37 -0
- package/dist/src/config/models.js.map +1 -1
- package/dist/src/config/models.test.js +51 -1
- package/dist/src/config/models.test.js.map +1 -1
- package/dist/src/config/storage.d.ts +1 -0
- package/dist/src/config/storage.js +3 -0
- package/dist/src/config/storage.js.map +1 -1
- package/dist/src/core/baseLlmClient.js +19 -3
- package/dist/src/core/baseLlmClient.js.map +1 -1
- package/dist/src/core/baseLlmClient.test.js +2 -0
- package/dist/src/core/baseLlmClient.test.js.map +1 -1
- package/dist/src/core/client.d.ts +4 -3
- package/dist/src/core/client.js +42 -17
- package/dist/src/core/client.js.map +1 -1
- package/dist/src/core/client.test.js +8 -0
- package/dist/src/core/client.test.js.map +1 -1
- package/dist/src/core/contentGenerator.d.ts +1 -0
- package/dist/src/core/contentGenerator.js +35 -3
- package/dist/src/core/contentGenerator.js.map +1 -1
- package/dist/src/core/contentGenerator.test.js +137 -2
- package/dist/src/core/contentGenerator.test.js.map +1 -1
- package/dist/src/core/coreToolHookTriggers.d.ts +2 -3
- package/dist/src/core/coreToolHookTriggers.js +5 -11
- package/dist/src/core/coreToolHookTriggers.js.map +1 -1
- package/dist/src/core/coreToolHookTriggers.test.js +24 -0
- package/dist/src/core/coreToolHookTriggers.test.js.map +1 -1
- package/dist/src/core/coreToolScheduler.js +1 -1
- package/dist/src/core/coreToolScheduler.js.map +1 -1
- package/dist/src/core/geminiChat.js +31 -21
- package/dist/src/core/geminiChat.js.map +1 -1
- package/dist/src/core/geminiChat.test.js +6 -4
- package/dist/src/core/geminiChat.test.js.map +1 -1
- package/dist/src/core/geminiChat_network_retry.test.js +21 -11
- package/dist/src/core/geminiChat_network_retry.test.js.map +1 -1
- package/dist/src/fallback/handler.js +0 -4
- package/dist/src/fallback/handler.js.map +1 -1
- package/dist/src/fallback/handler.test.js +0 -6
- package/dist/src/fallback/handler.test.js.map +1 -1
- package/dist/src/generated/git-commit.d.ts +2 -2
- package/dist/src/generated/git-commit.js +2 -2
- package/dist/src/generated/git-commit.js.map +1 -1
- package/dist/src/ide/detect-ide.d.ts +8 -0
- package/dist/src/ide/detect-ide.js +12 -1
- package/dist/src/ide/detect-ide.js.map +1 -1
- package/dist/src/ide/detect-ide.test.js +12 -0
- package/dist/src/ide/detect-ide.test.js.map +1 -1
- package/dist/src/ide/ide-installer.js +20 -8
- package/dist/src/ide/ide-installer.js.map +1 -1
- package/dist/src/ide/ide-installer.test.js +60 -4
- package/dist/src/ide/ide-installer.test.js.map +1 -1
- package/dist/src/mcp/oauth-provider.js +0 -2
- package/dist/src/mcp/oauth-provider.js.map +1 -1
- package/dist/src/mcp/oauth-token-storage.test.js +6 -10
- package/dist/src/mcp/oauth-token-storage.test.js.map +1 -1
- package/dist/src/mcp/oauth-utils.js +0 -2
- package/dist/src/mcp/oauth-utils.js.map +1 -1
- package/dist/src/mcp/token-storage/file-token-storage.d.ts +24 -0
- package/dist/src/mcp/token-storage/file-token-storage.js +152 -0
- package/dist/src/mcp/token-storage/file-token-storage.js.map +1 -0
- package/dist/src/mcp/token-storage/file-token-storage.test.d.ts +6 -0
- package/dist/src/mcp/token-storage/file-token-storage.test.js +276 -0
- package/dist/src/mcp/token-storage/file-token-storage.test.js.map +1 -0
- package/dist/src/mcp/token-storage/hybrid-token-storage.js +21 -9
- package/dist/src/mcp/token-storage/hybrid-token-storage.js.map +1 -1
- package/dist/src/mcp/token-storage/hybrid-token-storage.test.js +59 -10
- package/dist/src/mcp/token-storage/hybrid-token-storage.test.js.map +1 -1
- package/dist/src/mcp/token-storage/index.d.ts +1 -1
- package/dist/src/mcp/token-storage/index.js +1 -1
- package/dist/src/mcp/token-storage/index.js.map +1 -1
- package/dist/src/mcp/token-storage/keychain-token-storage.d.ts +0 -1
- package/dist/src/mcp/token-storage/keychain-token-storage.js +0 -3
- package/dist/src/mcp/token-storage/keychain-token-storage.js.map +1 -1
- package/dist/src/policy/config.d.ts +14 -2
- package/dist/src/policy/config.js +94 -49
- package/dist/src/policy/config.js.map +1 -1
- package/dist/src/policy/config.test.js +208 -488
- package/dist/src/policy/config.test.js.map +1 -1
- package/dist/src/policy/policies/plan.toml +1 -1
- package/dist/src/policy/stable-stringify.js +15 -5
- package/dist/src/policy/stable-stringify.js.map +1 -1
- package/dist/src/policy/types.d.ts +1 -0
- package/dist/src/policy/types.js.map +1 -1
- package/dist/src/policy/utils.d.ts +17 -0
- package/dist/src/policy/utils.js +27 -7
- package/dist/src/policy/utils.js.map +1 -1
- package/dist/src/prompts/snippets.js +2 -1
- package/dist/src/prompts/snippets.js.map +1 -1
- package/dist/src/prompts/utils.test.d.ts +6 -0
- package/dist/src/prompts/utils.test.js +225 -0
- package/dist/src/prompts/utils.test.js.map +1 -0
- package/dist/src/routing/modelRouterService.js +2 -2
- package/dist/src/routing/modelRouterService.js.map +1 -1
- package/dist/src/routing/modelRouterService.test.js +4 -3
- package/dist/src/routing/modelRouterService.test.js.map +1 -1
- package/dist/src/routing/strategies/numericalClassifierStrategy.js +6 -40
- package/dist/src/routing/strategies/numericalClassifierStrategy.js.map +1 -1
- package/dist/src/routing/strategies/numericalClassifierStrategy.test.js +29 -64
- package/dist/src/routing/strategies/numericalClassifierStrategy.test.js.map +1 -1
- package/dist/src/scheduler/policy.d.ts +3 -7
- package/dist/src/scheduler/policy.js +4 -3
- package/dist/src/scheduler/policy.js.map +1 -1
- package/dist/src/scheduler/policy.test.js +51 -31
- package/dist/src/scheduler/policy.test.js.map +1 -1
- package/dist/src/scheduler/scheduler.d.ts +4 -2
- package/dist/src/scheduler/scheduler.js +19 -16
- package/dist/src/scheduler/scheduler.js.map +1 -1
- package/dist/src/scheduler/scheduler.test.js +33 -10
- package/dist/src/scheduler/scheduler.test.js.map +1 -1
- package/dist/src/scheduler/scheduler_parallel.test.js +40 -2
- package/dist/src/scheduler/scheduler_parallel.test.js.map +1 -1
- package/dist/src/scheduler/scheduler_waiting_callback.test.js +1 -1
- package/dist/src/scheduler/scheduler_waiting_callback.test.js.map +1 -1
- package/dist/src/scheduler/tool-executor.d.ts +3 -3
- package/dist/src/scheduler/tool-executor.js +15 -21
- package/dist/src/scheduler/tool-executor.js.map +1 -1
- package/dist/src/scheduler/tool-executor.test.js +43 -8
- package/dist/src/scheduler/tool-executor.test.js.map +1 -1
- package/dist/src/services/chatRecordingService.js +2 -1
- package/dist/src/services/chatRecordingService.js.map +1 -1
- package/dist/src/services/chatRecordingService.test.js +21 -0
- package/dist/src/services/chatRecordingService.test.js.map +1 -1
- package/dist/src/services/executionLifecycleService.d.ts +83 -0
- package/dist/src/services/executionLifecycleService.js +271 -0
- package/dist/src/services/executionLifecycleService.js.map +1 -0
- package/dist/src/services/executionLifecycleService.test.d.ts +6 -0
- package/dist/src/services/executionLifecycleService.test.js +227 -0
- package/dist/src/services/executionLifecycleService.test.js.map +1 -0
- package/dist/src/services/keychainService.d.ts +0 -5
- package/dist/src/services/keychainService.js +13 -30
- package/dist/src/services/keychainService.js.map +1 -1
- package/dist/src/services/keychainService.test.js +22 -52
- package/dist/src/services/keychainService.test.js.map +1 -1
- package/dist/src/services/sandboxManager.d.ts +54 -0
- package/dist/src/services/sandboxManager.js +30 -0
- package/dist/src/services/sandboxManager.js.map +1 -0
- package/dist/src/services/sandboxManager.test.d.ts +6 -0
- package/dist/src/services/sandboxManager.test.js +95 -0
- package/dist/src/services/sandboxManager.test.js.map +1 -0
- package/dist/src/services/shellExecutionService.d.ts +4 -52
- package/dist/src/services/shellExecutionService.js +437 -498
- package/dist/src/services/shellExecutionService.js.map +1 -1
- package/dist/src/services/shellExecutionService.test.js +10 -21
- package/dist/src/services/shellExecutionService.test.js.map +1 -1
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.d.ts +13 -2
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +91 -1
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -1
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js +77 -0
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js.map +1 -1
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.d.ts +10 -1
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.js +25 -1
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.js.map +1 -1
- package/dist/src/telemetry/index.d.ts +3 -3
- package/dist/src/telemetry/index.js +3 -3
- package/dist/src/telemetry/index.js.map +1 -1
- package/dist/src/telemetry/loggers.d.ts +2 -1
- package/dist/src/telemetry/loggers.js +32 -1
- package/dist/src/telemetry/loggers.js.map +1 -1
- package/dist/src/telemetry/loggers.test.js +37 -2
- package/dist/src/telemetry/loggers.test.js.map +1 -1
- package/dist/src/telemetry/metrics.d.ts +13 -0
- package/dist/src/telemetry/metrics.js +17 -0
- package/dist/src/telemetry/metrics.js.map +1 -1
- package/dist/src/telemetry/startupProfiler.js +4 -4
- package/dist/src/telemetry/startupProfiler.js.map +1 -1
- package/dist/src/telemetry/startupProfiler.test.js +19 -0
- package/dist/src/telemetry/startupProfiler.test.js.map +1 -1
- package/dist/src/telemetry/telemetry-utils.test.js +3 -3
- package/dist/src/telemetry/types.d.ts +16 -2
- package/dist/src/telemetry/types.js +34 -0
- package/dist/src/telemetry/types.js.map +1 -1
- package/dist/src/telemetry/uiTelemetry.d.ts +7 -0
- package/dist/src/telemetry/uiTelemetry.js +78 -0
- package/dist/src/telemetry/uiTelemetry.js.map +1 -1
- package/dist/src/telemetry/uiTelemetry.test.js +101 -0
- package/dist/src/telemetry/uiTelemetry.test.js.map +1 -1
- package/dist/src/tools/exit-plan-mode.js +10 -2
- package/dist/src/tools/exit-plan-mode.js.map +1 -1
- package/dist/src/tools/exit-plan-mode.test.js +15 -0
- package/dist/src/tools/exit-plan-mode.test.js.map +1 -1
- package/dist/src/tools/ls.js +2 -2
- package/dist/src/tools/ls.js.map +1 -1
- package/dist/src/tools/mcp-client.js +0 -1
- package/dist/src/tools/mcp-client.js.map +1 -1
- package/dist/src/tools/mcp-client.test.js +4 -0
- package/dist/src/tools/mcp-client.test.js.map +1 -1
- package/dist/src/tools/mcp-tool.test.js +10 -1
- package/dist/src/tools/mcp-tool.test.js.map +1 -1
- package/dist/src/tools/read-many-files.js +2 -4
- package/dist/src/tools/read-many-files.js.map +1 -1
- package/dist/src/tools/shell.d.ts +1 -1
- package/dist/src/tools/shell.js +3 -3
- package/dist/src/tools/shell.js.map +1 -1
- package/dist/src/tools/tool-registry.test.js +4 -0
- package/dist/src/tools/tool-registry.test.js.map +1 -1
- package/dist/src/tools/tools.d.ts +34 -1
- package/dist/src/tools/tools.js +47 -1
- package/dist/src/tools/tools.js.map +1 -1
- package/dist/src/tools/web-fetch.d.ts +5 -0
- package/dist/src/tools/web-fetch.js +177 -100
- package/dist/src/tools/web-fetch.js.map +1 -1
- package/dist/src/tools/web-fetch.test.js +130 -26
- package/dist/src/tools/web-fetch.test.js.map +1 -1
- package/dist/src/tools/web-search.test.js +2 -0
- package/dist/src/tools/web-search.test.js.map +1 -1
- package/dist/src/utils/fetch.d.ts +0 -29
- package/dist/src/utils/fetch.js +10 -123
- package/dist/src/utils/fetch.js.map +1 -1
- package/dist/src/utils/fetch.test.js +1 -103
- package/dist/src/utils/fetch.test.js.map +1 -1
- package/dist/src/utils/language-detection.js +96 -89
- package/dist/src/utils/language-detection.js.map +1 -1
- package/dist/src/utils/language-detection.test.d.ts +6 -0
- package/dist/src/utils/language-detection.test.js +39 -0
- package/dist/src/utils/language-detection.test.js.map +1 -0
- package/dist/src/utils/oauth-flow.js +0 -2
- package/dist/src/utils/oauth-flow.js.map +1 -1
- package/dist/src/utils/paths.js +5 -2
- package/dist/src/utils/paths.js.map +1 -1
- package/dist/src/utils/paths.test.js +11 -0
- package/dist/src/utils/paths.test.js.map +1 -1
- package/dist/src/utils/process-utils.js +18 -4
- package/dist/src/utils/process-utils.js.map +1 -1
- package/dist/src/utils/process-utils.test.js +32 -10
- package/dist/src/utils/process-utils.test.js.map +1 -1
- package/dist/src/utils/retry.d.ts +7 -0
- package/dist/src/utils/retry.js +40 -3
- package/dist/src/utils/retry.js.map +1 -1
- package/dist/src/utils/retry.test.js +13 -0
- package/dist/src/utils/retry.test.js.map +1 -1
- package/dist/src/utils/summarizer.test.js +5 -0
- package/dist/src/utils/summarizer.test.js.map +1 -1
- package/dist/src/utils/surface.d.ts +18 -0
- package/dist/src/utils/surface.js +46 -0
- package/dist/src/utils/surface.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/dist/google-gemini-cli-core-0.34.0-preview.2.tgz +0 -0
- package/dist/src/services/fileKeychain.d.ts +0 -24
- package/dist/src/services/fileKeychain.js +0 -123
- package/dist/src/services/fileKeychain.js.map +0 -1
|
@@ -3,41 +3,51 @@
|
|
|
3
3
|
* Copyright 2025 Google LLC
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
|
-
import { ClientFactory, ClientFactoryOptions, DefaultAgentCardResolver,
|
|
6
|
+
import { ClientFactory, ClientFactoryOptions, DefaultAgentCardResolver, JsonRpcTransportFactory, RestTransportFactory, createAuthenticatingFetchWithRetry, } from '@a2a-js/sdk/client';
|
|
7
|
+
import { GrpcTransportFactory } from '@a2a-js/sdk/client/grpc';
|
|
8
|
+
import * as grpc from '@grpc/grpc-js';
|
|
7
9
|
import { v4 as uuidv4 } from 'uuid';
|
|
8
|
-
import { Agent as UndiciAgent } from 'undici';
|
|
10
|
+
import { Agent as UndiciAgent, ProxyAgent } from 'undici';
|
|
11
|
+
import { normalizeAgentCard } from './a2aUtils.js';
|
|
9
12
|
import { debugLogger } from '../utils/debugLogger.js';
|
|
10
|
-
import { safeLookup } from '../utils/fetch.js';
|
|
11
13
|
import { classifyAgentError } from './a2a-errors.js';
|
|
12
14
|
// Remote agents can take 10+ minutes (e.g. Deep Research).
|
|
13
15
|
// Use a dedicated dispatcher so the global 5-min timeout isn't affected.
|
|
14
16
|
const A2A_TIMEOUT = 1800000; // 30 minutes
|
|
15
|
-
const a2aDispatcher = new UndiciAgent({
|
|
16
|
-
headersTimeout: A2A_TIMEOUT,
|
|
17
|
-
bodyTimeout: A2A_TIMEOUT,
|
|
18
|
-
connect: {
|
|
19
|
-
lookup: safeLookup, // SSRF protection at connection level
|
|
20
|
-
},
|
|
21
|
-
});
|
|
22
|
-
const a2aFetch = (input, init) =>
|
|
23
|
-
// eslint-disable-next-line no-restricted-syntax -- TODO: Migrate to safeFetch for SSRF protection
|
|
24
|
-
fetch(input, { ...init, dispatcher: a2aDispatcher });
|
|
25
17
|
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
18
|
+
* Orchestrates communication with remote A2A agents.
|
|
19
|
+
* Manages protocol negotiation, authentication, and transport selection.
|
|
28
20
|
*/
|
|
29
21
|
export class A2AClientManager {
|
|
30
22
|
static instance;
|
|
31
23
|
// Each agent should manage their own context/taskIds/card/etc
|
|
32
24
|
clients = new Map();
|
|
33
25
|
agentCards = new Map();
|
|
34
|
-
|
|
26
|
+
a2aDispatcher;
|
|
27
|
+
a2aFetch;
|
|
28
|
+
constructor(config) {
|
|
29
|
+
const proxyUrl = config?.getProxy();
|
|
30
|
+
const agentOptions = {
|
|
31
|
+
headersTimeout: A2A_TIMEOUT,
|
|
32
|
+
bodyTimeout: A2A_TIMEOUT,
|
|
33
|
+
};
|
|
34
|
+
if (proxyUrl) {
|
|
35
|
+
this.a2aDispatcher = new ProxyAgent({
|
|
36
|
+
uri: proxyUrl,
|
|
37
|
+
...agentOptions,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
this.a2aDispatcher = new UndiciAgent(agentOptions);
|
|
42
|
+
}
|
|
43
|
+
this.a2aFetch = (input, init) => fetch(input, { ...init, dispatcher: this.a2aDispatcher });
|
|
44
|
+
}
|
|
35
45
|
/**
|
|
36
46
|
* Gets the singleton instance of the A2AClientManager.
|
|
37
47
|
*/
|
|
38
|
-
static getInstance() {
|
|
48
|
+
static getInstance(config) {
|
|
39
49
|
if (!A2AClientManager.instance) {
|
|
40
|
-
A2AClientManager.instance = new A2AClientManager();
|
|
50
|
+
A2AClientManager.instance = new A2AClientManager(config);
|
|
41
51
|
}
|
|
42
52
|
return A2AClientManager.instance;
|
|
43
53
|
}
|
|
@@ -61,15 +71,15 @@ export class A2AClientManager {
|
|
|
61
71
|
throw new Error(`Agent with name '${name}' is already loaded.`);
|
|
62
72
|
}
|
|
63
73
|
// Authenticated fetch for API calls (transports).
|
|
64
|
-
let authFetch = a2aFetch;
|
|
74
|
+
let authFetch = this.a2aFetch;
|
|
65
75
|
if (authHandler) {
|
|
66
|
-
authFetch = createAuthenticatingFetchWithRetry(a2aFetch, authHandler);
|
|
76
|
+
authFetch = createAuthenticatingFetchWithRetry(this.a2aFetch, authHandler);
|
|
67
77
|
}
|
|
68
78
|
// Use unauthenticated fetch for the agent card unless explicitly required.
|
|
69
79
|
// Some servers reject unexpected auth headers on the card endpoint (e.g. 400).
|
|
70
80
|
const cardFetch = async (input, init) => {
|
|
71
81
|
// Try without auth first
|
|
72
|
-
const response = await a2aFetch(input, init);
|
|
82
|
+
const response = await this.a2aFetch(input, init);
|
|
73
83
|
// Retry with auth if we hit a 401/403
|
|
74
84
|
if ((response.status === 401 || response.status === 403) && authFetch) {
|
|
75
85
|
return authFetch(input, init);
|
|
@@ -77,17 +87,28 @@ export class A2AClientManager {
|
|
|
77
87
|
return response;
|
|
78
88
|
};
|
|
79
89
|
const resolver = new DefaultAgentCardResolver({ fetchImpl: cardFetch });
|
|
80
|
-
const
|
|
90
|
+
const rawCard = await resolver.resolve(agentCardUrl, '');
|
|
91
|
+
// TODO: Remove normalizeAgentCard once @a2a-js/sdk handles
|
|
92
|
+
// proto field name aliases (supportedInterfaces → additionalInterfaces,
|
|
93
|
+
// protocolBinding → transport).
|
|
94
|
+
const agentCard = normalizeAgentCard(rawCard);
|
|
95
|
+
const grpcUrl = agentCard.additionalInterfaces?.find((i) => i.transport === 'GRPC')
|
|
96
|
+
?.url ?? agentCard.url;
|
|
97
|
+
const clientOptions = ClientFactoryOptions.createFrom(ClientFactoryOptions.default, {
|
|
81
98
|
transports: [
|
|
82
99
|
new RestTransportFactory({ fetchImpl: authFetch }),
|
|
83
100
|
new JsonRpcTransportFactory({ fetchImpl: authFetch }),
|
|
101
|
+
new GrpcTransportFactory({
|
|
102
|
+
grpcChannelCredentials: grpcUrl.startsWith('https://')
|
|
103
|
+
? grpc.credentials.createSsl()
|
|
104
|
+
: grpc.credentials.createInsecure(),
|
|
105
|
+
}),
|
|
84
106
|
],
|
|
85
107
|
cardResolver: resolver,
|
|
86
108
|
});
|
|
87
109
|
try {
|
|
88
|
-
const factory = new ClientFactory(
|
|
89
|
-
const client = await factory.
|
|
90
|
-
const agentCard = await client.getAgentCard();
|
|
110
|
+
const factory = new ClientFactory(clientOptions);
|
|
111
|
+
const client = await factory.createFromAgentCard(agentCard);
|
|
91
112
|
this.clients.set(name, client);
|
|
92
113
|
this.agentCards.set(name, agentCard);
|
|
93
114
|
debugLogger.debug(`[A2AClientManager] Loaded agent '${name}' from ${agentCardUrl}`);
|
|
@@ -115,9 +136,8 @@ export class A2AClientManager {
|
|
|
115
136
|
*/
|
|
116
137
|
async *sendMessageStream(agentName, message, options) {
|
|
117
138
|
const client = this.clients.get(agentName);
|
|
118
|
-
if (!client)
|
|
139
|
+
if (!client)
|
|
119
140
|
throw new Error(`Agent '${agentName}' not found.`);
|
|
120
|
-
}
|
|
121
141
|
const messageParams = {
|
|
122
142
|
message: {
|
|
123
143
|
kind: 'message',
|
|
@@ -128,9 +148,18 @@ export class A2AClientManager {
|
|
|
128
148
|
taskId: options?.taskId,
|
|
129
149
|
},
|
|
130
150
|
};
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
151
|
+
try {
|
|
152
|
+
yield* client.sendMessageStream(messageParams, {
|
|
153
|
+
signal: options?.signal,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
const prefix = `[A2AClientManager] sendMessageStream Error [${agentName}]`;
|
|
158
|
+
if (error instanceof Error) {
|
|
159
|
+
throw new Error(`${prefix}: ${error.message}`, { cause: error });
|
|
160
|
+
}
|
|
161
|
+
throw new Error(`${prefix}: Unexpected error during sendMessageStream: ${String(error)}`);
|
|
162
|
+
}
|
|
134
163
|
}
|
|
135
164
|
/**
|
|
136
165
|
* Retrieves a loaded agent card.
|
|
@@ -156,9 +185,8 @@ export class A2AClientManager {
|
|
|
156
185
|
*/
|
|
157
186
|
async getTask(agentName, taskId) {
|
|
158
187
|
const client = this.clients.get(agentName);
|
|
159
|
-
if (!client)
|
|
188
|
+
if (!client)
|
|
160
189
|
throw new Error(`Agent '${agentName}' not found.`);
|
|
161
|
-
}
|
|
162
190
|
try {
|
|
163
191
|
return await client.getTask({ id: taskId });
|
|
164
192
|
}
|
|
@@ -178,9 +206,8 @@ export class A2AClientManager {
|
|
|
178
206
|
*/
|
|
179
207
|
async cancelTask(agentName, taskId) {
|
|
180
208
|
const client = this.clients.get(agentName);
|
|
181
|
-
if (!client)
|
|
209
|
+
if (!client)
|
|
182
210
|
throw new Error(`Agent '${agentName}' not found.`);
|
|
183
|
-
}
|
|
184
211
|
try {
|
|
185
212
|
return await client.cancelTask({ id: taskId });
|
|
186
213
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"a2a-client-manager.js","sourceRoot":"","sources":["../../../src/agents/a2a-client-manager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"a2a-client-manager.js","sourceRoot":"","sources":["../../../src/agents/a2a-client-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,66 +4,72 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
7
|
-
import { A2AClientManager
|
|
7
|
+
import { A2AClientManager } from './a2a-client-manager.js';
|
|
8
8
|
import { ClientFactory, DefaultAgentCardResolver, createAuthenticatingFetchWithRetry, ClientFactoryOptions, } from '@a2a-js/sdk/client';
|
|
9
|
+
import { Agent as UndiciAgent, ProxyAgent } from 'undici';
|
|
9
10
|
import { debugLogger } from '../utils/debugLogger.js';
|
|
11
|
+
vi.mock('@a2a-js/sdk/client', async (importOriginal) => {
|
|
12
|
+
const actual = await importOriginal();
|
|
13
|
+
return {
|
|
14
|
+
...actual,
|
|
15
|
+
createAuthenticatingFetchWithRetry: vi.fn(),
|
|
16
|
+
ClientFactory: vi.fn(),
|
|
17
|
+
DefaultAgentCardResolver: vi.fn(),
|
|
18
|
+
ClientFactoryOptions: {
|
|
19
|
+
createFrom: vi.fn(),
|
|
20
|
+
default: {},
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
});
|
|
10
24
|
vi.mock('../utils/debugLogger.js', () => ({
|
|
11
25
|
debugLogger: {
|
|
12
26
|
debug: vi.fn(),
|
|
13
27
|
},
|
|
14
28
|
}));
|
|
15
|
-
vi.mock('@a2a-js/sdk/client', () => {
|
|
16
|
-
const ClientFactory = vi.fn();
|
|
17
|
-
const DefaultAgentCardResolver = vi.fn();
|
|
18
|
-
const RestTransportFactory = vi.fn();
|
|
19
|
-
const JsonRpcTransportFactory = vi.fn();
|
|
20
|
-
const ClientFactoryOptions = {
|
|
21
|
-
default: {},
|
|
22
|
-
createFrom: vi.fn(),
|
|
23
|
-
};
|
|
24
|
-
const createAuthenticatingFetchWithRetry = vi.fn();
|
|
25
|
-
DefaultAgentCardResolver.prototype.resolve = vi.fn();
|
|
26
|
-
ClientFactory.prototype.createFromUrl = vi.fn();
|
|
27
|
-
return {
|
|
28
|
-
ClientFactory,
|
|
29
|
-
ClientFactoryOptions,
|
|
30
|
-
DefaultAgentCardResolver,
|
|
31
|
-
RestTransportFactory,
|
|
32
|
-
JsonRpcTransportFactory,
|
|
33
|
-
createAuthenticatingFetchWithRetry,
|
|
34
|
-
};
|
|
35
|
-
});
|
|
36
29
|
describe('A2AClientManager', () => {
|
|
37
30
|
let manager;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
31
|
+
const mockAgentCard = {
|
|
32
|
+
name: 'test-agent',
|
|
33
|
+
description: 'A test agent',
|
|
34
|
+
url: 'http://test.agent',
|
|
35
|
+
version: '1.0.0',
|
|
36
|
+
protocolVersion: '0.1.0',
|
|
37
|
+
capabilities: {},
|
|
38
|
+
skills: [],
|
|
39
|
+
defaultInputModes: [],
|
|
40
|
+
defaultOutputModes: [],
|
|
41
|
+
};
|
|
44
42
|
const mockClient = {
|
|
45
|
-
sendMessageStream:
|
|
46
|
-
getTask:
|
|
47
|
-
cancelTask:
|
|
48
|
-
getAgentCard: getAgentCardMock,
|
|
43
|
+
sendMessageStream: vi.fn(),
|
|
44
|
+
getTask: vi.fn(),
|
|
45
|
+
cancelTask: vi.fn(),
|
|
49
46
|
};
|
|
50
|
-
const
|
|
47
|
+
const authFetchMock = vi.fn();
|
|
51
48
|
beforeEach(() => {
|
|
52
49
|
vi.clearAllMocks();
|
|
53
50
|
A2AClientManager.resetInstanceForTesting();
|
|
54
51
|
manager = A2AClientManager.getInstance();
|
|
55
|
-
//
|
|
56
|
-
|
|
52
|
+
// Re-create the instances as plain objects that can be spied on
|
|
53
|
+
const factoryInstance = {
|
|
54
|
+
createFromUrl: vi.fn(),
|
|
55
|
+
createFromAgentCard: vi.fn(),
|
|
56
|
+
};
|
|
57
|
+
const resolverInstance = {
|
|
58
|
+
resolve: vi.fn(),
|
|
59
|
+
};
|
|
60
|
+
vi.mocked(ClientFactory).mockReturnValue(factoryInstance);
|
|
61
|
+
vi.mocked(DefaultAgentCardResolver).mockReturnValue(resolverInstance);
|
|
62
|
+
vi.spyOn(factoryInstance, 'createFromUrl').mockResolvedValue(mockClient);
|
|
63
|
+
vi.spyOn(factoryInstance, 'createFromAgentCard').mockResolvedValue(mockClient);
|
|
64
|
+
vi.spyOn(resolverInstance, 'resolve').mockResolvedValue({
|
|
57
65
|
...mockAgentCard,
|
|
58
66
|
url: 'http://test.agent/real/endpoint',
|
|
59
67
|
});
|
|
60
|
-
vi.
|
|
61
|
-
vi.mocked(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
});
|
|
65
|
-
vi.mocked(ClientFactoryOptions.createFrom).mockImplementation((_defaults, overrides) => overrides);
|
|
66
|
-
vi.mocked(createAuthenticatingFetchWithRetry).mockReturnValue(authFetchMock);
|
|
68
|
+
vi.spyOn(ClientFactoryOptions, 'createFrom').mockImplementation((_defaults, overrides) => overrides);
|
|
69
|
+
vi.mocked(createAuthenticatingFetchWithRetry).mockImplementation(() => authFetchMock.mockResolvedValue({
|
|
70
|
+
ok: true,
|
|
71
|
+
json: async () => ({}),
|
|
72
|
+
}));
|
|
67
73
|
vi.stubGlobal('fetch', vi.fn().mockResolvedValue({
|
|
68
74
|
ok: true,
|
|
69
75
|
json: async () => ({}),
|
|
@@ -78,16 +84,51 @@ describe('A2AClientManager', () => {
|
|
|
78
84
|
const instance2 = A2AClientManager.getInstance();
|
|
79
85
|
expect(instance1).toBe(instance2);
|
|
80
86
|
});
|
|
87
|
+
describe('getInstance / dispatcher initialization', () => {
|
|
88
|
+
it('should use UndiciAgent when no proxy is configured', async () => {
|
|
89
|
+
await manager.loadAgent('TestAgent', 'http://test.agent/card');
|
|
90
|
+
const resolverOptions = vi.mocked(DefaultAgentCardResolver).mock
|
|
91
|
+
.calls[0][0];
|
|
92
|
+
const cardFetch = resolverOptions?.fetchImpl;
|
|
93
|
+
await cardFetch('http://test.agent/card');
|
|
94
|
+
const fetchCall = vi
|
|
95
|
+
.mocked(fetch)
|
|
96
|
+
.mock.calls.find((call) => call[0] === 'http://test.agent/card');
|
|
97
|
+
expect(fetchCall).toBeDefined();
|
|
98
|
+
expect(fetchCall[1]?.dispatcher).toBeInstanceOf(UndiciAgent);
|
|
99
|
+
expect(fetchCall[1]?.dispatcher).not.toBeInstanceOf(ProxyAgent);
|
|
100
|
+
});
|
|
101
|
+
it('should use ProxyAgent when a proxy is configured via Config', async () => {
|
|
102
|
+
A2AClientManager.resetInstanceForTesting();
|
|
103
|
+
const mockConfig = {
|
|
104
|
+
getProxy: () => 'http://my-proxy:8080',
|
|
105
|
+
};
|
|
106
|
+
manager = A2AClientManager.getInstance(mockConfig);
|
|
107
|
+
await manager.loadAgent('TestProxyAgent', 'http://test.proxy.agent/card');
|
|
108
|
+
const resolverOptions = vi.mocked(DefaultAgentCardResolver).mock
|
|
109
|
+
.calls[0][0];
|
|
110
|
+
const cardFetch = resolverOptions?.fetchImpl;
|
|
111
|
+
await cardFetch('http://test.proxy.agent/card');
|
|
112
|
+
const fetchCall = vi
|
|
113
|
+
.mocked(fetch)
|
|
114
|
+
.mock.calls.find((call) => call[0] === 'http://test.proxy.agent/card');
|
|
115
|
+
expect(fetchCall).toBeDefined();
|
|
116
|
+
expect(fetchCall[1]?.dispatcher).toBeInstanceOf(ProxyAgent);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
81
119
|
describe('loadAgent', () => {
|
|
82
120
|
it('should create and cache an A2AClient', async () => {
|
|
83
121
|
const agentCard = await manager.loadAgent('TestAgent', 'http://test.agent/card');
|
|
84
|
-
expect(agentCard).toMatchObject(mockAgentCard);
|
|
85
122
|
expect(manager.getAgentCard('TestAgent')).toBe(agentCard);
|
|
86
123
|
expect(manager.getClient('TestAgent')).toBeDefined();
|
|
87
124
|
});
|
|
125
|
+
it('should configure ClientFactory with REST, JSON-RPC, and gRPC transports', async () => {
|
|
126
|
+
await manager.loadAgent('TestAgent', 'http://test.agent/card');
|
|
127
|
+
expect(ClientFactoryOptions.createFrom).toHaveBeenCalled();
|
|
128
|
+
});
|
|
88
129
|
it('should throw an error if an agent with the same name is already loaded', async () => {
|
|
89
130
|
await manager.loadAgent('TestAgent', 'http://test.agent/card');
|
|
90
|
-
await expect(manager.loadAgent('TestAgent', 'http://
|
|
131
|
+
await expect(manager.loadAgent('TestAgent', 'http://test.agent/card')).rejects.toThrow("Agent with name 'TestAgent' is already loaded.");
|
|
91
132
|
});
|
|
92
133
|
it('should use native fetch by default', async () => {
|
|
93
134
|
await manager.loadAgent('TestAgent', 'http://test.agent/card');
|
|
@@ -98,12 +139,8 @@ describe('A2AClientManager', () => {
|
|
|
98
139
|
headers: vi.fn(),
|
|
99
140
|
shouldRetryWithHeaders: vi.fn(),
|
|
100
141
|
};
|
|
101
|
-
await manager.loadAgent('
|
|
102
|
-
expect(createAuthenticatingFetchWithRetry).toHaveBeenCalledWith(expect.anything(), customAuthHandler);
|
|
142
|
+
await manager.loadAgent('TestAgent', 'http://test.agent/card', customAuthHandler);
|
|
103
143
|
// Card resolver should NOT use the authenticated fetch by default.
|
|
104
|
-
const resolverInstance = vi.mocked(DefaultAgentCardResolver).mock
|
|
105
|
-
.instances[0];
|
|
106
|
-
expect(resolverInstance).toBeDefined();
|
|
107
144
|
const resolverOptions = vi.mocked(DefaultAgentCardResolver).mock
|
|
108
145
|
.calls[0][0];
|
|
109
146
|
expect(resolverOptions?.fetchImpl).not.toBe(authFetchMock);
|
|
@@ -143,103 +180,134 @@ describe('A2AClientManager', () => {
|
|
|
143
180
|
});
|
|
144
181
|
it('should log a debug message upon loading an agent', async () => {
|
|
145
182
|
await manager.loadAgent('TestAgent', 'http://test.agent/card');
|
|
146
|
-
expect(debugLogger.debug).toHaveBeenCalledWith("
|
|
183
|
+
expect(debugLogger.debug).toHaveBeenCalledWith(expect.stringContaining("Loaded agent 'TestAgent'"));
|
|
147
184
|
});
|
|
148
185
|
it('should clear the cache', async () => {
|
|
149
186
|
await manager.loadAgent('TestAgent', 'http://test.agent/card');
|
|
150
|
-
expect(manager.getAgentCard('TestAgent')).toBeDefined();
|
|
151
|
-
expect(manager.getClient('TestAgent')).toBeDefined();
|
|
152
187
|
manager.clearCache();
|
|
153
188
|
expect(manager.getAgentCard('TestAgent')).toBeUndefined();
|
|
154
189
|
expect(manager.getClient('TestAgent')).toBeUndefined();
|
|
155
|
-
|
|
190
|
+
});
|
|
191
|
+
it('should throw if resolveAgentCard fails', async () => {
|
|
192
|
+
const resolverInstance = {
|
|
193
|
+
resolve: vi.fn().mockRejectedValue(new Error('Resolution failed')),
|
|
194
|
+
};
|
|
195
|
+
vi.mocked(DefaultAgentCardResolver).mockReturnValue(resolverInstance);
|
|
196
|
+
await expect(manager.loadAgent('FailAgent', 'http://fail.agent')).rejects.toThrow('Resolution failed');
|
|
197
|
+
});
|
|
198
|
+
it('should throw if factory.createFromAgentCard fails', async () => {
|
|
199
|
+
const factoryInstance = {
|
|
200
|
+
createFromAgentCard: vi
|
|
201
|
+
.fn()
|
|
202
|
+
.mockRejectedValue(new Error('Factory failed')),
|
|
203
|
+
};
|
|
204
|
+
vi.mocked(ClientFactory).mockReturnValue(factoryInstance);
|
|
205
|
+
await expect(manager.loadAgent('FailAgent', 'http://fail.agent')).rejects.toThrow('Factory failed');
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
describe('getAgentCard and getClient', () => {
|
|
209
|
+
it('should return undefined if agent is not found', () => {
|
|
210
|
+
expect(manager.getAgentCard('Unknown')).toBeUndefined();
|
|
211
|
+
expect(manager.getClient('Unknown')).toBeUndefined();
|
|
156
212
|
});
|
|
157
213
|
});
|
|
158
214
|
describe('sendMessageStream', () => {
|
|
159
215
|
beforeEach(async () => {
|
|
160
|
-
await manager.loadAgent('TestAgent', 'http://test.agent');
|
|
216
|
+
await manager.loadAgent('TestAgent', 'http://test.agent/card');
|
|
161
217
|
});
|
|
162
218
|
it('should send a message and return a stream', async () => {
|
|
163
|
-
|
|
164
|
-
kind: 'message'
|
|
165
|
-
messageId: 'a',
|
|
166
|
-
parts: [],
|
|
167
|
-
role: 'agent',
|
|
168
|
-
};
|
|
169
|
-
sendMessageStreamMock.mockReturnValue((async function* () {
|
|
170
|
-
yield mockResult;
|
|
219
|
+
mockClient.sendMessageStream.mockReturnValue((async function* () {
|
|
220
|
+
yield { kind: 'message' };
|
|
171
221
|
})());
|
|
172
222
|
const stream = manager.sendMessageStream('TestAgent', 'Hello');
|
|
173
223
|
const results = [];
|
|
174
|
-
for await (const
|
|
175
|
-
results.push(
|
|
224
|
+
for await (const result of stream) {
|
|
225
|
+
results.push(result);
|
|
176
226
|
}
|
|
177
|
-
expect(results).
|
|
178
|
-
expect(
|
|
179
|
-
message: expect.anything(),
|
|
180
|
-
}), expect.any(Object));
|
|
227
|
+
expect(results).toHaveLength(1);
|
|
228
|
+
expect(mockClient.sendMessageStream).toHaveBeenCalled();
|
|
181
229
|
});
|
|
182
230
|
it('should use contextId and taskId when provided', async () => {
|
|
183
|
-
|
|
184
|
-
yield {
|
|
185
|
-
kind: 'message',
|
|
186
|
-
messageId: 'a',
|
|
187
|
-
parts: [],
|
|
188
|
-
role: 'agent',
|
|
189
|
-
};
|
|
231
|
+
mockClient.sendMessageStream.mockReturnValue((async function* () {
|
|
232
|
+
yield { kind: 'message' };
|
|
190
233
|
})());
|
|
191
|
-
const expectedContextId = 'user-context-id';
|
|
192
|
-
const expectedTaskId = 'user-task-id';
|
|
193
234
|
const stream = manager.sendMessageStream('TestAgent', 'Hello', {
|
|
194
|
-
contextId:
|
|
195
|
-
taskId:
|
|
235
|
+
contextId: 'ctx123',
|
|
236
|
+
taskId: 'task456',
|
|
196
237
|
});
|
|
238
|
+
// trigger execution
|
|
197
239
|
for await (const _ of stream) {
|
|
198
|
-
|
|
240
|
+
break;
|
|
199
241
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
242
|
+
expect(mockClient.sendMessageStream).toHaveBeenCalledWith(expect.objectContaining({
|
|
243
|
+
message: expect.objectContaining({
|
|
244
|
+
contextId: 'ctx123',
|
|
245
|
+
taskId: 'task456',
|
|
246
|
+
}),
|
|
247
|
+
}), expect.any(Object));
|
|
203
248
|
});
|
|
204
|
-
it('should propagate
|
|
205
|
-
|
|
206
|
-
|
|
249
|
+
it('should correctly propagate AbortSignal to the stream', async () => {
|
|
250
|
+
mockClient.sendMessageStream.mockReturnValue((async function* () {
|
|
251
|
+
yield { kind: 'message' };
|
|
252
|
+
})());
|
|
253
|
+
const controller = new AbortController();
|
|
254
|
+
const stream = manager.sendMessageStream('TestAgent', 'Hello', {
|
|
255
|
+
signal: controller.signal,
|
|
256
|
+
});
|
|
257
|
+
// trigger execution
|
|
258
|
+
for await (const _ of stream) {
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
261
|
+
expect(mockClient.sendMessageStream).toHaveBeenCalledWith(expect.any(Object), expect.objectContaining({ signal: controller.signal }));
|
|
262
|
+
});
|
|
263
|
+
it('should handle a multi-chunk stream with different event types', async () => {
|
|
264
|
+
mockClient.sendMessageStream.mockReturnValue((async function* () {
|
|
265
|
+
yield { kind: 'message', messageId: 'm1' };
|
|
266
|
+
yield { kind: 'status-update', taskId: 't1' };
|
|
267
|
+
})());
|
|
268
|
+
const stream = manager.sendMessageStream('TestAgent', 'Hello');
|
|
269
|
+
const results = [];
|
|
270
|
+
for await (const result of stream) {
|
|
271
|
+
results.push(result);
|
|
272
|
+
}
|
|
273
|
+
expect(results).toHaveLength(2);
|
|
274
|
+
expect(results[0].kind).toBe('message');
|
|
275
|
+
expect(results[1].kind).toBe('status-update');
|
|
276
|
+
});
|
|
277
|
+
it('should throw prefixed error on failure', async () => {
|
|
278
|
+
mockClient.sendMessageStream.mockImplementation(() => {
|
|
279
|
+
throw new Error('Network failure');
|
|
207
280
|
});
|
|
208
281
|
const stream = manager.sendMessageStream('TestAgent', 'Hello');
|
|
209
282
|
await expect(async () => {
|
|
210
283
|
for await (const _ of stream) {
|
|
211
|
-
//
|
|
284
|
+
// empty
|
|
212
285
|
}
|
|
213
|
-
}).rejects.toThrow('Network
|
|
286
|
+
}).rejects.toThrow('[A2AClientManager] sendMessageStream Error [TestAgent]: Network failure');
|
|
214
287
|
});
|
|
215
288
|
it('should throw an error if the agent is not found', async () => {
|
|
216
289
|
const stream = manager.sendMessageStream('NonExistentAgent', 'Hello');
|
|
217
290
|
await expect(async () => {
|
|
218
291
|
for await (const _ of stream) {
|
|
219
|
-
//
|
|
292
|
+
// empty
|
|
220
293
|
}
|
|
221
294
|
}).rejects.toThrow("Agent 'NonExistentAgent' not found.");
|
|
222
295
|
});
|
|
223
296
|
});
|
|
224
297
|
describe('getTask', () => {
|
|
225
298
|
beforeEach(async () => {
|
|
226
|
-
await manager.loadAgent('TestAgent', 'http://test.agent');
|
|
299
|
+
await manager.loadAgent('TestAgent', 'http://test.agent/card');
|
|
227
300
|
});
|
|
228
301
|
it('should get a task from the correct agent', async () => {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
});
|
|
235
|
-
await manager.getTask('TestAgent', 'task123');
|
|
236
|
-
expect(getTaskMock).toHaveBeenCalledWith({
|
|
237
|
-
id: 'task123',
|
|
238
|
-
});
|
|
302
|
+
const mockTask = { id: 'task123', kind: 'task' };
|
|
303
|
+
mockClient.getTask.mockResolvedValue(mockTask);
|
|
304
|
+
const result = await manager.getTask('TestAgent', 'task123');
|
|
305
|
+
expect(result).toBe(mockTask);
|
|
306
|
+
expect(mockClient.getTask).toHaveBeenCalledWith({ id: 'task123' });
|
|
239
307
|
});
|
|
240
308
|
it('should throw prefixed error on failure', async () => {
|
|
241
|
-
|
|
242
|
-
await expect(manager.getTask('TestAgent', 'task123')).rejects.toThrow('A2AClient getTask Error [TestAgent]:
|
|
309
|
+
mockClient.getTask.mockRejectedValue(new Error('Not found'));
|
|
310
|
+
await expect(manager.getTask('TestAgent', 'task123')).rejects.toThrow('A2AClient getTask Error [TestAgent]: Not found');
|
|
243
311
|
});
|
|
244
312
|
it('should throw an error if the agent is not found', async () => {
|
|
245
313
|
await expect(manager.getTask('NonExistentAgent', 'task123')).rejects.toThrow("Agent 'NonExistentAgent' not found.");
|
|
@@ -247,23 +315,18 @@ describe('A2AClientManager', () => {
|
|
|
247
315
|
});
|
|
248
316
|
describe('cancelTask', () => {
|
|
249
317
|
beforeEach(async () => {
|
|
250
|
-
await manager.loadAgent('TestAgent', 'http://test.agent');
|
|
318
|
+
await manager.loadAgent('TestAgent', 'http://test.agent/card');
|
|
251
319
|
});
|
|
252
320
|
it('should cancel a task on the correct agent', async () => {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
});
|
|
259
|
-
await manager.cancelTask('TestAgent', 'task123');
|
|
260
|
-
expect(cancelTaskMock).toHaveBeenCalledWith({
|
|
261
|
-
id: 'task123',
|
|
262
|
-
});
|
|
321
|
+
const mockTask = { id: 'task123', kind: 'task' };
|
|
322
|
+
mockClient.cancelTask.mockResolvedValue(mockTask);
|
|
323
|
+
const result = await manager.cancelTask('TestAgent', 'task123');
|
|
324
|
+
expect(result).toBe(mockTask);
|
|
325
|
+
expect(mockClient.cancelTask).toHaveBeenCalledWith({ id: 'task123' });
|
|
263
326
|
});
|
|
264
327
|
it('should throw prefixed error on failure', async () => {
|
|
265
|
-
|
|
266
|
-
await expect(manager.cancelTask('TestAgent', 'task123')).rejects.toThrow('A2AClient cancelTask Error [TestAgent]:
|
|
328
|
+
mockClient.cancelTask.mockRejectedValue(new Error('Cannot cancel'));
|
|
329
|
+
await expect(manager.cancelTask('TestAgent', 'task123')).rejects.toThrow('A2AClient cancelTask Error [TestAgent]: Cannot cancel');
|
|
267
330
|
});
|
|
268
331
|
it('should throw an error if the agent is not found', async () => {
|
|
269
332
|
await expect(manager.cancelTask('NonExistentAgent', 'task123')).rejects.toThrow("Agent 'NonExistentAgent' not found.");
|