@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
package/dist/vercel/index.js
CHANGED
|
@@ -8,11 +8,20 @@ var JSON_RPC_ERRORS = {
|
|
|
8
8
|
METHOD_NOT_FOUND: -32601,
|
|
9
9
|
INVALID_PARAMS: -32602,
|
|
10
10
|
INTERNAL_ERROR: -32603,
|
|
11
|
-
//
|
|
11
|
+
// A2A spec error codes
|
|
12
12
|
TASK_NOT_FOUND: -32001,
|
|
13
|
+
TASK_NOT_CANCELABLE: -32002,
|
|
14
|
+
PUSH_NOTIFICATION_NOT_SUPPORTED: -32003,
|
|
15
|
+
UNSUPPORTED_OPERATION: -32004,
|
|
16
|
+
CONTENT_TYPE_NOT_SUPPORTED: -32005,
|
|
17
|
+
INVALID_AGENT_RESPONSE: -32006,
|
|
18
|
+
/** @deprecated Use TASK_NOT_CANCELABLE */
|
|
13
19
|
SKILL_NOT_FOUND: -32002,
|
|
20
|
+
/** @deprecated */
|
|
14
21
|
UNAUTHORIZED: -32003,
|
|
22
|
+
/** @deprecated */
|
|
15
23
|
RATE_LIMITED: -32004,
|
|
24
|
+
/** @deprecated */
|
|
16
25
|
TASK_CANCELED: -32005
|
|
17
26
|
};
|
|
18
27
|
|
|
@@ -46,10 +55,10 @@ function createResponse(result, source) {
|
|
|
46
55
|
}
|
|
47
56
|
function extractInput(message) {
|
|
48
57
|
for (const part of message.parts) {
|
|
49
|
-
if (part.type === "data" && part.data) {
|
|
58
|
+
if ((part.type === "data" || part.data !== void 0) && part.data) {
|
|
50
59
|
return part.data;
|
|
51
60
|
}
|
|
52
|
-
if (part.type === "text" && part.text) {
|
|
61
|
+
if ((part.type === "text" || part.text !== void 0) && part.text) {
|
|
53
62
|
try {
|
|
54
63
|
return JSON.parse(part.text);
|
|
55
64
|
} catch {
|
|
@@ -265,7 +274,7 @@ var TOOL_STOP_CONDITION = stepCountIs(5);
|
|
|
265
274
|
var TOOL_TAG = "tool";
|
|
266
275
|
var LLM_TAG = "llm";
|
|
267
276
|
function extractTextFromMessage(message) {
|
|
268
|
-
return message.parts.filter((p) => p.type === "text" && p.text).map((p) => p.text).join("\n");
|
|
277
|
+
return message.parts.filter((p) => (p.type === "text" || p.text !== void 0) && p.text).map((p) => p.text).join("\n");
|
|
269
278
|
}
|
|
270
279
|
function createLLMProvider(config) {
|
|
271
280
|
const gatewayKey = process.env.AI_GATEWAY_API_KEY;
|
|
@@ -614,8 +623,8 @@ function resolveConfig(config) {
|
|
|
614
623
|
version: config.version || "1.0.0",
|
|
615
624
|
skills: config.skills || DEFAULT_SKILLS,
|
|
616
625
|
provider: config.provider || { organization: "Runtype", url: "https://runtype.com" },
|
|
617
|
-
defaultInputModes: config.defaultInputModes || ["text", "
|
|
618
|
-
defaultOutputModes: config.defaultOutputModes || ["text", "
|
|
626
|
+
defaultInputModes: config.defaultInputModes || ["text/plain", "application/json"],
|
|
627
|
+
defaultOutputModes: config.defaultOutputModes || ["text/plain", "application/json"],
|
|
619
628
|
echoMode: config.echoMode ?? false,
|
|
620
629
|
llmConfig: config.llmConfig || DEFAULT_LLM_CONFIG,
|
|
621
630
|
agentUrl: config.agentUrl
|
|
@@ -626,10 +635,8 @@ function toAgentCardSkills(skills) {
|
|
|
626
635
|
id: s.id,
|
|
627
636
|
name: s.name,
|
|
628
637
|
description: s.description,
|
|
629
|
-
inputModes: ["text", "data"],
|
|
630
|
-
outputModes: ["text", "data"],
|
|
631
638
|
tags: s.tags ?? [],
|
|
632
|
-
|
|
639
|
+
examples: []
|
|
633
640
|
}));
|
|
634
641
|
}
|
|
635
642
|
|
|
@@ -655,12 +662,77 @@ function jsonResponse(data, status = 200) {
|
|
|
655
662
|
}
|
|
656
663
|
});
|
|
657
664
|
}
|
|
665
|
+
function normalizePart(part) {
|
|
666
|
+
if (part.type) return part;
|
|
667
|
+
if (part.text !== void 0) return { type: "text", text: part.text, mediaType: part.mediaType };
|
|
668
|
+
if (part.data !== void 0) return { type: "data", data: part.data, mediaType: part.mediaType };
|
|
669
|
+
if (part.url !== void 0 || part.raw !== void 0) return { type: "file", uri: part.url ?? part.uri, mimeType: part.mediaType };
|
|
670
|
+
return part;
|
|
671
|
+
}
|
|
672
|
+
function normalizeRole(role) {
|
|
673
|
+
if (role === "ROLE_USER" || role === "user") return "user";
|
|
674
|
+
if (role === "ROLE_AGENT" || role === "agent") return "agent";
|
|
675
|
+
return "user";
|
|
676
|
+
}
|
|
677
|
+
function normalizeMessage(msg) {
|
|
678
|
+
const raw = msg;
|
|
679
|
+
return {
|
|
680
|
+
role: normalizeRole(raw.role || "user"),
|
|
681
|
+
messageId: raw.messageId,
|
|
682
|
+
parts: (raw.parts || []).map(normalizePart),
|
|
683
|
+
contextId: raw.contextId,
|
|
684
|
+
taskId: raw.taskId,
|
|
685
|
+
metadata: raw.metadata
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
function extractSendParams(params) {
|
|
689
|
+
const rawMessage = params.message || {};
|
|
690
|
+
const message = normalizeMessage(rawMessage);
|
|
691
|
+
const metadata = params.metadata;
|
|
692
|
+
const skillId = params.skill ?? metadata?.skill;
|
|
693
|
+
const contextId = params.contextId ?? message.contextId;
|
|
694
|
+
return { skillId, message, contextId, metadata };
|
|
695
|
+
}
|
|
696
|
+
function resolveSkill(skillId, skills, echoMode) {
|
|
697
|
+
if (skillId) {
|
|
698
|
+
const found = skills.find((s) => s.id === skillId);
|
|
699
|
+
if (found) return found;
|
|
700
|
+
}
|
|
701
|
+
if (echoMode) return skills.find((s) => s.id === "echo") || skills[0];
|
|
702
|
+
return skills.find((s) => s.id === "chat") || skills[0];
|
|
703
|
+
}
|
|
704
|
+
function toSpecPart(part) {
|
|
705
|
+
const out = {};
|
|
706
|
+
if (part.type === "text" || part.text !== void 0) out.text = part.text ?? "";
|
|
707
|
+
else if (part.type === "data" || part.data !== void 0) out.data = part.data;
|
|
708
|
+
else if (part.type === "file") {
|
|
709
|
+
out.url = part.uri ?? part.url;
|
|
710
|
+
out.mediaType = part.mimeType ?? part.mediaType;
|
|
711
|
+
}
|
|
712
|
+
if (part.mediaType || part.mimeType) out.mediaType = part.mediaType ?? part.mimeType;
|
|
713
|
+
return out;
|
|
714
|
+
}
|
|
715
|
+
function toSpecArtifact(a) {
|
|
716
|
+
return {
|
|
717
|
+
artifactId: a.artifactId ?? uuidv4(),
|
|
718
|
+
name: a.name,
|
|
719
|
+
parts: a.parts.map(toSpecPart)
|
|
720
|
+
};
|
|
721
|
+
}
|
|
658
722
|
function createAgentCardHandler(config) {
|
|
659
723
|
const resolved = resolveConfig(config);
|
|
724
|
+
const agentUrl = resolved.agentUrl || "/api/a2a";
|
|
660
725
|
const agentCard = {
|
|
661
726
|
name: resolved.name,
|
|
662
727
|
description: resolved.description,
|
|
663
|
-
url:
|
|
728
|
+
url: agentUrl,
|
|
729
|
+
supportedInterfaces: [
|
|
730
|
+
{
|
|
731
|
+
url: agentUrl,
|
|
732
|
+
protocolBinding: "JSONRPC",
|
|
733
|
+
protocolVersion: A2A_PROTOCOL_VERSION
|
|
734
|
+
}
|
|
735
|
+
],
|
|
664
736
|
version: resolved.version,
|
|
665
737
|
protocolVersion: A2A_PROTOCOL_VERSION,
|
|
666
738
|
defaultInputModes: resolved.defaultInputModes,
|
|
@@ -668,14 +740,9 @@ function createAgentCardHandler(config) {
|
|
|
668
740
|
provider: resolved.provider,
|
|
669
741
|
capabilities: {
|
|
670
742
|
streaming: true,
|
|
671
|
-
pushNotifications: false
|
|
672
|
-
statefulness: "none"
|
|
673
|
-
// Serverless is stateless
|
|
743
|
+
pushNotifications: false
|
|
674
744
|
},
|
|
675
|
-
skills: toAgentCardSkills(resolved.skills)
|
|
676
|
-
authentication: {
|
|
677
|
-
type: "none"
|
|
678
|
-
}
|
|
745
|
+
skills: toAgentCardSkills(resolved.skills)
|
|
679
746
|
};
|
|
680
747
|
return async function handler(_request) {
|
|
681
748
|
return new Response(JSON.stringify(agentCard), {
|
|
@@ -720,8 +787,12 @@ function createA2AHandler(config) {
|
|
|
720
787
|
try {
|
|
721
788
|
switch (method) {
|
|
722
789
|
case "tasks/send":
|
|
790
|
+
case "message/send":
|
|
791
|
+
case "SendMessage":
|
|
723
792
|
return await handleTasksSend(id, params, skills, llmConfig, echoMode);
|
|
724
793
|
case "tasks/sendSubscribe":
|
|
794
|
+
case "message/stream":
|
|
795
|
+
case "SendStreamingMessage":
|
|
725
796
|
return await handleTasksSendSubscribe(
|
|
726
797
|
id,
|
|
727
798
|
params,
|
|
@@ -730,14 +801,16 @@ function createA2AHandler(config) {
|
|
|
730
801
|
echoMode
|
|
731
802
|
);
|
|
732
803
|
case "tasks/get":
|
|
804
|
+
case "GetTask":
|
|
733
805
|
return jsonResponse(
|
|
734
806
|
jsonRpcError(
|
|
735
807
|
id,
|
|
736
808
|
JSON_RPC_ERRORS.TASK_NOT_FOUND,
|
|
737
|
-
"Task state not available in serverless mode. Use
|
|
809
|
+
"Task state not available in serverless mode. Use message/stream for streaming."
|
|
738
810
|
)
|
|
739
811
|
);
|
|
740
812
|
case "tasks/cancel":
|
|
813
|
+
case "CancelTask":
|
|
741
814
|
return jsonResponse(
|
|
742
815
|
jsonRpcError(
|
|
743
816
|
id,
|
|
@@ -760,28 +833,22 @@ function createA2AHandler(config) {
|
|
|
760
833
|
};
|
|
761
834
|
}
|
|
762
835
|
async function handleTasksSend(id, params, skills, llmConfig, echoMode) {
|
|
763
|
-
const {
|
|
764
|
-
const skill =
|
|
765
|
-
|
|
766
|
-
return jsonResponse(
|
|
767
|
-
jsonRpcError(id, JSON_RPC_ERRORS.SKILL_NOT_FOUND, `Skill not found: ${skillId}`, {
|
|
768
|
-
availableSkills: skills.map((s) => s.id)
|
|
769
|
-
})
|
|
770
|
-
);
|
|
771
|
-
}
|
|
836
|
+
const { skillId, message, contextId, metadata } = extractSendParams(params);
|
|
837
|
+
const skill = resolveSkill(skillId, skills, echoMode);
|
|
838
|
+
const resolvedContextId = contextId || uuidv4();
|
|
772
839
|
const taskId = generateTaskId();
|
|
773
840
|
try {
|
|
774
841
|
const context = {
|
|
775
842
|
taskId,
|
|
776
|
-
contextId,
|
|
843
|
+
contextId: resolvedContextId,
|
|
777
844
|
skill,
|
|
778
845
|
message,
|
|
779
846
|
metadata
|
|
780
847
|
};
|
|
781
848
|
let result;
|
|
782
|
-
if (
|
|
849
|
+
if (skill.id.startsWith("time/")) {
|
|
783
850
|
result = await executeTimeSkill(context);
|
|
784
|
-
} else if (echoMode ||
|
|
851
|
+
} else if (echoMode || skill.id === "echo") {
|
|
785
852
|
result = await executeEcho(context);
|
|
786
853
|
} else {
|
|
787
854
|
result = await executeTask(context, llmConfig, skills);
|
|
@@ -790,9 +857,9 @@ async function handleTasksSend(id, params, skills, llmConfig, echoMode) {
|
|
|
790
857
|
jsonRpcSuccess(id, {
|
|
791
858
|
task: {
|
|
792
859
|
id: taskId,
|
|
793
|
-
contextId,
|
|
794
|
-
status: "completed",
|
|
795
|
-
artifacts: result.artifacts,
|
|
860
|
+
contextId: resolvedContextId,
|
|
861
|
+
status: { state: "completed", timestamp: (/* @__PURE__ */ new Date()).toISOString() },
|
|
862
|
+
artifacts: (result.artifacts || []).map(toSpecArtifact),
|
|
796
863
|
metadata
|
|
797
864
|
}
|
|
798
865
|
})
|
|
@@ -804,95 +871,112 @@ async function handleTasksSend(id, params, skills, llmConfig, echoMode) {
|
|
|
804
871
|
);
|
|
805
872
|
}
|
|
806
873
|
}
|
|
807
|
-
async function handleTasksSendSubscribe(
|
|
808
|
-
const {
|
|
809
|
-
const skill =
|
|
810
|
-
|
|
811
|
-
return jsonResponse(
|
|
812
|
-
jsonRpcError(void 0, JSON_RPC_ERRORS.SKILL_NOT_FOUND, `Skill not found: ${skillId}`, {
|
|
813
|
-
availableSkills: skills.map((s) => s.id)
|
|
814
|
-
})
|
|
815
|
-
);
|
|
816
|
-
}
|
|
874
|
+
async function handleTasksSendSubscribe(id, params, skills, llmConfig, echoMode) {
|
|
875
|
+
const { skillId, message, contextId, metadata } = extractSendParams(params);
|
|
876
|
+
const skill = resolveSkill(skillId, skills, echoMode);
|
|
877
|
+
const resolvedContextId = contextId || uuidv4();
|
|
817
878
|
const taskId = generateTaskId();
|
|
818
879
|
const stream = new ReadableStream({
|
|
819
880
|
async start(controller) {
|
|
820
881
|
const encoder = new TextEncoder();
|
|
821
|
-
const
|
|
822
|
-
|
|
823
|
-
data: ${JSON.stringify(
|
|
882
|
+
const sendStreamResponse = (result) => {
|
|
883
|
+
const rpcResponse = { jsonrpc: "2.0", id, result };
|
|
884
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify(rpcResponse)}
|
|
824
885
|
|
|
825
886
|
`));
|
|
826
887
|
};
|
|
827
|
-
|
|
828
|
-
|
|
888
|
+
sendStreamResponse({
|
|
889
|
+
task: {
|
|
890
|
+
id: taskId,
|
|
891
|
+
contextId: resolvedContextId,
|
|
892
|
+
status: { state: "submitted", timestamp: (/* @__PURE__ */ new Date()).toISOString() }
|
|
893
|
+
}
|
|
894
|
+
});
|
|
895
|
+
sendStreamResponse({
|
|
896
|
+
statusUpdate: {
|
|
897
|
+
taskId,
|
|
898
|
+
contextId: resolvedContextId,
|
|
899
|
+
status: { state: "working", timestamp: (/* @__PURE__ */ new Date()).toISOString() }
|
|
900
|
+
}
|
|
901
|
+
});
|
|
829
902
|
try {
|
|
830
903
|
const context = {
|
|
831
904
|
taskId,
|
|
832
|
-
contextId,
|
|
905
|
+
contextId: resolvedContextId,
|
|
833
906
|
skill,
|
|
834
907
|
message,
|
|
835
908
|
metadata
|
|
836
909
|
};
|
|
837
|
-
|
|
910
|
+
const artifactId = uuidv4();
|
|
911
|
+
let isFirstChunk = true;
|
|
838
912
|
const callbacks = {
|
|
839
913
|
onChunk: async (text) => {
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
append: artifactIndex > 0,
|
|
914
|
+
sendStreamResponse({
|
|
915
|
+
artifactUpdate: {
|
|
916
|
+
taskId,
|
|
917
|
+
contextId: resolvedContextId,
|
|
918
|
+
artifact: { artifactId, name: "response", parts: [{ text }] },
|
|
919
|
+
append: !isFirstChunk,
|
|
847
920
|
lastChunk: false
|
|
848
921
|
}
|
|
849
922
|
});
|
|
850
|
-
|
|
923
|
+
isFirstChunk = false;
|
|
851
924
|
},
|
|
852
925
|
onComplete: async () => {
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
index: artifactIndex,
|
|
926
|
+
sendStreamResponse({
|
|
927
|
+
artifactUpdate: {
|
|
928
|
+
taskId,
|
|
929
|
+
contextId: resolvedContextId,
|
|
930
|
+
artifact: { artifactId, name: "response", parts: [{ text: "" }] },
|
|
859
931
|
append: true,
|
|
860
932
|
lastChunk: true
|
|
861
933
|
}
|
|
862
934
|
});
|
|
863
|
-
|
|
935
|
+
sendStreamResponse({
|
|
936
|
+
statusUpdate: {
|
|
937
|
+
taskId,
|
|
938
|
+
contextId: resolvedContextId,
|
|
939
|
+
status: { state: "completed", timestamp: (/* @__PURE__ */ new Date()).toISOString() }
|
|
940
|
+
}
|
|
941
|
+
});
|
|
864
942
|
controller.close();
|
|
865
943
|
},
|
|
866
944
|
onError: async (error) => {
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
945
|
+
sendStreamResponse({
|
|
946
|
+
statusUpdate: {
|
|
947
|
+
taskId,
|
|
948
|
+
contextId: resolvedContextId,
|
|
949
|
+
status: {
|
|
950
|
+
state: "failed",
|
|
951
|
+
message: { role: "agent", parts: [{ text: error.message }] },
|
|
952
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
953
|
+
}
|
|
954
|
+
}
|
|
874
955
|
});
|
|
875
956
|
controller.close();
|
|
876
957
|
}
|
|
877
958
|
};
|
|
878
|
-
if (
|
|
959
|
+
if (skill.id.startsWith("time/")) {
|
|
879
960
|
const timeResult = await executeTimeSkill(context);
|
|
880
961
|
await callbacks.onChunk(timeResult.text);
|
|
881
962
|
await callbacks.onComplete();
|
|
882
|
-
} else if (echoMode ||
|
|
963
|
+
} else if (echoMode || skill.id === "echo") {
|
|
883
964
|
await executeEchoStreaming(context, callbacks);
|
|
884
965
|
} else {
|
|
885
966
|
await executeTaskStreaming(context, llmConfig, callbacks, skills);
|
|
886
967
|
}
|
|
887
968
|
} catch (error) {
|
|
888
969
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
970
|
+
sendStreamResponse({
|
|
971
|
+
statusUpdate: {
|
|
972
|
+
taskId,
|
|
973
|
+
contextId: resolvedContextId,
|
|
974
|
+
status: {
|
|
975
|
+
state: "failed",
|
|
976
|
+
message: { role: "agent", parts: [{ text: errorMessage }] },
|
|
977
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
978
|
+
}
|
|
979
|
+
}
|
|
896
980
|
});
|
|
897
981
|
controller.close();
|
|
898
982
|
}
|