@agent-native/core 0.118.1 → 0.119.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/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +11 -0
- package/corpus/core/docs/content/a2a-protocol.mdx +15 -0
- package/corpus/core/docs/content/template-chat.mdx +1 -1
- package/corpus/core/docs/content/template-plan.mdx +3 -3
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/a2a/activity.ts +371 -0
- package/corpus/core/src/a2a/client.ts +3 -1
- package/corpus/core/src/a2a/index.ts +21 -0
- package/corpus/core/src/a2a/types.ts +8 -0
- package/corpus/core/src/agent/model-config.ts +19 -23
- package/corpus/core/src/agent/production-agent.ts +167 -100
- package/corpus/core/src/agent/types.ts +16 -1
- package/corpus/core/src/client/chat/tool-call-display.tsx +190 -35
- package/corpus/core/src/client/chat-model-groups.ts +67 -27
- package/corpus/core/src/client/sharing/ShareButton.tsx +1 -27
- package/corpus/core/src/client/sharing/ShareDialog.tsx +0 -16
- package/corpus/core/src/client/sharing/useShareButtonController.ts +0 -7
- package/corpus/core/src/client/sharing/useShareDialogController.ts +0 -2
- package/corpus/core/src/client/sse-event-processor.ts +85 -1
- package/corpus/core/src/localization/default-messages.ts +6 -0
- package/corpus/core/src/scripts/agent-engines/list-agent-engines.ts +1 -18
- package/corpus/core/src/scripts/call-agent.ts +49 -6
- package/corpus/core/src/server/agent-chat-plugin.ts +50 -10
- package/corpus/core/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +16 -0
- package/corpus/templates/clips/changelog/2026-07-23-fixed-recordings-failing-to-save-with-a-cancelled-or-cleanup.md +6 -0
- package/corpus/templates/clips/server/plugins/db.ts +9 -1
- package/dist/a2a/activity.d.ts +50 -0
- package/dist/a2a/activity.d.ts.map +1 -0
- package/dist/a2a/activity.js +236 -0
- package/dist/a2a/activity.js.map +1 -0
- package/dist/a2a/client.d.ts +2 -0
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +1 -1
- package/dist/a2a/client.js.map +1 -1
- package/dist/a2a/index.d.ts +2 -1
- package/dist/a2a/index.d.ts.map +1 -1
- package/dist/a2a/index.js +1 -0
- package/dist/a2a/index.js.map +1 -1
- package/dist/a2a/types.d.ts +1 -0
- package/dist/a2a/types.d.ts.map +1 -1
- package/dist/a2a/types.js.map +1 -1
- package/dist/agent/engine/anthropic-engine.d.ts +1 -1
- package/dist/agent/engine/builder-engine.d.ts +2 -2
- package/dist/agent/engine/builder-engine.d.ts.map +1 -1
- package/dist/agent/model-config.d.ts +16 -16
- package/dist/agent/model-config.d.ts.map +1 -1
- package/dist/agent/model-config.js +19 -23
- package/dist/agent/model-config.js.map +1 -1
- package/dist/agent/production-agent.d.ts +26 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +137 -80
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/types.d.ts +10 -0
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/client/chat/tool-call-display.d.ts.map +1 -1
- package/dist/client/chat/tool-call-display.js +63 -14
- package/dist/client/chat/tool-call-display.js.map +1 -1
- package/dist/client/chat-model-groups.d.ts.map +1 -1
- package/dist/client/chat-model-groups.js +44 -21
- package/dist/client/chat-model-groups.js.map +1 -1
- package/dist/client/sharing/ShareButton.d.ts +1 -1
- package/dist/client/sharing/ShareButton.d.ts.map +1 -1
- package/dist/client/sharing/ShareButton.js +3 -4
- package/dist/client/sharing/ShareButton.js.map +1 -1
- package/dist/client/sharing/ShareDialog.d.ts.map +1 -1
- package/dist/client/sharing/ShareDialog.js +1 -2
- package/dist/client/sharing/ShareDialog.js.map +1 -1
- package/dist/client/sharing/useShareButtonController.d.ts +0 -1
- package/dist/client/sharing/useShareButtonController.d.ts.map +1 -1
- package/dist/client/sharing/useShareButtonController.js +0 -6
- package/dist/client/sharing/useShareButtonController.js.map +1 -1
- package/dist/client/sharing/useShareDialogController.d.ts +0 -1
- package/dist/client/sharing/useShareDialogController.d.ts.map +1 -1
- package/dist/client/sharing/useShareDialogController.js +0 -1
- package/dist/client/sharing/useShareDialogController.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts +12 -0
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +63 -1
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/localization/default-messages.d.ts +6 -0
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +6 -0
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/routes.d.ts +1 -1
- package/dist/scripts/agent-engines/list-agent-engines.d.ts.map +1 -1
- package/dist/scripts/agent-engines/list-agent-engines.js +1 -18
- package/dist/scripts/agent-engines/list-agent-engines.js.map +1 -1
- package/dist/scripts/call-agent.d.ts.map +1 -1
- package/dist/scripts/call-agent.js +49 -6
- package/dist/scripts/call-agent.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +38 -10
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +16 -0
- package/docs/content/a2a-protocol.mdx +15 -0
- package/docs/content/template-chat.mdx +1 -1
- package/docs/content/template-plan.mdx +3 -3
- package/package.json +1 -1
- package/src/a2a/activity.ts +371 -0
- package/src/a2a/client.ts +3 -1
- package/src/a2a/index.ts +21 -0
- package/src/a2a/types.ts +8 -0
- package/src/agent/model-config.ts +19 -23
- package/src/agent/production-agent.ts +167 -100
- package/src/agent/types.ts +16 -1
- package/src/client/chat/tool-call-display.tsx +190 -35
- package/src/client/chat-model-groups.ts +67 -27
- package/src/client/sharing/ShareButton.tsx +1 -27
- package/src/client/sharing/ShareDialog.tsx +0 -16
- package/src/client/sharing/useShareButtonController.ts +0 -7
- package/src/client/sharing/useShareDialogController.ts +0 -2
- package/src/client/sse-event-processor.ts +85 -1
- package/src/localization/default-messages.ts +6 -0
- package/src/scripts/agent-engines/list-agent-engines.ts +1 -18
- package/src/scripts/call-agent.ts +49 -6
- package/src/server/agent-chat-plugin.ts +50 -10
- package/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +16 -0
- package/corpus/core/src/observability/hosted-model-experiment.ts +0 -118
- package/dist/observability/hosted-model-experiment.d.ts +0 -39
- package/dist/observability/hosted-model-experiment.d.ts.map +0 -1
- package/dist/observability/hosted-model-experiment.js +0 -90
- package/dist/observability/hosted-model-experiment.js.map +0 -1
- package/src/observability/hosted-model-experiment.ts +0 -118
|
@@ -40,34 +40,64 @@ function addCurrentModel(
|
|
|
40
40
|
return next;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
const MODEL_COST_ORDER = [
|
|
44
|
+
"luna",
|
|
45
|
+
"terra",
|
|
46
|
+
"sol",
|
|
47
|
+
"haiku",
|
|
48
|
+
"sonnet",
|
|
49
|
+
"opus",
|
|
50
|
+
"fable",
|
|
51
|
+
"flash",
|
|
52
|
+
"pro",
|
|
53
|
+
] as const;
|
|
54
|
+
|
|
55
|
+
function modelCostRank(model: string): number {
|
|
56
|
+
const normalized = model.toLowerCase();
|
|
57
|
+
const rank = MODEL_COST_ORDER.findIndex((tier) => normalized.includes(tier));
|
|
58
|
+
return rank === -1 ? MODEL_COST_ORDER.length : rank;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function sortModelsByCost(models: readonly string[]): string[] {
|
|
62
|
+
return [...models].sort((a, b) => modelCostRank(a) - modelCostRank(b));
|
|
63
|
+
}
|
|
64
|
+
|
|
43
65
|
function groupBuilderModels(models: readonly string[]): EngineModelGroup[] {
|
|
44
|
-
const claude =
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
-
(model) =>
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
66
|
+
const claude = sortModelsByCost(
|
|
67
|
+
models.filter((model) => model.startsWith("claude-")),
|
|
68
|
+
);
|
|
69
|
+
const openai = sortModelsByCost(
|
|
70
|
+
models.filter((model) => model.startsWith("gpt-")),
|
|
71
|
+
);
|
|
72
|
+
const gemini = sortModelsByCost(
|
|
73
|
+
models.filter((model) => model.startsWith("gemini-")),
|
|
74
|
+
);
|
|
75
|
+
const other = sortModelsByCost(
|
|
76
|
+
models.filter(
|
|
77
|
+
(model) =>
|
|
78
|
+
!model.startsWith("claude-") &&
|
|
79
|
+
!model.startsWith("gpt-") &&
|
|
80
|
+
!model.startsWith("gemini-"),
|
|
81
|
+
),
|
|
52
82
|
);
|
|
53
83
|
|
|
54
84
|
return [
|
|
55
|
-
...(
|
|
85
|
+
...(openai.length
|
|
56
86
|
? [
|
|
57
87
|
{
|
|
58
88
|
engine: "builder",
|
|
59
|
-
label: "
|
|
60
|
-
models:
|
|
89
|
+
label: "OpenAI",
|
|
90
|
+
models: openai,
|
|
61
91
|
configured: true,
|
|
62
92
|
},
|
|
63
93
|
]
|
|
64
94
|
: []),
|
|
65
|
-
...(
|
|
95
|
+
...(claude.length
|
|
66
96
|
? [
|
|
67
97
|
{
|
|
68
98
|
engine: "builder",
|
|
69
|
-
label: "
|
|
70
|
-
models:
|
|
99
|
+
label: "Claude",
|
|
100
|
+
models: claude,
|
|
71
101
|
configured: true,
|
|
72
102
|
},
|
|
73
103
|
]
|
|
@@ -115,16 +145,24 @@ function shouldShowDirectEngine(
|
|
|
115
145
|
return true;
|
|
116
146
|
}
|
|
117
147
|
|
|
118
|
-
function
|
|
148
|
+
function modelPickerEngineRank(engine: ChatModelEngineEntry): number {
|
|
149
|
+
if (engine.name === "ai-sdk:openai" || engine.label === "OpenAI") return 0;
|
|
150
|
+
if (
|
|
151
|
+
engine.name === "anthropic" ||
|
|
152
|
+
engine.name === "ai-sdk:anthropic" ||
|
|
153
|
+
engine.label === "Claude"
|
|
154
|
+
) {
|
|
155
|
+
return 1;
|
|
156
|
+
}
|
|
157
|
+
if (engine.name === "ai-sdk:openrouter") return 100;
|
|
158
|
+
return 2;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function sortModelPickerEngines(
|
|
119
162
|
a: ChatModelEngineEntry,
|
|
120
163
|
b: ChatModelEngineEntry,
|
|
121
164
|
): number {
|
|
122
|
-
|
|
123
|
-
const bIsOpenRouter = b.name === "ai-sdk:openrouter";
|
|
124
|
-
if (aIsOpenRouter === bIsOpenRouter) return 0;
|
|
125
|
-
if (aIsOpenRouter) return 1;
|
|
126
|
-
if (bIsOpenRouter) return -1;
|
|
127
|
-
return 0;
|
|
165
|
+
return modelPickerEngineRank(a) - modelPickerEngineRank(b);
|
|
128
166
|
}
|
|
129
167
|
|
|
130
168
|
export function buildChatModelGroups({
|
|
@@ -150,17 +188,19 @@ export function buildChatModelGroups({
|
|
|
150
188
|
return engines
|
|
151
189
|
.filter((engine) => engine.packageInstalled !== false)
|
|
152
190
|
.filter((engine) => shouldShowDirectEngine(engine, currentEngineName))
|
|
153
|
-
.sort(
|
|
191
|
+
.sort(sortModelPickerEngines)
|
|
154
192
|
.map((engine) => {
|
|
155
193
|
const requiredEnvVars = engine.requiredEnvVars ?? [];
|
|
156
194
|
return {
|
|
157
195
|
engine: engine.name,
|
|
158
196
|
label: engine.label,
|
|
159
|
-
models:
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
197
|
+
models: sortModelsByCost(
|
|
198
|
+
addCurrentModel(
|
|
199
|
+
engine.supportedModels ?? [],
|
|
200
|
+
engine.name,
|
|
201
|
+
currentEngineName,
|
|
202
|
+
currentModel,
|
|
203
|
+
),
|
|
164
204
|
),
|
|
165
205
|
configured:
|
|
166
206
|
requiredEnvVars.length === 0 ||
|
|
@@ -77,7 +77,7 @@ export interface ShareButtonProps {
|
|
|
77
77
|
shareUrlPlacement?: "top" | "bottom";
|
|
78
78
|
/** Whether to render copyable share URL fields. Defaults to true. */
|
|
79
79
|
showShareLinks?: boolean;
|
|
80
|
-
/**
|
|
80
|
+
/** @deprecated The Done action was removed; share popovers dismiss directly. */
|
|
81
81
|
showDoneButton?: boolean;
|
|
82
82
|
/** Optional placeholder shown in the share-URL slot when `shareUrl` is
|
|
83
83
|
* undefined. Use this to explain *why* there's no link yet (e.g. "Publish
|
|
@@ -301,7 +301,6 @@ function SharePanel(
|
|
|
301
301
|
const {
|
|
302
302
|
inviteEmail,
|
|
303
303
|
setInviteEmail: onInviteEmailChange,
|
|
304
|
-
handleOpenChange,
|
|
305
304
|
activeShareTab,
|
|
306
305
|
handleShareTabChange,
|
|
307
306
|
data,
|
|
@@ -326,7 +325,6 @@ function SharePanel(
|
|
|
326
325
|
handleAdd,
|
|
327
326
|
handleChangeRole,
|
|
328
327
|
handleRemove,
|
|
329
|
-
handleDone,
|
|
330
328
|
} = controller;
|
|
331
329
|
const hasInviteEmail = inviteEmail.trim().length > 0;
|
|
332
330
|
|
|
@@ -367,7 +365,6 @@ function SharePanel(
|
|
|
367
365
|
(Boolean(props.shareUrl) ||
|
|
368
366
|
Boolean(props.shareUrlPlaceholder) ||
|
|
369
367
|
Boolean(props.secondaryShareUrl));
|
|
370
|
-
const showDoneButton = props.showDoneButton ?? true;
|
|
371
368
|
const shareUrlPlacement = props.shareUrlPlacement ?? "bottom";
|
|
372
369
|
const extraTabs = props.shareTabs?.tabs ?? [];
|
|
373
370
|
const hasTabs = extraTabs.length > 0;
|
|
@@ -392,17 +389,6 @@ function SharePanel(
|
|
|
392
389
|
<div className="mb-4 h-7 rounded-md bg-muted animate-pulse" />
|
|
393
390
|
<div className="mb-2 text-sm font-semibold">{generalAccessLabel}</div>
|
|
394
391
|
<div className="mb-4 h-9 rounded-md bg-muted animate-pulse" />
|
|
395
|
-
{showDoneButton ? (
|
|
396
|
-
<div className="mt-2 flex justify-end">
|
|
397
|
-
<button
|
|
398
|
-
type="button"
|
|
399
|
-
onClick={() => handleOpenChange(false)}
|
|
400
|
-
className={BUTTON_PRIMARY_SM}
|
|
401
|
-
>
|
|
402
|
-
Done
|
|
403
|
-
</button>
|
|
404
|
-
</div>
|
|
405
|
-
) : null}
|
|
406
392
|
</div>
|
|
407
393
|
) : (
|
|
408
394
|
<div>
|
|
@@ -579,18 +565,6 @@ function SharePanel(
|
|
|
579
565
|
{showShareLinks && shareUrlPlacement === "bottom" ? shareLinks : null}
|
|
580
566
|
|
|
581
567
|
{props.shareFooterContent}
|
|
582
|
-
|
|
583
|
-
{showDoneButton ? (
|
|
584
|
-
<div className="mt-2 flex justify-end">
|
|
585
|
-
<button
|
|
586
|
-
type="button"
|
|
587
|
-
onClick={handleDone}
|
|
588
|
-
className={BUTTON_PRIMARY_SM}
|
|
589
|
-
>
|
|
590
|
-
Done
|
|
591
|
-
</button>
|
|
592
|
-
</div>
|
|
593
|
-
) : null}
|
|
594
568
|
</div>
|
|
595
569
|
);
|
|
596
570
|
|
|
@@ -61,10 +61,6 @@ const BUTTON_OUTLINE_SM = cn(
|
|
|
61
61
|
BUTTON_BASE,
|
|
62
62
|
"!h-9 !px-3 border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
|
63
63
|
);
|
|
64
|
-
const BUTTON_PRIMARY_SM = cn(
|
|
65
|
-
BUTTON_BASE,
|
|
66
|
-
"!h-9 !px-4 bg-primary text-primary-foreground hover:bg-primary/90",
|
|
67
|
-
);
|
|
68
64
|
const BUTTON_GHOST_ICON = cn(
|
|
69
65
|
BUTTON_BASE,
|
|
70
66
|
"!h-8 !w-8 !p-0 text-muted-foreground hover:bg-accent hover:text-accent-foreground",
|
|
@@ -171,18 +167,6 @@ export function ShareDialog({
|
|
|
171
167
|
? (embedTabContent ?? <DefaultEmbedBody controller={controller} />)
|
|
172
168
|
: null}
|
|
173
169
|
</div>
|
|
174
|
-
|
|
175
|
-
<div className="flex justify-end border-t border-border px-5 py-3">
|
|
176
|
-
<ActionButton
|
|
177
|
-
type="button"
|
|
178
|
-
intent="primary"
|
|
179
|
-
emphasis="solid"
|
|
180
|
-
onPress={controller.close}
|
|
181
|
-
className={BUTTON_PRIMARY_SM}
|
|
182
|
-
>
|
|
183
|
-
{controller.labels.done}
|
|
184
|
-
</ActionButton>
|
|
185
|
-
</div>
|
|
186
170
|
</DesignSystemDialog>
|
|
187
171
|
);
|
|
188
172
|
}
|
|
@@ -105,7 +105,6 @@ export interface ShareButtonController {
|
|
|
105
105
|
handleAdd: () => void;
|
|
106
106
|
handleChangeRole: (share: ShareButtonShare, role: ShareButtonRole) => void;
|
|
107
107
|
handleRemove: (share: ShareButtonShare) => void;
|
|
108
|
-
handleDone: () => void;
|
|
109
108
|
}
|
|
110
109
|
|
|
111
110
|
export function useShareButtonController(
|
|
@@ -547,11 +546,6 @@ export function useShareButtonController(
|
|
|
547
546
|
],
|
|
548
547
|
);
|
|
549
548
|
|
|
550
|
-
const handleDone = useCallback(() => {
|
|
551
|
-
if (canManage && inviteEmail.trim()) handleAdd();
|
|
552
|
-
handleOpenChange(false);
|
|
553
|
-
}, [canManage, handleAdd, handleOpenChange, inviteEmail]);
|
|
554
|
-
|
|
555
549
|
return {
|
|
556
550
|
open,
|
|
557
551
|
handleOpenChange,
|
|
@@ -585,7 +579,6 @@ export function useShareButtonController(
|
|
|
585
579
|
handleAdd,
|
|
586
580
|
handleChangeRole,
|
|
587
581
|
handleRemove,
|
|
588
|
-
handleDone,
|
|
589
582
|
};
|
|
590
583
|
}
|
|
591
584
|
|
|
@@ -71,7 +71,6 @@ export interface ShareDialogController {
|
|
|
71
71
|
tabs: Array<{ value: ShareDialogTab; label: string }>;
|
|
72
72
|
labels: {
|
|
73
73
|
close: string;
|
|
74
|
-
done: string;
|
|
75
74
|
shareOptions: string;
|
|
76
75
|
generalAccess: string;
|
|
77
76
|
shareLink: string;
|
|
@@ -407,7 +406,6 @@ export function useShareDialogController({
|
|
|
407
406
|
],
|
|
408
407
|
labels: {
|
|
409
408
|
close: t("share.close"),
|
|
410
|
-
done: t("share.done"),
|
|
411
409
|
shareOptions: t("share.shareOptions"),
|
|
412
410
|
generalAccess: t("share.generalAccess"),
|
|
413
411
|
shareLink: t("share.shareLink"),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ChatModelRunResult } from "@assistant-ui/react";
|
|
2
2
|
|
|
3
|
+
import type { A2AAgentActivitySnapshot } from "../a2a/activity.js";
|
|
3
4
|
import type { ActionChatUIConfig } from "../action-ui.js";
|
|
4
5
|
import {
|
|
5
6
|
LLM_MISSING_CREDENTIALS_ERROR_CODE,
|
|
@@ -74,6 +75,12 @@ export interface SSEEvent {
|
|
|
74
75
|
seq?: number;
|
|
75
76
|
agent?: string;
|
|
76
77
|
status?: string;
|
|
78
|
+
state?: string;
|
|
79
|
+
elapsedSeconds?: number;
|
|
80
|
+
detail?: string;
|
|
81
|
+
agentCallId?: string;
|
|
82
|
+
durationMs?: number;
|
|
83
|
+
snapshot?: A2AAgentActivitySnapshot;
|
|
77
84
|
reason?: string;
|
|
78
85
|
// Agent task fields
|
|
79
86
|
taskId?: string;
|
|
@@ -100,6 +107,12 @@ export type AgentAutoContinueReason =
|
|
|
100
107
|
|
|
101
108
|
export type AgentActivityTrailEntry = { label: string; tool?: string };
|
|
102
109
|
|
|
110
|
+
export interface AgentCallProgress {
|
|
111
|
+
state: string;
|
|
112
|
+
elapsedSeconds: number;
|
|
113
|
+
detail?: string;
|
|
114
|
+
}
|
|
115
|
+
|
|
103
116
|
export interface AgentAutoContinueErrorInfo {
|
|
104
117
|
message: string;
|
|
105
118
|
details?: string;
|
|
@@ -1365,7 +1378,7 @@ export function processEvent(
|
|
|
1365
1378
|
if (ev.type === "agent_call") {
|
|
1366
1379
|
const agentName = ev.agent ?? "agent";
|
|
1367
1380
|
if (ev.status === "start") {
|
|
1368
|
-
const toolCallId = `tc_${++toolCallCounter.value}`;
|
|
1381
|
+
const toolCallId = ev.agentCallId ?? `tc_${++toolCallCounter.value}`;
|
|
1369
1382
|
content.push({
|
|
1370
1383
|
type: "tool-call",
|
|
1371
1384
|
toolCallId,
|
|
@@ -1380,9 +1393,16 @@ export function processEvent(
|
|
|
1380
1393
|
if (
|
|
1381
1394
|
part.type === "tool-call" &&
|
|
1382
1395
|
part.toolName === `agent:${agentName}` &&
|
|
1396
|
+
(!ev.agentCallId || part.toolCallId === ev.agentCallId) &&
|
|
1383
1397
|
part.result === undefined
|
|
1384
1398
|
) {
|
|
1385
1399
|
part.result = ev.status === "error" ? "Error calling agent" : "Done";
|
|
1400
|
+
part.structuredMeta = {
|
|
1401
|
+
...part.structuredMeta,
|
|
1402
|
+
...(ev.durationMs != null
|
|
1403
|
+
? { agentDurationMs: ev.durationMs }
|
|
1404
|
+
: {}),
|
|
1405
|
+
};
|
|
1386
1406
|
break;
|
|
1387
1407
|
}
|
|
1388
1408
|
}
|
|
@@ -1401,6 +1421,7 @@ export function processEvent(
|
|
|
1401
1421
|
if (
|
|
1402
1422
|
part.type === "tool-call" &&
|
|
1403
1423
|
part.toolName === `agent:${agentName}` &&
|
|
1424
|
+
(!ev.agentCallId || part.toolCallId === ev.agentCallId) &&
|
|
1404
1425
|
part.result === undefined
|
|
1405
1426
|
) {
|
|
1406
1427
|
part.argsText += ev.text ?? "";
|
|
@@ -1413,6 +1434,69 @@ export function processEvent(
|
|
|
1413
1434
|
};
|
|
1414
1435
|
}
|
|
1415
1436
|
|
|
1437
|
+
if (ev.type === "agent_call_progress") {
|
|
1438
|
+
const agentName = ev.agent ?? "agent";
|
|
1439
|
+
if (typeof ev.state !== "string") {
|
|
1440
|
+
return { action: "continue" };
|
|
1441
|
+
}
|
|
1442
|
+
const elapsedSeconds =
|
|
1443
|
+
typeof ev.elapsedSeconds === "number" &&
|
|
1444
|
+
Number.isFinite(ev.elapsedSeconds) &&
|
|
1445
|
+
ev.elapsedSeconds >= 0
|
|
1446
|
+
? ev.elapsedSeconds
|
|
1447
|
+
: 0;
|
|
1448
|
+
for (let i = content.length - 1; i >= 0; i--) {
|
|
1449
|
+
const part = content[i];
|
|
1450
|
+
if (
|
|
1451
|
+
part.type === "tool-call" &&
|
|
1452
|
+
part.toolName === `agent:${agentName}` &&
|
|
1453
|
+
(!ev.agentCallId || part.toolCallId === ev.agentCallId) &&
|
|
1454
|
+
part.result === undefined
|
|
1455
|
+
) {
|
|
1456
|
+
part.structuredMeta = {
|
|
1457
|
+
...part.structuredMeta,
|
|
1458
|
+
agentProgress: {
|
|
1459
|
+
state: ev.state,
|
|
1460
|
+
elapsedSeconds,
|
|
1461
|
+
...(ev.detail ? { detail: ev.detail } : {}),
|
|
1462
|
+
} satisfies AgentCallProgress,
|
|
1463
|
+
};
|
|
1464
|
+
break;
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
return {
|
|
1468
|
+
action: "yield",
|
|
1469
|
+
result: { content: contentSnapshot(content) } as ChatModelRunResult,
|
|
1470
|
+
};
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
if (ev.type === "agent_call_activity" && ev.snapshot) {
|
|
1474
|
+
const agentName = ev.agent ?? "agent";
|
|
1475
|
+
for (let i = content.length - 1; i >= 0; i--) {
|
|
1476
|
+
const part = content[i];
|
|
1477
|
+
if (
|
|
1478
|
+
part.type === "tool-call" &&
|
|
1479
|
+
part.toolName === `agent:${agentName}` &&
|
|
1480
|
+
(!ev.agentCallId || part.toolCallId === ev.agentCallId)
|
|
1481
|
+
) {
|
|
1482
|
+
const previous = part.structuredMeta?.agentActivity as
|
|
1483
|
+
| A2AAgentActivitySnapshot
|
|
1484
|
+
| undefined;
|
|
1485
|
+
if (!previous || ev.snapshot.sequence >= previous.sequence) {
|
|
1486
|
+
part.structuredMeta = {
|
|
1487
|
+
...part.structuredMeta,
|
|
1488
|
+
agentActivity: ev.snapshot,
|
|
1489
|
+
};
|
|
1490
|
+
}
|
|
1491
|
+
break;
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
return {
|
|
1495
|
+
action: "yield",
|
|
1496
|
+
result: { content: contentSnapshot(content) } as ChatModelRunResult,
|
|
1497
|
+
};
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1416
1500
|
// ─── Agent task events (sub-agent chips) ─────────────────────────
|
|
1417
1501
|
// These events are dispatched as CustomEvents so AgentTaskCard components
|
|
1418
1502
|
// can listen for updates to their specific taskId.
|
|
@@ -337,6 +337,12 @@ const messages = {
|
|
|
337
337
|
configureProviderKeys: "Configure Anthropic, OpenAI, or another provider",
|
|
338
338
|
checkingAiConnection: "Checking AI connection...",
|
|
339
339
|
connectionUnavailable: "Unable to check AI connection. Click to retry.",
|
|
340
|
+
delegatedAgent: {
|
|
341
|
+
asking: "Asking {{name}}...",
|
|
342
|
+
asked: "Asked {{name}}",
|
|
343
|
+
error: "Error asking {{name}}",
|
|
344
|
+
elapsed: "{{duration}} elapsed",
|
|
345
|
+
},
|
|
340
346
|
voiceMode: {
|
|
341
347
|
entryButtonLabel: "Use microphone",
|
|
342
348
|
promptTitle: "Use your voice",
|
|
@@ -15,8 +15,6 @@ import {
|
|
|
15
15
|
normalizeModelForEngine,
|
|
16
16
|
} from "../../agent/engine/index.js";
|
|
17
17
|
import type { ActionTool } from "../../agent/types.js";
|
|
18
|
-
import { resolveHostedDefaultModelExperiment } from "../../observability/hosted-model-experiment.js";
|
|
19
|
-
import { getRequestUserEmail } from "../../server/request-context.js";
|
|
20
18
|
import { getSetting } from "../../settings/index.js";
|
|
21
19
|
|
|
22
20
|
export const tool: ActionTool = {
|
|
@@ -91,15 +89,6 @@ export async function run(args: Record<string, string> = {}): Promise<string> {
|
|
|
91
89
|
currentModelCandidate ?? currentEntry.defaultModel,
|
|
92
90
|
)
|
|
93
91
|
: (currentModelCandidate ?? DEFAULT_MODEL);
|
|
94
|
-
const hostedExperiment = currentEntry
|
|
95
|
-
? resolveHostedDefaultModelExperiment({
|
|
96
|
-
userId: getRequestUserEmail(),
|
|
97
|
-
engineName: currentEntry.name,
|
|
98
|
-
isDefaultModelSelection: currentModelCandidate == null,
|
|
99
|
-
supportedModels: currentEntry.supportedModels,
|
|
100
|
-
})
|
|
101
|
-
: null;
|
|
102
|
-
const effectiveCurrentModel = hostedExperiment?.model ?? currentModel;
|
|
103
92
|
const result = {
|
|
104
93
|
engines: engines.map((e) => ({
|
|
105
94
|
name: e.name,
|
|
@@ -116,13 +105,7 @@ export async function run(args: Record<string, string> = {}): Promise<string> {
|
|
|
116
105
|
? null
|
|
117
106
|
: {
|
|
118
107
|
engine: currentEngineName,
|
|
119
|
-
model:
|
|
120
|
-
...(hostedExperiment
|
|
121
|
-
? {
|
|
122
|
-
modelSelectionSource: "experiment",
|
|
123
|
-
experimentAssignments: [hostedExperiment.assignment],
|
|
124
|
-
}
|
|
125
|
-
: {}),
|
|
108
|
+
model: currentModel,
|
|
126
109
|
},
|
|
127
110
|
};
|
|
128
111
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
2
|
|
|
3
|
+
import { parseA2AAgentActivityPart } from "../a2a/activity.js";
|
|
3
4
|
import {
|
|
4
5
|
A2ATaskTimeoutError,
|
|
5
6
|
callAgent,
|
|
@@ -271,8 +272,15 @@ export async function run(
|
|
|
271
272
|
: undefined;
|
|
272
273
|
|
|
273
274
|
if (action) {
|
|
275
|
+
const agentCallId = randomUUID();
|
|
276
|
+
const startedAt = Date.now();
|
|
274
277
|
if (context?.send) {
|
|
275
|
-
context.send({
|
|
278
|
+
context.send({
|
|
279
|
+
type: "agent_call",
|
|
280
|
+
agent: agent.name,
|
|
281
|
+
status: "start",
|
|
282
|
+
agentCallId,
|
|
283
|
+
});
|
|
276
284
|
}
|
|
277
285
|
try {
|
|
278
286
|
const output = await invokeReadOnlyAppAction(
|
|
@@ -281,10 +289,24 @@ export async function run(
|
|
|
281
289
|
input as Record<string, unknown>,
|
|
282
290
|
buildDelegationCorrelation(context, selfAppId, randomUUID()),
|
|
283
291
|
);
|
|
292
|
+
if (context?.send && output) {
|
|
293
|
+
context.send({
|
|
294
|
+
type: "agent_call_text",
|
|
295
|
+
agent: agent.name,
|
|
296
|
+
text: output,
|
|
297
|
+
agentCallId,
|
|
298
|
+
});
|
|
299
|
+
}
|
|
284
300
|
return output;
|
|
285
301
|
} finally {
|
|
286
302
|
if (context?.send) {
|
|
287
|
-
context.send({
|
|
303
|
+
context.send({
|
|
304
|
+
type: "agent_call",
|
|
305
|
+
agent: agent.name,
|
|
306
|
+
status: "done",
|
|
307
|
+
agentCallId,
|
|
308
|
+
durationMs: Date.now() - startedAt,
|
|
309
|
+
});
|
|
288
310
|
}
|
|
289
311
|
}
|
|
290
312
|
}
|
|
@@ -363,6 +385,7 @@ export async function run(
|
|
|
363
385
|
|
|
364
386
|
let responseText = "";
|
|
365
387
|
let lastSentLength = 0;
|
|
388
|
+
const agentCallId = randomUUID();
|
|
366
389
|
const existingContinuationText = taskId
|
|
367
390
|
? null
|
|
368
391
|
: await formatExistingIntegrationContinuationIfRetry(agent, message);
|
|
@@ -372,6 +395,7 @@ export async function run(
|
|
|
372
395
|
type: "agent_call",
|
|
373
396
|
agent: agent.name,
|
|
374
397
|
status: "start",
|
|
398
|
+
agentCallId,
|
|
375
399
|
});
|
|
376
400
|
|
|
377
401
|
const emitNewText = (newText: string) => {
|
|
@@ -380,6 +404,7 @@ export async function run(
|
|
|
380
404
|
type: "agent_call_text",
|
|
381
405
|
agent: agent.name,
|
|
382
406
|
text: newText.slice(lastSentLength),
|
|
407
|
+
agentCallId,
|
|
383
408
|
});
|
|
384
409
|
lastSentLength = newText.length;
|
|
385
410
|
}
|
|
@@ -395,9 +420,10 @@ export async function run(
|
|
|
395
420
|
// time we get to the sync fallback, Lambda is dead and the second fetch
|
|
396
421
|
// errors out as "fetch failed". Async+poll has its own short fetches
|
|
397
422
|
// with their own budgets, so it works reliably across hosts. The
|
|
398
|
-
// trade-off is
|
|
399
|
-
//
|
|
400
|
-
//
|
|
423
|
+
// trade-off is that cross-app activity arrives at the poll cadence rather
|
|
424
|
+
// than token-by-token. Agent Native peers attach their current reasoning,
|
|
425
|
+
// tool status, and response preview to each task checkpoint, and the
|
|
426
|
+
// receiver's full response still surfaces below.
|
|
401
427
|
//
|
|
402
428
|
// That trade-off has a second-order cost: callAgent()'s poll (see
|
|
403
429
|
// A2AClient.sendAndWait in a2a/client.ts) can legitimately run for
|
|
@@ -450,8 +476,22 @@ export async function run(
|
|
|
450
476
|
]);
|
|
451
477
|
const callStartedAt = Date.now();
|
|
452
478
|
let lastProgressEmitAt = callStartedAt;
|
|
479
|
+
let lastActivitySequence = -1;
|
|
453
480
|
const onRemotePollUpdate = (task: Task) => {
|
|
454
481
|
const state = task?.status?.state;
|
|
482
|
+
const parts = task.status?.message?.parts;
|
|
483
|
+
const snapshot = Array.isArray(parts)
|
|
484
|
+
? parts.map(parseA2AAgentActivityPart).find((value) => value !== null)
|
|
485
|
+
: undefined;
|
|
486
|
+
if (snapshot && snapshot.sequence > lastActivitySequence) {
|
|
487
|
+
lastActivitySequence = snapshot.sequence;
|
|
488
|
+
context.send!({
|
|
489
|
+
type: "agent_call_activity",
|
|
490
|
+
agent: agent.name,
|
|
491
|
+
agentCallId,
|
|
492
|
+
snapshot,
|
|
493
|
+
});
|
|
494
|
+
}
|
|
455
495
|
if (!state || !ACTIVELY_WORKING_STATES.has(state)) return;
|
|
456
496
|
const now = Date.now();
|
|
457
497
|
if (now - lastProgressEmitAt < PROGRESS_MIN_INTERVAL_MS) return;
|
|
@@ -462,6 +502,7 @@ export async function run(
|
|
|
462
502
|
agent: agent.name,
|
|
463
503
|
state,
|
|
464
504
|
elapsedSeconds: Math.round((now - callStartedAt) / 1000),
|
|
505
|
+
agentCallId,
|
|
465
506
|
...(detail ? { detail } : {}),
|
|
466
507
|
});
|
|
467
508
|
};
|
|
@@ -549,6 +590,8 @@ export async function run(
|
|
|
549
590
|
type: "agent_call",
|
|
550
591
|
agent: agent.name,
|
|
551
592
|
status: "done",
|
|
593
|
+
agentCallId,
|
|
594
|
+
durationMs: Date.now() - callStartedAt,
|
|
552
595
|
});
|
|
553
596
|
|
|
554
597
|
return responseText || "(empty response)";
|
|
@@ -718,7 +761,7 @@ async function enqueueIntegrationContinuationIfPossible(
|
|
|
718
761
|
const MAX_PROGRESS_DETAIL_CHARS = 200;
|
|
719
762
|
function extractRemoteProgressDetail(task: Task): string | undefined {
|
|
720
763
|
const parts = task.status?.message?.parts;
|
|
721
|
-
if (!parts) return undefined;
|
|
764
|
+
if (!Array.isArray(parts)) return undefined;
|
|
722
765
|
const text = parts
|
|
723
766
|
.filter((p): p is { type: "text"; text: string } => p.type === "text")
|
|
724
767
|
.map((p) => p.text)
|