@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.
Files changed (184) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +19 -0
  3. package/corpus/core/docs/content/a2a-protocol.mdx +15 -0
  4. package/corpus/core/docs/content/template-chat.mdx +1 -1
  5. package/corpus/core/docs/content/template-plan.mdx +3 -3
  6. package/corpus/core/package.json +1 -1
  7. package/corpus/core/src/a2a/activity.ts +371 -0
  8. package/corpus/core/src/a2a/client.ts +3 -1
  9. package/corpus/core/src/a2a/index.ts +21 -0
  10. package/corpus/core/src/a2a/types.ts +8 -0
  11. package/corpus/core/src/agent/model-config.ts +19 -23
  12. package/corpus/core/src/agent/production-agent.ts +167 -100
  13. package/corpus/core/src/agent/types.ts +16 -1
  14. package/corpus/core/src/client/chat/tool-call-display.tsx +190 -35
  15. package/corpus/core/src/client/chat-model-groups.ts +67 -27
  16. package/corpus/core/src/client/sharing/ShareButton.tsx +1 -27
  17. package/corpus/core/src/client/sharing/ShareDialog.tsx +0 -16
  18. package/corpus/core/src/client/sharing/useShareButtonController.ts +0 -7
  19. package/corpus/core/src/client/sharing/useShareDialogController.ts +0 -2
  20. package/corpus/core/src/client/sse-event-processor.ts +85 -1
  21. package/corpus/core/src/ingestion/figma-node-to-html.ts +20 -99
  22. package/corpus/core/src/ingestion/figma-paint-math.ts +371 -0
  23. package/corpus/core/src/ingestion/index.ts +20 -0
  24. package/corpus/core/src/localization/default-messages.ts +6 -0
  25. package/corpus/core/src/scripts/agent-engines/list-agent-engines.ts +1 -18
  26. package/corpus/core/src/scripts/call-agent.ts +49 -6
  27. package/corpus/core/src/server/agent-chat-plugin.ts +50 -10
  28. package/corpus/core/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +16 -0
  29. package/corpus/templates/assets/app/routes/library.tsx +17 -9
  30. package/corpus/templates/clips/changelog/2026-07-23-fixed-recordings-failing-to-save-with-a-cancelled-or-cleanup.md +6 -0
  31. package/corpus/templates/clips/server/plugins/db.ts +9 -1
  32. package/corpus/templates/design/AGENTS.md +18 -5
  33. package/corpus/templates/design/FIGMA_INTEROPERABILITY.md +25 -12
  34. package/corpus/templates/design/actions/hydrate-figma-paste-images.ts +115 -0
  35. package/corpus/templates/design/actions/import-figma-clipboard.ts +83 -18
  36. package/corpus/templates/design/actions/import-figma-frame.ts +34 -21
  37. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +28 -1
  38. package/corpus/templates/design/app/components/design/DesignImportPanel.tsx +106 -11
  39. package/corpus/templates/design/app/components/design/FigmaHydrationDialog.tsx +273 -0
  40. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +7 -7
  41. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +57 -9
  42. package/corpus/templates/design/app/components/design/design-canvas/iframe-events.ts +10 -0
  43. package/corpus/templates/design/app/components/design/multi-screen/board-surface-html.ts +8 -1
  44. package/corpus/templates/design/app/components/design/multi-screen/types.ts +3 -0
  45. package/corpus/templates/design/app/i18n-data.ts +150 -2
  46. package/corpus/templates/design/app/lib/design-file-upload.ts +85 -0
  47. package/corpus/templates/design/app/lib/design-import.ts +19 -1
  48. package/corpus/templates/design/app/lib/figma-clipboard.ts +110 -10
  49. package/corpus/templates/design/changelog/2026-07-20-paste-figma-frames-directly-onto-the-canvas-no-token-needed.md +6 -0
  50. package/corpus/templates/design/changelog/2026-07-21-fig-upload-frame-url-and-rate-limit-errors.md +5 -0
  51. package/corpus/templates/design/changelog/2026-07-22-connecting-a-figma-token-now-actually-fills-in-a-pasted-desi.md +6 -0
  52. package/corpus/templates/design/changelog/2026-07-22-figma-line-arrow-vectors-and-stroked-icons-now-render-instea.md +6 -0
  53. package/corpus/templates/design/changelog/2026-07-22-fill-a-no-token-figma-paste-s-images-by-dropping-the-origina.md +6 -0
  54. package/corpus/templates/design/changelog/2026-07-22-imported-and-pasted-figma-frames-now-render-faithfully-fixed.md +6 -0
  55. package/corpus/templates/design/server/handlers/import-design-file.ts +50 -0
  56. package/corpus/templates/design/server/lib/fig-file-decoder.ts +90 -49
  57. package/corpus/templates/design/server/lib/fig-file-import.ts +19 -5
  58. package/corpus/templates/design/server/lib/fig-file-to-html.ts +583 -78
  59. package/corpus/templates/design/server/lib/figma-clipboard-local-decode.ts +238 -0
  60. package/corpus/templates/design/server/lib/figma-image-hydration.ts +389 -0
  61. package/corpus/templates/design/server/lib/figma-node-import.ts +136 -36
  62. package/corpus/templates/design/server/register-secrets.ts +14 -2
  63. package/dist/a2a/activity.d.ts +50 -0
  64. package/dist/a2a/activity.d.ts.map +1 -0
  65. package/dist/a2a/activity.js +236 -0
  66. package/dist/a2a/activity.js.map +1 -0
  67. package/dist/a2a/client.d.ts +2 -0
  68. package/dist/a2a/client.d.ts.map +1 -1
  69. package/dist/a2a/client.js +1 -1
  70. package/dist/a2a/client.js.map +1 -1
  71. package/dist/a2a/index.d.ts +2 -1
  72. package/dist/a2a/index.d.ts.map +1 -1
  73. package/dist/a2a/index.js +1 -0
  74. package/dist/a2a/index.js.map +1 -1
  75. package/dist/a2a/types.d.ts +1 -0
  76. package/dist/a2a/types.d.ts.map +1 -1
  77. package/dist/a2a/types.js.map +1 -1
  78. package/dist/agent/engine/anthropic-engine.d.ts +1 -1
  79. package/dist/agent/engine/builder-engine.d.ts +2 -2
  80. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  81. package/dist/agent/model-config.d.ts +16 -16
  82. package/dist/agent/model-config.d.ts.map +1 -1
  83. package/dist/agent/model-config.js +19 -23
  84. package/dist/agent/model-config.js.map +1 -1
  85. package/dist/agent/production-agent.d.ts +26 -0
  86. package/dist/agent/production-agent.d.ts.map +1 -1
  87. package/dist/agent/production-agent.js +137 -80
  88. package/dist/agent/production-agent.js.map +1 -1
  89. package/dist/agent/types.d.ts +10 -0
  90. package/dist/agent/types.d.ts.map +1 -1
  91. package/dist/agent/types.js.map +1 -1
  92. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  93. package/dist/client/chat/tool-call-display.js +63 -14
  94. package/dist/client/chat/tool-call-display.js.map +1 -1
  95. package/dist/client/chat-model-groups.d.ts.map +1 -1
  96. package/dist/client/chat-model-groups.js +44 -21
  97. package/dist/client/chat-model-groups.js.map +1 -1
  98. package/dist/client/sharing/ShareButton.d.ts +1 -1
  99. package/dist/client/sharing/ShareButton.d.ts.map +1 -1
  100. package/dist/client/sharing/ShareButton.js +3 -4
  101. package/dist/client/sharing/ShareButton.js.map +1 -1
  102. package/dist/client/sharing/ShareDialog.d.ts.map +1 -1
  103. package/dist/client/sharing/ShareDialog.js +1 -2
  104. package/dist/client/sharing/ShareDialog.js.map +1 -1
  105. package/dist/client/sharing/useShareButtonController.d.ts +0 -1
  106. package/dist/client/sharing/useShareButtonController.d.ts.map +1 -1
  107. package/dist/client/sharing/useShareButtonController.js +0 -6
  108. package/dist/client/sharing/useShareButtonController.js.map +1 -1
  109. package/dist/client/sharing/useShareDialogController.d.ts +0 -1
  110. package/dist/client/sharing/useShareDialogController.d.ts.map +1 -1
  111. package/dist/client/sharing/useShareDialogController.js +0 -1
  112. package/dist/client/sharing/useShareDialogController.js.map +1 -1
  113. package/dist/client/sse-event-processor.d.ts +12 -0
  114. package/dist/client/sse-event-processor.d.ts.map +1 -1
  115. package/dist/client/sse-event-processor.js +63 -1
  116. package/dist/client/sse-event-processor.js.map +1 -1
  117. package/dist/collab/routes.d.ts +1 -1
  118. package/dist/ingestion/figma-node-to-html.d.ts.map +1 -1
  119. package/dist/ingestion/figma-node-to-html.js +14 -88
  120. package/dist/ingestion/figma-node-to-html.js.map +1 -1
  121. package/dist/ingestion/figma-paint-math.d.ts +157 -0
  122. package/dist/ingestion/figma-paint-math.d.ts.map +1 -0
  123. package/dist/ingestion/figma-paint-math.js +274 -0
  124. package/dist/ingestion/figma-paint-math.js.map +1 -0
  125. package/dist/ingestion/index.d.ts +1 -0
  126. package/dist/ingestion/index.d.ts.map +1 -1
  127. package/dist/ingestion/index.js +1 -0
  128. package/dist/ingestion/index.js.map +1 -1
  129. package/dist/localization/default-messages.d.ts +6 -0
  130. package/dist/localization/default-messages.d.ts.map +1 -1
  131. package/dist/localization/default-messages.js +6 -0
  132. package/dist/localization/default-messages.js.map +1 -1
  133. package/dist/notifications/routes.d.ts +2 -2
  134. package/dist/observability/routes.d.ts +5 -5
  135. package/dist/progress/routes.d.ts +1 -1
  136. package/dist/provider-api/actions/custom-provider-registration.d.ts +12 -12
  137. package/dist/provider-api/actions/provider-api.d.ts +7 -7
  138. package/dist/resources/handlers.d.ts +1 -1
  139. package/dist/scripts/agent-engines/list-agent-engines.d.ts.map +1 -1
  140. package/dist/scripts/agent-engines/list-agent-engines.js +1 -18
  141. package/dist/scripts/agent-engines/list-agent-engines.js.map +1 -1
  142. package/dist/scripts/call-agent.d.ts.map +1 -1
  143. package/dist/scripts/call-agent.js +49 -6
  144. package/dist/scripts/call-agent.js.map +1 -1
  145. package/dist/secrets/routes.d.ts +3 -3
  146. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  147. package/dist/server/agent-chat-plugin.js +38 -10
  148. package/dist/server/agent-chat-plugin.js.map +1 -1
  149. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  150. package/dist/server/realtime-token.d.ts +1 -1
  151. package/dist/server/transcribe-voice.d.ts +1 -1
  152. package/dist/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +16 -0
  153. package/docs/content/a2a-protocol.mdx +15 -0
  154. package/docs/content/template-chat.mdx +1 -1
  155. package/docs/content/template-plan.mdx +3 -3
  156. package/package.json +1 -1
  157. package/src/a2a/activity.ts +371 -0
  158. package/src/a2a/client.ts +3 -1
  159. package/src/a2a/index.ts +21 -0
  160. package/src/a2a/types.ts +8 -0
  161. package/src/agent/model-config.ts +19 -23
  162. package/src/agent/production-agent.ts +167 -100
  163. package/src/agent/types.ts +16 -1
  164. package/src/client/chat/tool-call-display.tsx +190 -35
  165. package/src/client/chat-model-groups.ts +67 -27
  166. package/src/client/sharing/ShareButton.tsx +1 -27
  167. package/src/client/sharing/ShareDialog.tsx +0 -16
  168. package/src/client/sharing/useShareButtonController.ts +0 -7
  169. package/src/client/sharing/useShareDialogController.ts +0 -2
  170. package/src/client/sse-event-processor.ts +85 -1
  171. package/src/ingestion/figma-node-to-html.ts +20 -99
  172. package/src/ingestion/figma-paint-math.ts +371 -0
  173. package/src/ingestion/index.ts +20 -0
  174. package/src/localization/default-messages.ts +6 -0
  175. package/src/scripts/agent-engines/list-agent-engines.ts +1 -18
  176. package/src/scripts/call-agent.ts +49 -6
  177. package/src/server/agent-chat-plugin.ts +50 -10
  178. package/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +16 -0
  179. package/corpus/core/src/observability/hosted-model-experiment.ts +0 -118
  180. package/dist/observability/hosted-model-experiment.d.ts +0 -39
  181. package/dist/observability/hosted-model-experiment.d.ts.map +0 -1
  182. package/dist/observability/hosted-model-experiment.js +0 -90
  183. package/dist/observability/hosted-model-experiment.js.map +0 -1
  184. package/src/observability/hosted-model-experiment.ts +0 -118
@@ -27,11 +27,11 @@ export declare function resolveAgentEngineApiKeyWriteTarget(event: H3Event, scop
27
27
  export declare function createAgentEngineApiKeyHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
28
28
  error: any;
29
29
  } | {
30
- error?: undefined;
31
30
  ok: boolean;
32
31
  key: string;
33
32
  baseUrlKey?: string;
34
33
  scope: AgentEngineApiKeyScope;
34
+ error?: undefined;
35
35
  }>>;
36
36
  export {};
37
37
  //# sourceMappingURL=agent-engine-api-key-route.d.ts.map
@@ -26,9 +26,9 @@ export declare function createRealtimeTokenHandler(): import("h3").EventHandlerW
26
26
  expiresAt?: undefined;
27
27
  ttlSeconds?: undefined;
28
28
  } | {
29
- error?: undefined;
30
29
  token: string;
31
30
  expiresAt: string;
32
31
  ttlSeconds: number;
32
+ error?: undefined;
33
33
  }>>;
34
34
  //# sourceMappingURL=realtime-token.d.ts.map
@@ -20,7 +20,7 @@ export declare function createTranscribeVoiceHandler(): import("h3").EventHandle
20
20
  error: string;
21
21
  text?: undefined;
22
22
  } | {
23
- text: string;
24
23
  error?: undefined;
24
+ text: string;
25
25
  }>>;
26
26
  //# sourceMappingURL=transcribe-voice.d.ts.map
@@ -195,6 +195,22 @@ for await (const update of client.stream({
195
195
  }
196
196
  ```
197
197
 
198
+ ### Agent activity in delegated chat
199
+
200
+ Agent Native peers attach a bounded `data` part with
201
+ `kind: "agent-native/agent-activity"` to in-progress and terminal task status
202
+ messages. It contains the same user-visible reasoning summaries shown in the
203
+ receiving app, tool names and completion states, elapsed time, and progressive
204
+ response text. It never includes tool inputs, tool results, credentials, or
205
+ hidden provider reasoning.
206
+
207
+ `call-agent` reads this optional part while it polls an asynchronous task and
208
+ renders the remote work as a nested agent run. Unknown A2A peers do not need to
209
+ implement the extension: their ordinary status and final text still render in
210
+ the same nested block. Treat activity data as untrusted presentation content;
211
+ never use it for identity, authorization, approval, routing, or artifact
212
+ validation.
213
+
198
214
  ### Carrying explicit chat authorization
199
215
 
200
216
  When the authenticated caller has an exact consequential action that the user
@@ -434,6 +434,21 @@ Like `callAgent()`, the CLI defaults to async + poll (`invokeAgent` → `callAge
434
434
 
435
435
  The target resolves the same way as `agentNative.invoke()`: by workspace app id, by app name, or by a full URL — so the same command works against a sibling app in a multi-app workspace or an arbitrary A2A peer elsewhere.
436
436
 
437
+ ## Delegated agent activity {#delegated-agent-activity}
438
+
439
+ Agent Native peers may attach an optional `data` part with
440
+ `kind: "agent-native/agent-activity"` to task status messages. It carries a
441
+ bounded snapshot of the user-visible reasoning summaries, tool names and
442
+ completion states, elapsed time, and progressive response text. Calling apps
443
+ render these updates as a nested agent run and collapse the work history when
444
+ the delegated task finishes.
445
+
446
+ The activity part never includes tool inputs, tool results, credentials, or
447
+ hidden provider reasoning. Treat it as untrusted presentation data, never as
448
+ identity, authorization, approval, routing, or artifact validation. External
449
+ A2A peers can omit the extension; their ordinary status text and final response
450
+ still render in the same delegated-agent surface.
451
+
437
452
  ## Task lifecycle {#task-lifecycle}
438
453
 
439
454
  Each message creates a task that moves through these states:
@@ -13,7 +13,7 @@ If you want a finished domain product shape, start from [Calendar](/docs/templat
13
13
  <Screen
14
14
  surface="desktop"
15
15
  html={
16
- "<div style='min-height:560px;box-sizing:border-box;display:flex;align-items:center;justify-content:center;padding:56px 40px'><div style='display:flex;flex-direction:column;align-items:center;justify-content:center;gap:28px;width:min(700px,92%);min-height:430px'><div style='height:34px'></div><div style='text-align:center'><h1 style='margin:0'>How can I help?</h1><p class='wf-muted' style='margin:10px 0 0'>Chat about anything. Add actions, components, pages, jobs, or your own backend.</p></div><div class='wf-card' style='width:100%;min-height:150px;display:flex;flex-direction:column;gap:18px'><span class='wf-muted'>Message the agent...</span><div style='flex:1'></div><div style='display:flex;align-items:center;gap:10px'><span data-icon='plus' aria-label='Attach'></span><div style='flex:1'></div><span class='wf-pill'>Sonnet 5 · Auto</span><span class='wf-pill'>Act</span><button class='primary'>↑</button></div></div><div style='height:34px'></div></div></div>"
16
+ "<div style='min-height:560px;box-sizing:border-box;display:flex;align-items:center;justify-content:center;padding:56px 40px'><div style='display:flex;flex-direction:column;align-items:center;justify-content:center;gap:28px;width:min(700px,92%);min-height:430px'><div style='height:34px'></div><div style='text-align:center'><h1 style='margin:0'>How can I help?</h1><p class='wf-muted' style='margin:10px 0 0'>Chat about anything. Add actions, components, pages, jobs, or your own backend.</p></div><div class='wf-card' style='width:100%;min-height:150px;display:flex;flex-direction:column;gap:18px'><span class='wf-muted'>Message the agent...</span><div style='flex:1'></div><div style='display:flex;align-items:center;gap:10px'><span data-icon='plus' aria-label='Attach'></span><div style='flex:1'></div><span class='wf-pill'>GPT-5.6 Luna · Auto</span><span class='wf-pill'>Act</span><button class='primary'>↑</button></div></div><div style='height:34px'></div></div></div>"
17
17
  }
18
18
  />
19
19
  </WireframeBlock>
@@ -232,9 +232,9 @@ Generating a plan or recap runs a full agentic session against your coding
232
232
  agent's LLM, not a lightweight template fill, so cost scales with the size of
233
233
  the diff or plan and the model you choose.
234
234
 
235
- - The app's own default chat model is Sonnet 5; change it any time in
236
- **Settings**. Haiku is the cheaper Claude option, and Luna is the cheaper
237
- option in the GPT-5.6 family.
235
+ - The app's default chat model is GPT-5.6 Luna. Direct Anthropic connections
236
+ keep Claude Sonnet 5 as their default. Change models any time in **Settings**;
237
+ Haiku is the cheaper Claude option.
238
238
  - Automated PR recaps from the GitHub Action run separately from the
239
239
  interactive app and have their own model and cost knobs — see
240
240
  [PR Visual Recap](/docs/pr-visual-recap) for `VISUAL_RECAP_MODEL`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.118.1",
3
+ "version": "0.119.1",
4
4
  "description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -0,0 +1,371 @@
1
+ import { sanitizeToolErrorText } from "../agent/tool-error-redaction.js";
2
+ import type { AgentChatEvent } from "../agent/types.js";
3
+ import type { DataPart, Part } from "./types.js";
4
+
5
+ export const A2A_AGENT_ACTIVITY_KIND = "agent-native/agent-activity";
6
+ export const A2A_AGENT_ACTIVITY_VERSION = 1;
7
+ export const MAX_A2A_ACTIVITY_REASONING_CHARS = 32_768;
8
+ export const MAX_A2A_ACTIVITY_RESPONSE_CHARS = 32_768;
9
+ export const MAX_A2A_ACTIVITY_TOTAL_CHARS = 98_304;
10
+ export const MAX_A2A_ACTIVITY_REASONING_SEGMENTS = 128;
11
+ export const MAX_A2A_ACTIVITY_TOOL_CALLS = 64;
12
+ export const MAX_A2A_ACTIVITY_TOOL_NAME_CHARS = 96;
13
+ export const MAX_A2A_ACTIVITY_TOOL_ID_CHARS = 128;
14
+
15
+ export type A2AAgentActivityPhase =
16
+ | "reasoning"
17
+ | "tool"
18
+ | "responding"
19
+ | "complete"
20
+ | "error";
21
+
22
+ export type A2AAgentActivityToolStatus = "running" | "completed" | "failed";
23
+
24
+ export interface A2AAgentActivityToolCall {
25
+ name: string;
26
+ id?: string;
27
+ status: A2AAgentActivityToolStatus;
28
+ }
29
+
30
+ export interface A2AAgentActivitySnapshot extends Record<string, unknown> {
31
+ kind: typeof A2A_AGENT_ACTIVITY_KIND;
32
+ version: typeof A2A_AGENT_ACTIVITY_VERSION;
33
+ sequence: number;
34
+ startedAt: number;
35
+ updatedAt: number;
36
+ durationMs: number;
37
+ activePhase: A2AAgentActivityPhase;
38
+ reasoning: string[];
39
+ toolCalls: A2AAgentActivityToolCall[];
40
+ responseText?: string;
41
+ }
42
+
43
+ export interface A2AAgentActivityState {
44
+ sequence: number;
45
+ startedAt: number;
46
+ updatedAt: number;
47
+ activePhase: A2AAgentActivityPhase;
48
+ reasoning: string[];
49
+ toolCalls: A2AAgentActivityToolCall[];
50
+ responseText: string;
51
+ }
52
+
53
+ export function createA2AAgentActivityState(
54
+ startedAt = Date.now(),
55
+ ): A2AAgentActivityState {
56
+ return {
57
+ sequence: 0,
58
+ startedAt,
59
+ updatedAt: startedAt,
60
+ activePhase: "reasoning",
61
+ reasoning: [],
62
+ toolCalls: [],
63
+ responseText: "",
64
+ };
65
+ }
66
+
67
+ /**
68
+ * Converts internal loop events into a bounded activity snapshot. It carries
69
+ * only reasoning text already emitted to the local chat, never tool inputs or
70
+ * results.
71
+ */
72
+ export function applyA2AAgentActivityEvent(
73
+ state: A2AAgentActivityState,
74
+ event: AgentChatEvent,
75
+ updatedAt = Date.now(),
76
+ ): A2AAgentActivityState {
77
+ const next = { ...state, updatedAt: normalizeTimestamp(updatedAt) };
78
+ let changed = false;
79
+
80
+ switch (event.type) {
81
+ case "thinking":
82
+ next.activePhase = "reasoning";
83
+ next.reasoning = appendBoundedSegment(
84
+ next.reasoning,
85
+ event.text,
86
+ MAX_A2A_ACTIVITY_REASONING_CHARS,
87
+ next.toolCalls.length,
88
+ );
89
+ changed = true;
90
+ break;
91
+ case "tool_start":
92
+ next.activePhase = "tool";
93
+ next.responseText = "";
94
+ next.toolCalls = appendToolCall(next.toolCalls, toolFromEvent(event));
95
+ changed = true;
96
+ break;
97
+ case "tool_done":
98
+ next.activePhase = "tool";
99
+ next.toolCalls = settleToolCall(next.toolCalls, toolFromEvent(event));
100
+ changed = true;
101
+ break;
102
+ case "text":
103
+ next.activePhase = "responding";
104
+ next.responseText = appendBoundedText(
105
+ next.responseText,
106
+ event.text,
107
+ MAX_A2A_ACTIVITY_RESPONSE_CHARS,
108
+ );
109
+ changed = true;
110
+ break;
111
+ case "done":
112
+ next.activePhase = "complete";
113
+ changed = true;
114
+ break;
115
+ case "error":
116
+ next.activePhase = "error";
117
+ changed = true;
118
+ break;
119
+ case "clear":
120
+ next.responseText = "";
121
+ changed = true;
122
+ break;
123
+ }
124
+
125
+ return changed ? { ...next, sequence: state.sequence + 1 } : state;
126
+ }
127
+
128
+ export function buildA2AAgentActivitySnapshot(
129
+ state: A2AAgentActivityState,
130
+ ): A2AAgentActivitySnapshot {
131
+ return {
132
+ kind: A2A_AGENT_ACTIVITY_KIND,
133
+ version: A2A_AGENT_ACTIVITY_VERSION,
134
+ sequence: state.sequence,
135
+ startedAt: state.startedAt,
136
+ updatedAt: state.updatedAt,
137
+ durationMs: Math.max(0, state.updatedAt - state.startedAt),
138
+ activePhase: state.activePhase,
139
+ reasoning: state.reasoning,
140
+ toolCalls: state.toolCalls,
141
+ ...(state.responseText ? { responseText: state.responseText } : {}),
142
+ };
143
+ }
144
+
145
+ export function buildA2AAgentActivityPart(
146
+ state: A2AAgentActivityState,
147
+ ): DataPart {
148
+ return { type: "data", data: buildA2AAgentActivitySnapshot(state) };
149
+ }
150
+
151
+ export function parseA2AAgentActivityPart(
152
+ part: Part | unknown,
153
+ ): A2AAgentActivitySnapshot | null {
154
+ if (!part || typeof part !== "object") return null;
155
+ const candidate = part as { type?: unknown; data?: unknown };
156
+ if (candidate.type !== "data" || !isRecord(candidate.data)) return null;
157
+ const data = candidate.data;
158
+ if (
159
+ data.kind !== A2A_AGENT_ACTIVITY_KIND ||
160
+ data.version !== A2A_AGENT_ACTIVITY_VERSION ||
161
+ !isSafeInteger(data.sequence) ||
162
+ !isSafeInteger(data.startedAt) ||
163
+ !isSafeInteger(data.updatedAt) ||
164
+ !isSafeInteger(data.durationMs) ||
165
+ !isPhase(data.activePhase) ||
166
+ data.updatedAt < data.startedAt ||
167
+ data.durationMs !== data.updatedAt - data.startedAt ||
168
+ !isSafeReasoning(data.reasoning) ||
169
+ !isSafeToolCalls(data.toolCalls) ||
170
+ (data.responseText !== undefined &&
171
+ !isSafeText(data.responseText, MAX_A2A_ACTIVITY_RESPONSE_CHARS)) ||
172
+ activityCharacterCount(data) > MAX_A2A_ACTIVITY_TOTAL_CHARS
173
+ ) {
174
+ return null;
175
+ }
176
+
177
+ return data as unknown as A2AAgentActivitySnapshot;
178
+ }
179
+
180
+ function toolFromEvent(
181
+ event: Extract<AgentChatEvent, { type: "tool_start" | "tool_done" }>,
182
+ ): A2AAgentActivityToolCall {
183
+ const id = sanitizeToolId(event.id);
184
+ return {
185
+ name: sanitizeToolName(event.tool),
186
+ ...(id ? { id } : {}),
187
+ status:
188
+ event.type === "tool_start"
189
+ ? "running"
190
+ : event.isError
191
+ ? "failed"
192
+ : "completed",
193
+ };
194
+ }
195
+
196
+ function appendBoundedText(
197
+ current: string,
198
+ addition: string,
199
+ maxChars: number,
200
+ ) {
201
+ return sanitizeText(`${current}${addition}`, maxChars);
202
+ }
203
+
204
+ function appendBoundedSegment(
205
+ current: string[],
206
+ addition: string,
207
+ maxChars: number,
208
+ precedingToolCount: number,
209
+ ): string[] {
210
+ const used = current.reduce((total, text) => total + text.length, 0);
211
+ if (
212
+ used >= maxChars ||
213
+ current.length >= MAX_A2A_ACTIVITY_REASONING_SEGMENTS
214
+ ) {
215
+ return current;
216
+ }
217
+ const text = sanitizeText(addition, maxChars - used);
218
+ if (!text) return current;
219
+ const next = [...current];
220
+ while (
221
+ next.length < precedingToolCount &&
222
+ next.length < MAX_A2A_ACTIVITY_REASONING_SEGMENTS
223
+ ) {
224
+ next.push("");
225
+ }
226
+ if (next.length === precedingToolCount) {
227
+ return [...next, text];
228
+ }
229
+ next[precedingToolCount] = `${next[precedingToolCount] ?? ""}${text}`;
230
+ return next;
231
+ }
232
+
233
+ function appendToolCall(
234
+ current: A2AAgentActivityToolCall[],
235
+ tool: A2AAgentActivityToolCall,
236
+ ): A2AAgentActivityToolCall[] {
237
+ return current.length < MAX_A2A_ACTIVITY_TOOL_CALLS
238
+ ? [...current, tool]
239
+ : current;
240
+ }
241
+
242
+ function settleToolCall(
243
+ current: A2AAgentActivityToolCall[],
244
+ tool: A2AAgentActivityToolCall,
245
+ ): A2AAgentActivityToolCall[] {
246
+ for (let index = current.length - 1; index >= 0; index -= 1) {
247
+ const existing = current[index];
248
+ if (
249
+ (tool.id && tool.id === existing.id) ||
250
+ (!tool.id && tool.name === existing.name)
251
+ ) {
252
+ return current.map((value, itemIndex) =>
253
+ itemIndex === index ? tool : value,
254
+ );
255
+ }
256
+ }
257
+ return appendToolCall(current, tool);
258
+ }
259
+
260
+ function sanitizeText(value: string, maxChars: number): string {
261
+ return sanitizeToolErrorText(value)
262
+ .replace(/\r\n?/g, "\n")
263
+ .replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, "")
264
+ .slice(0, maxChars);
265
+ }
266
+
267
+ function sanitizeToolName(value: string): string {
268
+ return sanitizeText(value, MAX_A2A_ACTIVITY_TOOL_NAME_CHARS) || "tool";
269
+ }
270
+
271
+ function sanitizeToolId(value: string | undefined): string | undefined {
272
+ const sanitized = value
273
+ ? sanitizeText(value, MAX_A2A_ACTIVITY_TOOL_ID_CHARS)
274
+ : "";
275
+ return sanitized || undefined;
276
+ }
277
+
278
+ function normalizeTimestamp(value: number): number {
279
+ return isSafeInteger(value) ? value : Date.now();
280
+ }
281
+
282
+ function isRecord(value: unknown): value is Record<string, unknown> {
283
+ return !!value && typeof value === "object" && !Array.isArray(value);
284
+ }
285
+
286
+ function isSafeInteger(value: unknown): value is number {
287
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
288
+ }
289
+
290
+ function isPhase(value: unknown): value is A2AAgentActivityPhase {
291
+ return ["reasoning", "tool", "responding", "complete", "error"].includes(
292
+ value as string,
293
+ );
294
+ }
295
+
296
+ function isSafeReasoning(value: unknown): value is string[] {
297
+ return (
298
+ Array.isArray(value) &&
299
+ value.length <= MAX_A2A_ACTIVITY_REASONING_SEGMENTS &&
300
+ value.reduce(
301
+ (total, text) =>
302
+ total + (typeof text === "string" ? text.length : Infinity),
303
+ 0,
304
+ ) <= MAX_A2A_ACTIVITY_REASONING_CHARS &&
305
+ value.every((text) => isSafeText(text, MAX_A2A_ACTIVITY_REASONING_CHARS))
306
+ );
307
+ }
308
+
309
+ function isSafeToolCalls(value: unknown): value is A2AAgentActivityToolCall[] {
310
+ return (
311
+ Array.isArray(value) &&
312
+ value.length <= MAX_A2A_ACTIVITY_TOOL_CALLS &&
313
+ value.every(isSafeToolCall)
314
+ );
315
+ }
316
+
317
+ function isSafeToolCall(value: unknown): value is A2AAgentActivityToolCall {
318
+ if (!isRecord(value) || !isSafeToolName(value.name)) return false;
319
+ return (
320
+ (value.id === undefined || isSafeToolId(value.id)) &&
321
+ (value.status === "running" ||
322
+ value.status === "completed" ||
323
+ value.status === "failed")
324
+ );
325
+ }
326
+
327
+ function isSafeText(value: unknown, maxChars: number): value is string {
328
+ return (
329
+ typeof value === "string" &&
330
+ value.length <= maxChars &&
331
+ value === sanitizeText(value, maxChars)
332
+ );
333
+ }
334
+
335
+ function isSafeToolName(value: unknown): value is string {
336
+ return (
337
+ typeof value === "string" &&
338
+ value.length <= MAX_A2A_ACTIVITY_TOOL_NAME_CHARS &&
339
+ value === sanitizeToolName(value)
340
+ );
341
+ }
342
+
343
+ function isSafeToolId(value: unknown): value is string {
344
+ return (
345
+ typeof value === "string" &&
346
+ value.length <= MAX_A2A_ACTIVITY_TOOL_ID_CHARS &&
347
+ value === sanitizeToolId(value)
348
+ );
349
+ }
350
+
351
+ function activityCharacterCount(data: Record<string, unknown>): number {
352
+ const reasoning = Array.isArray(data.reasoning)
353
+ ? data.reasoning.reduce(
354
+ (total, text) => total + (typeof text === "string" ? text.length : 0),
355
+ 0,
356
+ )
357
+ : 0;
358
+ const response =
359
+ typeof data.responseText === "string" ? data.responseText.length : 0;
360
+ const tools = Array.isArray(data.toolCalls)
361
+ ? data.toolCalls.reduce((total, tool) => {
362
+ if (!isRecord(tool)) return total;
363
+ return (
364
+ total +
365
+ (typeof tool.name === "string" ? tool.name.length : 0) +
366
+ (typeof tool.id === "string" ? tool.id.length : 0)
367
+ );
368
+ }, 0)
369
+ : 0;
370
+ return reasoning + response + tools;
371
+ }
package/src/a2a/client.ts CHANGED
@@ -647,6 +647,8 @@ export async function callAgent(
647
647
  text: string,
648
648
  opts?: {
649
649
  apiKey?: string;
650
+ /** Additional transport metadata. Receivers must not use it as identity. */
651
+ metadata?: Record<string, unknown>;
650
652
  contextId?: string;
651
653
  userEmail?: string;
652
654
  orgDomain?: string;
@@ -694,7 +696,7 @@ export async function callAgent(
694
696
  onUpdate?: (task: Task) => void;
695
697
  },
696
698
  ): Promise<string> {
697
- const metadata: Record<string, unknown> = {};
699
+ const metadata: Record<string, unknown> = { ...opts?.metadata };
698
700
  if (opts?.userEmail) metadata.userEmail = opts.userEmail;
699
701
  if (opts?.orgDomain) metadata.orgDomain = opts.orgDomain;
700
702
  if (opts?.requestOrigin) metadata.requestOrigin = opts.requestOrigin;
package/src/a2a/index.ts CHANGED
@@ -2,6 +2,22 @@
2
2
  export { mountA2A, verifyA2AToken } from "./server.js";
3
3
  export type { A2ATokenPayload } from "./server.js";
4
4
  export { generateAgentCard } from "./agent-card.js";
5
+ export {
6
+ A2A_AGENT_ACTIVITY_KIND,
7
+ A2A_AGENT_ACTIVITY_VERSION,
8
+ MAX_A2A_ACTIVITY_REASONING_CHARS,
9
+ MAX_A2A_ACTIVITY_REASONING_SEGMENTS,
10
+ MAX_A2A_ACTIVITY_RESPONSE_CHARS,
11
+ MAX_A2A_ACTIVITY_TOOL_CALLS,
12
+ MAX_A2A_ACTIVITY_TOTAL_CHARS,
13
+ MAX_A2A_ACTIVITY_TOOL_ID_CHARS,
14
+ MAX_A2A_ACTIVITY_TOOL_NAME_CHARS,
15
+ applyA2AAgentActivityEvent,
16
+ buildA2AAgentActivityPart,
17
+ buildA2AAgentActivitySnapshot,
18
+ createA2AAgentActivityState,
19
+ parseA2AAgentActivityPart,
20
+ } from "./activity.js";
5
21
 
6
22
  // Client
7
23
  export { A2AClient, callAction, callAgent, signA2AToken } from "./client.js";
@@ -38,6 +54,11 @@ export type {
38
54
  A2ACorrelationMetadata,
39
55
  A2AReadOnlyActionInvocation,
40
56
  A2AReadOnlyActionResult,
57
+ A2AAgentActivityPhase,
58
+ A2AAgentActivitySnapshot,
59
+ A2AAgentActivityState,
60
+ A2AAgentActivityToolCall,
61
+ A2AAgentActivityToolStatus,
41
62
  } from "./types.js";
42
63
  export type {
43
64
  AgentInvocationErrorCode,
package/src/a2a/types.ts CHANGED
@@ -1,6 +1,14 @@
1
1
  // A2A Protocol types (spec v0.3) + framework config types
2
2
  import type { PublicAgentActionConfig } from "../action.js";
3
3
 
4
+ export type {
5
+ A2AAgentActivityPhase,
6
+ A2AAgentActivitySnapshot,
7
+ A2AAgentActivityState,
8
+ A2AAgentActivityToolCall,
9
+ A2AAgentActivityToolStatus,
10
+ } from "./activity.js";
11
+
4
12
  // --- Parts (content atoms) ---
5
13
 
6
14
  export interface TextPart {
@@ -242,11 +242,11 @@ function openRouterModelId(provider: string, model: string): string {
242
242
  return `${provider}/${model}`;
243
243
  }
244
244
 
245
- const FRAMEWORK_DEFAULT_OPENAI_MODEL = "gpt-5.6-sol";
246
- const FRAMEWORK_DEFAULT_BUILDER_MODEL = ANTHROPIC_DEFAULT_MODEL_ID;
245
+ const FRAMEWORK_DEFAULT_OPENAI_MODEL = "gpt-5.6-luna";
247
246
  const FRAMEWORK_DEFAULT_BUILDER_OPENAI_MODEL = builderGatewayModelId(
248
247
  FRAMEWORK_DEFAULT_OPENAI_MODEL,
249
248
  );
249
+ const FRAMEWORK_DEFAULT_BUILDER_MODEL = FRAMEWORK_DEFAULT_BUILDER_OPENAI_MODEL;
250
250
  const FRAMEWORK_DEFAULT_OPENROUTER_MODEL = openRouterModelId(
251
251
  "openai",
252
252
  FRAMEWORK_DEFAULT_OPENAI_MODEL,
@@ -257,14 +257,14 @@ export const AGENT_MODEL_CONFIG = {
257
257
  defaultModel: FRAMEWORK_DEFAULT_BUILDER_MODEL,
258
258
  supportedModels: [
259
259
  "auto",
260
- "claude-opus-4-8",
261
- CLAUDE_SONNET_MODEL_ID,
262
- "claude-haiku-4-5",
263
260
  FRAMEWORK_DEFAULT_BUILDER_OPENAI_MODEL,
264
261
  "gpt-5-6-terra",
265
- "gpt-5-6-luna",
266
- "gemini-3-1-pro",
262
+ "gpt-5-6-sol",
263
+ "claude-haiku-4-5",
264
+ CLAUDE_SONNET_MODEL_ID,
265
+ "claude-opus-4-8",
267
266
  "gemini-3-5-flash",
267
+ "gemini-3-1-pro",
268
268
  // Flash-Lite is a transcription-only public id. Advertising it as an
269
269
  // agent-chat option routes through a Vertex preview model whose
270
270
  // availability can lapse while the id remains accepted, leaving chat
@@ -274,39 +274,35 @@ export const AGENT_MODEL_CONFIG = {
274
274
  anthropic: {
275
275
  defaultModel: ANTHROPIC_DEFAULT_MODEL_ID,
276
276
  supportedModels: [
277
- "claude-fable-5",
278
- "claude-opus-4-8",
279
- CLAUDE_SONNET_MODEL_ID,
280
277
  "claude-haiku-4-5-20251001",
278
+ CLAUDE_SONNET_MODEL_ID,
279
+ "claude-opus-4-8",
280
+ "claude-fable-5",
281
281
  ],
282
282
  },
283
283
  aiSdk: {
284
284
  anthropic: {
285
285
  defaultModel: ANTHROPIC_DEFAULT_MODEL_ID,
286
286
  supportedModels: [
287
- "claude-fable-5",
288
- "claude-opus-4-8",
289
- CLAUDE_SONNET_MODEL_ID,
290
287
  "claude-haiku-4-5-20251001",
288
+ CLAUDE_SONNET_MODEL_ID,
289
+ "claude-opus-4-8",
290
+ "claude-fable-5",
291
291
  ],
292
292
  },
293
293
  openai: {
294
294
  defaultModel: FRAMEWORK_DEFAULT_OPENAI_MODEL,
295
- supportedModels: [
296
- FRAMEWORK_DEFAULT_OPENAI_MODEL,
297
- "gpt-5.6-terra",
298
- "gpt-5.6-luna",
299
- ],
295
+ supportedModels: ["gpt-5.6-luna", "gpt-5.6-terra", "gpt-5.6-sol"],
300
296
  },
301
297
  openrouter: {
302
298
  defaultModel: FRAMEWORK_DEFAULT_OPENROUTER_MODEL,
303
299
  supportedModels: [
304
- "anthropic/claude-fable-5",
305
- "anthropic/claude-opus-4.8",
306
- OPENROUTER_CLAUDE_SONNET_MODEL_ID,
307
- FRAMEWORK_DEFAULT_OPENROUTER_MODEL,
308
- "openai/gpt-5.6-terra",
309
300
  "openai/gpt-5.6-luna",
301
+ "openai/gpt-5.6-terra",
302
+ "openai/gpt-5.6-sol",
303
+ OPENROUTER_CLAUDE_SONNET_MODEL_ID,
304
+ "anthropic/claude-opus-4.8",
305
+ "anthropic/claude-fable-5",
310
306
  // Current stable Gemini on OpenRouter (2.5 Flash is GA)
311
307
  "google/gemini-2.5-flash",
312
308
  "z-ai/glm-5.2",