@runtypelabs/a2a-aisdk-example 0.2.3 → 0.3.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/README.md +64 -38
- package/dist/{chunk-OLB7ZZNY.js → chunk-EY4P4D5Y.js} +266 -153
- package/dist/chunk-EY4P4D5Y.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +114 -45
- package/dist/index.js +1 -1
- package/dist/vercel/index.d.ts +8 -7
- package/dist/vercel/index.js +165 -81
- package/dist/vercel/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-OLB7ZZNY.js.map +0 -1
|
@@ -7,11 +7,20 @@ var JSON_RPC_ERRORS = {
|
|
|
7
7
|
METHOD_NOT_FOUND: -32601,
|
|
8
8
|
INVALID_PARAMS: -32602,
|
|
9
9
|
INTERNAL_ERROR: -32603,
|
|
10
|
-
//
|
|
10
|
+
// A2A spec error codes
|
|
11
11
|
TASK_NOT_FOUND: -32001,
|
|
12
|
+
TASK_NOT_CANCELABLE: -32002,
|
|
13
|
+
PUSH_NOTIFICATION_NOT_SUPPORTED: -32003,
|
|
14
|
+
UNSUPPORTED_OPERATION: -32004,
|
|
15
|
+
CONTENT_TYPE_NOT_SUPPORTED: -32005,
|
|
16
|
+
INVALID_AGENT_RESPONSE: -32006,
|
|
17
|
+
/** @deprecated Use TASK_NOT_CANCELABLE */
|
|
12
18
|
SKILL_NOT_FOUND: -32002,
|
|
19
|
+
/** @deprecated */
|
|
13
20
|
UNAUTHORIZED: -32003,
|
|
21
|
+
/** @deprecated */
|
|
14
22
|
RATE_LIMITED: -32004,
|
|
23
|
+
/** @deprecated */
|
|
15
24
|
TASK_CANCELED: -32005
|
|
16
25
|
};
|
|
17
26
|
|
|
@@ -39,10 +48,10 @@ function createResponse(result, source) {
|
|
|
39
48
|
}
|
|
40
49
|
function extractInput(message) {
|
|
41
50
|
for (const part of message.parts) {
|
|
42
|
-
if (part.type === "data" && part.data) {
|
|
51
|
+
if ((part.type === "data" || part.data !== void 0) && part.data) {
|
|
43
52
|
return part.data;
|
|
44
53
|
}
|
|
45
|
-
if (part.type === "text" && part.text) {
|
|
54
|
+
if ((part.type === "text" || part.text !== void 0) && part.text) {
|
|
46
55
|
try {
|
|
47
56
|
return JSON.parse(part.text);
|
|
48
57
|
} catch {
|
|
@@ -262,7 +271,7 @@ var TOOL_STOP_CONDITION = stepCountIs(5);
|
|
|
262
271
|
var TOOL_TAG = "tool";
|
|
263
272
|
var LLM_TAG = "llm";
|
|
264
273
|
function extractTextFromMessage(message) {
|
|
265
|
-
return message.parts.filter((p) => p.type === "text" && p.text).map((p) => p.text).join("\n");
|
|
274
|
+
return message.parts.filter((p) => (p.type === "text" || p.text !== void 0) && p.text).map((p) => p.text).join("\n");
|
|
266
275
|
}
|
|
267
276
|
function createLLMProvider(config) {
|
|
268
277
|
const gatewayKey = process.env.AI_GATEWAY_API_KEY;
|
|
@@ -607,6 +616,56 @@ var DEFAULT_LLM_CONFIG = {
|
|
|
607
616
|
import express from "express";
|
|
608
617
|
import { v4 as uuidv4 } from "uuid";
|
|
609
618
|
var A2A_PROTOCOL_VERSION = "0.3";
|
|
619
|
+
function normalizePart(part) {
|
|
620
|
+
if (part.type) return part;
|
|
621
|
+
if (part.text !== void 0) return { type: "text", text: part.text, mediaType: part.mediaType };
|
|
622
|
+
if (part.data !== void 0) return { type: "data", data: part.data, mediaType: part.mediaType };
|
|
623
|
+
if (part.url !== void 0 || part.raw !== void 0) return { type: "file", uri: part.url ?? part.uri, mimeType: part.mediaType };
|
|
624
|
+
return part;
|
|
625
|
+
}
|
|
626
|
+
function normalizeRole(role) {
|
|
627
|
+
if (role === "ROLE_USER" || role === "user") return "user";
|
|
628
|
+
if (role === "ROLE_AGENT" || role === "agent") return "agent";
|
|
629
|
+
return "user";
|
|
630
|
+
}
|
|
631
|
+
function normalizeMessage(msg) {
|
|
632
|
+
const raw = msg;
|
|
633
|
+
return {
|
|
634
|
+
role: normalizeRole(raw.role || "user"),
|
|
635
|
+
messageId: raw.messageId,
|
|
636
|
+
parts: (raw.parts || []).map(normalizePart),
|
|
637
|
+
contextId: raw.contextId,
|
|
638
|
+
taskId: raw.taskId,
|
|
639
|
+
metadata: raw.metadata
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
function extractSendParams(params) {
|
|
643
|
+
const rawMessage = params.message || {};
|
|
644
|
+
const message = normalizeMessage(rawMessage);
|
|
645
|
+
const metadata = params.metadata;
|
|
646
|
+
const skillId = params.skill ?? metadata?.skill;
|
|
647
|
+
const contextId = params.contextId ?? message.contextId;
|
|
648
|
+
return { skillId, message, contextId, metadata };
|
|
649
|
+
}
|
|
650
|
+
function toSpecPart(part) {
|
|
651
|
+
const out = {};
|
|
652
|
+
if (part.type === "text" || part.text !== void 0) out.text = part.text ?? "";
|
|
653
|
+
else if (part.type === "data" || part.data !== void 0) out.data = part.data;
|
|
654
|
+
else if (part.type === "file") {
|
|
655
|
+
out.url = part.uri ?? part.url;
|
|
656
|
+
out.mediaType = part.mimeType ?? part.mediaType;
|
|
657
|
+
}
|
|
658
|
+
if (part.mediaType || part.mimeType) out.mediaType = part.mediaType ?? part.mimeType;
|
|
659
|
+
if (part.metadata) out.metadata = part.metadata;
|
|
660
|
+
return out;
|
|
661
|
+
}
|
|
662
|
+
function toSpecArtifact(a) {
|
|
663
|
+
return {
|
|
664
|
+
artifactId: a.artifactId ?? uuidv4(),
|
|
665
|
+
name: a.name,
|
|
666
|
+
parts: a.parts.map(toSpecPart)
|
|
667
|
+
};
|
|
668
|
+
}
|
|
610
669
|
var tasks = /* @__PURE__ */ new Map();
|
|
611
670
|
function generateTaskId() {
|
|
612
671
|
return `task_${Date.now()}_${uuidv4().substring(0, 8)}`;
|
|
@@ -621,52 +680,57 @@ function createA2AServer(options) {
|
|
|
621
680
|
const { config, llmConfig = DEFAULT_LLM_CONFIG, echoMode = false } = options;
|
|
622
681
|
const app = express();
|
|
623
682
|
app.use(express.json());
|
|
624
|
-
app.use((
|
|
683
|
+
app.use((req, res, next) => {
|
|
625
684
|
res.header("Access-Control-Allow-Origin", "*");
|
|
626
685
|
res.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
|
627
686
|
res.header("Access-Control-Allow-Headers", "Content-Type, Authorization, X-API-Key");
|
|
687
|
+
if (req.method === "OPTIONS") {
|
|
688
|
+
res.sendStatus(204);
|
|
689
|
+
return;
|
|
690
|
+
}
|
|
628
691
|
next();
|
|
629
692
|
});
|
|
630
|
-
app.options("*", (_req, res) => {
|
|
631
|
-
res.sendStatus(204);
|
|
632
|
-
});
|
|
633
693
|
const port = config.port || 9999;
|
|
634
694
|
const host = config.host || "localhost";
|
|
635
695
|
const skills = config.skills || DEFAULT_SKILLS;
|
|
696
|
+
const agentUrl = `http://${host}:${port}/a2a`;
|
|
636
697
|
const agentCard = {
|
|
637
698
|
name: config.name,
|
|
638
699
|
description: config.description || `A2A Agent: ${config.name}`,
|
|
639
|
-
url:
|
|
700
|
+
url: agentUrl,
|
|
701
|
+
supportedInterfaces: [
|
|
702
|
+
{
|
|
703
|
+
url: agentUrl,
|
|
704
|
+
protocolBinding: "JSONRPC",
|
|
705
|
+
protocolVersion: A2A_PROTOCOL_VERSION
|
|
706
|
+
}
|
|
707
|
+
],
|
|
640
708
|
version: config.version || "1.0.0",
|
|
641
709
|
protocolVersion: A2A_PROTOCOL_VERSION,
|
|
642
|
-
defaultInputModes: config.defaultInputModes || ["text", "
|
|
643
|
-
defaultOutputModes: config.defaultOutputModes || ["text", "
|
|
710
|
+
defaultInputModes: config.defaultInputModes || ["text/plain", "application/json"],
|
|
711
|
+
defaultOutputModes: config.defaultOutputModes || ["text/plain", "application/json"],
|
|
644
712
|
provider: config.provider || {
|
|
645
713
|
organization: "Runtype",
|
|
646
714
|
url: "https://runtype.com"
|
|
647
715
|
},
|
|
648
716
|
capabilities: {
|
|
649
717
|
streaming: true,
|
|
650
|
-
pushNotifications: false
|
|
651
|
-
statefulness: "task"
|
|
718
|
+
pushNotifications: false
|
|
652
719
|
},
|
|
653
720
|
skills: skills.map((s) => ({
|
|
654
721
|
id: s.id,
|
|
655
722
|
name: s.name,
|
|
656
723
|
description: s.description,
|
|
657
|
-
inputModes: ["text", "data"],
|
|
658
|
-
outputModes: ["text", "data"],
|
|
659
724
|
tags: s.tags ?? [],
|
|
660
|
-
|
|
661
|
-
}))
|
|
662
|
-
authentication: {
|
|
663
|
-
type: "none"
|
|
664
|
-
}
|
|
725
|
+
examples: []
|
|
726
|
+
}))
|
|
665
727
|
};
|
|
666
|
-
|
|
728
|
+
const agentCardHandler = (_req, res) => {
|
|
667
729
|
res.setHeader("Cache-Control", "public, max-age=3600");
|
|
668
730
|
res.json(agentCard);
|
|
669
|
-
}
|
|
731
|
+
};
|
|
732
|
+
app.get("/.well-known/agent.json", agentCardHandler);
|
|
733
|
+
app.get("/.well-known/agent-card.json", agentCardHandler);
|
|
670
734
|
app.get("/health", (_req, res) => {
|
|
671
735
|
res.json({ status: "healthy", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
672
736
|
});
|
|
@@ -681,17 +745,27 @@ function createA2AServer(options) {
|
|
|
681
745
|
try {
|
|
682
746
|
switch (method) {
|
|
683
747
|
case "tasks/send":
|
|
748
|
+
case "message/send":
|
|
749
|
+
case "SendMessage":
|
|
684
750
|
await handleTasksSend(req, res, id, params, skills, llmConfig, echoMode);
|
|
685
751
|
break;
|
|
686
752
|
case "tasks/sendSubscribe":
|
|
753
|
+
case "message/stream":
|
|
754
|
+
case "SendStreamingMessage":
|
|
687
755
|
await handleTasksSendSubscribe(req, res, id, params, skills, llmConfig, echoMode);
|
|
688
756
|
break;
|
|
689
757
|
case "tasks/get":
|
|
758
|
+
case "GetTask":
|
|
690
759
|
handleTasksGet(res, id, params);
|
|
691
760
|
break;
|
|
692
761
|
case "tasks/cancel":
|
|
762
|
+
case "CancelTask":
|
|
693
763
|
handleTasksCancel(res, id, params);
|
|
694
764
|
break;
|
|
765
|
+
case "tasks/resubscribe":
|
|
766
|
+
case "SubscribeToTask":
|
|
767
|
+
res.json(jsonRpcError(id, JSON_RPC_ERRORS.UNSUPPORTED_OPERATION, "SubscribeToTask is not supported"));
|
|
768
|
+
break;
|
|
695
769
|
case "ping":
|
|
696
770
|
res.json(jsonRpcSuccess(id, { pong: true }));
|
|
697
771
|
break;
|
|
@@ -713,7 +787,7 @@ function createA2AServer(options) {
|
|
|
713
787
|
console.log(`A2A Agent Server: ${config.name}`);
|
|
714
788
|
console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
|
|
715
789
|
console.log("");
|
|
716
|
-
console.log(` Agent Card: http://${host}:${port}/.well-known/agent.json`);
|
|
790
|
+
console.log(` Agent Card: http://${host}:${port}/.well-known/agent-card.json`);
|
|
717
791
|
console.log(` A2A Endpoint: http://${host}:${port}/a2a`);
|
|
718
792
|
console.log(` Health Check: http://${host}:${port}/health`);
|
|
719
793
|
console.log("");
|
|
@@ -741,23 +815,24 @@ function createA2AServer(options) {
|
|
|
741
815
|
})
|
|
742
816
|
};
|
|
743
817
|
}
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
res.json(
|
|
749
|
-
jsonRpcError(id, JSON_RPC_ERRORS.SKILL_NOT_FOUND, `Skill not found: ${skillId}`, {
|
|
750
|
-
availableSkills: skills.map((s) => s.id)
|
|
751
|
-
})
|
|
752
|
-
);
|
|
753
|
-
return;
|
|
818
|
+
function resolveSkill(skillId, skills, echoMode) {
|
|
819
|
+
if (skillId) {
|
|
820
|
+
const found = skills.find((s) => s.id === skillId);
|
|
821
|
+
if (found) return found;
|
|
754
822
|
}
|
|
823
|
+
if (echoMode) return skills.find((s) => s.id === "echo") || skills[0];
|
|
824
|
+
return skills.find((s) => s.id === "chat") || skills[0];
|
|
825
|
+
}
|
|
826
|
+
async function handleTasksSend(_req, res, id, params, skills, llmConfig, echoMode) {
|
|
827
|
+
const { skillId, message, contextId, metadata } = extractSendParams(params);
|
|
828
|
+
const skill = resolveSkill(skillId, skills, echoMode);
|
|
829
|
+
const resolvedContextId = contextId || uuidv4();
|
|
755
830
|
const taskId = generateTaskId();
|
|
756
831
|
const task = {
|
|
757
832
|
id: taskId,
|
|
758
|
-
contextId,
|
|
833
|
+
contextId: resolvedContextId,
|
|
759
834
|
status: "submitted",
|
|
760
|
-
skillId,
|
|
835
|
+
skillId: skill.id,
|
|
761
836
|
requestMessage: message,
|
|
762
837
|
artifacts: [],
|
|
763
838
|
metadata,
|
|
@@ -769,29 +844,29 @@ async function handleTasksSend(_req, res, id, params, skills, llmConfig, echoMod
|
|
|
769
844
|
try {
|
|
770
845
|
const context = {
|
|
771
846
|
taskId,
|
|
772
|
-
contextId,
|
|
847
|
+
contextId: resolvedContextId,
|
|
773
848
|
skill,
|
|
774
849
|
message,
|
|
775
850
|
metadata
|
|
776
851
|
};
|
|
777
852
|
let result;
|
|
778
|
-
if (
|
|
853
|
+
if (skill.id.startsWith("time/")) {
|
|
779
854
|
result = await executeTimeSkill(context);
|
|
780
|
-
} else if (echoMode ||
|
|
855
|
+
} else if (echoMode || skill.id === "echo") {
|
|
781
856
|
result = await executeEcho(context);
|
|
782
857
|
} else {
|
|
783
858
|
result = await executeTask(context, llmConfig, skills);
|
|
784
859
|
}
|
|
785
860
|
task.status = "completed";
|
|
786
|
-
task.artifacts = result.artifacts;
|
|
861
|
+
task.artifacts = result.artifacts || [];
|
|
787
862
|
task.history.push({ status: "completed", message: "Task completed", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
788
863
|
res.json(
|
|
789
864
|
jsonRpcSuccess(id, {
|
|
790
865
|
task: {
|
|
791
866
|
id: taskId,
|
|
792
|
-
contextId,
|
|
793
|
-
status: "completed",
|
|
794
|
-
artifacts: task.artifacts,
|
|
867
|
+
contextId: resolvedContextId,
|
|
868
|
+
status: { state: "completed", timestamp: (/* @__PURE__ */ new Date()).toISOString() },
|
|
869
|
+
artifacts: task.artifacts.map(toSpecArtifact),
|
|
795
870
|
metadata
|
|
796
871
|
}
|
|
797
872
|
})
|
|
@@ -805,22 +880,15 @@ async function handleTasksSend(_req, res, id, params, skills, llmConfig, echoMod
|
|
|
805
880
|
}
|
|
806
881
|
}
|
|
807
882
|
async function handleTasksSendSubscribe(_req, res, id, params, skills, llmConfig, echoMode) {
|
|
808
|
-
const {
|
|
809
|
-
const skill =
|
|
810
|
-
|
|
811
|
-
res.json(
|
|
812
|
-
jsonRpcError(id, JSON_RPC_ERRORS.SKILL_NOT_FOUND, `Skill not found: ${skillId}`, {
|
|
813
|
-
availableSkills: skills.map((s) => s.id)
|
|
814
|
-
})
|
|
815
|
-
);
|
|
816
|
-
return;
|
|
817
|
-
}
|
|
883
|
+
const { skillId, message, contextId, metadata } = extractSendParams(params);
|
|
884
|
+
const skill = resolveSkill(skillId, skills, echoMode);
|
|
885
|
+
const resolvedContextId = contextId || uuidv4();
|
|
818
886
|
const taskId = generateTaskId();
|
|
819
887
|
const task = {
|
|
820
888
|
id: taskId,
|
|
821
|
-
contextId,
|
|
889
|
+
contextId: resolvedContextId,
|
|
822
890
|
status: "submitted",
|
|
823
|
-
skillId,
|
|
891
|
+
skillId: skill.id,
|
|
824
892
|
requestMessage: message,
|
|
825
893
|
artifacts: [],
|
|
826
894
|
metadata,
|
|
@@ -831,72 +899,106 @@ async function handleTasksSendSubscribe(_req, res, id, params, skills, llmConfig
|
|
|
831
899
|
res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
|
832
900
|
res.setHeader("Connection", "keep-alive");
|
|
833
901
|
res.setHeader("X-Accel-Buffering", "no");
|
|
834
|
-
const
|
|
835
|
-
|
|
836
|
-
data: ${JSON.stringify(
|
|
902
|
+
const sendStreamResponse = (result) => {
|
|
903
|
+
const rpcResponse = { jsonrpc: "2.0", id, result };
|
|
904
|
+
res.write(`data: ${JSON.stringify(rpcResponse)}
|
|
837
905
|
|
|
838
906
|
`);
|
|
839
907
|
};
|
|
840
|
-
|
|
908
|
+
sendStreamResponse({
|
|
909
|
+
task: {
|
|
910
|
+
id: taskId,
|
|
911
|
+
contextId: resolvedContextId,
|
|
912
|
+
status: { state: "submitted", timestamp: (/* @__PURE__ */ new Date()).toISOString() }
|
|
913
|
+
}
|
|
914
|
+
});
|
|
841
915
|
task.status = "working";
|
|
842
916
|
task.history.push({ status: "working", message: "Execution started", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
843
|
-
|
|
917
|
+
sendStreamResponse({
|
|
918
|
+
statusUpdate: {
|
|
919
|
+
taskId,
|
|
920
|
+
contextId: resolvedContextId,
|
|
921
|
+
status: { state: "working", timestamp: (/* @__PURE__ */ new Date()).toISOString() }
|
|
922
|
+
}
|
|
923
|
+
});
|
|
844
924
|
try {
|
|
845
925
|
const context = {
|
|
846
926
|
taskId,
|
|
847
|
-
contextId,
|
|
927
|
+
contextId: resolvedContextId,
|
|
848
928
|
skill,
|
|
849
929
|
message,
|
|
850
930
|
metadata
|
|
851
931
|
};
|
|
852
|
-
|
|
932
|
+
const artifactId = uuidv4();
|
|
933
|
+
let isFirstChunk = true;
|
|
853
934
|
let fullText = "";
|
|
854
935
|
const callbacks = {
|
|
855
936
|
onChunk: async (text) => {
|
|
856
937
|
fullText += text;
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
938
|
+
sendStreamResponse({
|
|
939
|
+
artifactUpdate: {
|
|
940
|
+
taskId,
|
|
941
|
+
contextId: resolvedContextId,
|
|
942
|
+
artifact: {
|
|
943
|
+
artifactId,
|
|
944
|
+
name: "response",
|
|
945
|
+
parts: [{ text }]
|
|
946
|
+
},
|
|
947
|
+
append: !isFirstChunk,
|
|
864
948
|
lastChunk: false
|
|
865
949
|
}
|
|
866
950
|
});
|
|
867
|
-
|
|
951
|
+
isFirstChunk = false;
|
|
868
952
|
},
|
|
869
953
|
onComplete: async () => {
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
954
|
+
sendStreamResponse({
|
|
955
|
+
artifactUpdate: {
|
|
956
|
+
taskId,
|
|
957
|
+
contextId: resolvedContextId,
|
|
958
|
+
artifact: {
|
|
959
|
+
artifactId,
|
|
960
|
+
name: "response",
|
|
961
|
+
parts: [{ text: "" }]
|
|
962
|
+
},
|
|
876
963
|
append: true,
|
|
877
964
|
lastChunk: true
|
|
878
965
|
}
|
|
879
966
|
});
|
|
880
967
|
task.status = "completed";
|
|
881
|
-
task.artifacts = [{ name: "response", parts: [{ type: "text", text: fullText }] }];
|
|
968
|
+
task.artifacts = [{ artifactId, name: "response", parts: [{ type: "text", text: fullText }] }];
|
|
882
969
|
task.history.push({ status: "completed", message: "Task completed", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
883
|
-
|
|
970
|
+
sendStreamResponse({
|
|
971
|
+
statusUpdate: {
|
|
972
|
+
taskId,
|
|
973
|
+
contextId: resolvedContextId,
|
|
974
|
+
status: { state: "completed", timestamp: (/* @__PURE__ */ new Date()).toISOString() }
|
|
975
|
+
}
|
|
976
|
+
});
|
|
884
977
|
res.end();
|
|
885
978
|
},
|
|
886
979
|
onError: async (error) => {
|
|
887
980
|
task.status = "failed";
|
|
888
981
|
task.error = { message: error.message };
|
|
889
982
|
task.history.push({ status: "failed", message: error.message, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
890
|
-
|
|
891
|
-
|
|
983
|
+
sendStreamResponse({
|
|
984
|
+
statusUpdate: {
|
|
985
|
+
taskId,
|
|
986
|
+
contextId: resolvedContextId,
|
|
987
|
+
status: {
|
|
988
|
+
state: "failed",
|
|
989
|
+
message: { role: "agent", parts: [{ text: error.message }] },
|
|
990
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
});
|
|
892
994
|
res.end();
|
|
893
995
|
}
|
|
894
996
|
};
|
|
895
|
-
if (
|
|
997
|
+
if (skill.id.startsWith("time/")) {
|
|
896
998
|
const timeResult = await executeTimeSkill(context);
|
|
897
999
|
await callbacks.onChunk(timeResult.text);
|
|
898
1000
|
await callbacks.onComplete();
|
|
899
|
-
} else if (echoMode ||
|
|
1001
|
+
} else if (echoMode || skill.id === "echo") {
|
|
900
1002
|
await executeEchoStreaming(context, callbacks);
|
|
901
1003
|
} else {
|
|
902
1004
|
await executeTaskStreaming(context, llmConfig, callbacks, skills);
|
|
@@ -906,53 +1008,70 @@ data: ${JSON.stringify(data)}
|
|
|
906
1008
|
task.status = "failed";
|
|
907
1009
|
task.error = { message: errorMessage };
|
|
908
1010
|
task.history.push({ status: "failed", message: errorMessage, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
909
|
-
|
|
910
|
-
|
|
1011
|
+
sendStreamResponse({
|
|
1012
|
+
statusUpdate: {
|
|
1013
|
+
taskId,
|
|
1014
|
+
contextId: resolvedContextId,
|
|
1015
|
+
status: {
|
|
1016
|
+
state: "failed",
|
|
1017
|
+
message: { role: "agent", parts: [{ text: errorMessage }] },
|
|
1018
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
});
|
|
911
1022
|
res.end();
|
|
912
1023
|
}
|
|
913
1024
|
}
|
|
914
1025
|
function handleTasksGet(res, id, params) {
|
|
915
|
-
const
|
|
916
|
-
|
|
1026
|
+
const resolvedTaskId = params.id || params.taskId;
|
|
1027
|
+
if (!resolvedTaskId) {
|
|
1028
|
+
res.json(jsonRpcError(id, JSON_RPC_ERRORS.INVALID_PARAMS, "Missing task id"));
|
|
1029
|
+
return;
|
|
1030
|
+
}
|
|
1031
|
+
const task = tasks.get(resolvedTaskId);
|
|
917
1032
|
if (!task) {
|
|
918
|
-
res.json(jsonRpcError(id, JSON_RPC_ERRORS.TASK_NOT_FOUND, `Task not found: ${
|
|
1033
|
+
res.json(jsonRpcError(id, JSON_RPC_ERRORS.TASK_NOT_FOUND, `Task not found: ${resolvedTaskId}`));
|
|
919
1034
|
return;
|
|
920
1035
|
}
|
|
921
1036
|
const result = {
|
|
922
1037
|
task: {
|
|
923
1038
|
id: task.id,
|
|
924
1039
|
contextId: task.contextId,
|
|
925
|
-
status: task.status,
|
|
926
|
-
artifacts: task.artifacts,
|
|
1040
|
+
status: { state: task.status, timestamp: (/* @__PURE__ */ new Date()).toISOString() },
|
|
1041
|
+
artifacts: task.artifacts.map(toSpecArtifact),
|
|
927
1042
|
metadata: task.metadata
|
|
928
1043
|
}
|
|
929
1044
|
};
|
|
930
|
-
if (task.error) {
|
|
931
|
-
result.task.error = task.error;
|
|
932
|
-
}
|
|
933
|
-
if (includeHistory) {
|
|
934
|
-
result.task.history = task.history;
|
|
935
|
-
}
|
|
936
1045
|
res.json(jsonRpcSuccess(id, result));
|
|
937
1046
|
}
|
|
938
1047
|
function handleTasksCancel(res, id, params) {
|
|
939
|
-
const
|
|
940
|
-
|
|
1048
|
+
const resolvedTaskId = params.id || params.taskId;
|
|
1049
|
+
if (!resolvedTaskId) {
|
|
1050
|
+
res.json(jsonRpcError(id, JSON_RPC_ERRORS.INVALID_PARAMS, "Missing task id"));
|
|
1051
|
+
return;
|
|
1052
|
+
}
|
|
1053
|
+
const task = tasks.get(resolvedTaskId);
|
|
941
1054
|
if (!task) {
|
|
942
|
-
res.json(jsonRpcError(id, JSON_RPC_ERRORS.TASK_NOT_FOUND, `Task not found: ${
|
|
1055
|
+
res.json(jsonRpcError(id, JSON_RPC_ERRORS.TASK_NOT_FOUND, `Task not found: ${resolvedTaskId}`));
|
|
943
1056
|
return;
|
|
944
1057
|
}
|
|
945
1058
|
if (["completed", "failed", "canceled"].includes(task.status)) {
|
|
946
|
-
res.json(jsonRpcError(id, JSON_RPC_ERRORS.
|
|
1059
|
+
res.json(jsonRpcError(id, JSON_RPC_ERRORS.TASK_NOT_CANCELABLE, `Task cannot be canceled: already ${task.status}`));
|
|
947
1060
|
return;
|
|
948
1061
|
}
|
|
949
1062
|
task.status = "canceled";
|
|
950
1063
|
task.history.push({
|
|
951
1064
|
status: "canceled",
|
|
952
|
-
message: reason || "Canceled by request",
|
|
1065
|
+
message: params.reason || "Canceled by request",
|
|
953
1066
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
954
1067
|
});
|
|
955
|
-
res.json(jsonRpcSuccess(id, {
|
|
1068
|
+
res.json(jsonRpcSuccess(id, {
|
|
1069
|
+
task: {
|
|
1070
|
+
id: resolvedTaskId,
|
|
1071
|
+
contextId: task.contextId,
|
|
1072
|
+
status: { state: "canceled", timestamp: (/* @__PURE__ */ new Date()).toISOString() }
|
|
1073
|
+
}
|
|
1074
|
+
}));
|
|
956
1075
|
}
|
|
957
1076
|
|
|
958
1077
|
// src/client.ts
|
|
@@ -966,13 +1085,10 @@ var A2AClient = class {
|
|
|
966
1085
|
this.baseUrl = options.baseUrl.replace(/\/$/, "");
|
|
967
1086
|
const isA2aBase = this.baseUrl.endsWith("/a2a");
|
|
968
1087
|
this.rpcUrl = isA2aBase ? this.baseUrl : `${this.baseUrl}/a2a`;
|
|
969
|
-
this.agentCardUrl = `${this.baseUrl}/.well-known/agent.json`;
|
|
1088
|
+
this.agentCardUrl = `${this.baseUrl}/.well-known/agent-card.json`;
|
|
970
1089
|
this.apiKey = options.apiKey;
|
|
971
1090
|
this.headers = options.headers || {};
|
|
972
1091
|
}
|
|
973
|
-
/**
|
|
974
|
-
* Get the agent card for discovery
|
|
975
|
-
*/
|
|
976
1092
|
async getAgentCard() {
|
|
977
1093
|
const response = await fetch(this.agentCardUrl, {
|
|
978
1094
|
headers: this.getHeaders()
|
|
@@ -982,15 +1098,12 @@ var A2AClient = class {
|
|
|
982
1098
|
}
|
|
983
1099
|
return response.json();
|
|
984
1100
|
}
|
|
985
|
-
/**
|
|
986
|
-
* Send a task and wait for completion (synchronous)
|
|
987
|
-
*/
|
|
988
1101
|
async sendTask(params) {
|
|
989
1102
|
const request = {
|
|
990
1103
|
jsonrpc: "2.0",
|
|
991
1104
|
id: `req_${Date.now()}`,
|
|
992
|
-
method: "
|
|
993
|
-
params
|
|
1105
|
+
method: "message/send",
|
|
1106
|
+
params: this.toSendMessageRequest(params)
|
|
994
1107
|
};
|
|
995
1108
|
const response = await this.sendJsonRpc(request);
|
|
996
1109
|
if (response.error) {
|
|
@@ -998,17 +1111,14 @@ var A2AClient = class {
|
|
|
998
1111
|
}
|
|
999
1112
|
return response.result.task;
|
|
1000
1113
|
}
|
|
1001
|
-
/**
|
|
1002
|
-
* Send a task with streaming (SSE)
|
|
1003
|
-
*/
|
|
1004
1114
|
async sendTaskStreaming(params, callbacks) {
|
|
1005
1115
|
const request = {
|
|
1006
1116
|
jsonrpc: "2.0",
|
|
1007
1117
|
id: `req_${Date.now()}`,
|
|
1008
|
-
method: "
|
|
1009
|
-
params
|
|
1118
|
+
method: "message/stream",
|
|
1119
|
+
params: this.toSendMessageRequest(params)
|
|
1010
1120
|
};
|
|
1011
|
-
const response = await fetch(
|
|
1121
|
+
const response = await fetch(this.rpcUrl, {
|
|
1012
1122
|
method: "POST",
|
|
1013
1123
|
headers: {
|
|
1014
1124
|
"Content-Type": "application/json",
|
|
@@ -1031,43 +1141,37 @@ var A2AClient = class {
|
|
|
1031
1141
|
buffer += decoder.decode(value, { stream: true });
|
|
1032
1142
|
const lines = buffer.split("\n");
|
|
1033
1143
|
buffer = lines.pop() || "";
|
|
1034
|
-
let currentEvent = "";
|
|
1035
1144
|
for (const line of lines) {
|
|
1036
|
-
if (line.startsWith("
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
}
|
|
1051
|
-
}
|
|
1052
|
-
}
|
|
1053
|
-
break;
|
|
1054
|
-
case "task/error":
|
|
1055
|
-
callbacks.onError?.(data.error);
|
|
1056
|
-
break;
|
|
1145
|
+
if (!line.startsWith("data: ")) continue;
|
|
1146
|
+
const payload = JSON.parse(line.substring(6));
|
|
1147
|
+
const result = payload.result || payload;
|
|
1148
|
+
if (result.statusUpdate) {
|
|
1149
|
+
const state = result.statusUpdate.status?.state || result.statusUpdate.status;
|
|
1150
|
+
callbacks.onStatus?.(state, result.statusUpdate);
|
|
1151
|
+
} else if (result.artifactUpdate) {
|
|
1152
|
+
const artifact = result.artifactUpdate.artifact;
|
|
1153
|
+
callbacks.onArtifact?.(artifact);
|
|
1154
|
+
if (artifact?.parts) {
|
|
1155
|
+
for (const part of artifact.parts) {
|
|
1156
|
+
const text = part.text ?? (part.type === "text" ? part.text : void 0);
|
|
1157
|
+
if (text) callbacks.onChunk?.(text);
|
|
1158
|
+
}
|
|
1057
1159
|
}
|
|
1160
|
+
} else if (result.task) {
|
|
1161
|
+
const state = result.task.status?.state || result.task.status;
|
|
1162
|
+
if (state) callbacks.onStatus?.(state, result.task);
|
|
1163
|
+
} else if (result.error || payload.error) {
|
|
1164
|
+
callbacks.onError?.(result.error || payload.error);
|
|
1058
1165
|
}
|
|
1059
1166
|
}
|
|
1060
1167
|
}
|
|
1061
1168
|
}
|
|
1062
|
-
|
|
1063
|
-
* Get task status
|
|
1064
|
-
*/
|
|
1065
|
-
async getTask(taskId, includeHistory = false) {
|
|
1169
|
+
async getTask(taskId, historyLength) {
|
|
1066
1170
|
const request = {
|
|
1067
1171
|
jsonrpc: "2.0",
|
|
1068
1172
|
id: `req_${Date.now()}`,
|
|
1069
|
-
method: "
|
|
1070
|
-
params: { taskId,
|
|
1173
|
+
method: "GetTask",
|
|
1174
|
+
params: { id: taskId, historyLength }
|
|
1071
1175
|
};
|
|
1072
1176
|
const response = await this.sendJsonRpc(request);
|
|
1073
1177
|
if (response.error) {
|
|
@@ -1075,15 +1179,12 @@ var A2AClient = class {
|
|
|
1075
1179
|
}
|
|
1076
1180
|
return response.result.task;
|
|
1077
1181
|
}
|
|
1078
|
-
/**
|
|
1079
|
-
* Cancel a task
|
|
1080
|
-
*/
|
|
1081
1182
|
async cancelTask(taskId, reason) {
|
|
1082
1183
|
const request = {
|
|
1083
1184
|
jsonrpc: "2.0",
|
|
1084
1185
|
id: `req_${Date.now()}`,
|
|
1085
|
-
method: "
|
|
1086
|
-
params: { taskId, reason }
|
|
1186
|
+
method: "CancelTask",
|
|
1187
|
+
params: { id: taskId, metadata: reason ? { reason } : void 0 }
|
|
1087
1188
|
};
|
|
1088
1189
|
const response = await this.sendJsonRpc(request);
|
|
1089
1190
|
if (response.error) {
|
|
@@ -1092,8 +1193,23 @@ var A2AClient = class {
|
|
|
1092
1193
|
return response.result.task;
|
|
1093
1194
|
}
|
|
1094
1195
|
/**
|
|
1095
|
-
*
|
|
1196
|
+
* Convert legacy TasksSendParams to spec SendMessageRequest format
|
|
1096
1197
|
*/
|
|
1198
|
+
toSendMessageRequest(params) {
|
|
1199
|
+
return {
|
|
1200
|
+
message: {
|
|
1201
|
+
messageId: `msg_${Date.now()}`,
|
|
1202
|
+
role: "user",
|
|
1203
|
+
parts: params.message.parts,
|
|
1204
|
+
contextId: params.contextId,
|
|
1205
|
+
taskId: params.message.taskId
|
|
1206
|
+
},
|
|
1207
|
+
metadata: {
|
|
1208
|
+
...params.metadata,
|
|
1209
|
+
...params.skill ? { skill: params.skill } : {}
|
|
1210
|
+
}
|
|
1211
|
+
};
|
|
1212
|
+
}
|
|
1097
1213
|
async sendJsonRpc(request) {
|
|
1098
1214
|
const response = await fetch(this.rpcUrl, {
|
|
1099
1215
|
method: "POST",
|
|
@@ -1108,9 +1224,6 @@ var A2AClient = class {
|
|
|
1108
1224
|
}
|
|
1109
1225
|
return response.json();
|
|
1110
1226
|
}
|
|
1111
|
-
/**
|
|
1112
|
-
* Get headers for requests
|
|
1113
|
-
*/
|
|
1114
1227
|
getHeaders() {
|
|
1115
1228
|
const headers = { ...this.headers };
|
|
1116
1229
|
if (this.apiKey) {
|
|
@@ -1150,4 +1263,4 @@ export {
|
|
|
1150
1263
|
A2AClient,
|
|
1151
1264
|
createRuntypeA2AClient
|
|
1152
1265
|
};
|
|
1153
|
-
//# sourceMappingURL=chunk-
|
|
1266
|
+
//# sourceMappingURL=chunk-EY4P4D5Y.js.map
|