test-a2a-interop
정보
이 스킬은 에이전트 카드 규정 준수를 검증하고, 모든 작업 생명주기 상태를 점검하며, 스트리밍 및 오류 처리를 확인하여 A2A 상호운용성을 테스트합니다. 새로운 A2A 서버 구현 검증, 에이전트 간 상호운용성 확인, CI/CD 파이프라인에서의 규정 준수 테스트 실행에 사용하세요. 다중 에이전트 워크플로우 디버깅과 A2A 프로토콜 요구사항에 따른 에이전트 인증에 필수적입니다.
빠른 설치
Claude Code
추천npx skills add pjt222/agent-almanac -a claude-code/plugin add https://github.com/pjt222/agent-almanacgit clone https://github.com/pjt222/agent-almanac.git ~/.claude/skills/test-a2a-interopClaude Code에서 이 명령을 복사하여 붙여넣어 스킬을 설치하세요
문서
試 A2A 之互操
驗 A2A 代理之實合協規——試 Agent Card 之發現、任務生命週期之治、SSE 流、誤治、多代理之通模。
用時
- 驗新 A2A 服之實於部前乃用
- 驗二或多 A2A 代理之互操乃用
- 行合規之試於 A2A 之 CI/CD 乃用
- 調多代理 A2A 流之敗乃用
- 證代理合 A2A 協為註冊乃用
入
- 必要:所試 A2A 代理之基 URL
- 必要:驗身憑(若代理須之)
- 可選:第二代理之 URL 為雙向互操試
- 可選:所試之具技(默:Agent Card 中諸技)
- 可選:每任務試之超時(默:60 秒)
- 可選:合規報之出格(
json、markdown、junit)
法
第一步:取而驗 Agent Card
1.1. 自 well-known 端取 Agent Card:
curl -s https://agent.example.com/.well-known/agent.json -o agent-card.json
1.2. 驗頂層必之域:
const requiredFields = ["name", "description", "url", "skills"];
for (const field of requiredFields) {
assert(agentCard[field] !== undefined, `Missing required field: ${field}`);
}
1.3. 驗各技條:
for (const skill of agentCard.skills) {
assert(skill.id, "Skill missing id");
assert(skill.name, "Skill missing name");
assert(skill.description, "Skill missing description");
assert(
Array.isArray(skill.inputModes) && skill.inputModes.length > 0,
`Skill ${skill.id} missing inputModes`
);
assert(
Array.isArray(skill.outputModes) && skill.outputModes.length > 0,
`Skill ${skill.id} missing outputModes`
);
}
1.4. 驗驗身之設:
- 若
authentication.schemes含oauth2,驗credentials.oauth2有tokenUrl - 若
authentication.schemes含apiKey,驗credentials.apiKey有headerName
1.5. 驗能旗為布爾值。
1.6. 記驗果於合規報:
interface ConformanceResult {
test: string;
category: "agent-card" | "lifecycle" | "streaming" | "error-handling" | "interop";
status: "pass" | "fail" | "skip";
message?: string;
duration_ms?: number;
}
得:Agent Card 過諸構驗察。
敗則:記各驗敗附其域與因。勿止;續他試。無效之 Agent Card 自為一試果。
第二步:發試任務以覆諸生命態
2.1. 試:任務之投(submitted -> working -> completed)
依代理所宣之技發其能治之任務:
const submitResult = await sendJsonRpc(agentUrl, {
jsonrpc: "2.0",
id: 1,
method: "tasks/send",
params: {
id: `test-${uuid()}`,
sessionId: `session-${uuid()}`,
message: {
role: "user",
parts: [{ type: "text", text: skillExamples[0] }],
},
},
});
assert(submitResult.result, "tasks/send should return a result");
assert(submitResult.result.id, "Result should include task ID");
assert(
["submitted", "working", "completed"].includes(submitResult.result.status.state),
`Unexpected initial state: ${submitResult.result.status.state}`
);
2.2. 試:任務之輪詢(tasks/get)
輪詢至任務達終態:
let task = submitResult.result;
const startTime = Date.now();
while (!["completed", "failed", "canceled"].includes(task.status.state)) {
if (Date.now() - startTime > TEST_TIMEOUT_MS) {
fail(`Task ${task.id} did not complete within ${TEST_TIMEOUT_MS}ms`);
break;
}
await sleep(1000);
const getResult = await sendJsonRpc(agentUrl, {
jsonrpc: "2.0",
id: 2,
method: "tasks/get",
params: { id: task.id },
});
task = getResult.result;
}
assert(task.status.state === "completed", `Task should complete, got: ${task.status.state}`);
2.3. 試:任務之取消
投任務而即取消:
const cancelTask = await sendJsonRpc(agentUrl, {
jsonrpc: "2.0",
id: 3,
method: "tasks/send",
params: { id: `test-cancel-${uuid()}`, sessionId: `session-${uuid()}`, message: { ... } },
});
const cancelResult = await sendJsonRpc(agentUrl, {
jsonrpc: "2.0",
id: 4,
method: "tasks/cancel",
params: { id: cancelTask.result.id },
});
assert(
cancelResult.result.status.state === "canceled",
"Canceled task should be in canceled state"
);
2.4. 試:須輸入態(多輪)
若某技支多輪交互,發歧之請以致 input-required,而獻續:
// Send ambiguous request
const multiTurnTask = await sendJsonRpc(agentUrl, { ... });
// Poll until input-required or completed
// If input-required, send follow-up
if (task.status.state === "input-required") {
const followUp = await sendJsonRpc(agentUrl, {
jsonrpc: "2.0",
id: 6,
method: "tasks/send",
params: {
id: task.id,
sessionId: task.sessionId,
message: { role: "user", parts: [{ type: "text", text: "Column A and Column B" }] },
},
});
assert(
["working", "completed"].includes(followUp.result.status.state),
"Follow-up should resume task"
);
}
2.5. 試:態轉之史
若 Agent Card 宣 stateTransitionHistory: true:
const getWithHistory = await sendJsonRpc(agentUrl, {
jsonrpc: "2.0",
id: 7,
method: "tasks/get",
params: { id: completedTaskId, historyLength: 100 },
});
assert(
Array.isArray(getWithHistory.result.history),
"Task should include history array"
);
assert(
getWithHistory.result.history.length >= 2,
"History should have at least 2 entries (submitted and completed)"
);
得:諸生命態之轉皆正。任務成完、淨取消、多輪交互於支時行。
敗則:記敗之具態轉,期態,實態。報含全 JSON-RPC 應為調。
第三步:驗 SSE 流之應
3.1. 若 Agent Card 宣 streaming: false,略此步。
3.2. 發 tasks/sendSubscribe 請而驗 SSE 流:
const response = await fetch(`${agentUrl}/subscribe`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
id: 10,
method: "tasks/sendSubscribe",
params: {
id: `test-stream-${uuid()}`,
sessionId: `session-${uuid()}`,
message: { role: "user", parts: [{ type: "text", text: "Stream test task" }] },
},
}),
});
assert(
response.headers.get("content-type")?.includes("text/event-stream"),
"Response must be text/event-stream"
);
3.3. 析 SSE 事件而驗其構:
const events: SSEEvent[] = [];
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
// Parse SSE events from buffer
const lines = buffer.split("\n");
for (const line of lines) {
if (line.startsWith("event: ")) {
currentEvent.type = line.slice(7);
} else if (line.startsWith("data: ")) {
currentEvent.data = JSON.parse(line.slice(6));
events.push(currentEvent);
}
}
}
3.4. 驗事序:
- 首事當為
status事,態為submitted或working - 中事可含
status之新與artifact之獻 - 末事當有
final: true與終態 - 末事後無事至
3.5. 驗 SSE 連之清:
- 流中關連
- 驗仍可由
tasks/get取任務 - 驗無服誤自此早斷
得:SSE 流獻正格之事於正序,終於末終事。
敗則:若宣 SSE 而端返非 SSE,記為合規敗。若事至序亂,記其序。若流不終,記超時。
第四步:試誤治與邊例
4.1. 試:未知之法
const unknownMethod = await sendJsonRpc(agentUrl, {
jsonrpc: "2.0",
id: 20,
method: "tasks/nonexistent",
params: {},
});
assert(unknownMethod.error?.code === -32601, "Should return method not found");
4.2. 試:壞 JSON-RPC 之請
const malformed = await fetch(agentUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: '{"not": "valid jsonrpc"}',
});
const response = await malformed.json();
assert(response.error?.code === -32600, "Should return invalid request");
4.3. 試:取不存之任務
const notFound = await sendJsonRpc(agentUrl, {
jsonrpc: "2.0",
id: 22,
method: "tasks/get",
params: { id: "nonexistent-task-id" },
});
assert(notFound.error, "Should return error for nonexistent task");
4.4. 試:取消已完之任務
const cancelCompleted = await sendJsonRpc(agentUrl, {
jsonrpc: "2.0",
id: 23,
method: "tasks/cancel",
params: { id: completedTaskId },
});
assert(cancelCompleted.error, "Should error when canceling completed task");
4.5. 試:驗身之施
若驗身已設,發無憑之請:
const unauthResponse = await fetch(agentUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ jsonrpc: "2.0", id: 24, method: "tasks/get", params: { id: "x" } }),
});
assert(unauthResponse.status === 401, "Should reject unauthenticated requests");
4.6. 試:Agent Card 公可取,無須驗
const publicCard = await fetch(`${agentUrl}/.well-known/agent.json`);
assert(publicCard.status === 200, "Agent Card should be publicly accessible");
得:諸誤之境返宜 JSON-RPC 誤碼,不潰服。
敗則:記每敗之誤治試。誤試中之服潰為要敗,部前必修。
第五步:生互操合規報
5.1. 合諸試果為構之報:
interface ConformanceReport {
agentUrl: string;
agentName: string;
agentVersion: string;
testDate: string;
summary: {
total: number;
passed: number;
failed: number;
skipped: number;
};
categories: {
agentCard: ConformanceResult[];
lifecycle: ConformanceResult[];
streaming: ConformanceResult[];
errorHandling: ConformanceResult[];
interop: ConformanceResult[];
};
conformanceLevel: "full" | "partial" | "minimal" | "non-conformant";
}
5.2. 算合規之階:
- full:諸試皆過,含流與推通
- partial:核生命試過,某可選敗
- minimal:Agent Card 有效,基任務 send/get 行
- non-conformant:Agent Card 無效或基生命斷
5.3. 生報於所請之格:
- json:機讀為 CI/CD 合
- markdown:人讀,過敗之表
- junit:XML 格為試框合
5.4. 含修敗之薦:
## Failed Tests
| Test | Category | Message | Recommendation |
|------|----------|---------|----------------|
| cancel-completed-task | error-handling | Server returned 500 | Add guard for terminal state transitions |
| sse-final-event | streaming | No final event received | Ensure SSE sends event with final:true |
5.5. 若請雙向試(二代理),驗:
- 代理甲可發現代理乙之 Agent Card
- 代理甲可發任務於乙
- 代理乙可發任務於甲
- 二代理治並發任務無互擾
得:完之合規報,含過敗果、合規階、可行薦。
敗則:若報生本身敗,出生試果於 stdout 為退。試資不當因報誤而失。
驗
- Agent Card 已取而構驗
- 至少一任務完全生命循(submitted -> working -> completed)
- 任務之取消正行
- 誤之應用正 JSON-RPC 誤碼
- 若能宣 SSE,已試流
- 任務端施驗身而 Agent Card 不施
- 合規報於所請之格已生
- 敗試含可行修導
- 試套可於 CI/CD 行而不須手介
陷
- 試於冷服:某代理須時始。試前加健察或暖請。
- 硬編試資:用動之任務與會 ID(UUIDs)以避反復行試之撞。勿假特任務 ID 可得。
- 忽時序:任務之轉異步。常以退而輪詢,勿假即態變。
- SSE 析之繁:SSE 事或跨多塊。緩入資而析全事,非生塊。
- 唯試樂路:誤治試與成試同要。壞請、無效轉、驗身敗皆當覆。
- 網依:試當可於本機行為開發,於遠 URL 行為產。參數化代理 URL。
- 假技行:試套驗協合規,非技正。用 Agent Card 之例語觸技,勿斷具出容。
參
design-a2a-agent-card— 設所試之 Agent Cardimplement-a2a-server— 實所試之服build-ci-cd-pipeline— 合合規試於 CI/CDtroubleshoot-mcp-connection— 適 A2A 連之調模review-software-architecture— 多代理系之構審
GitHub 저장소
연관 스킬
evaluating-llms-harness
테스팅이 Claude Skill은 MMLU, GSM8K를 포함한 60개 이상의 표준화된 학술 과제에서 LLM 성능을 벤치마크하기 위해 lm-evaluation-harness를 실행합니다. 개발자들이 모델 품질을 비교하고, 학습 진행 상황을 추적하거나 학술 결과를 보고할 수 있도록 설계되었습니다. 이 도구는 HuggingFace와 vLLM 모델을 포함한 다양한 백엔드를 지원합니다.
cloudflare-cron-triggers
테스팅이 스킬은 cron 표현식을 사용하여 Worker를 스케줄링하기 위한 Cloudflare Cron Triggers 구현에 관한 포괄적인 지식을 제공합니다. 주기적 작업, 유지보수 작업, 자동화된 워크플로우 설정 방법을 다루며, 잘못된 cron 표현식이나 시간대 문제 같은 일반적인 이슈들을 해결하는 방법을 포함합니다. 개발자들은 이를 통해 스케줄된 핸들러 구성, cron 트리거 테스트, Workflows 및 Green Compute와의 연동 작업을 수행할 수 있습니다.
webapp-testing
테스팅이 Claude Skill은 Python 스크립트를 통해 로컬 웹 애플리케이션을 테스트하기 위한 Playwright 기반 툴킷을 제공합니다. 프론트엔드 검증, UI 디버깅, 스크린샷 캡처, 로그 확인 기능을 지원하며 서버 라이프사이클을 관리합니다. 브라우저 자동화 작업에 사용하되 컨텍스트 오염을 방지하기 위해 소스 코드를 읽지 않고 스크립트를 직접 실행하세요.
finishing-a-development-branch
테스팅이 스킬은 테스트 통과를 확인한 후 체계적인 통합 옵션을 제시하여 개발자가 완성된 작업을 마무리하도록 돕습니다. 구현이 완료된 후 머지, PR 생성, 브랜치 정리와 같은 워크플로우를 안내합니다. 코드가 준비되고 테스트가 완료되었을 때 개발 프로세스를 체계적으로 마무리하기 위해 사용하세요.
