@builder.io/ai-utils 0.95.0 → 0.96.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@builder.io/ai-utils",
3
- "version": "0.95.0",
3
+ "version": "0.96.1",
4
4
  "description": "Builder.io AI utils",
5
5
  "files": [
6
6
  "src"
@@ -12,11 +12,34 @@ export interface InvestigationCompletionJSON {
12
12
  messages?: MessageParam[];
13
13
  }
14
14
  export declare function serializeContentToBlocks(message: string | ContentMessage | undefined): string;
15
+ export declare function serializeMessage(message: MessageParam): string;
15
16
  export declare function messagesToText(messages: MessageParam[]): string;
16
17
  export declare function truncateToolResultsInTranscript(text: string): string;
18
+ export interface InvestigationTimelineEntry {
19
+ id: string;
20
+ timestampMs?: number;
21
+ role?: string;
22
+ message?: string;
23
+ hasError?: boolean;
24
+ }
17
25
  export interface BuildInvestigationSystemPromptInput {
18
26
  event: InvestigationEvent;
19
27
  completionJson: InvestigationCompletionJSON | undefined;
28
+ timeline?: InvestigationTimelineEntry[];
29
+ }
30
+ export declare function buildInvestigationSystemPrompt({ event, completionJson, timeline, }: BuildInvestigationSystemPromptInput): string;
31
+ export interface InvestigationSessionTurn {
32
+ id: string;
33
+ timestampMs?: number;
34
+ hasError?: boolean;
35
+ completionJson?: InvestigationCompletionJSON;
36
+ }
37
+ export interface BuildSessionInvestigationSystemPromptInput {
38
+ focusEvent: InvestigationEvent;
39
+ focusCompletionJson: InvestigationCompletionJSON | undefined;
40
+ turns: InvestigationSessionTurn[];
41
+ timeline?: InvestigationTimelineEntry[];
20
42
  }
21
- export declare function buildInvestigationSystemPrompt({ event, completionJson, }: BuildInvestigationSystemPromptInput): string;
43
+ export declare function buildSessionInvestigationSystemPrompt({ focusEvent, focusCompletionJson, turns, timeline, }: BuildSessionInvestigationSystemPromptInput): string;
22
44
  export declare const SUGGESTED_QUESTIONS: readonly string[];
45
+ export declare const SESSION_SUGGESTED_QUESTIONS: readonly string[];
@@ -48,13 +48,12 @@ export function serializeContentToBlocks(message) {
48
48
  })
49
49
  .join("\n\n");
50
50
  }
51
+ export function serializeMessage(message) {
52
+ const content = serializeContentToBlocks(message.content);
53
+ return `<___llm_message___ role=${JSON.stringify(message.role)}>\n${content}\n</___llm_message___>`;
54
+ }
51
55
  export function messagesToText(messages) {
52
- return messages
53
- .map((message) => {
54
- const content = serializeContentToBlocks(message.content);
55
- return `<___llm_message___ role=${JSON.stringify(message.role)}>\n${content}\n</___llm_message___>`;
56
- })
57
- .join("\n\n");
56
+ return messages.map(serializeMessage).join("\n\n");
58
57
  }
59
58
  export function truncateToolResultsInTranscript(text) {
60
59
  // Truncate any oversized tool_result block content so a single huge tool
@@ -110,33 +109,139 @@ export function truncateToolResultsInTranscript(text) {
110
109
  }
111
110
  return result;
112
111
  }
113
- export function buildInvestigationSystemPrompt({ event, completionJson, }) {
112
+ // Oldest-first; entries without a timestamp keep their relative order at the end.
113
+ function byTimestampAsc(entries) {
114
+ return [...entries].sort((a, b) => { var _a, _b; return ((_a = a.timestampMs) !== null && _a !== void 0 ? _a : Infinity) - ((_b = b.timestampMs) !== null && _b !== void 0 ? _b : Infinity); });
115
+ }
116
+ function buildTimelineBlock(timeline, currentEventId) {
117
+ if (!(timeline === null || timeline === void 0 ? void 0 : timeline.length))
118
+ return "";
119
+ const MESSAGE_PREVIEW_CHARS = 200;
120
+ const lines = byTimestampAsc(timeline).map((entry, index) => {
121
+ var _a;
122
+ const when = entry.timestampMs != null && Number.isFinite(entry.timestampMs)
123
+ ? new Date(entry.timestampMs).toISOString()
124
+ : "(no timestamp)";
125
+ const role = entry.role ? `[${entry.role}]` : "[?]";
126
+ const marker = entry.id === currentEventId ? " ▶" : "";
127
+ const error = entry.hasError ? " (error)" : "";
128
+ const flat = ((_a = entry.message) !== null && _a !== void 0 ? _a : "").replace(/\s+/g, " ").trim();
129
+ const preview = flat.length > MESSAGE_PREVIEW_CHARS
130
+ ? `${flat.slice(0, MESSAGE_PREVIEW_CHARS)}…`
131
+ : flat;
132
+ return `${index + 1}. ${when} ${role}${marker}${error} ${JSON.stringify(preview)}`;
133
+ });
134
+ return `## Session timeline (turn timestamps)\n\nEach line is one turn in this session — the same list shown on the left of the UI — oldest first, timestamps in UTC (ISO 8601). The event under investigation is marked ▶.\n\n${lines.join("\n")}`;
135
+ }
136
+ export function buildInvestigationSystemPrompt({ event, completionJson, timeline, }) {
114
137
  var _a, _b;
115
138
  const role = `You are a senior AI engineer helping debug a single codegen agent call.
116
139
  You have exactly the same context the engineer sees on the LLM tab for this
117
140
  event: the system prompt and the message transcript (with tool_use,
118
- tool_result, and thinking blocks). Be concise, specific, and critical.
141
+ tool_result, and thinking blocks), plus a session timeline giving the
142
+ timestamp of every turn. Be concise, specific, and critical.
119
143
 
120
144
  Ground every answer in the concrete data below: cite specific tool calls
121
- (by name + id), specific messages (by role + index), or system prompt
122
- sections. When you suggest improvements, propose concrete changes (e.g.
123
- "remove tool X", "add this instruction", "split this prompt section"). If
124
- the data does not support a claim, say so.`;
145
+ (by name + id), specific messages (by role + index), timeline entries (by
146
+ timestamp), or system prompt sections. When you suggest improvements, propose
147
+ concrete changes (e.g. "remove tool X", "add this instruction", "split this
148
+ prompt section"). If the data does not support a claim, say so.`;
125
149
  const header = `## Event\n\nid: ${event.id}\nmodel: ${(_a = completionJson === null || completionJson === void 0 ? void 0 : completionJson.model) !== null && _a !== void 0 ? _a : "(unknown)"}${event.hasError ? "\nstatus: ERROR" : ""}`;
150
+ const timelineBlock = buildTimelineBlock(timeline, event.id);
126
151
  // Use XML-style delimiters instead of triple-backtick fences: codegen
127
152
  // transcripts often contain markdown code fences themselves which would
128
153
  // otherwise close the outer block and corrupt the prompt.
129
154
  const systemPromptBlock = `## System prompt (verbatim)\n\n<___event_system_prompt___>\n${truncate((_b = completionJson === null || completionJson === void 0 ? void 0 : completionJson.systemPrompt) !== null && _b !== void 0 ? _b : "(no system prompt)", MAX_SYSTEM_PROMPT_CHARS)}\n</___event_system_prompt___>`;
155
+ // Debugging a long session needs the whole transcript verbatim, so this is
156
+ // sent in full — no per-tool-result or overall transcript truncation.
130
157
  const transcriptText = (completionJson === null || completionJson === void 0 ? void 0 : completionJson.messages)
131
- ? truncateToolResultsInTranscript(messagesToText(completionJson.messages))
158
+ ? messagesToText(completionJson.messages)
132
159
  : "(no messages)";
133
- const transcriptBlock = `## Message transcript (tool_use / tool_result / thinking)\n\n<___event_transcript___>\n${truncate(transcriptText, MAX_TRANSCRIPT_CHARS)}\n</___event_transcript___>`;
160
+ const transcriptBlock = `## Message transcript (tool_use / tool_result / thinking)\n\n<___event_transcript___>\n${transcriptText}\n</___event_transcript___>`;
134
161
  const guidance = `## How to answer
135
162
 
136
163
  - Start with a 1-2 sentence direct answer.
137
164
  - Back it up with specific evidence (tool names, message indices, prompt phrases).
138
165
  - End with concrete improvement suggestions when applicable.`;
139
- return [role, header, systemPromptBlock, transcriptBlock, guidance].join("\n\n");
166
+ return [
167
+ role,
168
+ header,
169
+ timelineBlock,
170
+ systemPromptBlock,
171
+ transcriptBlock,
172
+ guidance,
173
+ ]
174
+ .filter(Boolean)
175
+ .join("\n\n");
176
+ }
177
+ export function buildSessionInvestigationSystemPrompt({ focusEvent, focusCompletionJson, turns, timeline, }) {
178
+ var _a;
179
+ const role = `You are a senior AI engineer helping debug an entire codegen session:
180
+ a sequence of agent calls (turns). You have the same context the engineer sees
181
+ in the UI — a timeline of every turn with timestamps, and the message
182
+ transcript of the session (with tool_use, tool_result, and thinking blocks).
183
+ Because each turn re-sends the whole prior conversation, each turn below shows
184
+ only the messages it added; earlier messages it carried over are counted, not
185
+ repeated. Be concise, specific, and critical.
186
+
187
+ Ground every answer in the concrete data below: cite specific turns (by event
188
+ id or timestamp), tool calls (by name + id), or messages. Reason about how the
189
+ session evolved across turns — what changed, what regressed, and where. If the
190
+ data does not support a claim, say so.`;
191
+ const header = `## Session\n\nturns: ${turns.length}\nfocus turn (currently selected in UI): ${focusEvent.id}`;
192
+ const timelineBlock = buildTimelineBlock(timeline, focusEvent.id);
193
+ // Per-turn system prompts are largely shared within a session; include the
194
+ // focus turn's verbatim and point elsewhere for exact per-turn prompts.
195
+ const systemPromptBlock = `## System prompt (verbatim — from focus turn ${focusEvent.id}; other turns may differ)\n\n<___event_system_prompt___>\n${truncate((_a = focusCompletionJson === null || focusCompletionJson === void 0 ? void 0 : focusCompletionJson.systemPrompt) !== null && _a !== void 0 ? _a : "(no system prompt)", MAX_SYSTEM_PROMPT_CHARS)}\n</___event_system_prompt___>`;
196
+ // Each turn re-sends the whole prior conversation, so a turn's messages are
197
+ // a growing prefix of the next. Emit only the messages a turn adds beyond the
198
+ // previous one, so every message appears once instead of O(turns) times.
199
+ let prevSerialized = [];
200
+ const turnBlocks = byTimestampAsc(turns)
201
+ .map((turn, index) => {
202
+ var _a, _b;
203
+ var _c;
204
+ const when = turn.timestampMs != null && Number.isFinite(turn.timestampMs)
205
+ ? new Date(turn.timestampMs).toISOString()
206
+ : "(no timestamp)";
207
+ const model = (_c = (_a = turn.completionJson) === null || _a === void 0 ? void 0 : _a.model) !== null && _c !== void 0 ? _c : "(unknown)";
208
+ const status = turn.hasError ? ' status="ERROR"' : "";
209
+ const focus = turn.id === focusEvent.id ? ' focus="true"' : "";
210
+ if (!((_b = turn.completionJson) === null || _b === void 0 ? void 0 : _b.messages)) {
211
+ return `<___session_turn___ index="${index + 1}" event_id="${turn.id}" ts="${when}" model="${model}"${status}${focus}>\n(transcript not loaded)\n</___session_turn___>`;
212
+ }
213
+ const serialized = turn.completionJson.messages.map(serializeMessage);
214
+ let common = 0;
215
+ while (common < serialized.length &&
216
+ common < prevSerialized.length &&
217
+ serialized[common] === prevSerialized[common]) {
218
+ common++;
219
+ }
220
+ prevSerialized = serialized;
221
+ const added = serialized.slice(common);
222
+ const body = added.length
223
+ ? added.join("\n\n")
224
+ : "(no new messages beyond the previous turn)";
225
+ const carried = common > 0 ? ` carried_over_messages="${common}"` : "";
226
+ return `<___session_turn___ index="${index + 1}" event_id="${turn.id}" ts="${when}" model="${model}"${status}${focus}${carried}>\n${body}\n</___session_turn___>`;
227
+ })
228
+ .join("\n\n");
229
+ const transcriptBlock = `## Message transcripts (one block per turn, oldest first)\n\nEach turn re-sends the full prior conversation, so only the messages a turn adds are shown; \`carried_over_messages\` counts identical earlier messages omitted from that turn.\n\n${turnBlocks}`;
230
+ const guidance = `## How to answer
231
+
232
+ - Start with a 1-2 sentence direct answer.
233
+ - Back it up with specific evidence (turn ids/timestamps, tool names, message indices).
234
+ - End with concrete improvement suggestions when applicable.`;
235
+ return [
236
+ role,
237
+ header,
238
+ timelineBlock,
239
+ systemPromptBlock,
240
+ transcriptBlock,
241
+ guidance,
242
+ ]
243
+ .filter(Boolean)
244
+ .join("\n\n");
140
245
  }
141
246
  export const SUGGESTED_QUESTIONS = [
142
247
  "Why did this call fail or behave suboptimally?",
@@ -145,3 +250,10 @@ export const SUGGESTED_QUESTIONS = [
145
250
  "How could the system prompt be improved for this case?",
146
251
  "Walk me through the agent's reasoning step by step.",
147
252
  ];
253
+ export const SESSION_SUGGESTED_QUESTIONS = [
254
+ "Summarize what happened across this whole session.",
255
+ "Where did the session go wrong, and at which turn?",
256
+ "What did the user keep asking for that wasn't delivered?",
257
+ "Which turns were redundant or repeated work?",
258
+ "How did the agent's approach change over time?",
259
+ ];
package/src/codegen.d.ts CHANGED
@@ -2107,7 +2107,7 @@ export declare const DEFAULT_QUEUE_BEHAVIOR: QueueBehavior;
2107
2107
  /** True for any schedule that aborts the in-flight run on enqueue. */
2108
2108
  export declare function isInterruptSchedule(schedule: QueueSchedule): boolean;
2109
2109
  export declare function normalizeQueueMode(mode: QueueMode | undefined): QueueBehavior;
2110
- export declare const BASE_CODEGEN_POSITIONS: readonly ["fusion", "editor-ai", "repo-indexing", "cli", "create-app-firebase", "create-app-lovable", "builder-code-panel", "setup-project", "code-review-orchestrator", "project-configuration", "org-agent", "org-worker", "browser-testing", "projects-scheduler-memory-extraction", "builder-code", "unknown", "dsi-mcp", "design-system-indexer", "builder-publish-integration"];
2110
+ export declare const BASE_CODEGEN_POSITIONS: readonly ["fusion", "editor-ai", "repo-indexing", "cli", "create-app-firebase", "create-app-lovable", "builder-code-panel", "setup-project", "code-review-orchestrator", "project-configuration", "org-agent", "org-worker", "browser-testing", "projects-scheduler-memory-extraction", "builder-code", "unknown", "dsi-mcp", "design-system-indexer", "builder-publish-integration", "publish-agent"];
2111
2111
  export type BaseCodeGenPosition = (typeof BASE_CODEGEN_POSITIONS)[number];
2112
2112
  export declare const BaseCodeGenPositionSchema: z.ZodEnum<{
2113
2113
  "browser-testing": "browser-testing";
@@ -2126,6 +2126,7 @@ export declare const BaseCodeGenPositionSchema: z.ZodEnum<{
2126
2126
  "org-worker": "org-worker";
2127
2127
  "project-configuration": "project-configuration";
2128
2128
  "projects-scheduler-memory-extraction": "projects-scheduler-memory-extraction";
2129
+ "publish-agent": "publish-agent";
2129
2130
  "repo-indexing": "repo-indexing";
2130
2131
  "setup-project": "setup-project";
2131
2132
  unknown: "unknown";
@@ -2147,11 +2148,97 @@ export declare const CodeGenPositionSchema: z.ZodUnion<readonly [z.ZodEnum<{
2147
2148
  "org-worker": "org-worker";
2148
2149
  "project-configuration": "project-configuration";
2149
2150
  "projects-scheduler-memory-extraction": "projects-scheduler-memory-extraction";
2151
+ "publish-agent": "publish-agent";
2150
2152
  "repo-indexing": "repo-indexing";
2151
2153
  "setup-project": "setup-project";
2152
2154
  unknown: "unknown";
2153
- }>, z.ZodTemplateLiteral<"browser-testing-agent" | "builder-code-agent" | "builder-code-panel-agent" | "builder-publish-integration-agent" | "cli-agent" | "code-review-orchestrator-agent" | "create-app-firebase-agent" | "create-app-lovable-agent" | "design-system-indexer-agent" | "dsi-mcp-agent" | "editor-ai-agent" | "fusion-agent" | "org-agent-agent" | "org-worker-agent" | "project-configuration-agent" | "projects-scheduler-memory-extraction-agent" | "repo-indexing-agent" | "setup-project-agent" | "unknown-agent">]>;
2155
+ }>, z.ZodTemplateLiteral<"browser-testing-agent" | "builder-code-agent" | "builder-code-panel-agent" | "builder-publish-integration-agent" | "cli-agent" | "code-review-orchestrator-agent" | "create-app-firebase-agent" | "create-app-lovable-agent" | "design-system-indexer-agent" | "dsi-mcp-agent" | "editor-ai-agent" | "fusion-agent" | "org-agent-agent" | "org-worker-agent" | "project-configuration-agent" | "projects-scheduler-memory-extraction-agent" | "publish-agent-agent" | "repo-indexing-agent" | "setup-project-agent" | "unknown-agent">]>;
2154
2156
  export type CodeGenPosition = z.infer<typeof CodeGenPositionSchema>;
2157
+ export declare const PublishAgentMessageRequestSchema: z.ZodObject<{
2158
+ message: z.ZodOptional<z.ZodString>;
2159
+ sessionId: z.ZodOptional<z.ZodString>;
2160
+ toolResults: z.ZodOptional<z.ZodArray<z.ZodObject<{
2161
+ type: z.ZodLiteral<"tool_result">;
2162
+ tool_use_id: z.ZodString;
2163
+ tool_name: z.ZodOptional<z.ZodString>;
2164
+ tool_input: z.ZodOptional<z.ZodString>;
2165
+ title: z.ZodOptional<z.ZodString>;
2166
+ content: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
2167
+ type: z.ZodLiteral<"text">;
2168
+ text: z.ZodString;
2169
+ cache: z.ZodOptional<z.ZodBoolean>;
2170
+ citations: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
2171
+ cited_text: z.ZodString;
2172
+ document_index: z.ZodNumber;
2173
+ document_title: z.ZodNullable<z.ZodString>;
2174
+ end_char_index: z.ZodNumber;
2175
+ start_char_index: z.ZodNumber;
2176
+ type: z.ZodLiteral<"char_location">;
2177
+ }, z.core.$strip>, z.ZodObject<{
2178
+ cited_text: z.ZodString;
2179
+ document_index: z.ZodNumber;
2180
+ document_title: z.ZodNullable<z.ZodString>;
2181
+ end_page_number: z.ZodNumber;
2182
+ start_page_number: z.ZodNumber;
2183
+ type: z.ZodLiteral<"page_location">;
2184
+ }, z.core.$strip>, z.ZodObject<{
2185
+ cited_text: z.ZodString;
2186
+ document_index: z.ZodNumber;
2187
+ document_title: z.ZodNullable<z.ZodString>;
2188
+ end_block_index: z.ZodNumber;
2189
+ start_block_index: z.ZodNumber;
2190
+ type: z.ZodLiteral<"content_block_location">;
2191
+ }, z.core.$strip>, z.ZodObject<{
2192
+ cited_text: z.ZodString;
2193
+ encrypted_index: z.ZodString;
2194
+ title: z.ZodNullable<z.ZodString>;
2195
+ type: z.ZodLiteral<"web_search_result_location">;
2196
+ url: z.ZodString;
2197
+ }, z.core.$strip>], "type">>>>;
2198
+ ephemeral: z.ZodOptional<z.ZodBoolean>;
2199
+ thoughtSignature: z.ZodOptional<z.ZodString>;
2200
+ tag: z.ZodOptional<z.ZodString>;
2201
+ }, z.core.$strip>, z.ZodObject<{
2202
+ type: z.ZodLiteral<"image">;
2203
+ source: z.ZodDiscriminatedUnion<[z.ZodObject<{
2204
+ type: z.ZodLiteral<"base64">;
2205
+ media_type: z.ZodEnum<{
2206
+ "image/gif": "image/gif";
2207
+ "image/jpeg": "image/jpeg";
2208
+ "image/png": "image/png";
2209
+ "image/webp": "image/webp";
2210
+ }>;
2211
+ data: z.ZodString;
2212
+ original_url: z.ZodOptional<z.ZodString>;
2213
+ }, z.core.$strip>, z.ZodObject<{
2214
+ type: z.ZodLiteral<"url">;
2215
+ url: z.ZodString;
2216
+ }, z.core.$strip>], "type">;
2217
+ cache: z.ZodOptional<z.ZodBoolean>;
2218
+ ephemeral: z.ZodOptional<z.ZodBoolean>;
2219
+ }, z.core.$strip>, z.ZodObject<{
2220
+ type: z.ZodLiteral<"resource">;
2221
+ resource: z.ZodObject<{
2222
+ uri: z.ZodString;
2223
+ mimeType: z.ZodOptional<z.ZodString>;
2224
+ text: z.ZodOptional<z.ZodString>;
2225
+ blob: z.ZodOptional<z.ZodString>;
2226
+ }, z.core.$strip>;
2227
+ }, z.core.$strip>], "type">>]>;
2228
+ is_error: z.ZodOptional<z.ZodBoolean>;
2229
+ cache: z.ZodOptional<z.ZodBoolean>;
2230
+ ephemeral: z.ZodOptional<z.ZodBoolean>;
2231
+ structured_result: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
2232
+ }, z.core.$strip>>>;
2233
+ confirmation: z.ZodOptional<z.ZodObject<{
2234
+ actionId: z.ZodString;
2235
+ decision: z.ZodEnum<{
2236
+ approve: "approve";
2237
+ reject: "reject";
2238
+ }>;
2239
+ }, z.core.$strip>>;
2240
+ }, z.core.$strip>;
2241
+ export type PublishAgentMessageRequest = z.infer<typeof PublishAgentMessageRequestSchema>;
2155
2242
  export declare const RepoIndexingConfigSchema: z.ZodObject<{
2156
2243
  designSystems: z.ZodArray<z.ZodString>;
2157
2244
  }, z.core.$strip>;
@@ -2422,10 +2509,11 @@ export declare const CodeGenInputOptionsSchema: z.ZodObject<{
2422
2509
  "org-worker": "org-worker";
2423
2510
  "project-configuration": "project-configuration";
2424
2511
  "projects-scheduler-memory-extraction": "projects-scheduler-memory-extraction";
2512
+ "publish-agent": "publish-agent";
2425
2513
  "repo-indexing": "repo-indexing";
2426
2514
  "setup-project": "setup-project";
2427
2515
  unknown: "unknown";
2428
- }>, z.ZodTemplateLiteral<"browser-testing-agent" | "builder-code-agent" | "builder-code-panel-agent" | "builder-publish-integration-agent" | "cli-agent" | "code-review-orchestrator-agent" | "create-app-firebase-agent" | "create-app-lovable-agent" | "design-system-indexer-agent" | "dsi-mcp-agent" | "editor-ai-agent" | "fusion-agent" | "org-agent-agent" | "org-worker-agent" | "project-configuration-agent" | "projects-scheduler-memory-extraction-agent" | "repo-indexing-agent" | "setup-project-agent" | "unknown-agent">]>;
2516
+ }>, z.ZodTemplateLiteral<"browser-testing-agent" | "builder-code-agent" | "builder-code-panel-agent" | "builder-publish-integration-agent" | "cli-agent" | "code-review-orchestrator-agent" | "create-app-firebase-agent" | "create-app-lovable-agent" | "design-system-indexer-agent" | "dsi-mcp-agent" | "editor-ai-agent" | "fusion-agent" | "org-agent-agent" | "org-worker-agent" | "project-configuration-agent" | "projects-scheduler-memory-extraction-agent" | "publish-agent-agent" | "repo-indexing-agent" | "setup-project-agent" | "unknown-agent">]>;
2429
2517
  eventName: z.ZodOptional<z.ZodString>;
2430
2518
  sessionId: z.ZodString;
2431
2519
  codeGenMode: z.ZodOptional<z.ZodEnum<{
@@ -3472,10 +3560,11 @@ export declare const CustomAgentDefinitionSchema: z.ZodObject<{
3472
3560
  "org-worker": "org-worker";
3473
3561
  "project-configuration": "project-configuration";
3474
3562
  "projects-scheduler-memory-extraction": "projects-scheduler-memory-extraction";
3563
+ "publish-agent": "publish-agent";
3475
3564
  "repo-indexing": "repo-indexing";
3476
3565
  "setup-project": "setup-project";
3477
3566
  unknown: "unknown";
3478
- }>, z.ZodTemplateLiteral<"browser-testing-agent" | "builder-code-agent" | "builder-code-panel-agent" | "builder-publish-integration-agent" | "cli-agent" | "code-review-orchestrator-agent" | "create-app-firebase-agent" | "create-app-lovable-agent" | "design-system-indexer-agent" | "dsi-mcp-agent" | "editor-ai-agent" | "fusion-agent" | "org-agent-agent" | "org-worker-agent" | "project-configuration-agent" | "projects-scheduler-memory-extraction-agent" | "repo-indexing-agent" | "setup-project-agent" | "unknown-agent">]>>;
3567
+ }>, z.ZodTemplateLiteral<"browser-testing-agent" | "builder-code-agent" | "builder-code-panel-agent" | "builder-publish-integration-agent" | "cli-agent" | "code-review-orchestrator-agent" | "create-app-firebase-agent" | "create-app-lovable-agent" | "design-system-indexer-agent" | "dsi-mcp-agent" | "editor-ai-agent" | "fusion-agent" | "org-agent-agent" | "org-worker-agent" | "project-configuration-agent" | "projects-scheduler-memory-extraction-agent" | "publish-agent-agent" | "repo-indexing-agent" | "setup-project-agent" | "unknown-agent">]>>;
3479
3568
  needDevServer: z.ZodOptional<z.ZodBoolean>;
3480
3569
  needValidation: z.ZodOptional<z.ZodBoolean>;
3481
3570
  includeMemories: z.ZodOptional<z.ZodBoolean>;
@@ -4348,6 +4437,12 @@ export interface FusionConfig {
4348
4437
  /** PR number for fork PRs - used for fetching refs/pulls/x/head */
4349
4438
  prNumber?: number;
4350
4439
  refreshPreview?: boolean;
4440
+ /**
4441
+ * Keep the session's commits when HEAD has drifted off `aiBranch`: move the
4442
+ * AI branch to HEAD rather than checking out onto it, and repair the same
4443
+ * drift at backup time instead of refusing to back up.
4444
+ */
4445
+ preserveWorkOnBranchDrift?: boolean;
4351
4446
  workingDirectory?: string;
4352
4447
  bashWorkingDirectory?: string;
4353
4448
  workspace?: WorkspaceConfiguration;
@@ -4824,6 +4919,7 @@ export interface SearchFileTreeResult {
4824
4919
  }
4825
4920
  export interface SetupCommandResult {
4826
4921
  code: number | null;
4922
+ signal?: string;
4827
4923
  output: string;
4828
4924
  capturedEnv?: Record<string, string>;
4829
4925
  }
@@ -4867,6 +4963,8 @@ export interface BuildCommandResultFailure {
4867
4963
  code?: number;
4868
4964
  signal?: string;
4869
4965
  output: string;
4966
+ /** Which step produced `output`. Absent means the build command itself. */
4967
+ phase?: "setup" | "build";
4870
4968
  }
4871
4969
  export interface ConfigureDevOrchestratorUpdates {
4872
4970
  devCommand: boolean;
@@ -5014,6 +5112,8 @@ export interface SessionData {
5014
5112
  repoHash: string | undefined;
5015
5113
  repoBranch: string | undefined;
5016
5114
  description?: string;
5115
+ /** Hidden from the session list, but still readable by id. Creator-set. */
5116
+ archived?: boolean;
5017
5117
  hasPlanToApply?: boolean;
5018
5118
  cost: number;
5019
5119
  /** Cost from tools (e.g. WebSearch LLM calls) and sub-agent roll-ups. Total session cost = cost + extraCost. */
package/src/codegen.js CHANGED
@@ -1746,6 +1746,7 @@ export const BASE_CODEGEN_POSITIONS = [
1746
1746
  "dsi-mcp",
1747
1747
  "design-system-indexer",
1748
1748
  "builder-publish-integration",
1749
+ "publish-agent",
1749
1750
  ];
1750
1751
  export const BaseCodeGenPositionSchema = z
1751
1752
  .enum(BASE_CODEGEN_POSITIONS)
@@ -1756,6 +1757,27 @@ export const CodeGenPositionSchema = z
1756
1757
  z.templateLiteral([BaseCodeGenPositionSchema, "-agent"]),
1757
1758
  ])
1758
1759
  .meta({ title: "CodeGenPosition" });
1760
+ export const PublishAgentMessageRequestSchema = z
1761
+ .object({
1762
+ message: z.string().max(100000).optional(),
1763
+ sessionId: z.string().min(1).max(256).optional(),
1764
+ toolResults: z.array(ContentMessageItemToolResultSchema).optional(),
1765
+ confirmation: z
1766
+ .object({
1767
+ actionId: z.string().min(1).max(256),
1768
+ decision: z.enum(["approve", "reject"]),
1769
+ })
1770
+ .optional(),
1771
+ })
1772
+ .refine(({ message, toolResults }) => Boolean(message) || Boolean(toolResults === null || toolResults === void 0 ? void 0 : toolResults.length), {
1773
+ path: ["message"],
1774
+ message: "A message or at least one tool result is required.",
1775
+ })
1776
+ .refine(({ message, sessionId }) => Boolean(message) || Boolean(sessionId), {
1777
+ path: ["sessionId"],
1778
+ message: "A session ID is required when continuing with tool results.",
1779
+ })
1780
+ .meta({ title: "PublishAgentMessageRequest" });
1759
1781
  export const RepoIndexingConfigSchema = z
1760
1782
  .object({
1761
1783
  designSystems: z.array(z.string()),
@@ -159,7 +159,7 @@ export const listSourceFilesQuerySchema = z.object({
159
159
  ref: z.string().optional(),
160
160
  });
161
161
  export const listPublicSourceFilesQuerySchema = z.object({
162
- /** Full repo URL (e.g. https://github.com/owner/repo). GitHub only. */
162
+ /** Full repo URL (e.g. https://github.com/owner/repo). Supported across all git providers. */
163
163
  repoUrl: z.string().url(),
164
164
  /** Directory to list, repo-relative. Empty/omitted → repo root. */
165
165
  path: z.string().optional(),
@@ -29,6 +29,7 @@ export declare const EditorAiEditRequestSchema: z.ZodObject<{
29
29
  components: z.ZodOptional<z.ZodArray<z.ZodObject<{
30
30
  name: z.ZodString;
31
31
  }, z.core.$loose>>>;
32
+ allowedComponentNames: z.ZodOptional<z.ZodArray<z.ZodString>>;
32
33
  }, z.core.$strip>;
33
34
  export type EditorAiEditRequest = z.infer<typeof EditorAiEditRequestSchema>;
34
35
  export declare const EditorAiEditResponseSchema: z.ZodObject<{
@@ -44,6 +45,7 @@ export declare const EditorAiWriteRequestSchema: z.ZodObject<{
44
45
  components: z.ZodOptional<z.ZodArray<z.ZodObject<{
45
46
  name: z.ZodString;
46
47
  }, z.core.$loose>>>;
48
+ allowedComponentNames: z.ZodOptional<z.ZodArray<z.ZodString>>;
47
49
  }, z.core.$strip>;
48
50
  export type EditorAiWriteRequest = z.infer<typeof EditorAiWriteRequestSchema>;
49
51
  export declare const EditorAiWriteResponseSchema: z.ZodObject<{
@@ -51,7 +53,7 @@ export declare const EditorAiWriteResponseSchema: z.ZodObject<{
51
53
  modifiedBuilderContent: z.ZodRecord<z.ZodString, z.ZodUnknown>;
52
54
  }, z.core.$strip>;
53
55
  export type EditorAiWriteResponse = z.infer<typeof EditorAiWriteResponseSchema>;
54
- export type EditorAiErrorCode = "BAD_REQUEST" | "UNAUTHORIZED" | "FORBIDDEN" | "NOT_FOUND" | "NO_MATCH" | "VALIDATION_FAILED" | "INTERNAL";
56
+ export type EditorAiErrorCode = "BAD_REQUEST" | "UNAUTHORIZED" | "FORBIDDEN" | "NOT_FOUND" | "NO_MATCH" | "VALIDATION_FAILED" | "COMPONENT_NOT_ALLOWED" | "INTERNAL";
55
57
  export declare const EditorAiErrorBodySchema: z.ZodObject<{
56
58
  error: z.ZodObject<{
57
59
  code: z.ZodString;
package/src/editor-ai.js CHANGED
@@ -13,6 +13,9 @@ export const EditorAiComponentSchema = z
13
13
  })
14
14
  .meta({ title: "EditorAiComponent" });
15
15
  const componentsField = z.array(EditorAiComponentSchema).optional();
16
+ // Omitted is unrestricted; empty forbids every component. Only components-only
17
+ // spaces send it.
18
+ const allowedComponentNamesField = z.array(z.string().min(1)).optional();
16
19
  export const EditorAiReadRequestSchema = z
17
20
  .object({
18
21
  contentId: z.string().min(1),
@@ -45,6 +48,7 @@ export const EditorAiEditRequestSchema = z
45
48
  // Locale to operate on; defaults to "Default" when omitted.
46
49
  activeLocale: z.string().min(1).optional(),
47
50
  components: componentsField,
51
+ allowedComponentNames: allowedComponentNamesField,
48
52
  })
49
53
  .meta({ title: "EditorAiEditRequest" });
50
54
  export const EditorAiEditResponseSchema = z
@@ -61,6 +65,7 @@ export const EditorAiWriteRequestSchema = z
61
65
  // Locale to operate on; defaults to "Default" when omitted.
62
66
  activeLocale: z.string().min(1).optional(),
63
67
  components: componentsField,
68
+ allowedComponentNames: allowedComponentNamesField,
64
69
  })
65
70
  .meta({ title: "EditorAiWriteRequest" });
66
71
  export const EditorAiWriteResponseSchema = z
package/src/events.d.ts CHANGED
@@ -4,6 +4,7 @@ import type { AssistantSettings } from "./settings.js";
4
4
  import type { ExitState, UserSource, CodeGenPosition, ReviewSeverity, ReviewVerdict } from "./codegen.js";
5
5
  import type { FileUpload } from "./messages.js";
6
6
  import type { BuilderConfigRealtime } from "./builder-config.js";
7
+ import type { DeployFailureReport } from "./projects.js";
7
8
  export type BuilderAssistantEventHandler = (ev: BuilderAssistantEvent) => void;
8
9
  export type BuilderAssistantEvent = AssistantCompletionResultEvent | AssistantErrorEvent | AssistantStreamErrorEvent | AppCloseEvent | AppMessagesClickEvent | AppMessagesGenerationEvent | AppMessageEditCustomInstructionsEvent | AppPromptAbortEvent | AppPromptFocusEvent | AppPromptSubmitEvent | AppReadyEvent | AppSettingsSetEvent | AppThreadNewEvent | AssistantStatsEvent | AssistantThemeEvent | BuilderEditorAuthEvent | BuilderEditorStateEvent | ContentUpdateEvent | ContentApplySnapshotEvent | ModelUndoEvent | ModelRedoEvent | ResultEvent | ThreadCreatedEvent | ThreadMessageCompletedEvent | ThreadMessageCreatedEvent | ThreadMessageDeltaEvent | ThreadMessageFeedbackEvent | ThreadRunStepCreatedEvent | ThreadRunStepDeltaEvent | AppAcceptChangeEvent | AppAcceptRejectEvent | AssistantTrackEvent | AssistantEditorAuthMessage | AppAttachmentTemplateEvent | AppPasteSmartExportEvent | ThreadMessageRetryEvent | AppFigmaImportEvent | AppWebImportEvent | AppMcpServersEvent | AssistantContentInitialEvent | ThreadMessageSummaryEvent | ThreadMessageSummaryCodegenDeltaEvent | ThreadMessageThinkingDeltaEvent | AssistantHeartbeatEvent | ShowUpgradeDialogEvent | AssistantFusionSuggestionEvent | AppNavigateToFusionEvent | ModelPermissionRequiredEvent | ModelPermissionResponseEvent;
9
10
  export interface AssistantCompletionResultEvent {
@@ -901,6 +902,13 @@ export type ProjectSnapshotRefreshV1 = FusionEventVariant<"project.snapshot.refr
901
902
  projectId: string;
902
903
  requestedBy: string;
903
904
  reason: string;
905
+ /**
906
+ * When set, the resulting VolumeSnapshot is labeled
907
+ * `fusion-golden-source=<id>` (a baked golden starter snapshot) in addition
908
+ * to the usual per-project labels. Only set for the golden-starter-snapshots
909
+ * producer.
910
+ */
911
+ goldenTemplateId?: string;
904
912
  }, {
905
913
  projectId: string;
906
914
  }, 1>;
@@ -982,9 +990,12 @@ export type ProjectSnapshotPodWatchV1 = FusionEventVariant<"project.snapshot.pod
982
990
  namespace: string;
983
991
  podName: string;
984
992
  source: "pr.merged" | "project.snapshot.refresh";
993
+ provider?: GitPrMergedV1["data"]["provider"];
985
994
  gitSha?: string;
986
995
  startedAtMs: number;
987
996
  timeoutMs: number;
997
+ /** Propagated to the golden starter snapshot's `fusion-golden-source` label. */
998
+ goldenTemplateId?: string;
988
999
  }, {
989
1000
  projectId: string;
990
1001
  }, 1>;
@@ -1283,6 +1294,13 @@ export type ClientDevtoolsBuildUploadedV1 = FusionEventVariant<"client.devtools.
1283
1294
  * falls back to reading the repo at the deployed commit.
1284
1295
  */
1285
1296
  realtimeTransport?: BuilderConfigRealtime["transport"];
1297
+ /**
1298
+ * What the pod's build env resolved each `HOSTED_DEPLOY_ENV_DEFAULTS` key to, so
1299
+ * the runtime env can agree with the artifact that was built — a build-scope opt-in
1300
+ * shouldn't emit a scheduled function the runtime then reports as disabled. Older
1301
+ * pods omit it and the service falls back to the defaults.
1302
+ */
1303
+ resolvedHostedEnvDefaults?: Record<string, string>;
1286
1304
  }, {
1287
1305
  projectId: string;
1288
1306
  deployId: string;
@@ -1295,7 +1313,7 @@ export type ClientDevtoolsBuildFailedV1 = FusionEventVariant<"client.devtools.bu
1295
1313
  deployId: string;
1296
1314
  projectId: string;
1297
1315
  error: string;
1298
- }, {
1316
+ } & DeployFailureReport, {
1299
1317
  projectId: string;
1300
1318
  deployId: string;
1301
1319
  }, 1>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,61 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { applyHostedBuildEnvDefaults, hasResolvableHostingBuildConfig, resolveHostedEnvDefaults, } from "./projects";
3
+ describe("applyHostedBuildEnvDefaults", () => {
4
+ it("disables recurring jobs when the build config sets no env", () => {
5
+ expect(applyHostedBuildEnvDefaults({ buildOutputDir: "dist" })).toEqual({
6
+ buildOutputDir: "dist",
7
+ environment: { AGENT_NATIVE_DISABLE_RECURRING_JOBS: "true" },
8
+ });
9
+ });
10
+ it("keeps the default alongside the project's own build env", () => {
11
+ const result = applyHostedBuildEnvDefaults({
12
+ environment: { NITRO_PRESET: "netlify" },
13
+ });
14
+ expect(result.environment).toEqual({
15
+ AGENT_NATIVE_DISABLE_RECURRING_JOBS: "true",
16
+ NITRO_PRESET: "netlify",
17
+ });
18
+ });
19
+ it("lets an explicit project value win so jobs can be opted back in", () => {
20
+ const result = applyHostedBuildEnvDefaults({
21
+ environment: { AGENT_NATIVE_DISABLE_RECURRING_JOBS: "false" },
22
+ });
23
+ expect(result.environment).toEqual({
24
+ AGENT_NATIVE_DISABLE_RECURRING_JOBS: "false",
25
+ });
26
+ });
27
+ it("lets a whitespace-padded project key win instead of duplicating the default", () => {
28
+ // Otherwise the build would read the canonical default key and silently
29
+ // ignore the project's padded one.
30
+ const result = applyHostedBuildEnvDefaults({
31
+ environment: {
32
+ " AGENT_NATIVE_DISABLE_RECURRING_JOBS ": "false",
33
+ " ": "dropped",
34
+ },
35
+ });
36
+ expect(result.environment).toEqual({
37
+ AGENT_NATIVE_DISABLE_RECURRING_JOBS: "false",
38
+ });
39
+ });
40
+ it("cannot make an unresolvable config look deployable", () => {
41
+ // Callers must gate first: applying the defaults makes any config resolvable.
42
+ expect(hasResolvableHostingBuildConfig({})).toBe(false);
43
+ expect(hasResolvableHostingBuildConfig(applyHostedBuildEnvDefaults({}))).toBe(true);
44
+ });
45
+ });
46
+ describe("resolveHostedEnvDefaults", () => {
47
+ it("reports what the build env resolved each default key to", () => {
48
+ expect(resolveHostedEnvDefaults(applyHostedBuildEnvDefaults({
49
+ environment: { AGENT_NATIVE_DISABLE_RECURRING_JOBS: "false" },
50
+ }).environment)).toEqual({ AGENT_NATIVE_DISABLE_RECURRING_JOBS: "false" });
51
+ });
52
+ it("normalizes keys and drops env the defaults don't own", () => {
53
+ expect(resolveHostedEnvDefaults({
54
+ " AGENT_NATIVE_DISABLE_RECURRING_JOBS ": "false",
55
+ NITRO_PRESET: "netlify",
56
+ })).toEqual({ AGENT_NATIVE_DISABLE_RECURRING_JOBS: "false" });
57
+ });
58
+ it("returns nothing for a missing env", () => {
59
+ expect(resolveHostedEnvDefaults(undefined)).toEqual({});
60
+ });
61
+ });
package/src/index.d.ts CHANGED
@@ -6,6 +6,7 @@ export * from "./settings.js";
6
6
  export * from "./mapping.js";
7
7
  export * from "./common-schemas.js";
8
8
  export * from "./codegen.js";
9
+ export * from "./publish-agent.js";
9
10
  export * from "./codegen/investigation-context.js";
10
11
  export * from "./diff-hunks.js";
11
12
  export * from "./projects.js";
package/src/index.js CHANGED
@@ -6,6 +6,7 @@ export * from "./settings.js";
6
6
  export * from "./mapping.js";
7
7
  export * from "./common-schemas.js";
8
8
  export * from "./codegen.js";
9
+ export * from "./publish-agent.js";
9
10
  export * from "./codegen/investigation-context.js";
10
11
  export * from "./diff-hunks.js";
11
12
  export * from "./projects.js";