@agent-native/core 0.131.6 → 0.131.9

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 (113) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +31 -0
  3. package/corpus/core/docs/content/deployment.mdx +12 -10
  4. package/corpus/core/docs/content/security.mdx +2 -2
  5. package/corpus/core/package.json +1 -1
  6. package/corpus/core/src/a2a/invoke.ts +4 -2
  7. package/corpus/core/src/agent/action-continuation-guidance.ts +2 -1
  8. package/corpus/core/src/agent/engine/registry.ts +61 -9
  9. package/corpus/core/src/application-state/store.ts +18 -31
  10. package/corpus/core/src/cli/create.ts +115 -16
  11. package/corpus/core/src/client/AssistantChat.tsx +10 -2
  12. package/corpus/core/src/client/frame-protocol.ts +5 -1
  13. package/corpus/core/src/guards/no-env-credentials.ts +2 -0
  14. package/corpus/core/src/scripts/call-agent.ts +4 -2
  15. package/corpus/core/src/secrets/crypto.ts +44 -15
  16. package/corpus/core/src/secrets/storage.ts +6 -4
  17. package/corpus/core/src/server/agent-chat/action-filters-a2a.ts +2 -0
  18. package/corpus/core/src/templates/default/.agents/skills/secrets/SKILL.md +14 -9
  19. package/corpus/core/src/templates/headless/.agents/skills/secrets/SKILL.md +14 -9
  20. package/corpus/core/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +14 -9
  21. package/corpus/core/src/workspace-files/tool.ts +18 -11
  22. package/corpus/templates/analytics/AGENTS.md +1 -0
  23. package/corpus/templates/analytics/changelog/2026-07-30-delegated-analytics-questions-now-return-a-useful-current-me.md +6 -0
  24. package/corpus/templates/analytics/server/lib/real-data-actions.ts +10 -0
  25. package/corpus/templates/clips/actions/generate-workflow.ts +6 -4
  26. package/corpus/templates/clips/actions/reconcile-workflow-generation.ts +257 -0
  27. package/corpus/templates/clips/app/hooks/use-auto-title.ts +166 -4
  28. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +1 -1
  29. package/corpus/templates/clips/changelog/2026-07-27-stopped-agent-runs-no-longer-leave-generated-workflow-cards-.md +6 -0
  30. package/corpus/templates/clips/changelog/2026-07-30-workflow-generation-now-stops-retrying-after-repeated-failur.md +6 -0
  31. package/corpus/templates/clips/shared/workflow.ts +5 -0
  32. package/corpus/templates/plan/actions/get-visual-plan.ts +10 -6
  33. package/corpus/templates/plan/actions/patch-visual-plan-source.ts +117 -1
  34. package/corpus/templates/plan/actions/update-visual-plan.ts +56 -14
  35. package/corpus/templates/plan/app/pages/PlansPage.tsx +1 -1
  36. package/corpus/templates/plan/changelog/2026-07-30-plan-agents-recover-with-targeted-writes.md +6 -0
  37. package/corpus/templates/plan/shared/plan-content.ts +35 -0
  38. package/corpus/templates/slides/actions/create-deck.ts +1 -1
  39. package/corpus/templates/slides/changelog/2026-07-30-new-decks-now-start-with-an-empty-slide-list-when-no-slides-.md +6 -0
  40. package/dist/a2a/invoke.d.ts.map +1 -1
  41. package/dist/a2a/invoke.js +4 -2
  42. package/dist/a2a/invoke.js.map +1 -1
  43. package/dist/agent/action-continuation-guidance.d.ts.map +1 -1
  44. package/dist/agent/action-continuation-guidance.js +2 -1
  45. package/dist/agent/action-continuation-guidance.js.map +1 -1
  46. package/dist/agent/engine/registry.d.ts.map +1 -1
  47. package/dist/agent/engine/registry.js +59 -12
  48. package/dist/agent/engine/registry.js.map +1 -1
  49. package/dist/application-state/store.d.ts.map +1 -1
  50. package/dist/application-state/store.js +20 -36
  51. package/dist/application-state/store.js.map +1 -1
  52. package/dist/cli/create.d.ts +8 -1
  53. package/dist/cli/create.d.ts.map +1 -1
  54. package/dist/cli/create.js +98 -16
  55. package/dist/cli/create.js.map +1 -1
  56. package/dist/client/AssistantChat.d.ts.map +1 -1
  57. package/dist/client/AssistantChat.js +10 -2
  58. package/dist/client/AssistantChat.js.map +1 -1
  59. package/dist/client/frame-protocol.d.ts +1 -0
  60. package/dist/client/frame-protocol.d.ts.map +1 -1
  61. package/dist/client/frame-protocol.js.map +1 -1
  62. package/dist/collab/routes.d.ts +1 -1
  63. package/dist/collab/struct-routes.d.ts +1 -1
  64. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  65. package/dist/guards/no-env-credentials.d.ts.map +1 -1
  66. package/dist/guards/no-env-credentials.js +2 -0
  67. package/dist/guards/no-env-credentials.js.map +1 -1
  68. package/dist/mcp/screen-memory-stdio.d.ts +7 -7
  69. package/dist/mcp/screen-memory-stdio.d.ts.map +1 -1
  70. package/dist/notifications/routes.d.ts +6 -6
  71. package/dist/observability/routes.d.ts +3 -3
  72. package/dist/scripts/call-agent.d.ts.map +1 -1
  73. package/dist/scripts/call-agent.js +4 -2
  74. package/dist/scripts/call-agent.js.map +1 -1
  75. package/dist/secrets/crypto.d.ts +14 -9
  76. package/dist/secrets/crypto.d.ts.map +1 -1
  77. package/dist/secrets/crypto.js +42 -16
  78. package/dist/secrets/crypto.js.map +1 -1
  79. package/dist/secrets/storage.d.ts +6 -4
  80. package/dist/secrets/storage.d.ts.map +1 -1
  81. package/dist/secrets/storage.js +6 -4
  82. package/dist/secrets/storage.js.map +1 -1
  83. package/dist/server/agent-chat/action-filters-a2a.d.ts +1 -1
  84. package/dist/server/agent-chat/action-filters-a2a.d.ts.map +1 -1
  85. package/dist/server/agent-chat/action-filters-a2a.js +2 -0
  86. package/dist/server/agent-chat/action-filters-a2a.js.map +1 -1
  87. package/dist/server/realtime-token.d.ts +1 -1
  88. package/dist/server/transcribe-voice.d.ts +1 -1
  89. package/dist/templates/default/.agents/skills/secrets/SKILL.md +14 -9
  90. package/dist/templates/headless/.agents/skills/secrets/SKILL.md +14 -9
  91. package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +14 -9
  92. package/dist/workspace-files/tool.d.ts.map +1 -1
  93. package/dist/workspace-files/tool.js +18 -11
  94. package/dist/workspace-files/tool.js.map +1 -1
  95. package/docs/content/deployment.mdx +12 -10
  96. package/docs/content/security.mdx +2 -2
  97. package/package.json +1 -1
  98. package/src/a2a/invoke.ts +4 -2
  99. package/src/agent/action-continuation-guidance.ts +2 -1
  100. package/src/agent/engine/registry.ts +61 -9
  101. package/src/application-state/store.ts +18 -31
  102. package/src/cli/create.ts +115 -16
  103. package/src/client/AssistantChat.tsx +10 -2
  104. package/src/client/frame-protocol.ts +5 -1
  105. package/src/guards/no-env-credentials.ts +2 -0
  106. package/src/scripts/call-agent.ts +4 -2
  107. package/src/secrets/crypto.ts +44 -15
  108. package/src/secrets/storage.ts +6 -4
  109. package/src/server/agent-chat/action-filters-a2a.ts +2 -0
  110. package/src/templates/default/.agents/skills/secrets/SKILL.md +14 -9
  111. package/src/templates/headless/.agents/skills/secrets/SKILL.md +14 -9
  112. package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +14 -9
  113. package/src/workspace-files/tool.ts +18 -11
@@ -1,5 +1,7 @@
1
1
  import {
2
+ generateTabId,
2
3
  sendToAgentChat,
4
+ sendToAgentChatAndConfirm,
3
5
  type AgentChatMessage,
4
6
  } from "@agent-native/core/client/agent-chat";
5
7
  import { agentNativePath } from "@agent-native/core/client/api-path";
@@ -11,6 +13,8 @@ import { useRecordings, type RecordingSummary } from "./use-library";
11
13
 
12
14
  const DEFAULT_TITLE = "Untitled recording";
13
15
  const TWO_MINUTES_MS = 2 * 60 * 1000;
16
+ export const WORKFLOW_ACTION_MAX_ATTEMPTS = 5;
17
+ const WORKFLOW_ACTION_RETRY_DELAY_MS = 1000;
14
18
 
15
19
  /** True when `title` is blank or equal to the server-seeded default. */
16
20
  export function isDefaultTitle(title: string | null | undefined): boolean {
@@ -45,6 +49,8 @@ interface AiRequest {
45
49
  message?: string;
46
50
  includeFullVideoInAi?: boolean;
47
51
  openInChat?: boolean;
52
+ deliveredAt?: string;
53
+ deliveredTabId?: string;
48
54
  }
49
55
 
50
56
  const DISPATCHABLE_REQUESTS = new Set([
@@ -99,6 +105,36 @@ export function useAutoTitleBridge(): void {
99
105
  const dispatched = useRef<Set<string>>(new Set());
100
106
  const inflight = useRef<boolean>(false);
101
107
 
108
+ useEffect(() => {
109
+ const handleChatRunning = (event: Event) => {
110
+ const detail = (event as CustomEvent).detail;
111
+ if (
112
+ detail?.isRunning !== false ||
113
+ (detail.reason !== "stopped" && detail.reason !== "failed") ||
114
+ typeof detail.tabId !== "string"
115
+ )
116
+ return;
117
+
118
+ const recordingId = recordingIdFromTab(detail.tabId);
119
+ const requestedAt = requestedAtFromTab(detail.tabId);
120
+ if (!recordingId || !requestedAt) return;
121
+
122
+ void retryWorkflowAction(
123
+ {
124
+ operation: "stop",
125
+ recordingId,
126
+ requestedAt,
127
+ tabId: detail.tabId,
128
+ },
129
+ "reconciled",
130
+ );
131
+ };
132
+
133
+ window.addEventListener("agentNative.chatRunning", handleChatRunning);
134
+ return () =>
135
+ window.removeEventListener("agentNative.chatRunning", handleChatRunning);
136
+ }, []);
137
+
102
138
  const readyRecordings = recordings.filter((r) => r.status === "ready");
103
139
  const readyRecordingsKey = readyRecordings
104
140
  .map(
@@ -144,7 +180,6 @@ export function useAutoTitleBridge(): void {
144
180
  request.requestedAt ?? "0"
145
181
  }`;
146
182
  if (dispatched.current.has(dispatchKey)) continue;
147
- dispatched.current.add(dispatchKey);
148
183
  if (
149
184
  request.kind === "generate-metadata" ||
150
185
  request.kind === "regenerate-title"
@@ -155,8 +190,67 @@ export function useAutoTitleBridge(): void {
155
190
  dispatched.current.add(`${rec.id}:fallback`);
156
191
  }
157
192
 
158
- dispatchAiRequest(rec, request);
193
+ if (
194
+ request.kind === "generate-workflow" &&
195
+ typeof request.requestedAt === "string"
196
+ ) {
197
+ if (request.deliveredTabId) {
198
+ dispatched.current.add(dispatchKey);
199
+ void consumeWorkflowRequest({
200
+ recordingId: rec.id,
201
+ requestedAt: request.requestedAt,
202
+ tabId: request.deliveredTabId,
203
+ });
204
+ continue;
205
+ }
159
206
 
207
+ const tabId = workflowTabId(rec.id, request.requestedAt);
208
+ try {
209
+ const result = (await callAction(
210
+ "reconcile-workflow-generation" as any,
211
+ {
212
+ operation: "track",
213
+ recordingId: rec.id,
214
+ requestedAt: request.requestedAt,
215
+ tabId,
216
+ } as any,
217
+ )) as { tracked?: boolean };
218
+ if (result.tracked !== true) {
219
+ fallbackTimer = setTimeout(() => void tick(), 1000);
220
+ continue;
221
+ }
222
+ } catch {
223
+ fallbackTimer = setTimeout(() => void tick(), 1000);
224
+ continue;
225
+ }
226
+ const delivery = await sendToAgentChatAndConfirm({
227
+ ...buildAiRequestChatOptions(rec, request),
228
+ tabId,
229
+ chatTarget: "local",
230
+ });
231
+ if (!delivery.delivered) {
232
+ await retryWorkflowAction(
233
+ {
234
+ operation: "release",
235
+ recordingId: rec.id,
236
+ requestedAt: request.requestedAt,
237
+ tabId,
238
+ },
239
+ "released",
240
+ );
241
+ fallbackTimer = setTimeout(() => void tick(), 1000);
242
+ continue;
243
+ }
244
+ dispatched.current.add(dispatchKey);
245
+ void persistAndConsumeWorkflowRequest({
246
+ recordingId: rec.id,
247
+ requestedAt: request.requestedAt,
248
+ tabId,
249
+ });
250
+ continue;
251
+ }
252
+ dispatchAiRequest(rec, request);
253
+ dispatched.current.add(dispatchKey);
160
254
  void clearRequest(rec.id);
161
255
  } else if (isAutoTitleReplaceable(rec.title, rec.titleSource)) {
162
256
  // No server-queued delegation. Only dispatch the fallback for
@@ -294,8 +388,76 @@ export function buildAiRequestChatOptions(
294
388
  };
295
389
  }
296
390
 
297
- function dispatchAiRequest(rec: RecordingSummary, request: AiRequest) {
298
- sendToAgentChat(buildAiRequestChatOptions(rec, request));
391
+ interface WorkflowRunRequest {
392
+ recordingId: string;
393
+ requestedAt: string;
394
+ tabId: string;
395
+ }
396
+
397
+ export async function retryWorkflowAction(
398
+ request: WorkflowRunRequest & { operation: string },
399
+ successKey: string,
400
+ ): Promise<boolean> {
401
+ for (let attempt = 0; attempt < WORKFLOW_ACTION_MAX_ATTEMPTS; attempt += 1) {
402
+ try {
403
+ const result = (await callAction(
404
+ "reconcile-workflow-generation" as any,
405
+ request as any,
406
+ )) as Record<string, unknown>;
407
+ if (result[successKey] === true) return true;
408
+ if (typeof result.reason === "string" && result.reason !== "stale") {
409
+ return false;
410
+ }
411
+ } catch {}
412
+
413
+ if (attempt === WORKFLOW_ACTION_MAX_ATTEMPTS - 1) return false;
414
+ await new Promise((resolve) =>
415
+ setTimeout(resolve, WORKFLOW_ACTION_RETRY_DELAY_MS * 2 ** attempt),
416
+ );
417
+ }
418
+
419
+ return false;
420
+ }
421
+
422
+ async function consumeWorkflowRequest(
423
+ request: WorkflowRunRequest,
424
+ ): Promise<boolean> {
425
+ return retryWorkflowAction({ ...request, operation: "consume" }, "consumed");
426
+ }
427
+
428
+ async function persistAndConsumeWorkflowRequest(
429
+ request: WorkflowRunRequest,
430
+ ): Promise<void> {
431
+ const delivered = await retryWorkflowAction(
432
+ { ...request, operation: "mark-delivered" },
433
+ "delivered",
434
+ );
435
+ if (delivered) await consumeWorkflowRequest(request);
436
+ }
437
+
438
+ function workflowTabId(recordingId: string, requestedAt: string) {
439
+ return `clips-workflow:${recordingId}:${encodeURIComponent(requestedAt)}:${generateTabId()}`;
440
+ }
441
+
442
+ function recordingIdFromTab(tabId: string) {
443
+ const match = /^clips-workflow:([^:]+):/.exec(tabId);
444
+ return match?.[1];
445
+ }
446
+
447
+ function requestedAtFromTab(tabId: string) {
448
+ const match = /^clips-workflow:[^:]+:([^:]+):/.exec(tabId);
449
+ return match ? decodeURIComponent(match[1]) : undefined;
450
+ }
451
+
452
+ function dispatchAiRequest(
453
+ rec: RecordingSummary,
454
+ request: AiRequest,
455
+ tabId?: string,
456
+ ) {
457
+ return sendToAgentChat({
458
+ ...buildAiRequestChatOptions(rec, request),
459
+ ...(tabId ? { tabId } : {}),
460
+ });
299
461
  }
300
462
 
301
463
  function parseJsonArray(raw: string | undefined): unknown[] {
@@ -27,6 +27,7 @@ import {
27
27
  DASHBOARD_REDIRECT_VALUE,
28
28
  REF_PARAM,
29
29
  } from "@shared/share-attribution";
30
+ import type { WorkflowKind } from "@shared/workflow";
30
31
  import {
31
32
  IconShare3,
32
33
  IconArrowLeft,
@@ -109,7 +110,6 @@ export function meta() {
109
110
  }
110
111
 
111
112
  type SidePanel = "transcript" | "comments" | "insights" | "agent" | "settings";
112
- type WorkflowKind = "pr" | "sop" | "ticket" | "email";
113
113
 
114
114
  const WORKFLOW_MENU_ITEMS: Array<{
115
115
  kind: WorkflowKind;
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-27
4
+ ---
5
+
6
+ Stopped agent runs no longer leave generated workflow cards spinning indefinitely.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-30
4
+ ---
5
+
6
+ Workflow generation now stops retrying after repeated failures instead of remaining active indefinitely.
@@ -0,0 +1,5 @@
1
+ import { z } from "zod";
2
+
3
+ export const WORKFLOW_KINDS = ["pr", "sop", "ticket", "email"] as const;
4
+ export const WorkflowKindSchema = z.enum(WORKFLOW_KINDS);
5
+ export type WorkflowKind = z.infer<typeof WorkflowKindSchema>;
@@ -39,13 +39,13 @@ export default defineAction({
39
39
  .boolean()
40
40
  .optional()
41
41
  .describe(
42
- "Include the exported MDX folder in the response. Defaults to true for agents; set false to skip the Prettier-formatted MDX export when you only need structured content or HTML.",
42
+ "Include the exported MDX folder in the response. Defaults to false for agent reads; set true for an explicit source-control workflow.",
43
43
  ),
44
44
  html: z
45
45
  .boolean()
46
46
  .optional()
47
47
  .describe(
48
- "Include the exported HTML bundle in the response. Defaults to true for legacy plans; set false to skip when you only need structured content.",
48
+ "Include the exported HTML bundle in the response. Defaults to false for agent reads; set true when you explicitly need the rendered legacy artifact.",
49
49
  ),
50
50
  })
51
51
  .optional()
@@ -80,10 +80,14 @@ export default defineAction({
80
80
  // for their iframe.
81
81
  const isFrontend = ctx?.caller === "frontend";
82
82
  const isModern = Boolean(bundle.plan.content);
83
- // Caller-controlled opt-out; defaults preserve existing behavior.
84
- const wantMdx = args.includeMdx ?? args.include?.mdx ?? true;
85
- const wantHtml = args.includeHtml ?? args.include?.html ?? true;
86
- const includeStoredPlanExportFields = !isFrontend || wantHtml || wantMdx;
83
+ const isAgentCaller =
84
+ ctx?.caller === "tool" || ctx?.caller === "mcp" || ctx?.caller === "a2a";
85
+ // Agent reads default to the structured model only; source-control and
86
+ // legacy-rendered exports remain opt-in so they do not inflate the next
87
+ // tool turn.
88
+ const wantMdx = args.includeMdx ?? args.include?.mdx ?? !isAgentCaller;
89
+ const wantHtml = args.includeHtml ?? args.include?.html ?? !isAgentCaller;
90
+ const includeStoredPlanExportFields = wantHtml || wantMdx;
87
91
  return {
88
92
  ...bundle,
89
93
  planId: bundle.plan.id,
@@ -28,6 +28,73 @@ import {
28
28
  } from "../server/plans.js";
29
29
  import type { PlanContent } from "../shared/plan-content.js";
30
30
 
31
+ const agentPlanMdxSourcePatchesSchema = z
32
+ .array(
33
+ z.discriminatedUnion("op", [
34
+ z.object({
35
+ op: z.literal("replace-markdown-block"),
36
+ blockId: z.string().min(1),
37
+ markdown: z.string().max(16_000),
38
+ title: z.string().optional(),
39
+ }),
40
+ z.object({
41
+ op: z.literal("update-component-prop"),
42
+ file: z.enum(["plan.mdx", "canvas.mdx", "prototype.mdx"]),
43
+ componentId: z.string().min(1),
44
+ prop: z.string().min(1),
45
+ value: z.unknown(),
46
+ }),
47
+ z.object({
48
+ op: z.literal("update-wireframe-node"),
49
+ nodeId: z.string().min(1),
50
+ patch: z.record(z.string(), z.unknown()),
51
+ }),
52
+ z.object({
53
+ op: z.literal("update-annotation"),
54
+ annotationId: z.string().min(1),
55
+ patch: z.object({
56
+ type: z.enum(["note", "text", "callout", "arrow"]).optional(),
57
+ title: z.string().optional(),
58
+ text: z.string().max(2_000).optional(),
59
+ points: z
60
+ .array(z.object({ x: z.number(), y: z.number() }))
61
+ .min(1)
62
+ .max(12)
63
+ .optional(),
64
+ style: z
65
+ .object({
66
+ tone: z
67
+ .enum(["default", "accent", "warn", "ok", "muted"])
68
+ .optional(),
69
+ stroke: z.enum(["solid", "dashed"]).optional(),
70
+ width: z.number().min(1).max(12).optional(),
71
+ })
72
+ .optional(),
73
+ targetId: z.string().optional(),
74
+ placement: z
75
+ .enum([
76
+ "top",
77
+ "right",
78
+ "bottom",
79
+ "left",
80
+ "top-left",
81
+ "top-right",
82
+ "bottom-left",
83
+ "bottom-right",
84
+ ])
85
+ .optional(),
86
+ x: z.number().optional(),
87
+ y: z.number().optional(),
88
+ }),
89
+ }),
90
+ ]),
91
+ )
92
+ .max(80)
93
+ .describe(
94
+ "Small exported-MDX patches only. Never send replace-file or replace-artboard " +
95
+ "from an agent; for a live plan use update-visual-plan contentPatches instead.",
96
+ );
97
+
31
98
  type PlanSurfaceCounts = {
32
99
  blocks: number;
33
100
  canvasFrames: number;
@@ -42,6 +109,28 @@ function planSurfaceCounts(content: PlanContent | null | undefined) {
42
109
  } satisfies PlanSurfaceCounts;
43
110
  }
44
111
 
112
+ function compactAgentWriteResult(
113
+ bundle: Awaited<ReturnType<typeof loadPlanBundle>>,
114
+ changed: Record<string, unknown>,
115
+ ) {
116
+ return {
117
+ planId: bundle.plan.id,
118
+ plan: {
119
+ id: bundle.plan.id,
120
+ title: bundle.plan.title,
121
+ brief: bundle.plan.brief,
122
+ kind: bundle.plan.kind,
123
+ status: bundle.plan.status,
124
+ currentFocus: bundle.plan.currentFocus,
125
+ updatedAt: bundle.plan.updatedAt,
126
+ surfaces: planSurfaceCounts(bundle.plan.content),
127
+ },
128
+ changed,
129
+ path: planPath(bundle.plan.id, bundle.plan.kind),
130
+ url: planPath(bundle.plan.id, bundle.plan.kind),
131
+ };
132
+ }
133
+
45
134
  function stableJson(value: unknown): string {
46
135
  if (value === null) return "null";
47
136
  if (value === undefined) return "undefined";
@@ -140,7 +229,7 @@ function assertNoUnexpectedSurfaceCollapse(
140
229
 
141
230
  export default defineAction({
142
231
  description:
143
- "Patch the MDX source for an Agent-Native Plan by stable semantic IDs, then normalize it back into runtime JSON. Use ONLY when working with exported MDX source files (repo check-in workflows); for live plans prefer update-visual-plan with contentPatches. Suitable for tiny source-control friendly diffs: one markdown block, one artboard, one annotation, or one wireframe node.",
232
+ "Patch the MDX source for an Agent-Native Plan by stable semantic IDs, then normalize it back into runtime JSON. Use ONLY when working with exported MDX source files (repo check-in workflows); for live plans prefer update-visual-plan with contentPatches. For agent calls, use only small semantic patches and never resend replace-file or replace-artboard payloads.",
144
233
  schema: z.object({
145
234
  planId: z.string().describe("Plan ID"),
146
235
  expectedUpdatedAt: z
@@ -162,6 +251,21 @@ export default defineAction({
162
251
  ),
163
252
  note: z.string().optional().describe("Short audit note for plan history."),
164
253
  }),
254
+ agentInputSchema: z.object({
255
+ planId: z.string().describe("Plan ID"),
256
+ expectedUpdatedAt: z
257
+ .string()
258
+ .min(1)
259
+ .optional()
260
+ .describe("Revision from the latest plan read when required."),
261
+ allowDestructive: z
262
+ .boolean()
263
+ .optional()
264
+ .default(false)
265
+ .describe("Allow an intentional nonempty-to-empty collapse."),
266
+ patches: agentPlanMdxSourcePatchesSchema,
267
+ note: z.string().optional().describe("Short audit note for plan history."),
268
+ }),
165
269
  publicAgent: {
166
270
  expose: true,
167
271
  readOnly: false,
@@ -321,6 +425,18 @@ export default defineAction({
321
425
  ),
322
426
  })
323
427
  : null;
428
+ if (isAgentCaller) {
429
+ return {
430
+ ...compactAgentWriteResult(updated, {
431
+ patchOps: args.patches.map((patch) => patch.op),
432
+ counts: {
433
+ before: beforeCounts,
434
+ after: afterCounts,
435
+ },
436
+ }),
437
+ ...(local?.written ? { localFiles: local } : {}),
438
+ };
439
+ }
324
440
  return {
325
441
  ...updated,
326
442
  planId: updated.plan.id,
@@ -49,8 +49,7 @@ import {
49
49
  sectionInputSchema,
50
50
  } from "../server/plans.js";
51
51
  import {
52
- agentPlanContentPatchesSchema,
53
- agentPlanContentSchema,
52
+ agentPlanIncrementalContentPatchesSchema,
54
53
  applyPlanContentPatches,
55
54
  planContentPatchesSchema,
56
55
  planContentSchema,
@@ -454,6 +453,32 @@ const CONTENT_DESCRIPTION =
454
453
  const CONTENT_PATCHES_DESCRIPTION =
455
454
  "Targeted structured content edits addressed by stable id. Prefer granular operations for live plans. The destructive replace-blocks operation requires expectedUpdatedAt from a fresh read. patch-visual-plan-source is only for exported MDX folders. Supported ops: set-metadata for title/brief; set-visual-render-mode to persist `design` (high fidelity, authored CSS, no rough.js for any viewer) or `wireframe` across canvas, linked blocks, and prototype screens; set-prototype / remove-prototype / update-prototype-screen / patch-prototype-html for live prototype surfaces; update-block / replace-block, update-rich-text, patch-wireframe-html, patch-diagram-html, update-wireframe-node, replace-wireframe-screen, update-canvas-frame, update-canvas-annotation / append-canvas-annotation, append-block / remove-block, update-custom-html. A fidelity upgrade must also replace or patch the existing screen HTML/CSS with deliberate branded design; changing render mode alone only removes the sketch treatment.";
456
455
 
456
+ function compactAgentWriteResult(
457
+ bundle: Awaited<ReturnType<typeof loadPlanBundle>>,
458
+ changed: Record<string, unknown>,
459
+ ) {
460
+ return {
461
+ planId: bundle.plan.id,
462
+ plan: {
463
+ id: bundle.plan.id,
464
+ title: bundle.plan.title,
465
+ brief: bundle.plan.brief,
466
+ kind: bundle.plan.kind,
467
+ status: bundle.plan.status,
468
+ currentFocus: bundle.plan.currentFocus,
469
+ updatedAt: bundle.plan.updatedAt,
470
+ surfaces: {
471
+ blocks: bundle.plan.content?.blocks.length ?? 0,
472
+ canvasFrames: bundle.plan.content?.canvas?.frames.length ?? 0,
473
+ prototypeScreens: bundle.plan.content?.prototype?.screens.length ?? 0,
474
+ },
475
+ },
476
+ changed,
477
+ path: planPath(bundle.plan.id, bundle.plan.kind),
478
+ url: planPath(bundle.plan.id, bundle.plan.kind),
479
+ };
480
+ }
481
+
457
482
  // Named so `agentInputSchema` below can `.extend()` it with compact
458
483
  // `content`/`contentPatches` fields instead of duplicating every other key.
459
484
  const updateVisualPlanSchema = z.object({
@@ -527,21 +552,26 @@ const updateVisualPlanSchema = z.object({
527
552
  .describe("Short label saved as the version-history snapshot label."),
528
553
  });
529
554
 
555
+ // ADVERTISED-ONLY: agent edits to an existing plan must stay incremental. The
556
+ // runtime schema above still accepts full replacements for the browser editor
557
+ // and explicit callers that have intentionally chosen that workflow.
558
+ const agentUpdateVisualPlanSchema = updateVisualPlanSchema
559
+ .omit({ content: true, html: true, markdown: true, sections: true })
560
+ .extend({
561
+ contentPatches: agentPlanIncrementalContentPatchesSchema
562
+ .optional()
563
+ .default([])
564
+ .describe(
565
+ "Small targeted edits only. Do not send full content or replace-blocks; " +
566
+ "append or patch one existing block at a time.",
567
+ ),
568
+ });
569
+
530
570
  export default defineAction({
531
571
  description:
532
- "Update an Agent-Native Plan's structured content blocks, prototype screens, visual fidelity, sections, comments, or status. Prefer contentPatches for targeted edits. When a user asks for higher fidelity on an existing plan, update that same plan in place: use set-visual-render-mode with design and provide polished screen HTML/CSS in the same call instead of creating a duplicate plan or only toggling the viewer-local clean style. Use full content only for broad restructuring. Works on plans and recaps alike when you have editor access; with viewer access (common on PR recaps published by CI) only comment-only calls succeed to change a recap you cannot edit, publish a replacement with create-visual-recap instead of retrying this call.",
572
+ "Update an Agent-Native Plan's structured content blocks, prototype screens, visual fidelity, sections, comments, or status. For an existing plan, use small contentPatches such as append-block, update-rich-text, or a text patch; do not resend the full document for an incremental edit. When a user asks for higher fidelity on an existing plan, update that same plan in place: use set-visual-render-mode with design and provide polished screen HTML/CSS in the same call instead of creating a duplicate plan or only toggling the viewer-local clean style. Use a full replacement only for an explicit broad rebuild. Works on plans and recaps alike when you have editor access; with viewer access (common on PR recaps published by CI) only comment-only calls succeed - to change a recap you cannot edit, publish a replacement with create-visual-recap instead of retrying this call.",
533
573
  schema: updateVisualPlanSchema,
534
- // ADVERTISED-ONLY: same top-level shape, but `content`/`contentPatches`
535
- // swap the deep per-block-type union for a compact `type`-enum stand-in.
536
- // Runtime validation always runs the full schema above — see the `actions`
537
- // skill.
538
- agentInputSchema: updateVisualPlanSchema.extend({
539
- content: agentPlanContentSchema.optional().describe(CONTENT_DESCRIPTION),
540
- contentPatches: agentPlanContentPatchesSchema
541
- .optional()
542
- .default([])
543
- .describe(CONTENT_PATCHES_DESCRIPTION),
544
- }),
574
+ agentInputSchema: agentUpdateVisualPlanSchema,
545
575
  publicAgent: {
546
576
  expose: true,
547
577
  readOnly: false,
@@ -1173,6 +1203,18 @@ export default defineAction({
1173
1203
  ),
1174
1204
  })
1175
1205
  : null;
1206
+ if (isAgentCaller) {
1207
+ return {
1208
+ ...compactAgentWriteResult(bundle, {
1209
+ titleChanged: args.title !== undefined,
1210
+ briefChanged: args.brief !== undefined,
1211
+ statusChanged: args.status !== undefined,
1212
+ contentPatchOps: args.contentPatches.map((patch) => patch.op),
1213
+ commentCount: insertedCommentIds.length,
1214
+ }),
1215
+ ...(local?.written ? { localFiles: local } : {}),
1216
+ };
1217
+ }
1176
1218
  return {
1177
1219
  ...bundle,
1178
1220
  planId: bundle.plan.id,
@@ -1602,7 +1602,7 @@ export function buildPlanAgentContext(input: {
1602
1602
  : [
1603
1603
  "Fast iteration workflow:",
1604
1604
  "1. Call get-visual-plan with this plan ID to read structured content, exported HTML, sections, comments, and activity.",
1605
- '2. Prefer update-visual-plan contentPatches for targeted edits. Examples: update-rich-text for copy, patch-prototype-html / update-prototype-screen for live prototype states, update-wireframe-node for one kit-tree node, update-canvas-frame for frame layout, append-canvas-annotation / update-canvas-annotation for canvas markup, append-block/remove-block for document changes, or replace-block for a single block. When the user asks for higher fidelity, polished mockups, production-like UI, real design, or anything "not sketchy," update this same plan in place: rewrite the relevant screen HTML/CSS and include set-visual-render-mode with renderMode design. Do not create a second plan, put CSS in style tags, or treat the viewer-local Clean toggle as a fidelity upgrade. Use full content only for broad restructuring. Use html only when preserving or importing a legacy standalone HTML artifact.',
1605
+ '2. Prefer small update-visual-plan contentPatches for every edit to an existing plan. Examples: append-block for new tasks, update-rich-text for a bounded copy change, patch-prototype-html / update-prototype-screen for live prototype states, update-wireframe-node for one kit-tree node, update-canvas-frame for frame layout, append-canvas-annotation / update-canvas-annotation for canvas markup, or remove-block for one block. Never resend the full plan, use replace-blocks, or use patch-visual-plan-source replace-file for an incremental change - those payloads can be truncated before the tool receives them. When the user asks for higher fidelity, polished mockups, production-like UI, real design, or anything "not sketchy," update this same plan in place: rewrite the relevant screen HTML/CSS and include set-visual-render-mode with renderMode design. Do not create a second plan, put CSS in style tags, or treat the viewer-local Clean toggle as a fidelity upgrade. Use a full replacement only for an explicit broad rebuild. Use html only when preserving or importing a legacy standalone HTML artifact.',
1606
1606
  "3. Preserve the user's existing annotation comments and intent unless the user asks to remove or resolve them.",
1607
1607
  "4. Match the requested fidelity: ordinary UI planning can use sketch diagrams and wireframes; high-fidelity requests need the persisted Design surface with deliberate branded HTML/CSS and stable data-design-id targets.",
1608
1608
  "5. After applying feedback, keep the plan scannable, editable, and serious instead of turning it into a marketing page.",
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-30
4
+ ---
5
+
6
+ Plan agents now recover interrupted edits with small targeted writes.
@@ -2944,6 +2944,41 @@ export const agentPlanContentPatchesSchema = z
2944
2944
  "replace-block / replace-blocks / append-block.",
2945
2945
  );
2946
2946
 
2947
+ /**
2948
+ * Model-facing patch vocabulary for edits to an existing hosted plan. Full
2949
+ * block/content replacement remains valid at runtime for the browser editor
2950
+ * and explicit callers, but advertising it to an agent makes it too easy to
2951
+ * resend the whole document and hit the provider's streamed-JSON limit.
2952
+ */
2953
+ const AGENT_INCREMENTAL_PATCH_EXCLUDED_OPS = new Set([
2954
+ "set-prototype",
2955
+ "replace-block",
2956
+ "replace-blocks",
2957
+ "replace-wireframe-screen",
2958
+ ]);
2959
+
2960
+ const agentIncrementalPlanContentPatchOptions =
2961
+ agentPlanContentPatchOptions.filter((option) => {
2962
+ const op = (option.shape as { op: { value: string } }).op.value;
2963
+ return !AGENT_INCREMENTAL_PATCH_EXCLUDED_OPS.has(op);
2964
+ });
2965
+
2966
+ export const agentPlanIncrementalContentPatchesSchema = z
2967
+ .array(
2968
+ z.discriminatedUnion(
2969
+ "op",
2970
+ agentIncrementalPlanContentPatchOptions as unknown as Parameters<
2971
+ typeof z.discriminatedUnion
2972
+ >[1],
2973
+ ),
2974
+ )
2975
+ .max(80)
2976
+ .describe(
2977
+ "Small targeted edits to an existing plan. Prefer append-block, update-rich-text, " +
2978
+ "patch-wireframe-html, patch-prototype-html, or update-block. Do not " +
2979
+ "resend the full plan; use get-visual-plan for context and keep each call incremental.",
2980
+ );
2981
+
2947
2982
  export function applyPlanContentPatches(
2948
2983
  content: PlanContent,
2949
2984
  patches: PlanContentPatch[],
@@ -75,7 +75,7 @@ const SlideSchema = z.object({
75
75
 
76
76
  // Accept either a parsed array (HTTP/agent) or a JSON string (CLI)
77
77
  const SlidesSchema = z.preprocess(
78
- (v) => (typeof v === "string" ? JSON.parse(v) : v),
78
+ (v) => (v === undefined ? [] : typeof v === "string" ? JSON.parse(v) : v),
79
79
  z.array(SlideSchema),
80
80
  );
81
81
 
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-30
4
+ ---
5
+
6
+ New decks now start with an empty slide list when no slides are provided
@@ -1 +1 @@
1
- {"version":3,"file":"invoke.d.ts","sourceRoot":"","sources":["../../src/a2a/invoke.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"invoke.d.ts","sourceRoot":"","sources":["../../src/a2a/invoke.ts"],"names":[],"mappings":"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"}
@@ -121,9 +121,11 @@ export async function invokeAgentAction(options) {
121
121
  }
122
122
  export function buildAgentInvocationPrompt(prompt, agentUrl) {
123
123
  return (`${prompt}\n\n` +
124
- `[Note: this request comes from another app via A2A. The caller cannot see your local UI, resource list, or navigation - only the literal text you put in your reply. ` +
124
+ `<a2a-caller-hint>\n` +
125
+ `This request comes from another app via A2A. The caller cannot see your local UI, resource list, or navigation - only the literal text you put in your reply. ` +
125
126
  `If you create or reference a deck/document/design/dashboard/resource, include its FULLY-QUALIFIED URL (e.g. ${agentUrl.replace(/\/$/, "")}/<path>/<id>) in your reply, not a relative path. ` +
126
- `Use only artifact IDs and URL paths returned by successful actions - never invent slugs, IDs, or hosts.]`);
127
+ `Use only artifact IDs and URL paths returned by successful actions - never invent slugs, IDs, or hosts.\n` +
128
+ `</a2a-caller-hint>`);
127
129
  }
128
130
  export function looksLikeAgentUrl(value) {
129
131
  return /^[a-z][a-z0-9+.-]*:\/\//i.test(value.trim());