@renseiai/agentfactory 0.8.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/LICENSE +21 -0
- package/README.md +125 -0
- package/dist/src/config/index.d.ts +3 -0
- package/dist/src/config/index.d.ts.map +1 -0
- package/dist/src/config/index.js +1 -0
- package/dist/src/config/repository-config.d.ts +44 -0
- package/dist/src/config/repository-config.d.ts.map +1 -0
- package/dist/src/config/repository-config.js +88 -0
- package/dist/src/config/repository-config.test.d.ts +2 -0
- package/dist/src/config/repository-config.test.d.ts.map +1 -0
- package/dist/src/config/repository-config.test.js +249 -0
- package/dist/src/deployment/deployment-checker.d.ts +110 -0
- package/dist/src/deployment/deployment-checker.d.ts.map +1 -0
- package/dist/src/deployment/deployment-checker.js +242 -0
- package/dist/src/deployment/index.d.ts +3 -0
- package/dist/src/deployment/index.d.ts.map +1 -0
- package/dist/src/deployment/index.js +2 -0
- package/dist/src/frontend/index.d.ts +2 -0
- package/dist/src/frontend/index.d.ts.map +1 -0
- package/dist/src/frontend/index.js +1 -0
- package/dist/src/frontend/types.d.ts +106 -0
- package/dist/src/frontend/types.d.ts.map +1 -0
- package/dist/src/frontend/types.js +11 -0
- package/dist/src/governor/decision-engine.d.ts +52 -0
- package/dist/src/governor/decision-engine.d.ts.map +1 -0
- package/dist/src/governor/decision-engine.js +220 -0
- package/dist/src/governor/decision-engine.test.d.ts +2 -0
- package/dist/src/governor/decision-engine.test.d.ts.map +1 -0
- package/dist/src/governor/decision-engine.test.js +629 -0
- package/dist/src/governor/event-bus.d.ts +43 -0
- package/dist/src/governor/event-bus.d.ts.map +1 -0
- package/dist/src/governor/event-bus.js +8 -0
- package/dist/src/governor/event-deduplicator.d.ts +43 -0
- package/dist/src/governor/event-deduplicator.d.ts.map +1 -0
- package/dist/src/governor/event-deduplicator.js +53 -0
- package/dist/src/governor/event-driven-governor.d.ts +131 -0
- package/dist/src/governor/event-driven-governor.d.ts.map +1 -0
- package/dist/src/governor/event-driven-governor.js +379 -0
- package/dist/src/governor/event-driven-governor.test.d.ts +2 -0
- package/dist/src/governor/event-driven-governor.test.d.ts.map +1 -0
- package/dist/src/governor/event-driven-governor.test.js +673 -0
- package/dist/src/governor/event-types.d.ts +78 -0
- package/dist/src/governor/event-types.d.ts.map +1 -0
- package/dist/src/governor/event-types.js +32 -0
- package/dist/src/governor/governor-types.d.ts +82 -0
- package/dist/src/governor/governor-types.d.ts.map +1 -0
- package/dist/src/governor/governor-types.js +21 -0
- package/dist/src/governor/governor.d.ts +100 -0
- package/dist/src/governor/governor.d.ts.map +1 -0
- package/dist/src/governor/governor.js +262 -0
- package/dist/src/governor/governor.test.d.ts +2 -0
- package/dist/src/governor/governor.test.d.ts.map +1 -0
- package/dist/src/governor/governor.test.js +514 -0
- package/dist/src/governor/human-touchpoints.d.ts +131 -0
- package/dist/src/governor/human-touchpoints.d.ts.map +1 -0
- package/dist/src/governor/human-touchpoints.js +251 -0
- package/dist/src/governor/human-touchpoints.test.d.ts +2 -0
- package/dist/src/governor/human-touchpoints.test.d.ts.map +1 -0
- package/dist/src/governor/human-touchpoints.test.js +366 -0
- package/dist/src/governor/in-memory-event-bus.d.ts +29 -0
- package/dist/src/governor/in-memory-event-bus.d.ts.map +1 -0
- package/dist/src/governor/in-memory-event-bus.js +79 -0
- package/dist/src/governor/index.d.ts +14 -0
- package/dist/src/governor/index.d.ts.map +1 -0
- package/dist/src/governor/index.js +13 -0
- package/dist/src/governor/override-parser.d.ts +60 -0
- package/dist/src/governor/override-parser.d.ts.map +1 -0
- package/dist/src/governor/override-parser.js +98 -0
- package/dist/src/governor/override-parser.test.d.ts +2 -0
- package/dist/src/governor/override-parser.test.d.ts.map +1 -0
- package/dist/src/governor/override-parser.test.js +312 -0
- package/dist/src/governor/platform-adapter.d.ts +69 -0
- package/dist/src/governor/platform-adapter.d.ts.map +1 -0
- package/dist/src/governor/platform-adapter.js +11 -0
- package/dist/src/governor/processing-state.d.ts +66 -0
- package/dist/src/governor/processing-state.d.ts.map +1 -0
- package/dist/src/governor/processing-state.js +43 -0
- package/dist/src/governor/processing-state.test.d.ts +2 -0
- package/dist/src/governor/processing-state.test.d.ts.map +1 -0
- package/dist/src/governor/processing-state.test.js +96 -0
- package/dist/src/governor/top-of-funnel.d.ts +118 -0
- package/dist/src/governor/top-of-funnel.d.ts.map +1 -0
- package/dist/src/governor/top-of-funnel.js +168 -0
- package/dist/src/governor/top-of-funnel.test.d.ts +2 -0
- package/dist/src/governor/top-of-funnel.test.d.ts.map +1 -0
- package/dist/src/governor/top-of-funnel.test.js +331 -0
- package/dist/src/index.d.ts +11 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +10 -0
- package/dist/src/linear-cli.d.ts +38 -0
- package/dist/src/linear-cli.d.ts.map +1 -0
- package/dist/src/linear-cli.js +674 -0
- package/dist/src/logger.d.ts +117 -0
- package/dist/src/logger.d.ts.map +1 -0
- package/dist/src/logger.js +430 -0
- package/dist/src/manifest/generate.d.ts +20 -0
- package/dist/src/manifest/generate.d.ts.map +1 -0
- package/dist/src/manifest/generate.js +65 -0
- package/dist/src/manifest/index.d.ts +4 -0
- package/dist/src/manifest/index.d.ts.map +1 -0
- package/dist/src/manifest/index.js +2 -0
- package/dist/src/manifest/route-manifest.d.ts +34 -0
- package/dist/src/manifest/route-manifest.d.ts.map +1 -0
- package/dist/src/manifest/route-manifest.js +148 -0
- package/dist/src/orchestrator/activity-emitter.d.ts +119 -0
- package/dist/src/orchestrator/activity-emitter.d.ts.map +1 -0
- package/dist/src/orchestrator/activity-emitter.js +306 -0
- package/dist/src/orchestrator/api-activity-emitter.d.ts +167 -0
- package/dist/src/orchestrator/api-activity-emitter.d.ts.map +1 -0
- package/dist/src/orchestrator/api-activity-emitter.js +417 -0
- package/dist/src/orchestrator/heartbeat-writer.d.ts +57 -0
- package/dist/src/orchestrator/heartbeat-writer.d.ts.map +1 -0
- package/dist/src/orchestrator/heartbeat-writer.js +137 -0
- package/dist/src/orchestrator/index.d.ts +20 -0
- package/dist/src/orchestrator/index.d.ts.map +1 -0
- package/dist/src/orchestrator/index.js +22 -0
- package/dist/src/orchestrator/log-analyzer.d.ts +160 -0
- package/dist/src/orchestrator/log-analyzer.d.ts.map +1 -0
- package/dist/src/orchestrator/log-analyzer.js +572 -0
- package/dist/src/orchestrator/log-config.d.ts +39 -0
- package/dist/src/orchestrator/log-config.d.ts.map +1 -0
- package/dist/src/orchestrator/log-config.js +45 -0
- package/dist/src/orchestrator/orchestrator.d.ts +316 -0
- package/dist/src/orchestrator/orchestrator.d.ts.map +1 -0
- package/dist/src/orchestrator/orchestrator.js +3290 -0
- package/dist/src/orchestrator/parse-work-result.d.ts +16 -0
- package/dist/src/orchestrator/parse-work-result.d.ts.map +1 -0
- package/dist/src/orchestrator/parse-work-result.js +135 -0
- package/dist/src/orchestrator/parse-work-result.test.d.ts +2 -0
- package/dist/src/orchestrator/parse-work-result.test.d.ts.map +1 -0
- package/dist/src/orchestrator/parse-work-result.test.js +234 -0
- package/dist/src/orchestrator/progress-logger.d.ts +72 -0
- package/dist/src/orchestrator/progress-logger.d.ts.map +1 -0
- package/dist/src/orchestrator/progress-logger.js +135 -0
- package/dist/src/orchestrator/session-logger.d.ts +159 -0
- package/dist/src/orchestrator/session-logger.d.ts.map +1 -0
- package/dist/src/orchestrator/session-logger.js +275 -0
- package/dist/src/orchestrator/state-recovery.d.ts +96 -0
- package/dist/src/orchestrator/state-recovery.d.ts.map +1 -0
- package/dist/src/orchestrator/state-recovery.js +302 -0
- package/dist/src/orchestrator/state-types.d.ts +165 -0
- package/dist/src/orchestrator/state-types.d.ts.map +1 -0
- package/dist/src/orchestrator/state-types.js +7 -0
- package/dist/src/orchestrator/stream-parser.d.ts +151 -0
- package/dist/src/orchestrator/stream-parser.d.ts.map +1 -0
- package/dist/src/orchestrator/stream-parser.js +137 -0
- package/dist/src/orchestrator/types.d.ts +232 -0
- package/dist/src/orchestrator/types.d.ts.map +1 -0
- package/dist/src/orchestrator/types.js +4 -0
- package/dist/src/orchestrator/validate-git-remote.test.d.ts +2 -0
- package/dist/src/orchestrator/validate-git-remote.test.d.ts.map +1 -0
- package/dist/src/orchestrator/validate-git-remote.test.js +61 -0
- package/dist/src/providers/a2a-auth.d.ts +81 -0
- package/dist/src/providers/a2a-auth.d.ts.map +1 -0
- package/dist/src/providers/a2a-auth.js +188 -0
- package/dist/src/providers/a2a-auth.test.d.ts +2 -0
- package/dist/src/providers/a2a-auth.test.d.ts.map +1 -0
- package/dist/src/providers/a2a-auth.test.js +232 -0
- package/dist/src/providers/a2a-provider.d.ts +254 -0
- package/dist/src/providers/a2a-provider.d.ts.map +1 -0
- package/dist/src/providers/a2a-provider.integration.test.d.ts +9 -0
- package/dist/src/providers/a2a-provider.integration.test.d.ts.map +1 -0
- package/dist/src/providers/a2a-provider.integration.test.js +665 -0
- package/dist/src/providers/a2a-provider.js +811 -0
- package/dist/src/providers/a2a-provider.test.d.ts +2 -0
- package/dist/src/providers/a2a-provider.test.d.ts.map +1 -0
- package/dist/src/providers/a2a-provider.test.js +681 -0
- package/dist/src/providers/amp-provider.d.ts +20 -0
- package/dist/src/providers/amp-provider.d.ts.map +1 -0
- package/dist/src/providers/amp-provider.js +24 -0
- package/dist/src/providers/claude-provider.d.ts +18 -0
- package/dist/src/providers/claude-provider.d.ts.map +1 -0
- package/dist/src/providers/claude-provider.js +437 -0
- package/dist/src/providers/codex-provider.d.ts +133 -0
- package/dist/src/providers/codex-provider.d.ts.map +1 -0
- package/dist/src/providers/codex-provider.js +381 -0
- package/dist/src/providers/codex-provider.test.d.ts +2 -0
- package/dist/src/providers/codex-provider.test.d.ts.map +1 -0
- package/dist/src/providers/codex-provider.test.js +387 -0
- package/dist/src/providers/index.d.ts +44 -0
- package/dist/src/providers/index.d.ts.map +1 -0
- package/dist/src/providers/index.js +85 -0
- package/dist/src/providers/spring-ai-provider.d.ts +90 -0
- package/dist/src/providers/spring-ai-provider.d.ts.map +1 -0
- package/dist/src/providers/spring-ai-provider.integration.test.d.ts +13 -0
- package/dist/src/providers/spring-ai-provider.integration.test.d.ts.map +1 -0
- package/dist/src/providers/spring-ai-provider.integration.test.js +351 -0
- package/dist/src/providers/spring-ai-provider.js +317 -0
- package/dist/src/providers/spring-ai-provider.test.d.ts +2 -0
- package/dist/src/providers/spring-ai-provider.test.d.ts.map +1 -0
- package/dist/src/providers/spring-ai-provider.test.js +200 -0
- package/dist/src/providers/types.d.ts +165 -0
- package/dist/src/providers/types.d.ts.map +1 -0
- package/dist/src/providers/types.js +13 -0
- package/dist/src/templates/adapters.d.ts +51 -0
- package/dist/src/templates/adapters.d.ts.map +1 -0
- package/dist/src/templates/adapters.js +104 -0
- package/dist/src/templates/adapters.test.d.ts +2 -0
- package/dist/src/templates/adapters.test.d.ts.map +1 -0
- package/dist/src/templates/adapters.test.js +165 -0
- package/dist/src/templates/agent-definition.d.ts +85 -0
- package/dist/src/templates/agent-definition.d.ts.map +1 -0
- package/dist/src/templates/agent-definition.js +97 -0
- package/dist/src/templates/agent-definition.test.d.ts +2 -0
- package/dist/src/templates/agent-definition.test.d.ts.map +1 -0
- package/dist/src/templates/agent-definition.test.js +209 -0
- package/dist/src/templates/index.d.ts +14 -0
- package/dist/src/templates/index.d.ts.map +1 -0
- package/dist/src/templates/index.js +11 -0
- package/dist/src/templates/loader.d.ts +41 -0
- package/dist/src/templates/loader.d.ts.map +1 -0
- package/dist/src/templates/loader.js +114 -0
- package/dist/src/templates/registry.d.ts +80 -0
- package/dist/src/templates/registry.d.ts.map +1 -0
- package/dist/src/templates/registry.js +177 -0
- package/dist/src/templates/registry.test.d.ts +2 -0
- package/dist/src/templates/registry.test.d.ts.map +1 -0
- package/dist/src/templates/registry.test.js +198 -0
- package/dist/src/templates/renderer.d.ts +29 -0
- package/dist/src/templates/renderer.d.ts.map +1 -0
- package/dist/src/templates/renderer.js +35 -0
- package/dist/src/templates/strategy-templates.test.d.ts +2 -0
- package/dist/src/templates/strategy-templates.test.d.ts.map +1 -0
- package/dist/src/templates/strategy-templates.test.js +619 -0
- package/dist/src/templates/types.d.ts +233 -0
- package/dist/src/templates/types.d.ts.map +1 -0
- package/dist/src/templates/types.js +127 -0
- package/dist/src/templates/types.test.d.ts +2 -0
- package/dist/src/templates/types.test.d.ts.map +1 -0
- package/dist/src/templates/types.test.js +232 -0
- package/dist/src/tools/index.d.ts +6 -0
- package/dist/src/tools/index.d.ts.map +1 -0
- package/dist/src/tools/index.js +3 -0
- package/dist/src/tools/linear-runner.d.ts +34 -0
- package/dist/src/tools/linear-runner.d.ts.map +1 -0
- package/dist/src/tools/linear-runner.js +700 -0
- package/dist/src/tools/plugins/linear.d.ts +9 -0
- package/dist/src/tools/plugins/linear.d.ts.map +1 -0
- package/dist/src/tools/plugins/linear.js +138 -0
- package/dist/src/tools/registry.d.ts +9 -0
- package/dist/src/tools/registry.d.ts.map +1 -0
- package/dist/src/tools/registry.js +18 -0
- package/dist/src/tools/types.d.ts +18 -0
- package/dist/src/tools/types.d.ts.map +1 -0
- package/dist/src/tools/types.js +1 -0
- package/package.json +78 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A2A Authentication Utilities
|
|
3
|
+
*
|
|
4
|
+
* Client-side: resolve credentials from env vars and build HTTP auth headers
|
|
5
|
+
* for outbound requests to remote A2A agents.
|
|
6
|
+
*
|
|
7
|
+
* Server-side: validate inbound A2A request auth using timing-safe comparison,
|
|
8
|
+
* following the same pattern as worker-auth.ts.
|
|
9
|
+
*/
|
|
10
|
+
import crypto from 'crypto';
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Client-side: credential resolution
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
/**
|
|
15
|
+
* Normalise a hostname into an env-var suffix.
|
|
16
|
+
*
|
|
17
|
+
* - Uppercases
|
|
18
|
+
* - Replaces dots and hyphens with underscores
|
|
19
|
+
*
|
|
20
|
+
* Example: "spring-agent.example.com" -> "SPRING_AGENT_EXAMPLE_COM"
|
|
21
|
+
*/
|
|
22
|
+
function hostnameToEnvSuffix(hostname) {
|
|
23
|
+
return hostname.toUpperCase().replace(/[.\-]/g, '_');
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Resolve credentials from environment variables for outbound A2A requests.
|
|
27
|
+
*
|
|
28
|
+
* Resolution order:
|
|
29
|
+
* 1. If agentUrl is provided, try host-specific env vars first:
|
|
30
|
+
* - A2A_API_KEY_{HOSTNAME}
|
|
31
|
+
* - A2A_BEARER_TOKEN_{HOSTNAME}
|
|
32
|
+
* 2. Fall back to generic env vars:
|
|
33
|
+
* - A2A_API_KEY
|
|
34
|
+
* - A2A_BEARER_TOKEN
|
|
35
|
+
*
|
|
36
|
+
* @param env - Environment variable map (e.g. process.env)
|
|
37
|
+
* @param agentUrl - Optional URL of the remote agent for host-specific lookup
|
|
38
|
+
* @returns Resolved credentials (may be empty if no env vars are set)
|
|
39
|
+
*/
|
|
40
|
+
export function resolveA2aCredentials(env, agentUrl) {
|
|
41
|
+
const creds = {};
|
|
42
|
+
let hostSuffix;
|
|
43
|
+
if (agentUrl) {
|
|
44
|
+
try {
|
|
45
|
+
const url = new URL(agentUrl);
|
|
46
|
+
hostSuffix = hostnameToEnvSuffix(url.hostname);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// Invalid URL — skip host-specific lookup
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// Resolve API key: host-specific first, then generic
|
|
53
|
+
if (hostSuffix) {
|
|
54
|
+
const hostKey = env[`A2A_API_KEY_${hostSuffix}`];
|
|
55
|
+
if (hostKey) {
|
|
56
|
+
creds.apiKey = hostKey;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (!creds.apiKey) {
|
|
60
|
+
const genericKey = env['A2A_API_KEY'];
|
|
61
|
+
if (genericKey) {
|
|
62
|
+
creds.apiKey = genericKey;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Resolve bearer token: host-specific first, then generic
|
|
66
|
+
if (hostSuffix) {
|
|
67
|
+
const hostToken = env[`A2A_BEARER_TOKEN_${hostSuffix}`];
|
|
68
|
+
if (hostToken) {
|
|
69
|
+
creds.bearerToken = hostToken;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (!creds.bearerToken) {
|
|
73
|
+
const genericToken = env['A2A_BEARER_TOKEN'];
|
|
74
|
+
if (genericToken) {
|
|
75
|
+
creds.bearerToken = genericToken;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return creds;
|
|
79
|
+
}
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
// Client-side: auth header construction
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
/**
|
|
84
|
+
* Build HTTP headers for authenticating an outbound A2A request.
|
|
85
|
+
*
|
|
86
|
+
* When auth schemes are provided (from the remote agent's AgentCard), the
|
|
87
|
+
* function matches credentials to the first compatible scheme:
|
|
88
|
+
* - apiKey scheme -> sets header {scheme.name}: {key} (default: x-api-key)
|
|
89
|
+
* - http + bearer -> sets Authorization: Bearer {token}
|
|
90
|
+
*
|
|
91
|
+
* When no auth schemes are provided, auto-detection is used:
|
|
92
|
+
* - bearerToken -> Authorization: Bearer {token}
|
|
93
|
+
* - apiKey -> x-api-key: {key}
|
|
94
|
+
*
|
|
95
|
+
* @param credentials - Resolved credentials
|
|
96
|
+
* @param authSchemes - Optional auth schemes from the remote agent's card
|
|
97
|
+
* @returns Headers object (may be empty)
|
|
98
|
+
*/
|
|
99
|
+
export function buildA2aAuthHeaders(credentials, authSchemes) {
|
|
100
|
+
const headers = {};
|
|
101
|
+
if (authSchemes && authSchemes.length > 0) {
|
|
102
|
+
// Match credentials to declared auth schemes
|
|
103
|
+
for (const scheme of authSchemes) {
|
|
104
|
+
if (scheme.type === 'apiKey' && credentials.apiKey) {
|
|
105
|
+
const headerName = scheme.name || 'x-api-key';
|
|
106
|
+
headers[headerName] = credentials.apiKey;
|
|
107
|
+
return headers;
|
|
108
|
+
}
|
|
109
|
+
if (scheme.type === 'http' && scheme.scheme === 'bearer' && credentials.bearerToken) {
|
|
110
|
+
headers['Authorization'] = `Bearer ${credentials.bearerToken}`;
|
|
111
|
+
return headers;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// No scheme matched — return empty
|
|
115
|
+
return headers;
|
|
116
|
+
}
|
|
117
|
+
// Auto-detect: no auth schemes provided
|
|
118
|
+
if (credentials.bearerToken) {
|
|
119
|
+
headers['Authorization'] = `Bearer ${credentials.bearerToken}`;
|
|
120
|
+
}
|
|
121
|
+
else if (credentials.apiKey) {
|
|
122
|
+
headers['x-api-key'] = credentials.apiKey;
|
|
123
|
+
}
|
|
124
|
+
return headers;
|
|
125
|
+
}
|
|
126
|
+
// ---------------------------------------------------------------------------
|
|
127
|
+
// Server-side: inbound request validation
|
|
128
|
+
// ---------------------------------------------------------------------------
|
|
129
|
+
/**
|
|
130
|
+
* Extract a bearer token or raw key from an Authorization header.
|
|
131
|
+
*
|
|
132
|
+
* Supports:
|
|
133
|
+
* - "Bearer <token>" -> returns the token
|
|
134
|
+
* - Raw value (no prefix) -> returns the value as-is
|
|
135
|
+
*/
|
|
136
|
+
function extractToken(authHeader) {
|
|
137
|
+
if (authHeader.startsWith('Bearer ')) {
|
|
138
|
+
return authHeader.slice(7);
|
|
139
|
+
}
|
|
140
|
+
return authHeader;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Validate an incoming A2A request's auth header using timing-safe comparison.
|
|
144
|
+
*
|
|
145
|
+
* Resolution of expected key:
|
|
146
|
+
* 1. config.apiKey (explicit value)
|
|
147
|
+
* 2. env var named by config.apiKeyEnvVar
|
|
148
|
+
* 3. A2A_SERVER_API_KEY env var
|
|
149
|
+
* 4. WORKER_API_KEY env var (fallback for backward compat)
|
|
150
|
+
*
|
|
151
|
+
* If no expected key is configured, returns false (fail closed).
|
|
152
|
+
*
|
|
153
|
+
* @param authHeader - The Authorization header value from the request
|
|
154
|
+
* @param config - Optional auth configuration
|
|
155
|
+
* @returns true if the auth is valid
|
|
156
|
+
*/
|
|
157
|
+
export function validateA2aAuth(authHeader, config) {
|
|
158
|
+
if (!authHeader) {
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
const providedKey = extractToken(authHeader);
|
|
162
|
+
if (!providedKey) {
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
// Resolve expected key
|
|
166
|
+
let expectedKey;
|
|
167
|
+
if (config?.apiKey) {
|
|
168
|
+
expectedKey = config.apiKey;
|
|
169
|
+
}
|
|
170
|
+
else if (config?.apiKeyEnvVar) {
|
|
171
|
+
expectedKey = process.env[config.apiKeyEnvVar];
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
// Default env var resolution chain
|
|
175
|
+
expectedKey = process.env.A2A_SERVER_API_KEY ?? process.env.WORKER_API_KEY;
|
|
176
|
+
}
|
|
177
|
+
if (!expectedKey) {
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
// Use timing-safe comparison to prevent timing attacks
|
|
181
|
+
try {
|
|
182
|
+
return crypto.timingSafeEqual(Buffer.from(providedKey), Buffer.from(expectedKey));
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
// Buffers have different lengths
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"a2a-auth.test.d.ts","sourceRoot":"","sources":["../../../src/providers/a2a-auth.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { resolveA2aCredentials, buildA2aAuthHeaders, validateA2aAuth, } from './a2a-auth.js';
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// resolveA2aCredentials
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
describe('resolveA2aCredentials', () => {
|
|
7
|
+
it('returns empty credentials when no env vars set', () => {
|
|
8
|
+
const result = resolveA2aCredentials({});
|
|
9
|
+
expect(result).toEqual({});
|
|
10
|
+
});
|
|
11
|
+
it('reads generic A2A_API_KEY', () => {
|
|
12
|
+
const result = resolveA2aCredentials({ A2A_API_KEY: 'my-api-key' });
|
|
13
|
+
expect(result.apiKey).toBe('my-api-key');
|
|
14
|
+
});
|
|
15
|
+
it('reads generic A2A_BEARER_TOKEN', () => {
|
|
16
|
+
const result = resolveA2aCredentials({ A2A_BEARER_TOKEN: 'my-token' });
|
|
17
|
+
expect(result.bearerToken).toBe('my-token');
|
|
18
|
+
});
|
|
19
|
+
it('reads both generic keys simultaneously', () => {
|
|
20
|
+
const result = resolveA2aCredentials({
|
|
21
|
+
A2A_API_KEY: 'key-1',
|
|
22
|
+
A2A_BEARER_TOKEN: 'token-1',
|
|
23
|
+
});
|
|
24
|
+
expect(result.apiKey).toBe('key-1');
|
|
25
|
+
expect(result.bearerToken).toBe('token-1');
|
|
26
|
+
});
|
|
27
|
+
it('reads host-specific keys when agentUrl provided', () => {
|
|
28
|
+
const result = resolveA2aCredentials({ A2A_API_KEY_EXAMPLE_COM: 'host-key' }, 'https://example.com/agent');
|
|
29
|
+
expect(result.apiKey).toBe('host-key');
|
|
30
|
+
});
|
|
31
|
+
it('host-specific takes precedence over generic', () => {
|
|
32
|
+
const result = resolveA2aCredentials({
|
|
33
|
+
A2A_API_KEY: 'generic-key',
|
|
34
|
+
A2A_API_KEY_EXAMPLE_COM: 'host-key',
|
|
35
|
+
A2A_BEARER_TOKEN: 'generic-token',
|
|
36
|
+
A2A_BEARER_TOKEN_EXAMPLE_COM: 'host-token',
|
|
37
|
+
}, 'https://example.com/agent');
|
|
38
|
+
expect(result.apiKey).toBe('host-key');
|
|
39
|
+
expect(result.bearerToken).toBe('host-token');
|
|
40
|
+
});
|
|
41
|
+
it('falls back to generic when host-specific not set', () => {
|
|
42
|
+
const result = resolveA2aCredentials({
|
|
43
|
+
A2A_API_KEY: 'generic-key',
|
|
44
|
+
A2A_BEARER_TOKEN: 'generic-token',
|
|
45
|
+
}, 'https://example.com/agent');
|
|
46
|
+
expect(result.apiKey).toBe('generic-key');
|
|
47
|
+
expect(result.bearerToken).toBe('generic-token');
|
|
48
|
+
});
|
|
49
|
+
it('handles URLs with ports correctly (port is not in hostname)', () => {
|
|
50
|
+
const result = resolveA2aCredentials({ A2A_API_KEY_LOCALHOST: 'local-key' }, 'http://localhost:8080/agent');
|
|
51
|
+
expect(result.apiKey).toBe('local-key');
|
|
52
|
+
});
|
|
53
|
+
it('handles hostnames with hyphens', () => {
|
|
54
|
+
const result = resolveA2aCredentials({ A2A_API_KEY_SPRING_AGENT_EXAMPLE_COM: 'spring-key' }, 'http://spring-agent.example.com:8080/');
|
|
55
|
+
expect(result.apiKey).toBe('spring-key');
|
|
56
|
+
});
|
|
57
|
+
it('handles hostnames with multiple dots and hyphens', () => {
|
|
58
|
+
const result = resolveA2aCredentials({ A2A_BEARER_TOKEN_MY_AGENT_US_EAST_1_EXAMPLE_IO: 'region-token' }, 'https://my-agent.us-east-1.example.io/a2a');
|
|
59
|
+
expect(result.bearerToken).toBe('region-token');
|
|
60
|
+
});
|
|
61
|
+
it('ignores invalid agentUrl and falls back to generic', () => {
|
|
62
|
+
const result = resolveA2aCredentials({ A2A_API_KEY: 'generic-key' }, 'not-a-url');
|
|
63
|
+
expect(result.apiKey).toBe('generic-key');
|
|
64
|
+
});
|
|
65
|
+
it('returns empty when agentUrl is invalid and no generic keys', () => {
|
|
66
|
+
const result = resolveA2aCredentials({}, 'not-a-url');
|
|
67
|
+
expect(result).toEqual({});
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
// buildA2aAuthHeaders
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
describe('buildA2aAuthHeaders', () => {
|
|
74
|
+
it('returns empty object when no credentials', () => {
|
|
75
|
+
const result = buildA2aAuthHeaders({});
|
|
76
|
+
expect(result).toEqual({});
|
|
77
|
+
});
|
|
78
|
+
it('sets bearer token in Authorization header (auto-detect)', () => {
|
|
79
|
+
const result = buildA2aAuthHeaders({ bearerToken: 'my-token' });
|
|
80
|
+
expect(result).toEqual({ Authorization: 'Bearer my-token' });
|
|
81
|
+
});
|
|
82
|
+
it('sets API key in x-api-key header (auto-detect)', () => {
|
|
83
|
+
const result = buildA2aAuthHeaders({ apiKey: 'my-key' });
|
|
84
|
+
expect(result).toEqual({ 'x-api-key': 'my-key' });
|
|
85
|
+
});
|
|
86
|
+
it('prefers bearer token over API key in auto-detect mode', () => {
|
|
87
|
+
const result = buildA2aAuthHeaders({
|
|
88
|
+
bearerToken: 'my-token',
|
|
89
|
+
apiKey: 'my-key',
|
|
90
|
+
});
|
|
91
|
+
expect(result).toEqual({ Authorization: 'Bearer my-token' });
|
|
92
|
+
});
|
|
93
|
+
it('respects apiKey auth scheme with custom header name', () => {
|
|
94
|
+
const schemes = [
|
|
95
|
+
{ type: 'apiKey', in: 'header', name: 'X-Custom-Key' },
|
|
96
|
+
];
|
|
97
|
+
const result = buildA2aAuthHeaders({ apiKey: 'my-key' }, schemes);
|
|
98
|
+
expect(result).toEqual({ 'X-Custom-Key': 'my-key' });
|
|
99
|
+
});
|
|
100
|
+
it('uses default x-api-key header when scheme has no name', () => {
|
|
101
|
+
const schemes = [
|
|
102
|
+
{ type: 'apiKey', in: 'header' },
|
|
103
|
+
];
|
|
104
|
+
const result = buildA2aAuthHeaders({ apiKey: 'my-key' }, schemes);
|
|
105
|
+
expect(result).toEqual({ 'x-api-key': 'my-key' });
|
|
106
|
+
});
|
|
107
|
+
it('respects http bearer auth scheme', () => {
|
|
108
|
+
const schemes = [
|
|
109
|
+
{ type: 'http', scheme: 'bearer' },
|
|
110
|
+
];
|
|
111
|
+
const result = buildA2aAuthHeaders({ bearerToken: 'my-token' }, schemes);
|
|
112
|
+
expect(result).toEqual({ Authorization: 'Bearer my-token' });
|
|
113
|
+
});
|
|
114
|
+
it('returns empty when scheme requires apiKey but only bearerToken provided', () => {
|
|
115
|
+
const schemes = [
|
|
116
|
+
{ type: 'apiKey', in: 'header', name: 'x-api-key' },
|
|
117
|
+
];
|
|
118
|
+
const result = buildA2aAuthHeaders({ bearerToken: 'my-token' }, schemes);
|
|
119
|
+
expect(result).toEqual({});
|
|
120
|
+
});
|
|
121
|
+
it('returns empty when scheme requires bearer but only apiKey provided', () => {
|
|
122
|
+
const schemes = [
|
|
123
|
+
{ type: 'http', scheme: 'bearer' },
|
|
124
|
+
];
|
|
125
|
+
const result = buildA2aAuthHeaders({ apiKey: 'my-key' }, schemes);
|
|
126
|
+
expect(result).toEqual({});
|
|
127
|
+
});
|
|
128
|
+
it('matches first compatible scheme when multiple provided', () => {
|
|
129
|
+
const schemes = [
|
|
130
|
+
{ type: 'http', scheme: 'bearer' },
|
|
131
|
+
{ type: 'apiKey', in: 'header', name: 'x-api-key' },
|
|
132
|
+
];
|
|
133
|
+
const creds = { bearerToken: 'my-token', apiKey: 'my-key' };
|
|
134
|
+
const result = buildA2aAuthHeaders(creds, schemes);
|
|
135
|
+
// First scheme (bearer) should match
|
|
136
|
+
expect(result).toEqual({ Authorization: 'Bearer my-token' });
|
|
137
|
+
});
|
|
138
|
+
it('falls to second scheme when first does not match', () => {
|
|
139
|
+
const schemes = [
|
|
140
|
+
{ type: 'http', scheme: 'bearer' },
|
|
141
|
+
{ type: 'apiKey', in: 'header', name: 'x-api-key' },
|
|
142
|
+
];
|
|
143
|
+
const creds = { apiKey: 'my-key' };
|
|
144
|
+
const result = buildA2aAuthHeaders(creds, schemes);
|
|
145
|
+
// Only apiKey scheme matches
|
|
146
|
+
expect(result).toEqual({ 'x-api-key': 'my-key' });
|
|
147
|
+
});
|
|
148
|
+
it('returns empty when auth schemes array is empty (treated as no schemes)', () => {
|
|
149
|
+
const result = buildA2aAuthHeaders({ apiKey: 'my-key' }, []);
|
|
150
|
+
// Empty array means no schemes -> auto-detect
|
|
151
|
+
expect(result).toEqual({ 'x-api-key': 'my-key' });
|
|
152
|
+
});
|
|
153
|
+
it('ignores unsupported oauth2 scheme and returns empty', () => {
|
|
154
|
+
const schemes = [
|
|
155
|
+
{ type: 'oauth2' },
|
|
156
|
+
];
|
|
157
|
+
const result = buildA2aAuthHeaders({ bearerToken: 'my-token' }, schemes);
|
|
158
|
+
expect(result).toEqual({});
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
// ---------------------------------------------------------------------------
|
|
162
|
+
// validateA2aAuth
|
|
163
|
+
// ---------------------------------------------------------------------------
|
|
164
|
+
describe('validateA2aAuth', () => {
|
|
165
|
+
const originalEnv = process.env;
|
|
166
|
+
beforeEach(() => {
|
|
167
|
+
process.env = { ...originalEnv };
|
|
168
|
+
// Clear relevant env vars
|
|
169
|
+
delete process.env.A2A_SERVER_API_KEY;
|
|
170
|
+
delete process.env.WORKER_API_KEY;
|
|
171
|
+
});
|
|
172
|
+
afterEach(() => {
|
|
173
|
+
process.env = originalEnv;
|
|
174
|
+
});
|
|
175
|
+
it('returns false when no auth header provided', () => {
|
|
176
|
+
expect(validateA2aAuth(undefined, { apiKey: 'expected' })).toBe(false);
|
|
177
|
+
});
|
|
178
|
+
it('returns false when no expected key configured', () => {
|
|
179
|
+
expect(validateA2aAuth('Bearer some-token')).toBe(false);
|
|
180
|
+
});
|
|
181
|
+
it('returns true for matching bearer token', () => {
|
|
182
|
+
const result = validateA2aAuth('Bearer secret-key', { apiKey: 'secret-key' });
|
|
183
|
+
expect(result).toBe(true);
|
|
184
|
+
});
|
|
185
|
+
it('returns true for matching raw API key (no Bearer prefix)', () => {
|
|
186
|
+
const result = validateA2aAuth('secret-key', { apiKey: 'secret-key' });
|
|
187
|
+
expect(result).toBe(true);
|
|
188
|
+
});
|
|
189
|
+
it('returns false for mismatched key (timing-safe)', () => {
|
|
190
|
+
const result = validateA2aAuth('Bearer wrong-key', { apiKey: 'correct-key' });
|
|
191
|
+
expect(result).toBe(false);
|
|
192
|
+
});
|
|
193
|
+
it('returns false for mismatched key of different length', () => {
|
|
194
|
+
const result = validateA2aAuth('Bearer short', { apiKey: 'a-much-longer-key' });
|
|
195
|
+
expect(result).toBe(false);
|
|
196
|
+
});
|
|
197
|
+
it('resolves expected key from A2A_SERVER_API_KEY env var', () => {
|
|
198
|
+
process.env.A2A_SERVER_API_KEY = 'env-key';
|
|
199
|
+
const result = validateA2aAuth('Bearer env-key');
|
|
200
|
+
expect(result).toBe(true);
|
|
201
|
+
});
|
|
202
|
+
it('falls back to WORKER_API_KEY env var', () => {
|
|
203
|
+
process.env.WORKER_API_KEY = 'worker-key';
|
|
204
|
+
const result = validateA2aAuth('Bearer worker-key');
|
|
205
|
+
expect(result).toBe(true);
|
|
206
|
+
});
|
|
207
|
+
it('A2A_SERVER_API_KEY takes precedence over WORKER_API_KEY', () => {
|
|
208
|
+
process.env.A2A_SERVER_API_KEY = 'a2a-key';
|
|
209
|
+
process.env.WORKER_API_KEY = 'worker-key';
|
|
210
|
+
expect(validateA2aAuth('Bearer a2a-key')).toBe(true);
|
|
211
|
+
expect(validateA2aAuth('Bearer worker-key')).toBe(false);
|
|
212
|
+
});
|
|
213
|
+
it('uses custom env var name from config', () => {
|
|
214
|
+
process.env.MY_CUSTOM_KEY = 'custom-value';
|
|
215
|
+
const result = validateA2aAuth('Bearer custom-value', {
|
|
216
|
+
apiKeyEnvVar: 'MY_CUSTOM_KEY',
|
|
217
|
+
});
|
|
218
|
+
expect(result).toBe(true);
|
|
219
|
+
// Clean up
|
|
220
|
+
delete process.env.MY_CUSTOM_KEY;
|
|
221
|
+
});
|
|
222
|
+
it('explicit apiKey in config takes precedence over env vars', () => {
|
|
223
|
+
process.env.A2A_SERVER_API_KEY = 'env-key';
|
|
224
|
+
const result = validateA2aAuth('Bearer explicit-key', { apiKey: 'explicit-key' });
|
|
225
|
+
expect(result).toBe(true);
|
|
226
|
+
});
|
|
227
|
+
it('returns false for empty auth header string', () => {
|
|
228
|
+
// extractToken with "Bearer " prefix but nothing after gives empty string
|
|
229
|
+
// but "" still gets compared — and empty provided vs non-empty expected -> false
|
|
230
|
+
expect(validateA2aAuth('', { apiKey: 'expected' })).toBe(false);
|
|
231
|
+
});
|
|
232
|
+
});
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A2A (Agent-to-Agent) Client Provider
|
|
3
|
+
*
|
|
4
|
+
* Invokes external A2A-compliant agents over HTTP using the Google A2A protocol.
|
|
5
|
+
* Uses JSON-RPC 2.0 for requests and SSE streaming for responses.
|
|
6
|
+
*
|
|
7
|
+
* A2A Protocol overview:
|
|
8
|
+
* - Agent discovery via GET /.well-known/agent-card.json
|
|
9
|
+
* - Task creation via POST /a2a with JSON-RPC method "message/send" or "message/stream"
|
|
10
|
+
* - Task lifecycle: submitted → working → completed/failed/canceled
|
|
11
|
+
* - Input-required is a paused state requesting user input
|
|
12
|
+
* - SSE events: TaskStatusUpdateEvent, TaskArtifactUpdateEvent
|
|
13
|
+
*
|
|
14
|
+
* Env vars:
|
|
15
|
+
* A2A_AGENT_URL — base URL of the A2A agent (e.g., https://agent.example.com)
|
|
16
|
+
* A2A_AGENT_URL_{WORKTYPE} — work-type-specific override (e.g., A2A_AGENT_URL_RESEARCH)
|
|
17
|
+
* A2A_API_KEY — API key for authentication (sent as x-api-key header)
|
|
18
|
+
* A2A_BEARER_TOKEN — Bearer token for authentication (sent as Authorization header)
|
|
19
|
+
*/
|
|
20
|
+
import type { AgentProvider, AgentSpawnConfig, AgentHandle, AgentEvent } from './types.js';
|
|
21
|
+
/** A2A message part: plain text */
|
|
22
|
+
export interface A2aTextPart {
|
|
23
|
+
/** Part type discriminator */
|
|
24
|
+
type: 'text';
|
|
25
|
+
/** The text content */
|
|
26
|
+
text: string;
|
|
27
|
+
}
|
|
28
|
+
/** A2A message part: file (inline or by URI) */
|
|
29
|
+
export interface A2aFilePart {
|
|
30
|
+
/** Part type discriminator */
|
|
31
|
+
type: 'file';
|
|
32
|
+
/** File metadata */
|
|
33
|
+
file: {
|
|
34
|
+
/** File name */
|
|
35
|
+
name?: string;
|
|
36
|
+
/** MIME type */
|
|
37
|
+
mimeType?: string;
|
|
38
|
+
/** Base64-encoded file content (mutually exclusive with uri) */
|
|
39
|
+
bytes?: string;
|
|
40
|
+
/** URI to the file (mutually exclusive with bytes) */
|
|
41
|
+
uri?: string;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/** A2A message part: structured data */
|
|
45
|
+
export interface A2aDataPart {
|
|
46
|
+
/** Part type discriminator */
|
|
47
|
+
type: 'data';
|
|
48
|
+
/** Arbitrary structured data */
|
|
49
|
+
data: Record<string, unknown>;
|
|
50
|
+
}
|
|
51
|
+
/** Union of all A2A message part types */
|
|
52
|
+
export type A2aPart = A2aTextPart | A2aFilePart | A2aDataPart;
|
|
53
|
+
/** A2A message with role and content parts */
|
|
54
|
+
export interface A2aMessage {
|
|
55
|
+
/** The role of the message sender */
|
|
56
|
+
role: 'user' | 'agent';
|
|
57
|
+
/** Content parts of the message */
|
|
58
|
+
parts: A2aPart[];
|
|
59
|
+
/** Optional metadata */
|
|
60
|
+
metadata?: Record<string, unknown>;
|
|
61
|
+
}
|
|
62
|
+
/** Task status values in the A2A protocol */
|
|
63
|
+
export type A2aTaskStatus = 'submitted' | 'working' | 'input-required' | 'completed' | 'failed' | 'canceled';
|
|
64
|
+
/** A2A task status object */
|
|
65
|
+
export interface A2aTaskStatusObject {
|
|
66
|
+
/** Current task state */
|
|
67
|
+
state: A2aTaskStatus;
|
|
68
|
+
/** Optional message associated with the status */
|
|
69
|
+
message?: A2aMessage;
|
|
70
|
+
/** Timestamp of the status update */
|
|
71
|
+
timestamp?: string;
|
|
72
|
+
}
|
|
73
|
+
/** A2A artifact produced by the agent */
|
|
74
|
+
export interface A2aArtifact {
|
|
75
|
+
/** Artifact name */
|
|
76
|
+
name?: string;
|
|
77
|
+
/** Artifact description */
|
|
78
|
+
description?: string;
|
|
79
|
+
/** Content parts of the artifact */
|
|
80
|
+
parts: A2aPart[];
|
|
81
|
+
/** Artifact index (for ordering) */
|
|
82
|
+
index?: number;
|
|
83
|
+
/** Whether this is the last chunk of a streaming artifact */
|
|
84
|
+
lastChunk?: boolean;
|
|
85
|
+
/** Optional metadata */
|
|
86
|
+
metadata?: Record<string, unknown>;
|
|
87
|
+
}
|
|
88
|
+
/** A2A task object */
|
|
89
|
+
export interface A2aTask {
|
|
90
|
+
/** Task identifier */
|
|
91
|
+
id: string;
|
|
92
|
+
/** Session identifier for multi-turn conversations */
|
|
93
|
+
sessionId?: string;
|
|
94
|
+
/** Current task status */
|
|
95
|
+
status: A2aTaskStatusObject;
|
|
96
|
+
/** Messages exchanged in the task */
|
|
97
|
+
messages?: A2aMessage[];
|
|
98
|
+
/** Artifacts produced by the agent */
|
|
99
|
+
artifacts?: A2aArtifact[];
|
|
100
|
+
/** Optional metadata */
|
|
101
|
+
metadata?: Record<string, unknown>;
|
|
102
|
+
}
|
|
103
|
+
/** SSE event: task status update */
|
|
104
|
+
export interface A2aTaskStatusUpdateEvent {
|
|
105
|
+
/** Event type discriminator */
|
|
106
|
+
type: 'TaskStatusUpdate';
|
|
107
|
+
/** Task ID */
|
|
108
|
+
id: string;
|
|
109
|
+
/** Session ID */
|
|
110
|
+
sessionId?: string;
|
|
111
|
+
/** Updated status */
|
|
112
|
+
status: A2aTaskStatusObject;
|
|
113
|
+
/** Whether this is the final event */
|
|
114
|
+
final?: boolean;
|
|
115
|
+
}
|
|
116
|
+
/** SSE event: task artifact update */
|
|
117
|
+
export interface A2aTaskArtifactUpdateEvent {
|
|
118
|
+
/** Event type discriminator */
|
|
119
|
+
type: 'TaskArtifactUpdate';
|
|
120
|
+
/** Task ID */
|
|
121
|
+
id: string;
|
|
122
|
+
/** Session ID */
|
|
123
|
+
sessionId?: string;
|
|
124
|
+
/** The artifact being updated */
|
|
125
|
+
artifact: A2aArtifact;
|
|
126
|
+
}
|
|
127
|
+
/** Union of all A2A SSE task event types */
|
|
128
|
+
export type A2aTaskEvent = A2aTaskStatusUpdateEvent | A2aTaskArtifactUpdateEvent;
|
|
129
|
+
/**
|
|
130
|
+
* A2A Agent Card — describes the agent's capabilities and metadata.
|
|
131
|
+
* Fetched from GET {baseUrl}/.well-known/agent-card.json
|
|
132
|
+
*/
|
|
133
|
+
export interface A2aAgentCard {
|
|
134
|
+
/** Agent name */
|
|
135
|
+
name: string;
|
|
136
|
+
/** Human-readable description */
|
|
137
|
+
description?: string;
|
|
138
|
+
/** Base URL of the agent */
|
|
139
|
+
url: string;
|
|
140
|
+
/** Agent version */
|
|
141
|
+
version?: string;
|
|
142
|
+
/** Skills the agent supports */
|
|
143
|
+
skills?: A2aAgentSkill[];
|
|
144
|
+
/** Authentication schemes supported */
|
|
145
|
+
authSchemes?: A2aAuthScheme[];
|
|
146
|
+
/** Agent capabilities */
|
|
147
|
+
capabilities?: A2aAgentCapabilities;
|
|
148
|
+
/** Optional metadata */
|
|
149
|
+
metadata?: Record<string, unknown>;
|
|
150
|
+
}
|
|
151
|
+
/** A2A agent skill descriptor */
|
|
152
|
+
export interface A2aAgentSkill {
|
|
153
|
+
/** Skill identifier */
|
|
154
|
+
id: string;
|
|
155
|
+
/** Human-readable name */
|
|
156
|
+
name: string;
|
|
157
|
+
/** Description of the skill */
|
|
158
|
+
description?: string;
|
|
159
|
+
/** Input content types */
|
|
160
|
+
inputContentTypes?: string[];
|
|
161
|
+
/** Output content types */
|
|
162
|
+
outputContentTypes?: string[];
|
|
163
|
+
}
|
|
164
|
+
/** A2A authentication scheme */
|
|
165
|
+
export interface A2aAuthScheme {
|
|
166
|
+
/** Auth scheme type (e.g., "apiKey", "bearer", "oauth2") */
|
|
167
|
+
type: string;
|
|
168
|
+
/** Additional scheme-specific configuration */
|
|
169
|
+
[key: string]: unknown;
|
|
170
|
+
}
|
|
171
|
+
/** A2A agent capabilities */
|
|
172
|
+
export interface A2aAgentCapabilities {
|
|
173
|
+
/** Whether the agent supports SSE streaming */
|
|
174
|
+
streaming?: boolean;
|
|
175
|
+
/** Whether the agent supports push notifications */
|
|
176
|
+
pushNotifications?: boolean;
|
|
177
|
+
/** Whether the agent supports multi-turn conversations */
|
|
178
|
+
multiTurn?: boolean;
|
|
179
|
+
}
|
|
180
|
+
/** JSON-RPC 2.0 request */
|
|
181
|
+
export interface A2aJsonRpcRequest {
|
|
182
|
+
/** JSON-RPC version — always "2.0" */
|
|
183
|
+
jsonrpc: '2.0';
|
|
184
|
+
/** Request identifier */
|
|
185
|
+
id: string;
|
|
186
|
+
/** Method name */
|
|
187
|
+
method: string;
|
|
188
|
+
/** Method parameters */
|
|
189
|
+
params: Record<string, unknown>;
|
|
190
|
+
}
|
|
191
|
+
/** JSON-RPC 2.0 success response */
|
|
192
|
+
export interface A2aJsonRpcResponse {
|
|
193
|
+
/** JSON-RPC version — always "2.0" */
|
|
194
|
+
jsonrpc: '2.0';
|
|
195
|
+
/** Request identifier (matches request) */
|
|
196
|
+
id: string;
|
|
197
|
+
/** Result payload */
|
|
198
|
+
result?: unknown;
|
|
199
|
+
/** Error payload */
|
|
200
|
+
error?: A2aJsonRpcError;
|
|
201
|
+
}
|
|
202
|
+
/** JSON-RPC 2.0 error object */
|
|
203
|
+
export interface A2aJsonRpcError {
|
|
204
|
+
/** Error code */
|
|
205
|
+
code: number;
|
|
206
|
+
/** Error message */
|
|
207
|
+
message: string;
|
|
208
|
+
/** Optional error data */
|
|
209
|
+
data?: unknown;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Fetch and parse the A2A Agent Card from the well-known endpoint.
|
|
213
|
+
*
|
|
214
|
+
* @param baseUrl - Base URL of the A2A agent (e.g., "https://agent.example.com")
|
|
215
|
+
* @returns Parsed agent card
|
|
216
|
+
* @throws Error if the fetch fails or the response is not valid JSON
|
|
217
|
+
*/
|
|
218
|
+
export declare function fetchAgentCard(baseUrl: string): Promise<A2aAgentCard>;
|
|
219
|
+
/**
|
|
220
|
+
* Mutable state tracked across A2A task events for a single session.
|
|
221
|
+
* Passed into mapA2aTaskEvent to accumulate session-level data.
|
|
222
|
+
*/
|
|
223
|
+
export interface A2aEventMapperState {
|
|
224
|
+
/** Session ID from the A2A task */
|
|
225
|
+
sessionId: string | null;
|
|
226
|
+
/** Task ID from the A2A task */
|
|
227
|
+
taskId: string | null;
|
|
228
|
+
/** Accumulated input tokens */
|
|
229
|
+
totalInputTokens: number;
|
|
230
|
+
/** Accumulated output tokens */
|
|
231
|
+
totalOutputTokens: number;
|
|
232
|
+
/** Number of turns/interactions */
|
|
233
|
+
turnCount: number;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Map a single A2A task event to one or more normalized AgentEvents.
|
|
237
|
+
* Exported for unit testing — the AgentHandle uses this internally.
|
|
238
|
+
*
|
|
239
|
+
* @param event - The A2A SSE task event
|
|
240
|
+
* @param state - Mutable state accumulator for the session
|
|
241
|
+
* @returns Array of normalized AgentEvent objects
|
|
242
|
+
*/
|
|
243
|
+
export declare function mapA2aTaskEvent(event: A2aTaskEvent, state: A2aEventMapperState): AgentEvent[];
|
|
244
|
+
export declare class A2aProvider implements AgentProvider {
|
|
245
|
+
readonly name: "a2a";
|
|
246
|
+
spawn(config: AgentSpawnConfig): AgentHandle;
|
|
247
|
+
resume(sessionId: string, config: AgentSpawnConfig): AgentHandle;
|
|
248
|
+
private createHandle;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Create a new A2A provider instance.
|
|
252
|
+
*/
|
|
253
|
+
export declare function createA2aProvider(): A2aProvider;
|
|
254
|
+
//# sourceMappingURL=a2a-provider.d.ts.map
|