chore: import upstream snapshot with attribution
CI / Shell Format Check (push) Has been cancelled
CI / Check Ruby (3.4) (push) Has been cancelled
CI / CI Config (push) Has been cancelled
CI / Test on Node ${{ matrix.node }} and ${{ matrix.os }}${{ matrix.shard && format(' (shard {0}/3)', matrix.shard) || '' }} (push) Has been cancelled
CI / Build on Node ${{ matrix.node }} (push) Has been cancelled
CI / Style Check (push) Has been cancelled
CI / Generate Assets (push) Has been cancelled
CI / Check Python (3.14) (push) Has been cancelled
CI / Check Python (3.9) (push) Has been cancelled
CI / Build Docs (push) Has been cancelled
CI / Code Scan Action (push) Has been cancelled
CI / Site tests (push) Has been cancelled
CI / webui tests (push) Has been cancelled
CI / Run Integration Tests (push) Has been cancelled
CI / Run Smoke Tests (push) Has been cancelled
CI / Go Tests (push) Has been cancelled
CI / Share Test (push) Has been cancelled
CI / Redteam (Production API) (push) Has been cancelled
CI / Redteam (Staging API) (push) Has been cancelled
CI / GitHub Actions Lint (push) Has been cancelled
CI / Check Ruby (3.0) (push) Has been cancelled
release-please / release-please (push) Has been cancelled
release-please / build (push) Has been cancelled
release-please / publish-npm (push) Has been cancelled
release-please / publish-npm-backfill (push) Has been cancelled
release-please / docker (push) Has been cancelled
release-please / publish-code-scan-action (push) Has been cancelled
release-please / attest-code-scan-action (push) Has been cancelled
Deploy local.promptfoo.app / Deploy to Cloudflare Pages (push) Has been cancelled
Test and Publish Multi-arch Docker Image / test (push) Has been cancelled
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-amd64 platform:linux/amd64 runner:ubuntu-latest]) (push) Has been cancelled
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-arm64 platform:linux/arm64 runner:ubuntu-24.04-arm]) (push) Has been cancelled
Test and Publish Multi-arch Docker Image / merge-docker-digests (push) Has been cancelled
Test and Publish Multi-arch Docker Image / Attest Multi-arch Image (push) Has been cancelled
Validate Renovate Config / Validate Renovate Configuration (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:24:08 +08:00
commit 0d3cb498a3
5438 changed files with 1316560 additions and 0 deletions
File diff suppressed because it is too large Load Diff
+122
View File
@@ -0,0 +1,122 @@
import { describe, expect, it } from 'vitest';
import { createTransformResponse } from '../../../src/providers/a2a/transforms';
describe('A2A createTransformResponse', () => {
const finalResponse = {
events: [{ statusUpdate: { status: { state: 'TASK_STATE_COMPLETED' } } }],
message: {
parts: [{ text: 'hello from message' }],
role: 'ROLE_AGENT',
},
raw: {
message: {
parts: [{ text: 'hello from message' }],
role: 'ROLE_AGENT',
},
},
task: {
id: 'task-1',
status: { state: 'TASK_STATE_COMPLETED' },
},
};
const context = {
events: finalResponse.events,
message: finalResponse.message,
mode: 'stream' as const,
raw: finalResponse.raw,
task: finalResponse.task,
};
it('returns extracted text when no transform is configured', async () => {
const transform = createTransformResponse(undefined);
await expect(transform(finalResponse, 'fallback text', context)).resolves.toEqual({
output: 'fallback text',
});
});
it('passes json, text, and context to function transforms', async () => {
const transform = createTransformResponse((json: any, text: string, transformContext: any) => ({
metadata: {
eventCount: transformContext.events.length,
mode: transformContext.mode,
taskId: json.task.id,
},
output: text.toUpperCase(),
}));
await expect(transform(finalResponse, 'fallback text', context)).resolves.toEqual({
metadata: {
eventCount: 1,
mode: 'stream',
taskId: 'task-1',
},
output: 'FALLBACK TEXT',
});
});
it('wraps primitive function transform results as provider output', async () => {
const transform = createTransformResponse((json: any) => json.task.id);
await expect(transform(finalResponse, 'fallback text', context)).resolves.toEqual({
output: 'task-1',
});
});
it('supports string expressions with json and result aliases', async () => {
const transform = createTransformResponse(
'({ output: `${json.task.id}:${result.message.role}:${text}:${context.mode}` })',
);
await expect(transform(finalResponse, 'fallback text', context)).resolves.toEqual({
output: 'task-1:ROLE_AGENT:fallback text:stream',
});
});
it('supports async string function expressions', async () => {
const transform = createTransformResponse('async (json, text) => `${json.task.id}:${text}`');
await expect(transform(finalResponse, 'fallback text', context)).resolves.toEqual({
output: 'task-1:fallback text',
});
});
it('wraps object string-expression results without provider response fields', async () => {
const transform = createTransformResponse('({ taskId: result.task.id })');
await expect(transform(finalResponse, 'fallback text', context)).resolves.toEqual({
output: { taskId: 'task-1' },
});
});
it('throws if file transforms are not pre-loaded', () => {
expect(() => createTransformResponse('file://parser.js')).toThrow(
/should be pre-loaded before calling createTransformResponse/,
);
});
it('rejects unsupported transform types', () => {
expect(() => createTransformResponse(123 as any)).toThrow(
/Unsupported response transform type: number/,
);
});
it('preserves errors from function transforms', async () => {
const transform = createTransformResponse(() => {
throw new Error('function transform failed');
});
await expect(transform(finalResponse, 'fallback text', context)).rejects.toThrow(
'function transform failed',
);
});
it('wraps errors from string transforms', async () => {
const transform = createTransformResponse('result.missing.value');
await expect(transform(finalResponse, 'fallback text', context)).rejects.toThrow(
/Failed to transform A2A response/,
);
});
});
+207
View File
@@ -0,0 +1,207 @@
import { describe, expect, it } from 'vitest';
import {
A2AAgentCardSchema,
A2AAuthSchema,
A2AProviderConfigSchema,
A2AStreamResponseSchema,
A2ATaskSchema,
} from '../../../src/providers/a2a/types';
describe('A2A type schemas', () => {
it('applies provider config defaults', () => {
const config = A2AProviderConfigSchema.parse({});
expect(config.mode).toBe('auto');
expect(config.polling).toEqual({
enabled: true,
intervalMs: 1000,
timeoutMs: 300000,
});
});
it.each(['', 'none', 'no_auth'])('normalizes %s auth to undefined', (type) => {
expect(A2AAuthSchema.parse({ type })).toBeUndefined();
});
it('parses bearer and basic auth configs', () => {
expect(A2AAuthSchema.parse({ token: 'token-1', type: 'bearer' })).toEqual({
token: 'token-1',
type: 'bearer',
});
expect(
A2AAuthSchema.parse({
password: 'pass-1',
type: 'basic',
username: 'user-1',
}),
).toEqual({
password: 'pass-1',
type: 'basic',
username: 'user-1',
});
});
it('accepts api key auth with either value field', () => {
expect(
A2AAuthSchema.parse({
keyName: 'X-API-Key',
placement: 'header',
type: 'api_key',
value: 'secret-1',
}),
).toEqual({
keyName: 'X-API-Key',
placement: 'header',
type: 'api_key',
value: 'secret-1',
});
expect(
A2AAuthSchema.parse({
api_key: 'secret-2',
placement: 'query',
type: 'api_key',
}),
).toEqual({
api_key: 'secret-2',
placement: 'query',
type: 'api_key',
});
});
it('rejects api key auth without a value', () => {
expect(() => A2AAuthSchema.parse({ type: 'api_key' })).toThrow(
/api_key auth requires value or api_key/,
);
});
it('preserves oauth client credentials string scopes until render time', () => {
expect(
A2AAuthSchema.parse({
clientId: 'client-1',
clientSecret: 'secret-1',
scopes: 'agent:read agent:write,profile',
tokenUrl: 'https://agent.example.com/oauth/token',
type: 'oauth',
}),
).toEqual({
clientId: 'client-1',
clientSecret: 'secret-1',
grantType: 'client_credentials',
scopes: 'agent:read agent:write,profile',
tokenUrl: 'https://agent.example.com/oauth/token',
type: 'oauth',
});
});
it('preserves templated oauth scope strings with spaced Nunjucks delimiters', () => {
expect(
A2AAuthSchema.parse({
clientId: 'client-1',
clientSecret: 'secret-1',
scopes: '{{ env.A2A_SCOPES }}',
type: 'oauth',
}),
).toMatchObject({
scopes: '{{ env.A2A_SCOPES }}',
});
});
it('parses oauth password auth with array scopes', () => {
expect(
A2AAuthSchema.parse({
grantType: 'password',
password: 'pass-1',
scopes: ['agent:read', 'agent:write'],
type: 'oauth',
username: 'user-1',
}),
).toEqual({
grantType: 'password',
password: 'pass-1',
scopes: ['agent:read', 'agent:write'],
type: 'oauth',
username: 'user-1',
});
});
it('parses task, stream, and agent card data models with loose extension fields', () => {
expect(
A2ATaskSchema.parse({
artifacts: [{ custom: true, parts: [{ text: { text: 'artifact text' } }] }],
history: [{ parts: [{ text: 'history text' }], role: 'ROLE_USER' }],
id: 'task-1',
status: {
message: { parts: [{ text: 'done' }], role: 'ROLE_AGENT' },
state: 'TASK_STATE_COMPLETED',
},
}),
).toMatchObject({
artifacts: [{ custom: true, parts: [{ text: { text: 'artifact text' } }] }],
id: 'task-1',
status: { state: 'TASK_STATE_COMPLETED' },
});
expect(
A2AStreamResponseSchema.parse({
artifactUpdate: {
artifact: { artifactId: 'artifact-1', parts: [{ data: { ok: true } }] },
taskId: 'task-1',
},
statusUpdate: {
status: { state: 'TASK_STATE_WORKING' },
taskId: 'task-1',
},
}),
).toMatchObject({
artifactUpdate: { artifact: { artifactId: 'artifact-1' }, taskId: 'task-1' },
statusUpdate: { status: { state: 'TASK_STATE_WORKING' }, taskId: 'task-1' },
});
expect(
A2AAgentCardSchema.parse({
capabilities: {
pushNotifications: true,
stateTransitionHistory: true,
streaming: true,
},
documentationUrl: 'https://agent.example.com/docs',
name: 'Travel Agent',
protocolVersion: '0.3.0',
additionalInterfaces: [
{
tenant: 'tenant-b',
transport: 'HTTP+JSON',
url: 'https://agent.example.com/a2a/http',
},
],
preferredTransport: 'JSONRPC',
skills: [
{
description: 'Books flights',
examples: ['Book SFO to JFK'],
id: 'book_flight',
input_modes: ['text'],
outputModes: ['text'],
tags: ['travel'],
},
],
supportedInterfaces: [
{
protocolBinding: 'HTTP+JSON',
protocolVersion: '1.0',
tenant: 'tenant-a',
url: 'https://agent.example.com/a2a/v1',
},
],
}),
).toMatchObject({
capabilities: { streaming: true },
name: 'Travel Agent',
protocolVersion: '0.3.0',
additionalInterfaces: [{ transport: 'HTTP+JSON' }],
preferredTransport: 'JSONRPC',
skills: [{ id: 'book_flight' }],
supportedInterfaces: [{ protocolBinding: 'HTTP+JSON' }],
});
});
});