@distri/core 0.2.3 → 0.2.5
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/dist/index.d.mts +797 -216
- package/dist/index.d.ts +797 -216
- package/dist/index.js +1171 -138
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1157 -138
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -1
package/dist/index.js
CHANGED
|
@@ -22,22 +22,155 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
22
22
|
// src/index.ts
|
|
23
23
|
var index_exports = {};
|
|
24
24
|
__export(index_exports, {
|
|
25
|
+
A2AProtocolError: () => A2AProtocolError,
|
|
25
26
|
Agent: () => Agent,
|
|
27
|
+
ApiError: () => ApiError,
|
|
28
|
+
ConnectionError: () => ConnectionError,
|
|
29
|
+
DEFAULT_BASE_URL: () => DEFAULT_BASE_URL,
|
|
26
30
|
DistriClient: () => DistriClient,
|
|
31
|
+
DistriError: () => DistriError,
|
|
32
|
+
ExternalToolValidationError: () => ExternalToolValidationError,
|
|
27
33
|
convertA2AMessageToDistri: () => convertA2AMessageToDistri,
|
|
28
34
|
convertA2APartToDistri: () => convertA2APartToDistri,
|
|
35
|
+
convertA2AStatusUpdateToDistri: () => convertA2AStatusUpdateToDistri,
|
|
29
36
|
convertDistriMessageToA2A: () => convertDistriMessageToA2A,
|
|
30
37
|
convertDistriPartToA2A: () => convertDistriPartToA2A,
|
|
38
|
+
createFailedToolResult: () => createFailedToolResult,
|
|
39
|
+
createSuccessfulToolResult: () => createSuccessfulToolResult,
|
|
40
|
+
decodeA2AStreamEvent: () => decodeA2AStreamEvent,
|
|
31
41
|
extractTextFromDistriMessage: () => extractTextFromDistriMessage,
|
|
32
42
|
extractToolCallsFromDistriMessage: () => extractToolCallsFromDistriMessage,
|
|
43
|
+
extractToolResultData: () => extractToolResultData,
|
|
33
44
|
extractToolResultsFromDistriMessage: () => extractToolResultsFromDistriMessage,
|
|
45
|
+
isArrayParts: () => isArrayParts,
|
|
34
46
|
isDistriEvent: () => isDistriEvent,
|
|
35
47
|
isDistriMessage: () => isDistriMessage,
|
|
48
|
+
processA2AMessagesData: () => processA2AMessagesData,
|
|
49
|
+
processA2AStreamData: () => processA2AStreamData,
|
|
36
50
|
uuidv4: () => uuidv4
|
|
37
51
|
});
|
|
38
52
|
module.exports = __toCommonJS(index_exports);
|
|
39
53
|
|
|
40
|
-
//
|
|
54
|
+
// src/types.ts
|
|
55
|
+
function isArrayParts(result) {
|
|
56
|
+
return Array.isArray(result) && result[0].part_type;
|
|
57
|
+
}
|
|
58
|
+
function createSuccessfulToolResult(toolCallId, toolName, result) {
|
|
59
|
+
const parts = isArrayParts(result) ? result : [{
|
|
60
|
+
part_type: "data",
|
|
61
|
+
data: {
|
|
62
|
+
result,
|
|
63
|
+
success: true,
|
|
64
|
+
error: void 0
|
|
65
|
+
}
|
|
66
|
+
}];
|
|
67
|
+
return {
|
|
68
|
+
tool_call_id: toolCallId,
|
|
69
|
+
tool_name: toolName,
|
|
70
|
+
parts
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function createFailedToolResult(toolCallId, toolName, error, result) {
|
|
74
|
+
return {
|
|
75
|
+
tool_call_id: toolCallId,
|
|
76
|
+
tool_name: toolName,
|
|
77
|
+
parts: [{
|
|
78
|
+
part_type: "data",
|
|
79
|
+
data: {
|
|
80
|
+
result: result ?? `Tool execution failed: ${error}`,
|
|
81
|
+
success: false,
|
|
82
|
+
error
|
|
83
|
+
}
|
|
84
|
+
}]
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function isDataPart(part) {
|
|
88
|
+
return typeof part === "object" && part !== null && "part_type" in part && part.part_type === "data" && "data" in part;
|
|
89
|
+
}
|
|
90
|
+
function isToolResultData(data) {
|
|
91
|
+
return typeof data === "object" && data !== null && "success" in data && typeof data.success === "boolean";
|
|
92
|
+
}
|
|
93
|
+
function extractToolResultData(toolResult) {
|
|
94
|
+
if (!toolResult.parts || !Array.isArray(toolResult.parts) || toolResult.parts.length === 0) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
const firstPart = toolResult.parts[0];
|
|
98
|
+
if (isDataPart(firstPart)) {
|
|
99
|
+
const data = firstPart.data;
|
|
100
|
+
if (isToolResultData(data)) {
|
|
101
|
+
return {
|
|
102
|
+
result: data.result,
|
|
103
|
+
success: data.success,
|
|
104
|
+
error: data.error
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
if (typeof data === "string") {
|
|
108
|
+
try {
|
|
109
|
+
const parsed = JSON.parse(data);
|
|
110
|
+
if (isToolResultData(parsed)) {
|
|
111
|
+
return {
|
|
112
|
+
result: parsed.result,
|
|
113
|
+
success: parsed.success,
|
|
114
|
+
error: parsed.error
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
result: parsed,
|
|
119
|
+
success: true,
|
|
120
|
+
error: void 0
|
|
121
|
+
};
|
|
122
|
+
} catch {
|
|
123
|
+
return {
|
|
124
|
+
result: data,
|
|
125
|
+
success: true,
|
|
126
|
+
error: void 0
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
result: data,
|
|
132
|
+
success: true,
|
|
133
|
+
error: void 0
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
var DEFAULT_BASE_URL = "https://api.distri.dev";
|
|
139
|
+
var DistriError = class extends Error {
|
|
140
|
+
constructor(message, code, details) {
|
|
141
|
+
super(message);
|
|
142
|
+
this.code = code;
|
|
143
|
+
this.details = details;
|
|
144
|
+
this.name = "DistriError";
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
var A2AProtocolError = class extends DistriError {
|
|
148
|
+
constructor(message, details) {
|
|
149
|
+
super(message, "A2A_PROTOCOL_ERROR", details);
|
|
150
|
+
this.name = "A2AProtocolError";
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
var ApiError = class extends DistriError {
|
|
154
|
+
constructor(message, statusCode, details) {
|
|
155
|
+
super(message, "API_ERROR", details);
|
|
156
|
+
this.statusCode = statusCode;
|
|
157
|
+
this.name = "ApiError";
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
var ConnectionError = class extends DistriError {
|
|
161
|
+
constructor(message, details) {
|
|
162
|
+
super(message, "CONNECTION_ERROR", details);
|
|
163
|
+
this.name = "ConnectionError";
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
function isDistriMessage(event) {
|
|
167
|
+
return "id" in event && "role" in event && "parts" in event;
|
|
168
|
+
}
|
|
169
|
+
function isDistriEvent(event) {
|
|
170
|
+
return "type" in event && "data" in event;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// ../../../node_modules/.pnpm/@a2a-js+sdk@https+++codeload.github.com+v3g42+a2a-js+tar.gz+51444c9/node_modules/@a2a-js/sdk/dist/chunk-CUGIRVQB.js
|
|
41
174
|
var A2AClient = class {
|
|
42
175
|
/**
|
|
43
176
|
* Constructs an A2AClient instance.
|
|
@@ -407,35 +540,6 @@ var A2AClient = class {
|
|
|
407
540
|
}
|
|
408
541
|
};
|
|
409
542
|
|
|
410
|
-
// src/types.ts
|
|
411
|
-
var DistriError = class extends Error {
|
|
412
|
-
constructor(message, code, details) {
|
|
413
|
-
super(message);
|
|
414
|
-
this.code = code;
|
|
415
|
-
this.details = details;
|
|
416
|
-
this.name = "DistriError";
|
|
417
|
-
}
|
|
418
|
-
};
|
|
419
|
-
var A2AProtocolError = class extends DistriError {
|
|
420
|
-
constructor(message, details) {
|
|
421
|
-
super(message, "A2A_PROTOCOL_ERROR", details);
|
|
422
|
-
this.name = "A2AProtocolError";
|
|
423
|
-
}
|
|
424
|
-
};
|
|
425
|
-
var ApiError = class extends DistriError {
|
|
426
|
-
constructor(message, statusCode, details) {
|
|
427
|
-
super(message, "API_ERROR", details);
|
|
428
|
-
this.statusCode = statusCode;
|
|
429
|
-
this.name = "ApiError";
|
|
430
|
-
}
|
|
431
|
-
};
|
|
432
|
-
function isDistriMessage(event) {
|
|
433
|
-
return "id" in event && "role" in event && "parts" in event;
|
|
434
|
-
}
|
|
435
|
-
function isDistriEvent(event) {
|
|
436
|
-
return "type" in event && "metadata" in event;
|
|
437
|
-
}
|
|
438
|
-
|
|
439
543
|
// src/encoder.ts
|
|
440
544
|
function convertA2AMessageToDistri(a2aMessage) {
|
|
441
545
|
const role = a2aMessage.role === "agent" ? "assistant" : "user";
|
|
@@ -446,31 +550,251 @@ function convertA2AMessageToDistri(a2aMessage) {
|
|
|
446
550
|
created_at: a2aMessage.createdAt
|
|
447
551
|
};
|
|
448
552
|
}
|
|
553
|
+
function convertA2AStatusUpdateToDistri(statusUpdate) {
|
|
554
|
+
if (!statusUpdate.metadata || !statusUpdate.metadata.type) {
|
|
555
|
+
return null;
|
|
556
|
+
}
|
|
557
|
+
const metadata = statusUpdate.metadata;
|
|
558
|
+
switch (metadata.type) {
|
|
559
|
+
case "run_started": {
|
|
560
|
+
const runStartedResult = {
|
|
561
|
+
type: "run_started",
|
|
562
|
+
data: {
|
|
563
|
+
runId: statusUpdate.runId,
|
|
564
|
+
taskId: statusUpdate.taskId
|
|
565
|
+
}
|
|
566
|
+
};
|
|
567
|
+
return runStartedResult;
|
|
568
|
+
}
|
|
569
|
+
case "run_error": {
|
|
570
|
+
const runErrorResult = {
|
|
571
|
+
type: "run_error",
|
|
572
|
+
data: {
|
|
573
|
+
message: statusUpdate.error,
|
|
574
|
+
code: statusUpdate.code
|
|
575
|
+
}
|
|
576
|
+
};
|
|
577
|
+
return runErrorResult;
|
|
578
|
+
}
|
|
579
|
+
case "run_finished": {
|
|
580
|
+
const runFinishedResult = {
|
|
581
|
+
type: "run_finished",
|
|
582
|
+
data: {
|
|
583
|
+
runId: statusUpdate.runId,
|
|
584
|
+
taskId: statusUpdate.taskId
|
|
585
|
+
}
|
|
586
|
+
};
|
|
587
|
+
return runFinishedResult;
|
|
588
|
+
}
|
|
589
|
+
case "plan_started": {
|
|
590
|
+
const planStartedResult = {
|
|
591
|
+
type: "plan_started",
|
|
592
|
+
data: {
|
|
593
|
+
initial_plan: metadata.initial_plan
|
|
594
|
+
}
|
|
595
|
+
};
|
|
596
|
+
return planStartedResult;
|
|
597
|
+
}
|
|
598
|
+
case "plan_finished": {
|
|
599
|
+
const planFinishedResult = {
|
|
600
|
+
type: "plan_finished",
|
|
601
|
+
data: {
|
|
602
|
+
total_steps: metadata.total_steps
|
|
603
|
+
}
|
|
604
|
+
};
|
|
605
|
+
return planFinishedResult;
|
|
606
|
+
}
|
|
607
|
+
case "step_started": {
|
|
608
|
+
const stepStartedResult = {
|
|
609
|
+
type: "step_started",
|
|
610
|
+
data: {
|
|
611
|
+
step_id: metadata.step_id,
|
|
612
|
+
step_title: metadata.step_title || "Processing",
|
|
613
|
+
step_index: metadata.step_index || 0
|
|
614
|
+
}
|
|
615
|
+
};
|
|
616
|
+
return stepStartedResult;
|
|
617
|
+
}
|
|
618
|
+
case "step_completed": {
|
|
619
|
+
const stepCompletedResult = {
|
|
620
|
+
type: "step_completed",
|
|
621
|
+
data: {
|
|
622
|
+
step_id: metadata.step_id,
|
|
623
|
+
step_title: metadata.step_title || "Processing",
|
|
624
|
+
step_index: metadata.step_index || 0
|
|
625
|
+
}
|
|
626
|
+
};
|
|
627
|
+
return stepCompletedResult;
|
|
628
|
+
}
|
|
629
|
+
case "tool_execution_start": {
|
|
630
|
+
const toolStartResult = {
|
|
631
|
+
type: "tool_execution_start",
|
|
632
|
+
data: {
|
|
633
|
+
tool_call_id: metadata.tool_call_id,
|
|
634
|
+
tool_call_name: metadata.tool_call_name || "Tool",
|
|
635
|
+
parent_message_id: statusUpdate.taskId
|
|
636
|
+
}
|
|
637
|
+
};
|
|
638
|
+
return toolStartResult;
|
|
639
|
+
}
|
|
640
|
+
case "tool_execution_end": {
|
|
641
|
+
const toolEndResult = {
|
|
642
|
+
type: "tool_execution_end",
|
|
643
|
+
data: {
|
|
644
|
+
tool_call_id: metadata.tool_call_id
|
|
645
|
+
}
|
|
646
|
+
};
|
|
647
|
+
return toolEndResult;
|
|
648
|
+
}
|
|
649
|
+
case "text_message_start": {
|
|
650
|
+
const textStartResult = {
|
|
651
|
+
type: "text_message_start",
|
|
652
|
+
data: {
|
|
653
|
+
message_id: metadata.message_id,
|
|
654
|
+
step_id: metadata.step_id || "",
|
|
655
|
+
role: metadata.role === "assistant" ? "assistant" : "user"
|
|
656
|
+
}
|
|
657
|
+
};
|
|
658
|
+
return textStartResult;
|
|
659
|
+
}
|
|
660
|
+
case "text_message_content": {
|
|
661
|
+
const textContentResult = {
|
|
662
|
+
type: "text_message_content",
|
|
663
|
+
data: {
|
|
664
|
+
message_id: metadata.message_id,
|
|
665
|
+
step_id: metadata.step_id || "",
|
|
666
|
+
delta: metadata.delta || ""
|
|
667
|
+
}
|
|
668
|
+
};
|
|
669
|
+
return textContentResult;
|
|
670
|
+
}
|
|
671
|
+
case "text_message_end": {
|
|
672
|
+
const textEndResult = {
|
|
673
|
+
type: "text_message_end",
|
|
674
|
+
data: {
|
|
675
|
+
message_id: metadata.message_id,
|
|
676
|
+
step_id: metadata.step_id || ""
|
|
677
|
+
}
|
|
678
|
+
};
|
|
679
|
+
return textEndResult;
|
|
680
|
+
}
|
|
681
|
+
case "tool_calls": {
|
|
682
|
+
const toolCallsResult = {
|
|
683
|
+
type: "tool_calls",
|
|
684
|
+
data: {
|
|
685
|
+
tool_calls: metadata.tool_calls || []
|
|
686
|
+
}
|
|
687
|
+
};
|
|
688
|
+
return toolCallsResult;
|
|
689
|
+
}
|
|
690
|
+
case "tool_results": {
|
|
691
|
+
const toolResultsResult = {
|
|
692
|
+
type: "tool_results",
|
|
693
|
+
data: {
|
|
694
|
+
results: metadata.results || []
|
|
695
|
+
}
|
|
696
|
+
};
|
|
697
|
+
return toolResultsResult;
|
|
698
|
+
}
|
|
699
|
+
case "browser_screenshot": {
|
|
700
|
+
const browserScreenshotResult = {
|
|
701
|
+
type: "browser_screenshot",
|
|
702
|
+
data: {
|
|
703
|
+
image: metadata.image || "",
|
|
704
|
+
format: metadata.format,
|
|
705
|
+
filename: metadata.filename,
|
|
706
|
+
size: metadata.size,
|
|
707
|
+
timestamp_ms: metadata.timestamp_ms
|
|
708
|
+
}
|
|
709
|
+
};
|
|
710
|
+
return browserScreenshotResult;
|
|
711
|
+
}
|
|
712
|
+
case "inline_hook_requested": {
|
|
713
|
+
const hookRequested = {
|
|
714
|
+
type: "inline_hook_requested",
|
|
715
|
+
data: {
|
|
716
|
+
hook_id: metadata.request?.hook_id || metadata.hook_id || "",
|
|
717
|
+
hook: metadata.request?.hook || metadata.hook || "",
|
|
718
|
+
context: metadata.request?.context || metadata.context || {
|
|
719
|
+
agent_id: statusUpdate.agentId,
|
|
720
|
+
thread_id: statusUpdate.contextId,
|
|
721
|
+
task_id: statusUpdate.taskId,
|
|
722
|
+
run_id: statusUpdate.agentId
|
|
723
|
+
},
|
|
724
|
+
timeout_ms: metadata.request?.timeout_ms || metadata.timeout_ms,
|
|
725
|
+
fire_and_forget: metadata.request?.fire_and_forget ?? metadata.fire_and_forget,
|
|
726
|
+
message: metadata.request?.message || metadata.message,
|
|
727
|
+
plan: metadata.request?.plan || metadata.plan,
|
|
728
|
+
result: metadata.request?.result || metadata.result
|
|
729
|
+
}
|
|
730
|
+
};
|
|
731
|
+
return hookRequested;
|
|
732
|
+
}
|
|
733
|
+
default: {
|
|
734
|
+
console.warn(`Unhandled status update metadata type: ${metadata.type}`, metadata);
|
|
735
|
+
const defaultResult = {
|
|
736
|
+
type: "run_started",
|
|
737
|
+
data: {
|
|
738
|
+
runId: statusUpdate.runId,
|
|
739
|
+
taskId: statusUpdate.taskId
|
|
740
|
+
}
|
|
741
|
+
};
|
|
742
|
+
return defaultResult;
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
function decodeA2AStreamEvent(event) {
|
|
747
|
+
if (event.kind === "message") {
|
|
748
|
+
return convertA2AMessageToDistri(event);
|
|
749
|
+
}
|
|
750
|
+
if (event.kind === "status-update") {
|
|
751
|
+
return convertA2AStatusUpdateToDistri(event);
|
|
752
|
+
}
|
|
753
|
+
return null;
|
|
754
|
+
}
|
|
755
|
+
function processA2AStreamData(streamData) {
|
|
756
|
+
const results = [];
|
|
757
|
+
for (const item of streamData) {
|
|
758
|
+
const converted = decodeA2AStreamEvent(item);
|
|
759
|
+
if (converted) {
|
|
760
|
+
results.push(converted);
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
return results;
|
|
764
|
+
}
|
|
765
|
+
function processA2AMessagesData(data) {
|
|
766
|
+
const results = [];
|
|
767
|
+
for (const item of data) {
|
|
768
|
+
if (item.kind === "message") {
|
|
769
|
+
const distriMessage = convertA2AMessageToDistri(item);
|
|
770
|
+
results.push(distriMessage);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
return results;
|
|
774
|
+
}
|
|
449
775
|
function convertA2APartToDistri(a2aPart) {
|
|
450
776
|
switch (a2aPart.kind) {
|
|
451
777
|
case "text":
|
|
452
|
-
return {
|
|
778
|
+
return { part_type: "text", data: a2aPart.text };
|
|
453
779
|
case "file":
|
|
454
780
|
if ("uri" in a2aPart.file) {
|
|
455
|
-
|
|
781
|
+
const fileUrl = { type: "url", mime_type: a2aPart.file.mimeType || "application/octet-stream", url: a2aPart.file.uri || "" };
|
|
782
|
+
return { part_type: "image", data: fileUrl };
|
|
456
783
|
} else {
|
|
457
|
-
|
|
784
|
+
const fileBytes = { type: "bytes", mime_type: a2aPart.file.mimeType || "application/octet-stream", data: a2aPart.file.bytes || "" };
|
|
785
|
+
return { part_type: "image", data: fileBytes };
|
|
458
786
|
}
|
|
459
787
|
case "data":
|
|
460
788
|
switch (a2aPart.data.part_type) {
|
|
461
789
|
case "tool_call":
|
|
462
|
-
return {
|
|
790
|
+
return { part_type: "tool_call", data: a2aPart.data };
|
|
463
791
|
case "tool_result":
|
|
464
|
-
return {
|
|
465
|
-
case "code_observation":
|
|
466
|
-
return { type: "code_observation", thought: a2aPart.data.thought, code: a2aPart.data.code };
|
|
467
|
-
case "plan":
|
|
468
|
-
return { type: "plan", plan: a2aPart.data.plan };
|
|
792
|
+
return { part_type: "tool_result", data: a2aPart.data };
|
|
469
793
|
default:
|
|
470
|
-
return {
|
|
794
|
+
return { part_type: "data", data: a2aPart.data };
|
|
471
795
|
}
|
|
472
796
|
default:
|
|
473
|
-
return {
|
|
797
|
+
return { part_type: "text", data: JSON.stringify(a2aPart) };
|
|
474
798
|
}
|
|
475
799
|
}
|
|
476
800
|
function convertDistriMessageToA2A(distriMessage, context) {
|
|
@@ -495,52 +819,95 @@ function convertDistriMessageToA2A(distriMessage, context) {
|
|
|
495
819
|
parts: distriMessage.parts.map(convertDistriPartToA2A),
|
|
496
820
|
kind: "message",
|
|
497
821
|
contextId: context.thread_id,
|
|
498
|
-
taskId: context.run_id
|
|
822
|
+
taskId: context.task_id || context.run_id || void 0
|
|
499
823
|
};
|
|
500
824
|
}
|
|
501
825
|
function convertDistriPartToA2A(distriPart) {
|
|
502
|
-
|
|
826
|
+
let result;
|
|
827
|
+
switch (distriPart.part_type) {
|
|
503
828
|
case "text":
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
829
|
+
result = { kind: "text", text: distriPart.data };
|
|
830
|
+
break;
|
|
831
|
+
case "image":
|
|
832
|
+
if ("url" in distriPart.data) {
|
|
833
|
+
const fileUri = { mimeType: distriPart.data.mime_type, uri: distriPart.data.url };
|
|
834
|
+
result = { kind: "file", file: fileUri };
|
|
835
|
+
} else {
|
|
836
|
+
const fileBytes = { mimeType: distriPart.data.mime_type, bytes: distriPart.data.data };
|
|
837
|
+
result = { kind: "file", file: fileBytes };
|
|
838
|
+
}
|
|
839
|
+
break;
|
|
509
840
|
case "tool_call":
|
|
510
|
-
|
|
511
|
-
case "tool_result":
|
|
512
|
-
let val = {
|
|
841
|
+
result = {
|
|
513
842
|
kind: "data",
|
|
514
843
|
data: {
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
part_type: "tool_result"
|
|
844
|
+
part_type: "tool_call",
|
|
845
|
+
data: distriPart.data
|
|
518
846
|
}
|
|
519
847
|
};
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
848
|
+
break;
|
|
849
|
+
case "tool_result": {
|
|
850
|
+
const toolResult = distriPart.data;
|
|
851
|
+
const parts = toolResult.parts.map((part) => {
|
|
852
|
+
if ("type" in part && part.type === "data") {
|
|
853
|
+
return {
|
|
854
|
+
part_type: "data",
|
|
855
|
+
data: part.data
|
|
856
|
+
};
|
|
857
|
+
} else if ("part_type" in part) {
|
|
858
|
+
return part;
|
|
859
|
+
} else {
|
|
860
|
+
return {
|
|
861
|
+
part_type: "data",
|
|
862
|
+
data: part
|
|
863
|
+
};
|
|
864
|
+
}
|
|
865
|
+
});
|
|
866
|
+
result = {
|
|
867
|
+
kind: "data",
|
|
868
|
+
data: {
|
|
869
|
+
part_type: "tool_result",
|
|
870
|
+
data: {
|
|
871
|
+
tool_call_id: toolResult.tool_call_id,
|
|
872
|
+
tool_name: toolResult.tool_name,
|
|
873
|
+
parts
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
};
|
|
877
|
+
break;
|
|
878
|
+
}
|
|
879
|
+
case "data": {
|
|
880
|
+
const dataValue = distriPart.data;
|
|
881
|
+
if (dataValue === null || typeof dataValue !== "object" || Array.isArray(dataValue)) {
|
|
882
|
+
result = { kind: "data", data: { value: dataValue } };
|
|
883
|
+
} else {
|
|
884
|
+
const dataObj = dataValue;
|
|
885
|
+
result = { kind: "data", data: dataObj };
|
|
886
|
+
}
|
|
887
|
+
break;
|
|
888
|
+
}
|
|
528
889
|
}
|
|
890
|
+
return result;
|
|
529
891
|
}
|
|
530
892
|
function extractTextFromDistriMessage(message) {
|
|
531
|
-
return message.parts.filter((part) => part.
|
|
893
|
+
return message.parts.filter((part) => part.part_type === "text").map((part) => part.data).join("\n");
|
|
532
894
|
}
|
|
533
895
|
function extractToolCallsFromDistriMessage(message) {
|
|
534
|
-
return message.parts.filter((part) => part.
|
|
896
|
+
return message.parts.filter((part) => part.part_type === "tool_call").map((part) => part.data);
|
|
535
897
|
}
|
|
536
898
|
function extractToolResultsFromDistriMessage(message) {
|
|
537
|
-
return message.parts.filter((part) => part.
|
|
899
|
+
return message.parts.filter((part) => part.part_type === "tool_result").map((part) => part.data);
|
|
538
900
|
}
|
|
539
901
|
|
|
540
902
|
// src/distri-client.ts
|
|
541
|
-
var
|
|
903
|
+
var _DistriClient = class _DistriClient {
|
|
542
904
|
constructor(config) {
|
|
543
905
|
this.agentClients = /* @__PURE__ */ new Map();
|
|
906
|
+
const headers = { ...config.headers };
|
|
907
|
+
this.accessToken = config.accessToken;
|
|
908
|
+
this.refreshToken = config.refreshToken;
|
|
909
|
+
this.tokenRefreshSkewMs = config.tokenRefreshSkewMs ?? 6e4;
|
|
910
|
+
this.onTokenRefresh = config.onTokenRefresh;
|
|
544
911
|
this.config = {
|
|
545
912
|
baseUrl: config.baseUrl.replace(/\/$/, ""),
|
|
546
913
|
apiVersion: config.apiVersion || "v1",
|
|
@@ -548,10 +915,362 @@ var DistriClient = class {
|
|
|
548
915
|
retryAttempts: config.retryAttempts || 3,
|
|
549
916
|
retryDelay: config.retryDelay || 1e3,
|
|
550
917
|
debug: config.debug || false,
|
|
551
|
-
headers
|
|
918
|
+
headers,
|
|
552
919
|
interceptor: config.interceptor || ((init) => Promise.resolve(init))
|
|
553
920
|
};
|
|
554
|
-
this.debug("DistriClient initialized with config:",
|
|
921
|
+
this.debug("DistriClient initialized with config:", {
|
|
922
|
+
baseUrl: this.config.baseUrl,
|
|
923
|
+
hasAccessToken: !!this.accessToken,
|
|
924
|
+
hasRefreshToken: !!this.refreshToken,
|
|
925
|
+
timeout: this.config.timeout
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
/**
|
|
929
|
+
* Create a client with default cloud configuration.
|
|
930
|
+
*
|
|
931
|
+
* @param overrides - Optional overrides for the default config
|
|
932
|
+
*/
|
|
933
|
+
static create(overrides = {}) {
|
|
934
|
+
return new _DistriClient({
|
|
935
|
+
baseUrl: DEFAULT_BASE_URL,
|
|
936
|
+
...overrides
|
|
937
|
+
});
|
|
938
|
+
}
|
|
939
|
+
/**
|
|
940
|
+
* Check if this client has authentication configured.
|
|
941
|
+
*/
|
|
942
|
+
hasAuth() {
|
|
943
|
+
return !!this.accessToken || !!this.refreshToken;
|
|
944
|
+
}
|
|
945
|
+
/**
|
|
946
|
+
* Check if this client is configured for local development.
|
|
947
|
+
*/
|
|
948
|
+
isLocal() {
|
|
949
|
+
return this.config.baseUrl.includes("localhost") || this.config.baseUrl.includes("127.0.0.1");
|
|
950
|
+
}
|
|
951
|
+
/**
|
|
952
|
+
* Session store: set a value (optionally with expiry)
|
|
953
|
+
*/
|
|
954
|
+
async setSessionValue(sessionId, key, value, expiry) {
|
|
955
|
+
const body = { key, value };
|
|
956
|
+
if (expiry) {
|
|
957
|
+
body.expiry = typeof expiry === "string" ? expiry : expiry.toISOString();
|
|
958
|
+
}
|
|
959
|
+
const resp = await this.fetch(`/session/${encodeURIComponent(sessionId)}/values`, {
|
|
960
|
+
method: "POST",
|
|
961
|
+
headers: {
|
|
962
|
+
"Content-Type": "application/json",
|
|
963
|
+
...this.config.headers
|
|
964
|
+
},
|
|
965
|
+
body: JSON.stringify(body)
|
|
966
|
+
});
|
|
967
|
+
if (!resp.ok && resp.status !== 204) {
|
|
968
|
+
const errorData = await resp.json().catch(() => ({}));
|
|
969
|
+
throw new ApiError(errorData.error || "Failed to set session value", resp.status);
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
/**
|
|
973
|
+
* Session store: get a single value
|
|
974
|
+
*/
|
|
975
|
+
async getSessionValue(sessionId, key) {
|
|
976
|
+
const resp = await this.fetch(`/session/${encodeURIComponent(sessionId)}/values/${encodeURIComponent(key)}`, {
|
|
977
|
+
method: "GET",
|
|
978
|
+
headers: {
|
|
979
|
+
...this.config.headers
|
|
980
|
+
}
|
|
981
|
+
});
|
|
982
|
+
if (!resp.ok) {
|
|
983
|
+
const errorData = await resp.json().catch(() => ({}));
|
|
984
|
+
throw new ApiError(errorData.error || "Failed to get session value", resp.status);
|
|
985
|
+
}
|
|
986
|
+
const data = await resp.json().catch(() => ({ value: null }));
|
|
987
|
+
return data?.value ?? null;
|
|
988
|
+
}
|
|
989
|
+
/**
|
|
990
|
+
* Session store: get all values in a session
|
|
991
|
+
*/
|
|
992
|
+
async getSessionValues(sessionId) {
|
|
993
|
+
const resp = await this.fetch(`/session/${encodeURIComponent(sessionId)}/values`, {
|
|
994
|
+
method: "GET",
|
|
995
|
+
headers: {
|
|
996
|
+
...this.config.headers
|
|
997
|
+
}
|
|
998
|
+
});
|
|
999
|
+
if (!resp.ok) {
|
|
1000
|
+
const errorData = await resp.json().catch(() => ({}));
|
|
1001
|
+
throw new ApiError(errorData.error || "Failed to get session values", resp.status);
|
|
1002
|
+
}
|
|
1003
|
+
const data = await resp.json().catch(() => ({ values: {} }));
|
|
1004
|
+
return data?.values ?? {};
|
|
1005
|
+
}
|
|
1006
|
+
/**
|
|
1007
|
+
* Session store: delete a single key
|
|
1008
|
+
*/
|
|
1009
|
+
async deleteSessionValue(sessionId, key) {
|
|
1010
|
+
const resp = await this.fetch(`/session/${encodeURIComponent(sessionId)}/values/${encodeURIComponent(key)}`, {
|
|
1011
|
+
method: "DELETE",
|
|
1012
|
+
headers: {
|
|
1013
|
+
...this.config.headers
|
|
1014
|
+
}
|
|
1015
|
+
});
|
|
1016
|
+
if (!resp.ok && resp.status !== 204) {
|
|
1017
|
+
const errorData = await resp.json().catch(() => ({}));
|
|
1018
|
+
throw new ApiError(errorData.error || "Failed to delete session value", resp.status);
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
/**
|
|
1022
|
+
* Session store: clear all keys in a session
|
|
1023
|
+
*/
|
|
1024
|
+
async clearSession(sessionId) {
|
|
1025
|
+
const resp = await this.fetch(`/session/${encodeURIComponent(sessionId)}`, {
|
|
1026
|
+
method: "DELETE",
|
|
1027
|
+
headers: {
|
|
1028
|
+
...this.config.headers
|
|
1029
|
+
}
|
|
1030
|
+
});
|
|
1031
|
+
if (!resp.ok && resp.status !== 204) {
|
|
1032
|
+
const errorData = await resp.json().catch(() => ({}));
|
|
1033
|
+
throw new ApiError(errorData.error || "Failed to clear session", resp.status);
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
/**
|
|
1037
|
+
* Set additional user message parts for the next agent iteration.
|
|
1038
|
+
* These parts will be appended to the user message in the prompt.
|
|
1039
|
+
* @param sessionId - The thread/session ID
|
|
1040
|
+
* @param parts - Array of DistriPart objects to append to user message
|
|
1041
|
+
*/
|
|
1042
|
+
async setAdditionalUserParts(sessionId, parts) {
|
|
1043
|
+
await this.setSessionValue(sessionId, _DistriClient.ADDITIONAL_PARTS_KEY, parts);
|
|
1044
|
+
}
|
|
1045
|
+
/**
|
|
1046
|
+
* Get the current additional user message parts.
|
|
1047
|
+
* @param sessionId - The thread/session ID
|
|
1048
|
+
* @returns Array of DistriPart objects or null if not set
|
|
1049
|
+
*/
|
|
1050
|
+
async getAdditionalUserParts(sessionId) {
|
|
1051
|
+
return this.getSessionValue(sessionId, _DistriClient.ADDITIONAL_PARTS_KEY);
|
|
1052
|
+
}
|
|
1053
|
+
/**
|
|
1054
|
+
* Clear/delete the additional user message parts.
|
|
1055
|
+
* @param sessionId - The thread/session ID
|
|
1056
|
+
*/
|
|
1057
|
+
async clearAdditionalUserParts(sessionId) {
|
|
1058
|
+
await this.deleteSessionValue(sessionId, _DistriClient.ADDITIONAL_PARTS_KEY);
|
|
1059
|
+
}
|
|
1060
|
+
/**
|
|
1061
|
+
* Issue an access token + refresh token for temporary authentication.
|
|
1062
|
+
* Requires an existing authenticated session (bearer token).
|
|
1063
|
+
*
|
|
1064
|
+
* @returns Token response with access/refresh token strings
|
|
1065
|
+
* @throws ApiError if not authenticated or token issuance fails
|
|
1066
|
+
*
|
|
1067
|
+
* @example
|
|
1068
|
+
* ```typescript
|
|
1069
|
+
* const { access_token, refresh_token } = await client.issueToken();
|
|
1070
|
+
* // Persist the refresh token and use access_token for requests
|
|
1071
|
+
* ```
|
|
1072
|
+
*/
|
|
1073
|
+
async issueToken() {
|
|
1074
|
+
const response = await this.fetch("/token", {
|
|
1075
|
+
method: "POST",
|
|
1076
|
+
headers: {
|
|
1077
|
+
"Content-Type": "application/json",
|
|
1078
|
+
...this.config.headers
|
|
1079
|
+
}
|
|
1080
|
+
});
|
|
1081
|
+
if (!response.ok) {
|
|
1082
|
+
const errorData = await response.json().catch(() => ({}));
|
|
1083
|
+
throw new ApiError(errorData.error || "Failed to issue token", response.status);
|
|
1084
|
+
}
|
|
1085
|
+
const tokens = await response.json();
|
|
1086
|
+
if (!tokens?.access_token || !tokens?.refresh_token || typeof tokens?.expires_at !== "number") {
|
|
1087
|
+
throw new ApiError("Invalid token response", response.status);
|
|
1088
|
+
}
|
|
1089
|
+
this.applyTokens(tokens.access_token, tokens.refresh_token, false);
|
|
1090
|
+
return tokens;
|
|
1091
|
+
}
|
|
1092
|
+
/**
|
|
1093
|
+
* Get the current access/refresh tokens.
|
|
1094
|
+
*/
|
|
1095
|
+
getTokens() {
|
|
1096
|
+
return { accessToken: this.accessToken, refreshToken: this.refreshToken };
|
|
1097
|
+
}
|
|
1098
|
+
/**
|
|
1099
|
+
* Update the access/refresh tokens in memory.
|
|
1100
|
+
*/
|
|
1101
|
+
setTokens(tokens) {
|
|
1102
|
+
if (tokens.accessToken !== void 0) {
|
|
1103
|
+
this.accessToken = tokens.accessToken;
|
|
1104
|
+
}
|
|
1105
|
+
if (tokens.refreshToken !== void 0) {
|
|
1106
|
+
this.refreshToken = tokens.refreshToken;
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
/**
|
|
1110
|
+
* Start streaming speech-to-text transcription via WebSocket
|
|
1111
|
+
*/
|
|
1112
|
+
async streamingTranscription(options = {}) {
|
|
1113
|
+
const baseUrl = this.config.baseUrl;
|
|
1114
|
+
const wsUrl = baseUrl.replace("http://", "ws://").replace("https://", "wss://") + "/voice/stream";
|
|
1115
|
+
return new Promise((resolve, reject) => {
|
|
1116
|
+
const ws = new WebSocket(wsUrl);
|
|
1117
|
+
let isResolved = false;
|
|
1118
|
+
ws.onopen = () => {
|
|
1119
|
+
ws.send(JSON.stringify({ type: "start_session" }));
|
|
1120
|
+
options.onStart?.();
|
|
1121
|
+
if (!isResolved) {
|
|
1122
|
+
isResolved = true;
|
|
1123
|
+
resolve({
|
|
1124
|
+
sendAudio: (audioData) => {
|
|
1125
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
1126
|
+
ws.send(audioData);
|
|
1127
|
+
}
|
|
1128
|
+
},
|
|
1129
|
+
sendText: (text) => {
|
|
1130
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
1131
|
+
ws.send(JSON.stringify({ type: "text_chunk", text }));
|
|
1132
|
+
}
|
|
1133
|
+
},
|
|
1134
|
+
stop: () => {
|
|
1135
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
1136
|
+
ws.send(JSON.stringify({ type: "end_session" }));
|
|
1137
|
+
}
|
|
1138
|
+
},
|
|
1139
|
+
close: () => {
|
|
1140
|
+
ws.close();
|
|
1141
|
+
}
|
|
1142
|
+
});
|
|
1143
|
+
}
|
|
1144
|
+
};
|
|
1145
|
+
ws.onmessage = (event) => {
|
|
1146
|
+
try {
|
|
1147
|
+
const data = JSON.parse(event.data);
|
|
1148
|
+
switch (data.type) {
|
|
1149
|
+
case "text_chunk":
|
|
1150
|
+
options.onTranscript?.(data.text || "", data.is_final || false);
|
|
1151
|
+
break;
|
|
1152
|
+
case "session_started":
|
|
1153
|
+
this.debug("Speech-to-text session started");
|
|
1154
|
+
break;
|
|
1155
|
+
case "session_ended":
|
|
1156
|
+
this.debug("Speech-to-text session ended");
|
|
1157
|
+
options.onEnd?.();
|
|
1158
|
+
break;
|
|
1159
|
+
case "error": {
|
|
1160
|
+
const error = new Error(data.message || "WebSocket error");
|
|
1161
|
+
this.debug("Speech-to-text error:", error);
|
|
1162
|
+
options.onError?.(error);
|
|
1163
|
+
break;
|
|
1164
|
+
}
|
|
1165
|
+
default:
|
|
1166
|
+
this.debug("Unknown message type:", data.type);
|
|
1167
|
+
}
|
|
1168
|
+
} catch (error) {
|
|
1169
|
+
const parseError = new Error("Failed to parse WebSocket message");
|
|
1170
|
+
this.debug("Parse error:", parseError);
|
|
1171
|
+
options.onError?.(parseError);
|
|
1172
|
+
}
|
|
1173
|
+
};
|
|
1174
|
+
ws.onerror = (event) => {
|
|
1175
|
+
const error = new Error("WebSocket connection error");
|
|
1176
|
+
this.debug("WebSocket error:", event);
|
|
1177
|
+
options.onError?.(error);
|
|
1178
|
+
if (!isResolved) {
|
|
1179
|
+
isResolved = true;
|
|
1180
|
+
reject(error);
|
|
1181
|
+
}
|
|
1182
|
+
};
|
|
1183
|
+
ws.onclose = (event) => {
|
|
1184
|
+
this.debug("WebSocket closed:", event.code, event.reason);
|
|
1185
|
+
options.onEnd?.();
|
|
1186
|
+
};
|
|
1187
|
+
});
|
|
1188
|
+
}
|
|
1189
|
+
/**
|
|
1190
|
+
* Transcribe audio blob to text using speech-to-text API
|
|
1191
|
+
*/
|
|
1192
|
+
async transcribe(audioBlob, config = {}) {
|
|
1193
|
+
try {
|
|
1194
|
+
const arrayBuffer = await audioBlob.arrayBuffer();
|
|
1195
|
+
const uint8Array = new Uint8Array(arrayBuffer);
|
|
1196
|
+
const base64String = btoa(String.fromCharCode(...uint8Array));
|
|
1197
|
+
const requestBody = {
|
|
1198
|
+
audio: base64String,
|
|
1199
|
+
model: config.model || "whisper-1",
|
|
1200
|
+
...config.language && { language: config.language },
|
|
1201
|
+
...config.temperature !== void 0 && { temperature: config.temperature }
|
|
1202
|
+
};
|
|
1203
|
+
this.debug("Transcribing audio:", {
|
|
1204
|
+
model: requestBody.model,
|
|
1205
|
+
language: config.language,
|
|
1206
|
+
audioSize: audioBlob.size
|
|
1207
|
+
});
|
|
1208
|
+
const response = await this.fetch(`/tts/transcribe`, {
|
|
1209
|
+
method: "POST",
|
|
1210
|
+
headers: {
|
|
1211
|
+
"Content-Type": "application/json",
|
|
1212
|
+
...this.config.headers
|
|
1213
|
+
},
|
|
1214
|
+
body: JSON.stringify(requestBody)
|
|
1215
|
+
});
|
|
1216
|
+
if (!response.ok) {
|
|
1217
|
+
const errorData = await response.json().catch(() => ({}));
|
|
1218
|
+
const errorMessage = errorData.error || `Transcription failed: ${response.status}`;
|
|
1219
|
+
throw new ApiError(errorMessage, response.status);
|
|
1220
|
+
}
|
|
1221
|
+
const result = await response.json();
|
|
1222
|
+
const transcription = result.text || "";
|
|
1223
|
+
this.debug("Transcription result:", { text: transcription });
|
|
1224
|
+
return transcription;
|
|
1225
|
+
} catch (error) {
|
|
1226
|
+
if (error instanceof ApiError) throw error;
|
|
1227
|
+
throw new DistriError("Failed to transcribe audio", "TRANSCRIPTION_ERROR", error);
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
async getConfiguration() {
|
|
1231
|
+
const response = await this.fetch(`/configuration`, {
|
|
1232
|
+
method: "GET",
|
|
1233
|
+
headers: {
|
|
1234
|
+
...this.config.headers
|
|
1235
|
+
}
|
|
1236
|
+
});
|
|
1237
|
+
if (!response.ok) {
|
|
1238
|
+
const errorData = await response.json().catch(() => ({}));
|
|
1239
|
+
throw new ApiError(errorData.error || "Failed to load configuration", response.status);
|
|
1240
|
+
}
|
|
1241
|
+
return response.json();
|
|
1242
|
+
}
|
|
1243
|
+
async updateConfiguration(configuration) {
|
|
1244
|
+
const response = await this.fetch(`/configuration`, {
|
|
1245
|
+
method: "PUT",
|
|
1246
|
+
headers: {
|
|
1247
|
+
"Content-Type": "application/json",
|
|
1248
|
+
...this.config.headers
|
|
1249
|
+
},
|
|
1250
|
+
body: JSON.stringify(configuration)
|
|
1251
|
+
});
|
|
1252
|
+
if (!response.ok) {
|
|
1253
|
+
const errorData = await response.json().catch(() => ({}));
|
|
1254
|
+
throw new ApiError(errorData.error || "Failed to update configuration", response.status);
|
|
1255
|
+
}
|
|
1256
|
+
return response.json();
|
|
1257
|
+
}
|
|
1258
|
+
/**
|
|
1259
|
+
* Minimal LLM helper that proxies to the Distri server using Distri messages.
|
|
1260
|
+
*/
|
|
1261
|
+
async llm(messages, tools = [], options) {
|
|
1262
|
+
const headers = { "Content-Type": "application/json" };
|
|
1263
|
+
const response = await this.fetch(`/llm/execute`, {
|
|
1264
|
+
method: "POST",
|
|
1265
|
+
headers,
|
|
1266
|
+
body: JSON.stringify({ messages, tools, ...options })
|
|
1267
|
+
});
|
|
1268
|
+
if (!response.ok) {
|
|
1269
|
+
const errorData = await response.json().catch(() => ({}));
|
|
1270
|
+
const message = errorData?.error || response.statusText || "LLM request failed";
|
|
1271
|
+
throw new ApiError(`LLM request failed: ${message}`, response.status);
|
|
1272
|
+
}
|
|
1273
|
+
return response.json();
|
|
555
1274
|
}
|
|
556
1275
|
/**
|
|
557
1276
|
* Get all available agents from the Distri server
|
|
@@ -608,14 +1327,18 @@ var DistriClient = class {
|
|
|
608
1327
|
* Get or create A2AClient for an agent
|
|
609
1328
|
*/
|
|
610
1329
|
getA2AClient(agentId) {
|
|
611
|
-
|
|
1330
|
+
const agentUrl = `${this.config.baseUrl}/agents/${agentId}`;
|
|
1331
|
+
const existing = this.agentClients.get(agentId);
|
|
1332
|
+
if (!existing || existing.url !== agentUrl) {
|
|
612
1333
|
const fetchFn = this.fetchAbsolute.bind(this);
|
|
613
|
-
const agentUrl = `${this.config.baseUrl}/agents/${agentId}`;
|
|
614
1334
|
const client = new A2AClient(agentUrl, fetchFn);
|
|
615
|
-
this.agentClients.set(agentId, client);
|
|
616
|
-
this.debug(
|
|
1335
|
+
this.agentClients.set(agentId, { url: agentUrl, client });
|
|
1336
|
+
this.debug(
|
|
1337
|
+
existing ? `Recreated A2AClient for agent ${agentId} with new URL ${agentUrl}` : `Created A2AClient for agent ${agentId} at ${agentUrl}`
|
|
1338
|
+
);
|
|
1339
|
+
return client;
|
|
617
1340
|
}
|
|
618
|
-
return
|
|
1341
|
+
return existing.client;
|
|
619
1342
|
}
|
|
620
1343
|
/**
|
|
621
1344
|
* Send a message to an agent
|
|
@@ -642,6 +1365,7 @@ var DistriClient = class {
|
|
|
642
1365
|
* Send a streaming message to an agent
|
|
643
1366
|
*/
|
|
644
1367
|
async *sendMessageStream(agentId, params) {
|
|
1368
|
+
console.log("sendMessageStream", agentId, params);
|
|
645
1369
|
try {
|
|
646
1370
|
const client = this.getA2AClient(agentId);
|
|
647
1371
|
yield* await client.sendMessageStream(params);
|
|
@@ -747,18 +1471,195 @@ var DistriClient = class {
|
|
|
747
1471
|
};
|
|
748
1472
|
await this.sendMessage(threadId, params);
|
|
749
1473
|
}
|
|
1474
|
+
/**
|
|
1475
|
+
* Complete an external tool call
|
|
1476
|
+
*/
|
|
1477
|
+
async completeTool(agentId, result) {
|
|
1478
|
+
try {
|
|
1479
|
+
const response = await this.fetch(`/agents/${agentId}/complete-tool`, {
|
|
1480
|
+
method: "POST",
|
|
1481
|
+
headers: {
|
|
1482
|
+
"Content-Type": "application/json",
|
|
1483
|
+
...this.config.headers
|
|
1484
|
+
},
|
|
1485
|
+
body: JSON.stringify({
|
|
1486
|
+
tool_call_id: result.tool_call_id,
|
|
1487
|
+
tool_response: result
|
|
1488
|
+
})
|
|
1489
|
+
});
|
|
1490
|
+
if (!response.ok) {
|
|
1491
|
+
throw new ApiError(`Failed to complete tool: ${response.statusText}`, response.status);
|
|
1492
|
+
}
|
|
1493
|
+
this.debug(`Tool completed: ${result.tool_name} (${result.tool_call_id}) for agent ${agentId}`);
|
|
1494
|
+
} catch (error) {
|
|
1495
|
+
if (error instanceof ApiError) throw error;
|
|
1496
|
+
throw new DistriError(`Failed to complete tool ${result.tool_name} (${result.tool_call_id}) for agent ${agentId}`, "COMPLETE_TOOL_ERROR", error);
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
/**
|
|
1500
|
+
* Complete an inline hook with a mutation payload.
|
|
1501
|
+
*/
|
|
1502
|
+
async completeInlineHook(hookId, mutation) {
|
|
1503
|
+
const response = await this.fetch(`/event/hooks`, {
|
|
1504
|
+
method: "POST",
|
|
1505
|
+
headers: {
|
|
1506
|
+
"Content-Type": "application/json",
|
|
1507
|
+
...this.config.headers
|
|
1508
|
+
},
|
|
1509
|
+
body: JSON.stringify({
|
|
1510
|
+
hook_id: hookId,
|
|
1511
|
+
mutation
|
|
1512
|
+
})
|
|
1513
|
+
});
|
|
1514
|
+
if (!response.ok) {
|
|
1515
|
+
throw new ApiError(`Failed to complete inline hook: ${response.statusText}`, response.status);
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
750
1518
|
/**
|
|
751
1519
|
* Get the base URL for making direct requests
|
|
752
1520
|
*/
|
|
753
1521
|
get baseUrl() {
|
|
754
1522
|
return this.config.baseUrl;
|
|
755
1523
|
}
|
|
1524
|
+
applyTokens(accessToken, refreshToken, notify) {
|
|
1525
|
+
this.accessToken = accessToken;
|
|
1526
|
+
this.refreshToken = refreshToken;
|
|
1527
|
+
if (notify && this.onTokenRefresh) {
|
|
1528
|
+
this.onTokenRefresh({ accessToken, refreshToken });
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
async ensureAccessToken() {
|
|
1532
|
+
if (!this.refreshToken) {
|
|
1533
|
+
return;
|
|
1534
|
+
}
|
|
1535
|
+
if (!this.accessToken || this.isTokenExpiring(this.accessToken)) {
|
|
1536
|
+
try {
|
|
1537
|
+
await this.refreshTokens();
|
|
1538
|
+
} catch (error) {
|
|
1539
|
+
this.debug("Token refresh failed:", error);
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
async refreshTokens() {
|
|
1544
|
+
if (!this.refreshToken) {
|
|
1545
|
+
return;
|
|
1546
|
+
}
|
|
1547
|
+
if (!this.refreshPromise) {
|
|
1548
|
+
this.refreshPromise = this.performTokenRefresh().finally(() => {
|
|
1549
|
+
this.refreshPromise = void 0;
|
|
1550
|
+
});
|
|
1551
|
+
}
|
|
1552
|
+
return this.refreshPromise;
|
|
1553
|
+
}
|
|
1554
|
+
async performTokenRefresh() {
|
|
1555
|
+
const response = await this.fetchAbsolute(
|
|
1556
|
+
`${this.config.baseUrl}/token`,
|
|
1557
|
+
{
|
|
1558
|
+
method: "POST",
|
|
1559
|
+
headers: {
|
|
1560
|
+
"Content-Type": "application/json",
|
|
1561
|
+
...this.config.headers
|
|
1562
|
+
},
|
|
1563
|
+
body: JSON.stringify({
|
|
1564
|
+
grant_type: "refresh_token",
|
|
1565
|
+
refresh_token: this.refreshToken
|
|
1566
|
+
})
|
|
1567
|
+
},
|
|
1568
|
+
{ skipAuth: true, retryOnAuth: false }
|
|
1569
|
+
);
|
|
1570
|
+
if (!response.ok) {
|
|
1571
|
+
const errorData = await response.json().catch(() => ({}));
|
|
1572
|
+
throw new ApiError(errorData.error || "Failed to refresh token", response.status);
|
|
1573
|
+
}
|
|
1574
|
+
const tokens = await response.json();
|
|
1575
|
+
if (!tokens?.access_token || !tokens?.refresh_token) {
|
|
1576
|
+
throw new ApiError("Invalid token response", response.status);
|
|
1577
|
+
}
|
|
1578
|
+
this.applyTokens(tokens.access_token, tokens.refresh_token, true);
|
|
1579
|
+
}
|
|
1580
|
+
isTokenExpiring(token) {
|
|
1581
|
+
const expiresAt = this.getTokenExpiry(token);
|
|
1582
|
+
if (!expiresAt) {
|
|
1583
|
+
return false;
|
|
1584
|
+
}
|
|
1585
|
+
return expiresAt <= Date.now() + this.tokenRefreshSkewMs;
|
|
1586
|
+
}
|
|
1587
|
+
getTokenExpiry(token) {
|
|
1588
|
+
const payload = this.decodeJwtPayload(token);
|
|
1589
|
+
const exp = payload?.exp;
|
|
1590
|
+
if (typeof exp !== "number") {
|
|
1591
|
+
return null;
|
|
1592
|
+
}
|
|
1593
|
+
return exp * 1e3;
|
|
1594
|
+
}
|
|
1595
|
+
decodeJwtPayload(token) {
|
|
1596
|
+
const parts = token.split(".");
|
|
1597
|
+
if (parts.length < 2) {
|
|
1598
|
+
return null;
|
|
1599
|
+
}
|
|
1600
|
+
const decoded = this.decodeBase64Url(parts[1]);
|
|
1601
|
+
if (!decoded) {
|
|
1602
|
+
return null;
|
|
1603
|
+
}
|
|
1604
|
+
try {
|
|
1605
|
+
return JSON.parse(decoded);
|
|
1606
|
+
} catch {
|
|
1607
|
+
return null;
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
decodeBase64Url(value) {
|
|
1611
|
+
const base64 = value.replace(/-/g, "+").replace(/_/g, "/");
|
|
1612
|
+
const padded = base64.padEnd(Math.ceil(base64.length / 4) * 4, "=");
|
|
1613
|
+
try {
|
|
1614
|
+
if (typeof atob === "function") {
|
|
1615
|
+
return atob(padded);
|
|
1616
|
+
}
|
|
1617
|
+
const buffer = globalThis.Buffer;
|
|
1618
|
+
if (typeof buffer !== "undefined") {
|
|
1619
|
+
return buffer.from(padded, "base64").toString("utf8");
|
|
1620
|
+
}
|
|
1621
|
+
} catch {
|
|
1622
|
+
return null;
|
|
1623
|
+
}
|
|
1624
|
+
return null;
|
|
1625
|
+
}
|
|
1626
|
+
applyAuthHeader(headers) {
|
|
1627
|
+
if (this.accessToken && !headers.has("authorization")) {
|
|
1628
|
+
headers.set("Authorization", `Bearer ${this.accessToken}`);
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
756
1631
|
/**
|
|
757
1632
|
* Enhanced fetch with retry logic
|
|
758
1633
|
*/
|
|
759
|
-
async fetchAbsolute(url, initialInit) {
|
|
1634
|
+
async fetchAbsolute(url, initialInit, options) {
|
|
1635
|
+
const { skipAuth = false, retryOnAuth = true } = options ?? {};
|
|
760
1636
|
const init = await this.config.interceptor(initialInit);
|
|
761
1637
|
let lastError;
|
|
1638
|
+
const headers = new Headers();
|
|
1639
|
+
const applyHeaders = (src) => {
|
|
1640
|
+
if (!src) return;
|
|
1641
|
+
if (src instanceof Headers) {
|
|
1642
|
+
src.forEach((value, key) => headers.set(key, value));
|
|
1643
|
+
} else if (Array.isArray(src)) {
|
|
1644
|
+
src.forEach(([key, value]) => headers.set(key, value));
|
|
1645
|
+
} else if (typeof src === "object") {
|
|
1646
|
+
Object.entries(src).forEach(([key, value]) => {
|
|
1647
|
+
if (typeof value === "string") {
|
|
1648
|
+
headers.set(key, value);
|
|
1649
|
+
}
|
|
1650
|
+
});
|
|
1651
|
+
}
|
|
1652
|
+
};
|
|
1653
|
+
applyHeaders(this.config.headers);
|
|
1654
|
+
applyHeaders(init?.headers);
|
|
1655
|
+
const hasBody = init?.body !== void 0 && !(init.body instanceof FormData) && !(init.body instanceof Blob);
|
|
1656
|
+
if (!headers.has("content-type") && hasBody) {
|
|
1657
|
+
headers.set("Content-Type", "application/json");
|
|
1658
|
+
}
|
|
1659
|
+
if (!skipAuth) {
|
|
1660
|
+
await this.ensureAccessToken();
|
|
1661
|
+
this.applyAuthHeader(headers);
|
|
1662
|
+
}
|
|
762
1663
|
for (let attempt = 0; attempt <= this.config.retryAttempts; attempt++) {
|
|
763
1664
|
try {
|
|
764
1665
|
const controller = new AbortController();
|
|
@@ -766,12 +1667,15 @@ var DistriClient = class {
|
|
|
766
1667
|
const response = await fetch(url, {
|
|
767
1668
|
...init,
|
|
768
1669
|
signal: controller.signal,
|
|
769
|
-
headers
|
|
770
|
-
...this.config.headers,
|
|
771
|
-
...init?.headers
|
|
772
|
-
}
|
|
1670
|
+
headers
|
|
773
1671
|
});
|
|
774
1672
|
clearTimeout(timeoutId);
|
|
1673
|
+
if (!skipAuth && retryOnAuth && response.status === 401 && this.refreshToken) {
|
|
1674
|
+
const refreshed = await this.refreshTokens().then(() => true).catch(() => false);
|
|
1675
|
+
if (refreshed) {
|
|
1676
|
+
return this.fetchAbsolute(url, initialInit, { skipAuth, retryOnAuth: false });
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
775
1679
|
return response;
|
|
776
1680
|
} catch (error) {
|
|
777
1681
|
lastError = error instanceof Error ? error : new Error(String(error));
|
|
@@ -826,7 +1730,7 @@ var DistriClient = class {
|
|
|
826
1730
|
id: id || uuidv4(),
|
|
827
1731
|
role,
|
|
828
1732
|
parts,
|
|
829
|
-
created_at
|
|
1733
|
+
created_at: created_at || (/* @__PURE__ */ new Date()).getTime()
|
|
830
1734
|
};
|
|
831
1735
|
}
|
|
832
1736
|
/**
|
|
@@ -856,6 +1760,25 @@ var DistriClient = class {
|
|
|
856
1760
|
};
|
|
857
1761
|
}
|
|
858
1762
|
};
|
|
1763
|
+
// ============================================================
|
|
1764
|
+
// Additional User Message Parts API
|
|
1765
|
+
// ============================================================
|
|
1766
|
+
// These methods allow external tools to append parts (text, images)
|
|
1767
|
+
// to the user message in the next agent iteration.
|
|
1768
|
+
// The parts are stored under the key "__additional_user_parts".
|
|
1769
|
+
_DistriClient.ADDITIONAL_PARTS_KEY = "__additional_user_parts";
|
|
1770
|
+
// ============================================================
|
|
1771
|
+
// Token API
|
|
1772
|
+
// ============================================================
|
|
1773
|
+
// Issue access + refresh tokens for temporary authentication (e.g., frontend use)
|
|
1774
|
+
/**
|
|
1775
|
+
* Response from the token endpoint
|
|
1776
|
+
*/
|
|
1777
|
+
_DistriClient.TokenType = {
|
|
1778
|
+
Main: "main",
|
|
1779
|
+
Short: "short"
|
|
1780
|
+
};
|
|
1781
|
+
var DistriClient = _DistriClient;
|
|
859
1782
|
function uuidv4() {
|
|
860
1783
|
if (typeof crypto?.randomUUID === "function") {
|
|
861
1784
|
return crypto.randomUUID();
|
|
@@ -870,42 +1793,32 @@ function uuidv4() {
|
|
|
870
1793
|
}
|
|
871
1794
|
|
|
872
1795
|
// src/agent.ts
|
|
1796
|
+
var ExternalToolValidationError = class extends DistriError {
|
|
1797
|
+
constructor(agentName, result) {
|
|
1798
|
+
super(
|
|
1799
|
+
result.message || "Missing required external tools for agent invocation.",
|
|
1800
|
+
"EXTERNAL_TOOL_VALIDATION_ERROR",
|
|
1801
|
+
{
|
|
1802
|
+
agentName,
|
|
1803
|
+
missingTools: result.missingTools,
|
|
1804
|
+
requiredTools: result.requiredTools,
|
|
1805
|
+
providedTools: result.providedTools
|
|
1806
|
+
}
|
|
1807
|
+
);
|
|
1808
|
+
this.name = "ExternalToolValidationError";
|
|
1809
|
+
this.agentName = agentName;
|
|
1810
|
+
this.missingTools = result.missingTools;
|
|
1811
|
+
this.requiredTools = result.requiredTools;
|
|
1812
|
+
this.providedTools = result.providedTools;
|
|
1813
|
+
}
|
|
1814
|
+
};
|
|
873
1815
|
var Agent = class _Agent {
|
|
874
1816
|
constructor(agentDefinition, client) {
|
|
875
|
-
this.
|
|
1817
|
+
this.hookHandlers = /* @__PURE__ */ new Map();
|
|
1818
|
+
this.defaultHookHandler = null;
|
|
876
1819
|
this.agentDefinition = agentDefinition;
|
|
877
1820
|
this.client = client;
|
|
878
1821
|
}
|
|
879
|
-
/**
|
|
880
|
-
* Add a tool to the agent (AG-UI style)
|
|
881
|
-
*/
|
|
882
|
-
registerTool(tool) {
|
|
883
|
-
this.tools.set(tool.name, tool);
|
|
884
|
-
}
|
|
885
|
-
/**
|
|
886
|
-
* Add multiple tools at once
|
|
887
|
-
*/
|
|
888
|
-
registerTools(tools) {
|
|
889
|
-
tools.forEach((tool) => this.registerTool(tool));
|
|
890
|
-
}
|
|
891
|
-
/**
|
|
892
|
-
* Remove a tool
|
|
893
|
-
*/
|
|
894
|
-
unregisterTool(toolName) {
|
|
895
|
-
this.tools.delete(toolName);
|
|
896
|
-
}
|
|
897
|
-
/**
|
|
898
|
-
* Get all registered tools
|
|
899
|
-
*/
|
|
900
|
-
getTools() {
|
|
901
|
-
return Array.from(this.tools.values());
|
|
902
|
-
}
|
|
903
|
-
/**
|
|
904
|
-
* Check if a tool is registered
|
|
905
|
-
*/
|
|
906
|
-
hasTool(toolName) {
|
|
907
|
-
return this.tools.has(toolName);
|
|
908
|
-
}
|
|
909
1822
|
/**
|
|
910
1823
|
* Get agent information
|
|
911
1824
|
*/
|
|
@@ -918,9 +1831,18 @@ var Agent = class _Agent {
|
|
|
918
1831
|
get description() {
|
|
919
1832
|
return this.agentDefinition.description;
|
|
920
1833
|
}
|
|
1834
|
+
get agentType() {
|
|
1835
|
+
return this.agentDefinition.agent_type ?? this.agentDefinition.agentType;
|
|
1836
|
+
}
|
|
921
1837
|
get iconUrl() {
|
|
922
1838
|
return this.agentDefinition.icon_url;
|
|
923
1839
|
}
|
|
1840
|
+
/**
|
|
1841
|
+
* Get the full agent definition (including backend tools)
|
|
1842
|
+
*/
|
|
1843
|
+
getDefinition() {
|
|
1844
|
+
return this.agentDefinition;
|
|
1845
|
+
}
|
|
924
1846
|
/**
|
|
925
1847
|
* Fetch messages for a thread (public method for useChat)
|
|
926
1848
|
*/
|
|
@@ -930,56 +1852,153 @@ var Agent = class _Agent {
|
|
|
930
1852
|
/**
|
|
931
1853
|
* Direct (non-streaming) invoke
|
|
932
1854
|
*/
|
|
933
|
-
async invoke(params) {
|
|
934
|
-
|
|
935
|
-
|
|
1855
|
+
async invoke(params, tools, hooks) {
|
|
1856
|
+
if (hooks) {
|
|
1857
|
+
this.registerHooks(hooks);
|
|
1858
|
+
}
|
|
1859
|
+
const enhancedParams = this.enhanceParamsWithTools(params, tools);
|
|
936
1860
|
return await this.client.sendMessage(this.agentDefinition.id, enhancedParams);
|
|
937
1861
|
}
|
|
938
1862
|
/**
|
|
939
1863
|
* Streaming invoke
|
|
940
1864
|
*/
|
|
941
|
-
async invokeStream(params) {
|
|
942
|
-
|
|
943
|
-
|
|
1865
|
+
async invokeStream(params, tools, hooks) {
|
|
1866
|
+
if (hooks) {
|
|
1867
|
+
this.registerHooks(hooks);
|
|
1868
|
+
}
|
|
1869
|
+
const enhancedParams = this.enhanceParamsWithTools(params, tools);
|
|
944
1870
|
const a2aStream = this.client.sendMessageStream(this.agentDefinition.id, enhancedParams);
|
|
945
|
-
|
|
1871
|
+
const self = this;
|
|
1872
|
+
return (async function* () {
|
|
946
1873
|
for await (const event of a2aStream) {
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
1874
|
+
const converted = decodeA2AStreamEvent(event);
|
|
1875
|
+
if (converted && converted.type === "inline_hook_requested") {
|
|
1876
|
+
const hookReq = converted.data;
|
|
1877
|
+
const handler = self.hookHandlers.get(hookReq.hook) || self.defaultHookHandler;
|
|
1878
|
+
if (handler) {
|
|
1879
|
+
try {
|
|
1880
|
+
const mutation = await handler(hookReq);
|
|
1881
|
+
await self.client.completeInlineHook(hookReq.hook_id, mutation);
|
|
1882
|
+
} catch (err) {
|
|
1883
|
+
await self.client.completeInlineHook(hookReq.hook_id, { dynamic_values: {} });
|
|
1884
|
+
}
|
|
1885
|
+
} else {
|
|
1886
|
+
await self.client.completeInlineHook(hookReq.hook_id, { dynamic_values: {} });
|
|
1887
|
+
}
|
|
1888
|
+
yield converted;
|
|
1889
|
+
} else if (converted) {
|
|
1890
|
+
yield converted;
|
|
955
1891
|
}
|
|
956
1892
|
}
|
|
957
|
-
}();
|
|
1893
|
+
})();
|
|
1894
|
+
}
|
|
1895
|
+
/**
|
|
1896
|
+
* Validate that required external tools are registered before invoking.
|
|
1897
|
+
*/
|
|
1898
|
+
validateExternalTools(tools = []) {
|
|
1899
|
+
const requiredTools = this.getRequiredExternalTools();
|
|
1900
|
+
const providedTools = tools.map((tool) => tool.name);
|
|
1901
|
+
if (requiredTools.length === 0) {
|
|
1902
|
+
return {
|
|
1903
|
+
isValid: true,
|
|
1904
|
+
requiredTools: [],
|
|
1905
|
+
providedTools,
|
|
1906
|
+
missingTools: []
|
|
1907
|
+
};
|
|
1908
|
+
}
|
|
1909
|
+
const providedSet = new Set(providedTools);
|
|
1910
|
+
const missingTools = requiredTools.filter((tool) => !providedSet.has(tool));
|
|
1911
|
+
const isValid = missingTools.length === 0;
|
|
1912
|
+
return {
|
|
1913
|
+
isValid,
|
|
1914
|
+
requiredTools,
|
|
1915
|
+
providedTools,
|
|
1916
|
+
missingTools,
|
|
1917
|
+
message: isValid ? void 0 : this.formatExternalToolValidationMessage(requiredTools, missingTools)
|
|
1918
|
+
};
|
|
958
1919
|
}
|
|
959
1920
|
/**
|
|
960
1921
|
* Enhance message params with tool definitions
|
|
961
1922
|
*/
|
|
962
|
-
enhanceParamsWithTools(params) {
|
|
963
|
-
|
|
1923
|
+
enhanceParamsWithTools(params, tools) {
|
|
1924
|
+
this.assertExternalTools(tools);
|
|
1925
|
+
const metadata = {
|
|
1926
|
+
...params.metadata,
|
|
1927
|
+
external_tools: tools?.map((tool) => ({
|
|
1928
|
+
name: tool.name,
|
|
1929
|
+
description: tool.description,
|
|
1930
|
+
parameters: tool.parameters,
|
|
1931
|
+
is_final: tool.is_final
|
|
1932
|
+
})) || []
|
|
1933
|
+
};
|
|
964
1934
|
return {
|
|
965
1935
|
...params,
|
|
966
|
-
metadata
|
|
967
|
-
...params.metadata,
|
|
968
|
-
tools: tools.map((tool) => ({
|
|
969
|
-
name: tool.name,
|
|
970
|
-
description: tool.description,
|
|
971
|
-
input_schema: tool.input_schema
|
|
972
|
-
}))
|
|
973
|
-
}
|
|
1936
|
+
metadata
|
|
974
1937
|
};
|
|
975
1938
|
}
|
|
1939
|
+
assertExternalTools(tools) {
|
|
1940
|
+
const result = this.validateExternalTools(tools ?? []);
|
|
1941
|
+
if (!result.isValid) {
|
|
1942
|
+
throw new ExternalToolValidationError(this.agentDefinition.name || this.agentDefinition.id, result);
|
|
1943
|
+
}
|
|
1944
|
+
}
|
|
1945
|
+
getRequiredExternalTools() {
|
|
1946
|
+
const toolConfig = this.resolveToolConfig();
|
|
1947
|
+
if (!toolConfig?.external || !Array.isArray(toolConfig.external)) {
|
|
1948
|
+
return [];
|
|
1949
|
+
}
|
|
1950
|
+
return toolConfig.external.filter((tool) => typeof tool === "string" && tool.trim().length > 0);
|
|
1951
|
+
}
|
|
1952
|
+
resolveToolConfig() {
|
|
1953
|
+
const root = this.agentDefinition;
|
|
1954
|
+
return this.extractToolConfig(root) || this.extractToolConfig(root?.agent) || this.extractToolConfig(root?.definition);
|
|
1955
|
+
}
|
|
1956
|
+
extractToolConfig(candidate) {
|
|
1957
|
+
if (!candidate) return null;
|
|
1958
|
+
const tools = candidate.tools;
|
|
1959
|
+
if (!tools || Array.isArray(tools) || typeof tools !== "object") {
|
|
1960
|
+
return null;
|
|
1961
|
+
}
|
|
1962
|
+
return tools;
|
|
1963
|
+
}
|
|
1964
|
+
formatExternalToolValidationMessage(requiredTools, missingTools) {
|
|
1965
|
+
const requiredList = requiredTools.join(", ");
|
|
1966
|
+
const missingList = missingTools.join(", ");
|
|
1967
|
+
return `Agent has external tools that are not registered: ${missingList}. This is an embedded agent that can run within the parent application. Register DistriWidget for embedding the parent component. Required tools: ${requiredList}.`;
|
|
1968
|
+
}
|
|
1969
|
+
/**
|
|
1970
|
+
* Register multiple hooks at once.
|
|
1971
|
+
*/
|
|
1972
|
+
registerHooks(hooks, defaultHandler) {
|
|
1973
|
+
Object.entries(hooks).forEach(([hook, handler]) => {
|
|
1974
|
+
this.hookHandlers.set(hook, handler);
|
|
1975
|
+
});
|
|
1976
|
+
if (defaultHandler) {
|
|
1977
|
+
this.defaultHookHandler = defaultHandler;
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
976
1980
|
/**
|
|
977
1981
|
* Create an agent instance from an agent ID
|
|
978
1982
|
*/
|
|
979
|
-
static async create(
|
|
980
|
-
const agentDefinition = await client.getAgent(
|
|
1983
|
+
static async create(agentIdOrDef, client) {
|
|
1984
|
+
const agentDefinition = typeof agentIdOrDef === "string" ? await client.getAgent(agentIdOrDef) : agentIdOrDef;
|
|
1985
|
+
console.log("\u{1F916} Agent definition loaded:", {
|
|
1986
|
+
id: agentDefinition.id,
|
|
1987
|
+
name: agentDefinition.name,
|
|
1988
|
+
tools: agentDefinition.tools?.map((t) => ({
|
|
1989
|
+
name: t.name,
|
|
1990
|
+
type: t.type || "function"
|
|
1991
|
+
})) || [],
|
|
1992
|
+
toolCount: agentDefinition.tools?.length || 0
|
|
1993
|
+
});
|
|
981
1994
|
return new _Agent(agentDefinition, client);
|
|
982
1995
|
}
|
|
1996
|
+
/**
|
|
1997
|
+
* Complete an external tool call by sending the result back to the server
|
|
1998
|
+
*/
|
|
1999
|
+
async completeTool(result) {
|
|
2000
|
+
await this.client.completeTool(this.agentDefinition.id, result);
|
|
2001
|
+
}
|
|
983
2002
|
/**
|
|
984
2003
|
* List all available agents
|
|
985
2004
|
*/
|
|
@@ -990,17 +2009,31 @@ var Agent = class _Agent {
|
|
|
990
2009
|
};
|
|
991
2010
|
// Annotate the CommonJS export names for ESM import in node:
|
|
992
2011
|
0 && (module.exports = {
|
|
2012
|
+
A2AProtocolError,
|
|
993
2013
|
Agent,
|
|
2014
|
+
ApiError,
|
|
2015
|
+
ConnectionError,
|
|
2016
|
+
DEFAULT_BASE_URL,
|
|
994
2017
|
DistriClient,
|
|
2018
|
+
DistriError,
|
|
2019
|
+
ExternalToolValidationError,
|
|
995
2020
|
convertA2AMessageToDistri,
|
|
996
2021
|
convertA2APartToDistri,
|
|
2022
|
+
convertA2AStatusUpdateToDistri,
|
|
997
2023
|
convertDistriMessageToA2A,
|
|
998
2024
|
convertDistriPartToA2A,
|
|
2025
|
+
createFailedToolResult,
|
|
2026
|
+
createSuccessfulToolResult,
|
|
2027
|
+
decodeA2AStreamEvent,
|
|
999
2028
|
extractTextFromDistriMessage,
|
|
1000
2029
|
extractToolCallsFromDistriMessage,
|
|
2030
|
+
extractToolResultData,
|
|
1001
2031
|
extractToolResultsFromDistriMessage,
|
|
2032
|
+
isArrayParts,
|
|
1002
2033
|
isDistriEvent,
|
|
1003
2034
|
isDistriMessage,
|
|
2035
|
+
processA2AMessagesData,
|
|
2036
|
+
processA2AStreamData,
|
|
1004
2037
|
uuidv4
|
|
1005
2038
|
});
|
|
1006
2039
|
//# sourceMappingURL=index.js.map
|