@agent-native/core 0.118.1 → 0.119.1
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 +2 -2
- package/corpus/core/CHANGELOG.md +19 -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/ingestion/figma-node-to-html.ts +20 -99
- package/corpus/core/src/ingestion/figma-paint-math.ts +371 -0
- package/corpus/core/src/ingestion/index.ts +20 -0
- 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/assets/app/routes/library.tsx +17 -9
- 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/corpus/templates/design/AGENTS.md +18 -5
- package/corpus/templates/design/FIGMA_INTEROPERABILITY.md +25 -12
- package/corpus/templates/design/actions/hydrate-figma-paste-images.ts +115 -0
- package/corpus/templates/design/actions/import-figma-clipboard.ts +83 -18
- package/corpus/templates/design/actions/import-figma-frame.ts +34 -21
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +28 -1
- package/corpus/templates/design/app/components/design/DesignImportPanel.tsx +106 -11
- package/corpus/templates/design/app/components/design/FigmaHydrationDialog.tsx +273 -0
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +7 -7
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +57 -9
- package/corpus/templates/design/app/components/design/design-canvas/iframe-events.ts +10 -0
- package/corpus/templates/design/app/components/design/multi-screen/board-surface-html.ts +8 -1
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +3 -0
- package/corpus/templates/design/app/i18n-data.ts +150 -2
- package/corpus/templates/design/app/lib/design-file-upload.ts +85 -0
- package/corpus/templates/design/app/lib/design-import.ts +19 -1
- package/corpus/templates/design/app/lib/figma-clipboard.ts +110 -10
- package/corpus/templates/design/changelog/2026-07-20-paste-figma-frames-directly-onto-the-canvas-no-token-needed.md +6 -0
- package/corpus/templates/design/changelog/2026-07-21-fig-upload-frame-url-and-rate-limit-errors.md +5 -0
- package/corpus/templates/design/changelog/2026-07-22-connecting-a-figma-token-now-actually-fills-in-a-pasted-desi.md +6 -0
- package/corpus/templates/design/changelog/2026-07-22-figma-line-arrow-vectors-and-stroked-icons-now-render-instea.md +6 -0
- package/corpus/templates/design/changelog/2026-07-22-fill-a-no-token-figma-paste-s-images-by-dropping-the-origina.md +6 -0
- package/corpus/templates/design/changelog/2026-07-22-imported-and-pasted-figma-frames-now-render-faithfully-fixed.md +6 -0
- package/corpus/templates/design/server/handlers/import-design-file.ts +50 -0
- package/corpus/templates/design/server/lib/fig-file-decoder.ts +90 -49
- package/corpus/templates/design/server/lib/fig-file-import.ts +19 -5
- package/corpus/templates/design/server/lib/fig-file-to-html.ts +583 -78
- package/corpus/templates/design/server/lib/figma-clipboard-local-decode.ts +238 -0
- package/corpus/templates/design/server/lib/figma-image-hydration.ts +389 -0
- package/corpus/templates/design/server/lib/figma-node-import.ts +136 -36
- package/corpus/templates/design/server/register-secrets.ts +14 -2
- 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/routes.d.ts +1 -1
- package/dist/ingestion/figma-node-to-html.d.ts.map +1 -1
- package/dist/ingestion/figma-node-to-html.js +14 -88
- package/dist/ingestion/figma-node-to-html.js.map +1 -1
- package/dist/ingestion/figma-paint-math.d.ts +157 -0
- package/dist/ingestion/figma-paint-math.d.ts.map +1 -0
- package/dist/ingestion/figma-paint-math.js +274 -0
- package/dist/ingestion/figma-paint-math.js.map +1 -0
- package/dist/ingestion/index.d.ts +1 -0
- package/dist/ingestion/index.d.ts.map +1 -1
- package/dist/ingestion/index.js +1 -0
- package/dist/ingestion/index.js.map +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 +5 -5
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +12 -12
- package/dist/provider-api/actions/provider-api.d.ts +7 -7
- package/dist/resources/handlers.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/secrets/routes.d.ts +3 -3
- 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/server/realtime-token.d.ts +1 -1
- package/dist/server/transcribe-voice.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/ingestion/figma-node-to-html.ts +20 -99
- package/src/ingestion/figma-paint-math.ts +371 -0
- package/src/ingestion/index.ts +20 -0
- 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
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
|
|
1
3
|
import Ajv, { type ValidateFunction } from "ajv";
|
|
2
4
|
import {
|
|
3
5
|
defineEventHandler,
|
|
@@ -8,6 +10,8 @@ import {
|
|
|
8
10
|
} from "h3";
|
|
9
11
|
import type { EventHandler as H3EventHandler } from "h3";
|
|
10
12
|
|
|
13
|
+
import { parseA2AAgentActivityPart } from "../a2a/activity.js";
|
|
14
|
+
import type { Task } from "../a2a/types.js";
|
|
11
15
|
import {
|
|
12
16
|
isAgentActionStopError,
|
|
13
17
|
type ActionAutomationContext,
|
|
@@ -1725,6 +1729,159 @@ export async function resolveSkillReferenceContent(
|
|
|
1725
1729
|
}
|
|
1726
1730
|
}
|
|
1727
1731
|
|
|
1732
|
+
export function createConnectedAgentReferenceEventRelay(input: {
|
|
1733
|
+
agent: string;
|
|
1734
|
+
send: (event: AgentChatEvent) => void;
|
|
1735
|
+
agentCallId?: string;
|
|
1736
|
+
now?: () => number;
|
|
1737
|
+
}) {
|
|
1738
|
+
const agentCallId = input.agentCallId ?? randomUUID();
|
|
1739
|
+
const now = input.now ?? Date.now;
|
|
1740
|
+
const startedAt = now();
|
|
1741
|
+
let lastActivitySequence = -1;
|
|
1742
|
+
let hasRichActivity = false;
|
|
1743
|
+
|
|
1744
|
+
const emitResponseText = (text: string) => {
|
|
1745
|
+
if (text) {
|
|
1746
|
+
input.send({
|
|
1747
|
+
type: "agent_call_text",
|
|
1748
|
+
agent: input.agent,
|
|
1749
|
+
text,
|
|
1750
|
+
agentCallId,
|
|
1751
|
+
});
|
|
1752
|
+
}
|
|
1753
|
+
};
|
|
1754
|
+
const observeActivity = (task: Task) => {
|
|
1755
|
+
const parts = task.status?.message?.parts;
|
|
1756
|
+
const snapshot = Array.isArray(parts)
|
|
1757
|
+
? parts.map(parseA2AAgentActivityPart).find((value) => value !== null)
|
|
1758
|
+
: undefined;
|
|
1759
|
+
if (snapshot) {
|
|
1760
|
+
hasRichActivity = true;
|
|
1761
|
+
}
|
|
1762
|
+
if (snapshot && snapshot.sequence > lastActivitySequence) {
|
|
1763
|
+
lastActivitySequence = snapshot.sequence;
|
|
1764
|
+
input.send({
|
|
1765
|
+
type: "agent_call_activity",
|
|
1766
|
+
agent: input.agent,
|
|
1767
|
+
agentCallId,
|
|
1768
|
+
snapshot,
|
|
1769
|
+
});
|
|
1770
|
+
}
|
|
1771
|
+
};
|
|
1772
|
+
const observePollUpdate = (task: Task) => {
|
|
1773
|
+
observeActivity(task);
|
|
1774
|
+
if (hasRichActivity) return;
|
|
1775
|
+
|
|
1776
|
+
const state = task.status?.state;
|
|
1777
|
+
if (
|
|
1778
|
+
state !== "submitted" &&
|
|
1779
|
+
state !== "working" &&
|
|
1780
|
+
state !== "processing"
|
|
1781
|
+
) {
|
|
1782
|
+
return;
|
|
1783
|
+
}
|
|
1784
|
+
const currentTime = now();
|
|
1785
|
+
const detail = extractConnectedAgentProgressDetail(task);
|
|
1786
|
+
input.send({
|
|
1787
|
+
type: "agent_call_progress",
|
|
1788
|
+
agent: input.agent,
|
|
1789
|
+
agentCallId,
|
|
1790
|
+
state,
|
|
1791
|
+
elapsedSeconds: Math.max(0, Math.round((currentTime - startedAt) / 1000)),
|
|
1792
|
+
...(detail ? { detail } : {}),
|
|
1793
|
+
});
|
|
1794
|
+
};
|
|
1795
|
+
|
|
1796
|
+
return {
|
|
1797
|
+
agentCallId,
|
|
1798
|
+
start() {
|
|
1799
|
+
input.send({
|
|
1800
|
+
type: "agent_call",
|
|
1801
|
+
agent: input.agent,
|
|
1802
|
+
status: "start",
|
|
1803
|
+
agentCallId,
|
|
1804
|
+
});
|
|
1805
|
+
},
|
|
1806
|
+
observeActivity,
|
|
1807
|
+
observePollUpdate,
|
|
1808
|
+
emitResponseText,
|
|
1809
|
+
finish(status: "done" | "error") {
|
|
1810
|
+
input.send({
|
|
1811
|
+
type: "agent_call",
|
|
1812
|
+
agent: input.agent,
|
|
1813
|
+
status,
|
|
1814
|
+
agentCallId,
|
|
1815
|
+
durationMs: Math.max(0, now() - startedAt),
|
|
1816
|
+
});
|
|
1817
|
+
},
|
|
1818
|
+
};
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1821
|
+
type ConnectedAgentCall = typeof import("../a2a/client.js").callAgent;
|
|
1822
|
+
type ResolveConnectedAgentCallerAuth =
|
|
1823
|
+
typeof import("../a2a/caller-auth.js").resolveA2ACallerAuth;
|
|
1824
|
+
|
|
1825
|
+
export async function callConnectedAgentReference(input: {
|
|
1826
|
+
agent: string;
|
|
1827
|
+
path: string;
|
|
1828
|
+
message: string;
|
|
1829
|
+
send: (event: AgentChatEvent) => void;
|
|
1830
|
+
callAgent: ConnectedAgentCall;
|
|
1831
|
+
resolveCallerAuth: ResolveConnectedAgentCallerAuth;
|
|
1832
|
+
agentCallId?: string;
|
|
1833
|
+
now?: () => number;
|
|
1834
|
+
}): Promise<string> {
|
|
1835
|
+
const relay = createConnectedAgentReferenceEventRelay({
|
|
1836
|
+
agent: input.agent,
|
|
1837
|
+
send: input.send,
|
|
1838
|
+
agentCallId: input.agentCallId,
|
|
1839
|
+
now: input.now,
|
|
1840
|
+
});
|
|
1841
|
+
relay.start();
|
|
1842
|
+
try {
|
|
1843
|
+
const callerAuth = await input.resolveCallerAuth({
|
|
1844
|
+
includeGoogleToken: true,
|
|
1845
|
+
});
|
|
1846
|
+
const response = await input.callAgent(input.path, input.message, {
|
|
1847
|
+
async: true,
|
|
1848
|
+
apiKey: callerAuth.apiKey,
|
|
1849
|
+
metadata: callerAuth.metadata,
|
|
1850
|
+
userEmail: callerAuth.userEmail,
|
|
1851
|
+
orgDomain: callerAuth.orgDomain,
|
|
1852
|
+
orgSecret: callerAuth.orgSecret,
|
|
1853
|
+
onUpdate: relay.observePollUpdate,
|
|
1854
|
+
});
|
|
1855
|
+
const responseText =
|
|
1856
|
+
userFacingLlmCredentialError(response, { agentName: input.agent }) ??
|
|
1857
|
+
response;
|
|
1858
|
+
relay.emitResponseText(responseText);
|
|
1859
|
+
relay.finish("done");
|
|
1860
|
+
return responseText;
|
|
1861
|
+
} catch (error) {
|
|
1862
|
+
relay.finish("error");
|
|
1863
|
+
throw error;
|
|
1864
|
+
}
|
|
1865
|
+
}
|
|
1866
|
+
|
|
1867
|
+
const MAX_CONNECTED_AGENT_PROGRESS_DETAIL_CHARS = 200;
|
|
1868
|
+
function extractConnectedAgentProgressDetail(task: Task): string | undefined {
|
|
1869
|
+
const parts = task.status?.message?.parts;
|
|
1870
|
+
if (!Array.isArray(parts)) return undefined;
|
|
1871
|
+
const text = parts
|
|
1872
|
+
.filter(
|
|
1873
|
+
(part): part is { type: "text"; text: string } => part.type === "text",
|
|
1874
|
+
)
|
|
1875
|
+
.map((part) => part.text)
|
|
1876
|
+
.join(" ")
|
|
1877
|
+
.replace(/\s+/g, " ")
|
|
1878
|
+
.trim();
|
|
1879
|
+
if (!text) return undefined;
|
|
1880
|
+
return text.length > MAX_CONNECTED_AGENT_PROGRESS_DETAIL_CHARS
|
|
1881
|
+
? `${text.slice(0, MAX_CONNECTED_AGENT_PROGRESS_DETAIL_CHARS - 1)}…`
|
|
1882
|
+
: text;
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1728
1885
|
async function enrichMessage(
|
|
1729
1886
|
message: string,
|
|
1730
1887
|
references: AgentChatReference[],
|
|
@@ -6700,22 +6857,6 @@ export function createProductionAgentHandler(
|
|
|
6700
6857
|
modelSelectionSource = "experiment";
|
|
6701
6858
|
}
|
|
6702
6859
|
}
|
|
6703
|
-
|
|
6704
|
-
if (modelSelectionSource === "default") {
|
|
6705
|
-
const { resolveHostedDefaultModelExperiment } =
|
|
6706
|
-
await import("../observability/hosted-model-experiment.js");
|
|
6707
|
-
const hostedExperiment = resolveHostedDefaultModelExperiment({
|
|
6708
|
-
userId: ownerEmail,
|
|
6709
|
-
engineName: engine.name,
|
|
6710
|
-
isDefaultModelSelection: true,
|
|
6711
|
-
supportedModels: engine.supportedModels,
|
|
6712
|
-
});
|
|
6713
|
-
if (hostedExperiment) {
|
|
6714
|
-
effectiveModel = hostedExperiment.model;
|
|
6715
|
-
experimentAssignments.push(hostedExperiment.assignment);
|
|
6716
|
-
modelSelectionSource = "experiment";
|
|
6717
|
-
}
|
|
6718
|
-
}
|
|
6719
6860
|
}
|
|
6720
6861
|
} catch {
|
|
6721
6862
|
// Experiments are best-effort. Model resolution must keep working if the
|
|
@@ -8015,97 +8156,23 @@ export function createProductionAgentHandler(
|
|
|
8015
8156
|
|
|
8016
8157
|
// Resolve connected agent @-mentions via A2A calls.
|
|
8017
8158
|
if (agentRefs.length > 0 && requestMode !== "plan") {
|
|
8018
|
-
const [{
|
|
8019
|
-
|
|
8020
|
-
|
|
8021
|
-
|
|
8022
|
-
]);
|
|
8159
|
+
const [{ callAgent }, { resolveA2ACallerAuth }] = await Promise.all([
|
|
8160
|
+
import("../a2a/client.js"),
|
|
8161
|
+
import("../a2a/caller-auth.js"),
|
|
8162
|
+
]);
|
|
8023
8163
|
const results = await Promise.allSettled(
|
|
8024
8164
|
agentRefs.map(async (ref) => {
|
|
8025
|
-
send({
|
|
8026
|
-
type: "agent_call",
|
|
8027
|
-
agent: ref.name,
|
|
8028
|
-
status: "start",
|
|
8029
|
-
});
|
|
8030
8165
|
try {
|
|
8031
|
-
const
|
|
8032
|
-
includeGoogleToken: true,
|
|
8033
|
-
});
|
|
8034
|
-
const a2aClient = new A2AClient(ref.path, callerAuth.apiKey, {
|
|
8035
|
-
...(callerAuth.apiKeyFallbacks
|
|
8036
|
-
? { fallbackApiKeys: callerAuth.apiKeyFallbacks }
|
|
8037
|
-
: {}),
|
|
8038
|
-
});
|
|
8039
|
-
const a2aMetadata = callerAuth.metadata;
|
|
8040
|
-
|
|
8041
|
-
let responseText = "";
|
|
8042
|
-
let lastSentLength = 0;
|
|
8043
|
-
|
|
8044
|
-
try {
|
|
8045
|
-
for await (const task of a2aClient.stream(
|
|
8046
|
-
{
|
|
8047
|
-
role: "user",
|
|
8048
|
-
parts: [
|
|
8049
|
-
{
|
|
8050
|
-
type: "text",
|
|
8051
|
-
text: enrichedMessage + screenContext,
|
|
8052
|
-
},
|
|
8053
|
-
],
|
|
8054
|
-
},
|
|
8055
|
-
Object.keys(a2aMetadata).length > 0
|
|
8056
|
-
? { metadata: a2aMetadata }
|
|
8057
|
-
: undefined,
|
|
8058
|
-
)) {
|
|
8059
|
-
const newText =
|
|
8060
|
-
task.status?.message?.parts
|
|
8061
|
-
?.filter(
|
|
8062
|
-
(p): p is { type: "text"; text: string } =>
|
|
8063
|
-
p.type === "text",
|
|
8064
|
-
)
|
|
8065
|
-
?.map((p) => p.text)
|
|
8066
|
-
?.join("") ?? "";
|
|
8067
|
-
|
|
8068
|
-
if (newText.length > lastSentLength) {
|
|
8069
|
-
send({
|
|
8070
|
-
type: "agent_call_text",
|
|
8071
|
-
agent: ref.name,
|
|
8072
|
-
text: newText.slice(lastSentLength),
|
|
8073
|
-
});
|
|
8074
|
-
lastSentLength = newText.length;
|
|
8075
|
-
}
|
|
8076
|
-
responseText = newText;
|
|
8077
|
-
}
|
|
8078
|
-
} catch {
|
|
8079
|
-
if (!responseText) {
|
|
8080
|
-
responseText = await callAgent(
|
|
8081
|
-
ref.path,
|
|
8082
|
-
enrichedMessage + screenContext,
|
|
8083
|
-
{
|
|
8084
|
-
apiKey: callerAuth.apiKey,
|
|
8085
|
-
userEmail: callerAuth.userEmail,
|
|
8086
|
-
orgDomain: callerAuth.orgDomain,
|
|
8087
|
-
orgSecret: callerAuth.orgSecret,
|
|
8088
|
-
},
|
|
8089
|
-
);
|
|
8090
|
-
}
|
|
8091
|
-
}
|
|
8092
|
-
responseText =
|
|
8093
|
-
userFacingLlmCredentialError(responseText, {
|
|
8094
|
-
agentName: ref.name,
|
|
8095
|
-
}) ?? responseText;
|
|
8096
|
-
|
|
8097
|
-
send({
|
|
8098
|
-
type: "agent_call",
|
|
8166
|
+
const responseText = await callConnectedAgentReference({
|
|
8099
8167
|
agent: ref.name,
|
|
8100
|
-
|
|
8168
|
+
path: ref.path,
|
|
8169
|
+
message: enrichedMessage + screenContext,
|
|
8170
|
+
send,
|
|
8171
|
+
callAgent,
|
|
8172
|
+
resolveCallerAuth: resolveA2ACallerAuth,
|
|
8101
8173
|
});
|
|
8102
8174
|
return `<agent-response name="${ref.name}" id="${ref.refId}">\n${responseText}\n</agent-response>`;
|
|
8103
8175
|
} catch (err: any) {
|
|
8104
|
-
send({
|
|
8105
|
-
type: "agent_call",
|
|
8106
|
-
agent: ref.name,
|
|
8107
|
-
status: "error",
|
|
8108
|
-
});
|
|
8109
8176
|
const message =
|
|
8110
8177
|
userFacingLlmCredentialError(err, {
|
|
8111
8178
|
agentName: ref.name,
|
package/src/agent/types.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { A2AAgentActivitySnapshot } from "../a2a/activity.js";
|
|
1
2
|
import type { ActionChatUIConfig } from "../action-ui.js";
|
|
2
3
|
import type { AgentMcpAppPayload } from "../mcp-client/app-result.js";
|
|
3
4
|
import type { ReasoningEffort } from "../shared/reasoning-effort.js";
|
|
@@ -273,6 +274,8 @@ export type AgentChatEvent =
|
|
|
273
274
|
type: "agent_call";
|
|
274
275
|
agent: string;
|
|
275
276
|
status: "start" | "done" | "error";
|
|
277
|
+
agentCallId?: string;
|
|
278
|
+
durationMs?: number;
|
|
276
279
|
}
|
|
277
280
|
| {
|
|
278
281
|
/**
|
|
@@ -296,8 +299,20 @@ export type AgentChatEvent =
|
|
|
296
299
|
elapsedSeconds: number;
|
|
297
300
|
/** Optional short text surfaced from the remote poll, when present. */
|
|
298
301
|
detail?: string;
|
|
302
|
+
agentCallId?: string;
|
|
303
|
+
}
|
|
304
|
+
| {
|
|
305
|
+
type: "agent_call_text";
|
|
306
|
+
agent: string;
|
|
307
|
+
text: string;
|
|
308
|
+
agentCallId?: string;
|
|
309
|
+
}
|
|
310
|
+
| {
|
|
311
|
+
type: "agent_call_activity";
|
|
312
|
+
agent: string;
|
|
313
|
+
snapshot: A2AAgentActivitySnapshot;
|
|
314
|
+
agentCallId?: string;
|
|
299
315
|
}
|
|
300
|
-
| { type: "agent_call_text"; agent: string; text: string }
|
|
301
316
|
| {
|
|
302
317
|
type: "agent_task";
|
|
303
318
|
taskId: string;
|
|
@@ -25,6 +25,7 @@ import React, {
|
|
|
25
25
|
useRef,
|
|
26
26
|
} from "react";
|
|
27
27
|
|
|
28
|
+
import type { A2AAgentActivitySnapshot } from "../../a2a/activity.js";
|
|
28
29
|
import type { ActionChatUIConfig } from "../../action-ui.js";
|
|
29
30
|
import type { AgentMcpAppPayload } from "../../mcp-client/app-result.js";
|
|
30
31
|
import { AgentTaskCard } from "../AgentTaskCard.js";
|
|
@@ -35,8 +36,9 @@ import {
|
|
|
35
36
|
PopoverTrigger,
|
|
36
37
|
} from "../components/ui/popover.js";
|
|
37
38
|
import { ConnectBuilderCard } from "../ConnectBuilderCard.js";
|
|
39
|
+
import { useT } from "../i18n.js";
|
|
38
40
|
import { McpAppRenderer } from "../mcp-apps/McpAppRenderer.js";
|
|
39
|
-
import type { ContentPart } from "../sse-event-processor.js";
|
|
41
|
+
import type { AgentCallProgress, ContentPart } from "../sse-event-processor.js";
|
|
40
42
|
import {
|
|
41
43
|
BashCell,
|
|
42
44
|
EditCell,
|
|
@@ -52,10 +54,6 @@ import { ActionChatUiSurface } from "./action-chat-ui-surface.js";
|
|
|
52
54
|
import {
|
|
53
55
|
SmoothMarkdownText,
|
|
54
56
|
HighlightedCodeBlock,
|
|
55
|
-
markdownComponents,
|
|
56
|
-
markdownModule,
|
|
57
|
-
remarkGfmFn,
|
|
58
|
-
markdownUrlTransform,
|
|
59
57
|
useSmoothStreamingText,
|
|
60
58
|
} from "./markdown-renderer.js";
|
|
61
59
|
import { resolveToolRenderer } from "./tool-render-registry.js";
|
|
@@ -631,6 +629,7 @@ export function ToolCallDisplay({
|
|
|
631
629
|
chatUI={chatUI}
|
|
632
630
|
isRunning={isRunning}
|
|
633
631
|
isActiveTail={showActiveTail}
|
|
632
|
+
structuredMeta={structuredMeta}
|
|
634
633
|
approval={approval}
|
|
635
634
|
repeatCount={repeatCount}
|
|
636
635
|
/>,
|
|
@@ -646,6 +645,7 @@ function ToolCallDisplayGeneric({
|
|
|
646
645
|
chatUI,
|
|
647
646
|
isRunning,
|
|
648
647
|
isActiveTail,
|
|
648
|
+
structuredMeta,
|
|
649
649
|
approval,
|
|
650
650
|
repeatCount,
|
|
651
651
|
}: {
|
|
@@ -657,27 +657,34 @@ function ToolCallDisplayGeneric({
|
|
|
657
657
|
chatUI?: ActionChatUIConfig;
|
|
658
658
|
isRunning: boolean;
|
|
659
659
|
isActiveTail: boolean;
|
|
660
|
+
structuredMeta?: Record<string, unknown>;
|
|
660
661
|
approval?: { approvalKey: string; dismissed?: boolean };
|
|
661
662
|
repeatCount?: number;
|
|
662
663
|
}) {
|
|
663
|
-
const
|
|
664
|
-
|
|
665
|
-
const isAgentCall = toolName.startsWith("agent:");
|
|
664
|
+
const isRawCallAgent = toolName === "call-agent";
|
|
665
|
+
const isAgentCall = toolName.startsWith("agent:") || isRawCallAgent;
|
|
666
666
|
const [expanded, setExpanded] = useState(isAgentCall);
|
|
667
667
|
const [outputOpen, setOutputOpen] = useState(false);
|
|
668
|
-
const agentName =
|
|
668
|
+
const agentName = toolName.startsWith("agent:")
|
|
669
|
+
? toolName.slice(6)
|
|
670
|
+
: typeof args.agent === "string"
|
|
671
|
+
? args.agent
|
|
672
|
+
: null;
|
|
669
673
|
const isAgentError = isAgentCall && result === "Error calling agent";
|
|
670
|
-
const agentStreamText =
|
|
674
|
+
const agentStreamText = isRawCallAgent
|
|
675
|
+
? (result ?? "")
|
|
676
|
+
: isAgentCall
|
|
677
|
+
? (argsText ?? "")
|
|
678
|
+
: "";
|
|
679
|
+
const agentActivity = structuredMeta?.agentActivity as
|
|
680
|
+
| A2AAgentActivitySnapshot
|
|
681
|
+
| undefined;
|
|
682
|
+
const agentProgress = structuredMeta?.agentProgress as
|
|
683
|
+
| AgentCallProgress
|
|
684
|
+
| undefined;
|
|
671
685
|
const hasStreamText = agentStreamText.length > 0;
|
|
672
686
|
const hasArgs = !isAgentCall && Object.keys(args).length > 0;
|
|
673
687
|
|
|
674
|
-
// NOTE: All hooks must be above any conditional returns
|
|
675
|
-
useEffect(() => {
|
|
676
|
-
if (isAgentCall && isRunning && streamRef.current) {
|
|
677
|
-
streamRef.current.scrollTop = streamRef.current.scrollHeight;
|
|
678
|
-
}
|
|
679
|
-
}, [agentStreamText, isAgentCall, isRunning]);
|
|
680
|
-
|
|
681
688
|
// Render connect-builder as ConnectBuilderCard once the result is available
|
|
682
689
|
if (toolName === "connect-builder" && result) {
|
|
683
690
|
try {
|
|
@@ -789,6 +796,24 @@ function ToolCallDisplayGeneric({
|
|
|
789
796
|
const ToolIcon = resolveToolIcon(toolName);
|
|
790
797
|
const outputTitle = `Raw ${toolName} tool call output`;
|
|
791
798
|
|
|
799
|
+
if (isAgentCall) {
|
|
800
|
+
return (
|
|
801
|
+
<AgentCallCell
|
|
802
|
+
agentName={agentName ?? "agent"}
|
|
803
|
+
activity={agentActivity}
|
|
804
|
+
progress={agentProgress}
|
|
805
|
+
responseText={agentStreamText}
|
|
806
|
+
isRunning={isRunning}
|
|
807
|
+
isError={isAgentError}
|
|
808
|
+
durationMs={
|
|
809
|
+
typeof structuredMeta?.agentDurationMs === "number"
|
|
810
|
+
? structuredMeta.agentDurationMs
|
|
811
|
+
: agentActivity?.durationMs
|
|
812
|
+
}
|
|
813
|
+
/>
|
|
814
|
+
);
|
|
815
|
+
}
|
|
816
|
+
|
|
792
817
|
return (
|
|
793
818
|
<div className="group/tool my-0.5 w-full overflow-hidden">
|
|
794
819
|
{mcpApp && <McpAppRenderer app={mcpApp} className="mb-1.5" />}
|
|
@@ -843,24 +868,6 @@ function ToolCallDisplayGeneric({
|
|
|
843
868
|
</span>
|
|
844
869
|
)}
|
|
845
870
|
</button>
|
|
846
|
-
<AnimatedCollapse open={isExpanded && isAgentCall && hasStreamText}>
|
|
847
|
-
<div
|
|
848
|
-
ref={streamRef}
|
|
849
|
-
className="mt-1 rounded-md bg-muted/50 px-3 py-2 text-xs text-muted-foreground break-words max-h-48 overflow-y-auto agent-markdown prose prose-sm prose-invert max-w-none"
|
|
850
|
-
>
|
|
851
|
-
{markdownModule?.default && remarkGfmFn ? (
|
|
852
|
-
<markdownModule.default
|
|
853
|
-
remarkPlugins={[remarkGfmFn]}
|
|
854
|
-
components={markdownComponents}
|
|
855
|
-
urlTransform={markdownUrlTransform}
|
|
856
|
-
>
|
|
857
|
-
{agentStreamText}
|
|
858
|
-
</markdownModule.default>
|
|
859
|
-
) : (
|
|
860
|
-
<span style={{ whiteSpace: "pre-wrap" }}>{agentStreamText}</span>
|
|
861
|
-
)}
|
|
862
|
-
</div>
|
|
863
|
-
</AnimatedCollapse>
|
|
864
871
|
<AnimatedCollapse
|
|
865
872
|
open={isExpanded && !isAgentCall && (hasArgs || result !== undefined)}
|
|
866
873
|
>
|
|
@@ -896,6 +903,154 @@ function ToolCallDisplayGeneric({
|
|
|
896
903
|
);
|
|
897
904
|
}
|
|
898
905
|
|
|
906
|
+
function AgentCallCell({
|
|
907
|
+
agentName,
|
|
908
|
+
activity,
|
|
909
|
+
progress,
|
|
910
|
+
responseText,
|
|
911
|
+
isRunning,
|
|
912
|
+
isError,
|
|
913
|
+
durationMs,
|
|
914
|
+
}: {
|
|
915
|
+
agentName: string;
|
|
916
|
+
activity?: A2AAgentActivitySnapshot;
|
|
917
|
+
progress?: AgentCallProgress;
|
|
918
|
+
responseText: string;
|
|
919
|
+
isRunning: boolean;
|
|
920
|
+
isError: boolean;
|
|
921
|
+
durationMs?: number;
|
|
922
|
+
}) {
|
|
923
|
+
const t = useT();
|
|
924
|
+
const [open, setOpen] = useState(true);
|
|
925
|
+
const finalText = isRunning
|
|
926
|
+
? activity?.responseText || responseText
|
|
927
|
+
: responseText || activity?.responseText;
|
|
928
|
+
const work = activity?.reasoning?.length || activity?.toolCalls?.length;
|
|
929
|
+
const workItemCount = Math.max(
|
|
930
|
+
activity?.reasoning?.length ?? 0,
|
|
931
|
+
activity?.toolCalls?.length ?? 0,
|
|
932
|
+
);
|
|
933
|
+
const label = isRunning
|
|
934
|
+
? t("agentPanel.delegatedAgent.asking", { name: agentName })
|
|
935
|
+
: isError
|
|
936
|
+
? t("agentPanel.delegatedAgent.error", { name: agentName })
|
|
937
|
+
: t("agentPanel.delegatedAgent.asked", { name: agentName });
|
|
938
|
+
const workContent = work ? (
|
|
939
|
+
<div className="space-y-1 ps-5">
|
|
940
|
+
{Array.from({ length: workItemCount }, (_, index) => {
|
|
941
|
+
const reasoningText = activity?.reasoning?.[index];
|
|
942
|
+
const tool = activity?.toolCalls?.[index];
|
|
943
|
+
return (
|
|
944
|
+
<React.Fragment key={`activity-${index}`}>
|
|
945
|
+
{reasoningText && (
|
|
946
|
+
<ReasoningCell
|
|
947
|
+
text={reasoningText}
|
|
948
|
+
isStreaming={
|
|
949
|
+
isRunning &&
|
|
950
|
+
activity.activePhase === "reasoning" &&
|
|
951
|
+
index === activity.reasoning.length - 1
|
|
952
|
+
}
|
|
953
|
+
defaultOpen={index === activity.reasoning.length - 1}
|
|
954
|
+
collapseWhenReplaced={index < activity.toolCalls.length}
|
|
955
|
+
/>
|
|
956
|
+
)}
|
|
957
|
+
{tool && (
|
|
958
|
+
<ToolCallDisplay
|
|
959
|
+
toolName={tool.name}
|
|
960
|
+
args={{}}
|
|
961
|
+
argsText=""
|
|
962
|
+
isRunning={tool.status === "running"}
|
|
963
|
+
result={
|
|
964
|
+
tool.status === "failed"
|
|
965
|
+
? "Failed"
|
|
966
|
+
: tool.status === "completed"
|
|
967
|
+
? "Done"
|
|
968
|
+
: undefined
|
|
969
|
+
}
|
|
970
|
+
isActiveTail={
|
|
971
|
+
isRunning && index === activity.toolCalls.length - 1
|
|
972
|
+
}
|
|
973
|
+
/>
|
|
974
|
+
)}
|
|
975
|
+
</React.Fragment>
|
|
976
|
+
);
|
|
977
|
+
})}
|
|
978
|
+
</div>
|
|
979
|
+
) : null;
|
|
980
|
+
const progressState = progress?.state.replaceAll(/[-_]+/g, " ");
|
|
981
|
+
const progressText =
|
|
982
|
+
isRunning && !activity && progress && progressState
|
|
983
|
+
? [
|
|
984
|
+
progressState.charAt(0).toUpperCase() + progressState.slice(1),
|
|
985
|
+
t("agentPanel.delegatedAgent.elapsed", {
|
|
986
|
+
duration: formatWorkedDuration(progress.elapsedSeconds * 1000),
|
|
987
|
+
}),
|
|
988
|
+
progress.detail,
|
|
989
|
+
]
|
|
990
|
+
.filter(Boolean)
|
|
991
|
+
.join(" · ")
|
|
992
|
+
: null;
|
|
993
|
+
return (
|
|
994
|
+
<div className="group/tool my-0.5 w-full">
|
|
995
|
+
<button
|
|
996
|
+
type="button"
|
|
997
|
+
onClick={() => setOpen((value) => !value)}
|
|
998
|
+
aria-expanded={open}
|
|
999
|
+
className="flex w-full items-center gap-1.5 rounded-md py-0.5 text-left text-[13px] text-muted-foreground transition-colors hover:text-foreground"
|
|
1000
|
+
>
|
|
1001
|
+
{isRunning ? (
|
|
1002
|
+
<IconLoader2 className="size-3.5 animate-spin" />
|
|
1003
|
+
) : isError ? (
|
|
1004
|
+
<IconCircleX className="size-3.5 text-destructive" />
|
|
1005
|
+
) : (
|
|
1006
|
+
<IconChevronRight
|
|
1007
|
+
className={cn("size-3.5 transition-transform", open && "rotate-90")}
|
|
1008
|
+
/>
|
|
1009
|
+
)}
|
|
1010
|
+
<span
|
|
1011
|
+
className={cn(
|
|
1012
|
+
"min-w-0 truncate font-normal",
|
|
1013
|
+
isRunning && "agent-running-shimmer",
|
|
1014
|
+
)}
|
|
1015
|
+
>
|
|
1016
|
+
{label}
|
|
1017
|
+
</span>
|
|
1018
|
+
</button>
|
|
1019
|
+
<AnimatedCollapse open={open}>
|
|
1020
|
+
<div className="ms-1 border-s border-border/50 ps-2 pt-1">
|
|
1021
|
+
{workContent &&
|
|
1022
|
+
(isRunning ? (
|
|
1023
|
+
workContent
|
|
1024
|
+
) : (
|
|
1025
|
+
<WorkedForSummary durationMs={durationMs}>
|
|
1026
|
+
{workContent}
|
|
1027
|
+
</WorkedForSummary>
|
|
1028
|
+
))}
|
|
1029
|
+
{progressText && (
|
|
1030
|
+
<p
|
|
1031
|
+
className="ps-5 pb-1 text-xs text-muted-foreground"
|
|
1032
|
+
data-testid="agent-call-progress"
|
|
1033
|
+
aria-live="polite"
|
|
1034
|
+
>
|
|
1035
|
+
{progressText}
|
|
1036
|
+
</p>
|
|
1037
|
+
)}
|
|
1038
|
+
{finalText && (
|
|
1039
|
+
<div className="ps-5 pb-1">
|
|
1040
|
+
<SmoothMarkdownText
|
|
1041
|
+
text={finalText}
|
|
1042
|
+
streaming={isRunning}
|
|
1043
|
+
resetKey={`agent-response-${agentName}`}
|
|
1044
|
+
statusType={isRunning ? "running" : "complete"}
|
|
1045
|
+
/>
|
|
1046
|
+
</div>
|
|
1047
|
+
)}
|
|
1048
|
+
</div>
|
|
1049
|
+
</AnimatedCollapse>
|
|
1050
|
+
</div>
|
|
1051
|
+
);
|
|
1052
|
+
}
|
|
1053
|
+
|
|
899
1054
|
// ─── ToolCallFallback ──────────────────────────────────────────────────────────
|
|
900
1055
|
|
|
901
1056
|
export function ToolCallFallback({
|