@kubuild/ai 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-YETTTWHI.js → chunk-CCV6S4YN.js} +26 -10
- package/dist/chunk-CCV6S4YN.js.map +1 -0
- package/dist/{chunk-K7CBTQCY.js → chunk-ORA6BS4P.js} +10 -3
- package/dist/chunk-ORA6BS4P.js.map +1 -0
- package/dist/client/ai-client.d.ts.map +1 -1
- package/dist/client/index.cjs +9 -2
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/core/prompt-compiler.d.ts +12 -1
- package/dist/core/prompt-compiler.d.ts.map +1 -1
- package/dist/index.cjs +36 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +5 -1
- package/dist/react/index.cjs +15 -4
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.js +7 -3
- package/dist/react/index.js.map +1 -1
- package/dist/react/use-ai-agent.d.ts +5 -0
- package/dist/react/use-ai-agent.d.ts.map +1 -1
- package/dist/react/use-ai-chat.d.ts +6 -0
- package/dist/react/use-ai-chat.d.ts.map +1 -1
- package/dist/react/use-ai-generator.d.ts.map +1 -1
- package/dist/server/agent.d.ts.map +1 -1
- package/dist/server/engine.d.ts +6 -0
- package/dist/server/engine.d.ts.map +1 -1
- package/dist/server/handler.d.ts +31 -2
- package/dist/server/handler.d.ts.map +1 -1
- package/dist/server/index.cjs +272 -157
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.js +237 -138
- package/dist/server/index.js.map +1 -1
- package/dist/types.d.ts +58 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -5
- package/dist/chunk-K7CBTQCY.js.map +0 -1
- package/dist/chunk-YETTTWHI.js.map +0 -1
package/dist/server/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
appendClientInstructions,
|
|
2
3
|
buildAgentSystemPrompt,
|
|
3
4
|
buildJsonSchemaForMode,
|
|
4
5
|
buildSelectionContext,
|
|
@@ -6,13 +7,14 @@ import {
|
|
|
6
7
|
compileComponentCatalog,
|
|
7
8
|
extractJsonFromResponse,
|
|
8
9
|
getNodeLabel,
|
|
10
|
+
joinInstructions,
|
|
9
11
|
normalizeAndValidatePageDocument,
|
|
10
12
|
normalizeAndValidateRefactoredNode,
|
|
11
13
|
normalizeAndValidateSectionNode,
|
|
12
14
|
normalizeNodeTree,
|
|
13
15
|
pruneNodeForPrompt,
|
|
14
16
|
summarizeNodeTree
|
|
15
|
-
} from "../chunk-
|
|
17
|
+
} from "../chunk-CCV6S4YN.js";
|
|
16
18
|
import {
|
|
17
19
|
AnthropicAdapter,
|
|
18
20
|
CustomHttpAdapter,
|
|
@@ -24,7 +26,40 @@ import {
|
|
|
24
26
|
} from "../chunk-ILLNRABB.js";
|
|
25
27
|
|
|
26
28
|
// src/server/engine.ts
|
|
27
|
-
import { DocumentMetadataSchema } from "@kubuild/schema";
|
|
29
|
+
import { DocumentMetadataSchema, CURRENT_SCHEMA_VERSION } from "@kubuild/schema";
|
|
30
|
+
function describeSectionCount(sectionCount) {
|
|
31
|
+
if (typeof sectionCount === "number" && Number.isFinite(sectionCount) && sectionCount > 0) {
|
|
32
|
+
return `exactly ${Math.floor(sectionCount)} cohesive sections`;
|
|
33
|
+
}
|
|
34
|
+
if (sectionCount && typeof sectionCount === "object" && (sectionCount.min || sectionCount.max)) {
|
|
35
|
+
const min = sectionCount.min ?? 3;
|
|
36
|
+
const max = sectionCount.max ?? 8;
|
|
37
|
+
return `between ${min} and ${max} cohesive sections`;
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
function hasPlannedSections(plan) {
|
|
42
|
+
return !!plan && Array.isArray(plan.sections) && plan.sections.length > 0;
|
|
43
|
+
}
|
|
44
|
+
function buildFallbackPlan(prompt) {
|
|
45
|
+
return {
|
|
46
|
+
title: "AI Generated Page",
|
|
47
|
+
description: "Generated by KUBUILD AI",
|
|
48
|
+
sections: [
|
|
49
|
+
{ type: "hero", title: "Hero Banner", prompt: `Hero section for: ${prompt}` },
|
|
50
|
+
{ type: "features", title: "Key Features", prompt: `Features grid for: ${prompt}` },
|
|
51
|
+
{
|
|
52
|
+
type: "testimonials",
|
|
53
|
+
title: "Testimonials",
|
|
54
|
+
prompt: `Social proof and customer reviews for: ${prompt}`
|
|
55
|
+
},
|
|
56
|
+
{ type: "cta", title: "Call To Action", prompt: `Call to action section for: ${prompt}` },
|
|
57
|
+
{ type: "footer", title: "Footer", prompt: `Footer navigation and copyright for: ${prompt}` }
|
|
58
|
+
],
|
|
59
|
+
usedFallback: true
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
var PLAN_FALLBACK_MESSAGE = "The AI response could not be parsed as a page plan, so a generic default plan was used instead.";
|
|
28
63
|
var KubuildAiEngine = class {
|
|
29
64
|
options;
|
|
30
65
|
catalog;
|
|
@@ -50,20 +85,31 @@ var KubuildAiEngine = class {
|
|
|
50
85
|
}
|
|
51
86
|
}
|
|
52
87
|
async generatePage(request, context) {
|
|
88
|
+
if (hasPlannedSections(request.plan)) {
|
|
89
|
+
return this.generatePageFromPlan(request, context);
|
|
90
|
+
}
|
|
53
91
|
let rawText = "";
|
|
54
92
|
try {
|
|
55
93
|
this.log("info", `Generating full page for prompt: "${request.prompt}"`);
|
|
56
|
-
const systemPrompt =
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
94
|
+
const systemPrompt = appendClientInstructions(
|
|
95
|
+
buildSystemPrompt({
|
|
96
|
+
catalog: this.catalog,
|
|
97
|
+
mode: "full-page",
|
|
98
|
+
prefix: this.options.systemPromptPrefix,
|
|
99
|
+
stylePreference: request.stylePreference
|
|
100
|
+
}),
|
|
101
|
+
request.instructions
|
|
102
|
+
);
|
|
62
103
|
let userPrompt = `User Request: ${request.prompt}`;
|
|
63
104
|
if (request.tone) userPrompt += `
|
|
64
105
|
Tone: ${request.tone}`;
|
|
65
106
|
if (request.locale) userPrompt += `
|
|
66
107
|
Language/Locale: ${request.locale}`;
|
|
108
|
+
const sectionCountPhrase = describeSectionCount(request.sectionCount);
|
|
109
|
+
if (sectionCountPhrase) {
|
|
110
|
+
userPrompt += `
|
|
111
|
+
Section Count: the page root must contain ${sectionCountPhrase} as its direct children.`;
|
|
112
|
+
}
|
|
67
113
|
if (request.conversationHistory && request.conversationHistory.length > 0) {
|
|
68
114
|
const chatContext = request.conversationHistory.map((m) => `${m.role.toUpperCase()}: ${getMessageText(m)}`).join("\n");
|
|
69
115
|
userPrompt += `
|
|
@@ -114,15 +160,42 @@ ${chatContext}`;
|
|
|
114
160
|
};
|
|
115
161
|
}
|
|
116
162
|
}
|
|
163
|
+
/**
|
|
164
|
+
* Non-streaming counterpart of `streamPage` for a pre-approved plan: drains the same
|
|
165
|
+
* progressive pipeline and returns the assembled document, so both paths produce the
|
|
166
|
+
* same sections for the same plan.
|
|
167
|
+
*/
|
|
168
|
+
async generatePageFromPlan(request, context) {
|
|
169
|
+
let document = null;
|
|
170
|
+
let error = null;
|
|
171
|
+
for await (const event of this.streamPage(request, context)) {
|
|
172
|
+
if (event.type === "complete") document = event.document;
|
|
173
|
+
if (event.type === "error") error = event.error;
|
|
174
|
+
}
|
|
175
|
+
if (document) {
|
|
176
|
+
return { success: true, data: document };
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
success: false,
|
|
180
|
+
error: {
|
|
181
|
+
code: "GENERATION_ERROR",
|
|
182
|
+
message: error?.message ?? "Page generation from the approved plan produced no document.",
|
|
183
|
+
details: error ? { streamCode: error.code } : void 0
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
}
|
|
117
187
|
async generateSection(request, context) {
|
|
118
188
|
let rawText = "";
|
|
119
189
|
try {
|
|
120
|
-
const systemPrompt =
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
190
|
+
const systemPrompt = appendClientInstructions(
|
|
191
|
+
buildSystemPrompt({
|
|
192
|
+
catalog: this.catalog,
|
|
193
|
+
mode: "section",
|
|
194
|
+
prefix: this.options.systemPromptPrefix,
|
|
195
|
+
stylePreference: request.stylePreference
|
|
196
|
+
}),
|
|
197
|
+
request.instructions
|
|
198
|
+
);
|
|
126
199
|
let userPrompt = `Generate a single section node for: ${request.prompt}`;
|
|
127
200
|
if (request.targetSectionType) {
|
|
128
201
|
userPrompt += `
|
|
@@ -167,12 +240,15 @@ Surrounding Page Context: ${request.parentContext}`;
|
|
|
167
240
|
async refactorNode(request, context) {
|
|
168
241
|
let rawText = "";
|
|
169
242
|
try {
|
|
170
|
-
const systemPrompt =
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
243
|
+
const systemPrompt = appendClientInstructions(
|
|
244
|
+
buildSystemPrompt({
|
|
245
|
+
catalog: this.catalog,
|
|
246
|
+
mode: "refactor",
|
|
247
|
+
prefix: this.options.systemPromptPrefix,
|
|
248
|
+
stylePreference: request.stylePreference
|
|
249
|
+
}),
|
|
250
|
+
request.instructions
|
|
251
|
+
);
|
|
176
252
|
const userPrompt = `Instruction: ${request.instruction}
|
|
177
253
|
|
|
178
254
|
Current Node:
|
|
@@ -210,16 +286,8 @@ ${JSON.stringify(request.node, null, 2)}`;
|
|
|
210
286
|
}
|
|
211
287
|
}
|
|
212
288
|
buildPlanPrompts(request) {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
sectionGuidance = `Plan exactly ${request.sectionCount} cohesive sections that fulfill the request.`;
|
|
216
|
-
} else if (request.sectionCount?.min || request.sectionCount?.max) {
|
|
217
|
-
const min = request.sectionCount.min ?? 3;
|
|
218
|
-
const max = request.sectionCount.max ?? 8;
|
|
219
|
-
sectionGuidance = `Plan between ${min} and ${max} cohesive sections that fulfill the request.`;
|
|
220
|
-
} else {
|
|
221
|
-
sectionGuidance += " If the user request mentions a specific number or list of sections, respect the user request.";
|
|
222
|
-
}
|
|
289
|
+
const sectionCountPhrase = describeSectionCount(request.sectionCount);
|
|
290
|
+
const sectionGuidance = sectionCountPhrase ? `Plan ${sectionCountPhrase} that fulfill the request.` : "Plan between 4 to 6 cohesive, essential sections (e.g., hero, features, testimonials, pricing, cta, footer) that fulfill the request thoroughly. If the user request mentions a specific number or list of sections, respect the user request.";
|
|
223
291
|
const planSystemPrompt = `
|
|
224
292
|
You are a web architect for the KUBUILD page builder.
|
|
225
293
|
Given the user's prompt, plan the website structure. Output pure JSON (no markdown fences, no explanatory text):
|
|
@@ -260,46 +328,59 @@ Locale: ${request.locale}`;
|
|
|
260
328
|
Prior Conversation Discussion Context:
|
|
261
329
|
${chatContext}`;
|
|
262
330
|
}
|
|
263
|
-
return {
|
|
331
|
+
return {
|
|
332
|
+
systemPrompt: appendClientInstructions(planSystemPrompt, request.instructions),
|
|
333
|
+
userPrompt: planUserPrompt
|
|
334
|
+
};
|
|
264
335
|
}
|
|
265
336
|
async planPage(request, context) {
|
|
266
|
-
|
|
337
|
+
const { systemPrompt, userPrompt } = this.buildPlanPrompts(request);
|
|
338
|
+
this.log("info", `Planning website layout for: "${request.prompt}"`);
|
|
339
|
+
let planResult;
|
|
267
340
|
try {
|
|
268
|
-
|
|
269
|
-
this.log("info", `Planning website layout for: "${request.prompt}"`);
|
|
270
|
-
const planResult = await this.options.adapter.generate({
|
|
341
|
+
planResult = await this.options.adapter.generate({
|
|
271
342
|
systemPrompt,
|
|
272
343
|
userPrompt,
|
|
273
344
|
signal: context?.signal
|
|
274
345
|
});
|
|
275
|
-
rawText = planResult.text;
|
|
276
|
-
const plan = extractJsonFromResponse(rawText);
|
|
277
|
-
return {
|
|
278
|
-
success: true,
|
|
279
|
-
data: plan,
|
|
280
|
-
usage: planResult.usage,
|
|
281
|
-
rawModelResponse: rawText
|
|
282
|
-
};
|
|
283
346
|
} catch (err) {
|
|
284
347
|
const message = err instanceof Error ? err.message : String(err);
|
|
285
|
-
this.log("
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
sections: [
|
|
290
|
-
{ type: "hero", title: "Hero Banner", prompt: `Hero section for: ${request.prompt}` },
|
|
291
|
-
{ type: "features", title: "Key Features", prompt: `Features grid for: ${request.prompt}` },
|
|
292
|
-
{ type: "testimonials", title: "Testimonials", prompt: `Social proof and customer reviews for: ${request.prompt}` },
|
|
293
|
-
{ type: "cta", title: "Call To Action", prompt: `Call to action section for: ${request.prompt}` },
|
|
294
|
-
{ type: "footer", title: "Footer", prompt: `Footer navigation and copyright for: ${request.prompt}` }
|
|
295
|
-
]
|
|
348
|
+
this.log("error", `Planning failed: ${message}`);
|
|
349
|
+
return {
|
|
350
|
+
success: false,
|
|
351
|
+
error: { code: "PLAN_ERROR", message }
|
|
296
352
|
};
|
|
353
|
+
}
|
|
354
|
+
const rawText = planResult.text;
|
|
355
|
+
let plan = null;
|
|
356
|
+
let parseError = "";
|
|
357
|
+
try {
|
|
358
|
+
const parsed = extractJsonFromResponse(rawText);
|
|
359
|
+
if (hasPlannedSections(parsed)) {
|
|
360
|
+
plan = parsed;
|
|
361
|
+
} else {
|
|
362
|
+
parseError = 'Plan JSON has no non-empty "sections" array';
|
|
363
|
+
}
|
|
364
|
+
} catch (err) {
|
|
365
|
+
parseError = err instanceof Error ? err.message : String(err);
|
|
366
|
+
}
|
|
367
|
+
if (plan) {
|
|
297
368
|
return {
|
|
298
369
|
success: true,
|
|
299
|
-
data:
|
|
300
|
-
|
|
370
|
+
data: plan,
|
|
371
|
+
usage: planResult.usage,
|
|
372
|
+
rawModelResponse: rawText
|
|
301
373
|
};
|
|
302
374
|
}
|
|
375
|
+
this.log("warn", "Failed to parse plan JSON, using fallback plan", parseError);
|
|
376
|
+
return {
|
|
377
|
+
success: true,
|
|
378
|
+
data: buildFallbackPlan(request.prompt),
|
|
379
|
+
usedFallback: true,
|
|
380
|
+
warnings: [{ code: "PLAN_FALLBACK", message: PLAN_FALLBACK_MESSAGE, details: parseError }],
|
|
381
|
+
usage: planResult.usage,
|
|
382
|
+
rawModelResponse: rawText || void 0
|
|
383
|
+
};
|
|
303
384
|
}
|
|
304
385
|
/**
|
|
305
386
|
* Progressive Section Streaming Generator.
|
|
@@ -313,7 +394,7 @@ ${chatContext}`;
|
|
|
313
394
|
message: "Analyzing requirements and planning page sections..."
|
|
314
395
|
};
|
|
315
396
|
let plan;
|
|
316
|
-
if (
|
|
397
|
+
if (hasPlannedSections(request.plan)) {
|
|
317
398
|
plan = request.plan;
|
|
318
399
|
this.log("info", `[SSE] Using approved pre-planned structure with ${plan.sections?.length ?? 0} sections`);
|
|
319
400
|
} else {
|
|
@@ -325,31 +406,21 @@ ${chatContext}`;
|
|
|
325
406
|
signal: context?.signal
|
|
326
407
|
});
|
|
327
408
|
this.log("debug", "[SSE] Raw plan response from model", planResult.text);
|
|
409
|
+
let parsedPlan = null;
|
|
328
410
|
try {
|
|
329
|
-
|
|
330
|
-
this.log("debug", "[SSE] Parsed plan successfully",
|
|
411
|
+
parsedPlan = extractJsonFromResponse(planResult.text);
|
|
412
|
+
this.log("debug", "[SSE] Parsed plan successfully", parsedPlan);
|
|
331
413
|
} catch (parseErr) {
|
|
332
414
|
this.log("warn", "[SSE] Failed to parse plan JSON, using fallback plan", parseErr);
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
{ type: "testimonials", title: "Testimonials", prompt: `Social proof for: ${request.prompt}` },
|
|
340
|
-
{ type: "cta", title: "Call To Action", prompt: `Call to action section for: ${request.prompt}` },
|
|
341
|
-
{ type: "footer", title: "Footer", prompt: `Footer for: ${request.prompt}` }
|
|
342
|
-
]
|
|
343
|
-
};
|
|
415
|
+
}
|
|
416
|
+
if (hasPlannedSections(parsedPlan)) {
|
|
417
|
+
plan = parsedPlan;
|
|
418
|
+
} else {
|
|
419
|
+
plan = buildFallbackPlan(request.prompt);
|
|
420
|
+
yield { type: "status", message: PLAN_FALLBACK_MESSAGE };
|
|
344
421
|
}
|
|
345
422
|
}
|
|
346
|
-
const sectionsToGenerate =
|
|
347
|
-
{ type: "hero", title: "Hero Section", prompt: `Hero banner for: ${request.prompt}` },
|
|
348
|
-
{ type: "features", title: "Features", prompt: `Features grid for: ${request.prompt}` },
|
|
349
|
-
{ type: "testimonials", title: "Testimonials", prompt: `Social proof for: ${request.prompt}` },
|
|
350
|
-
{ type: "cta", title: "Call To Action", prompt: `CTA section for: ${request.prompt}` },
|
|
351
|
-
{ type: "footer", title: "Footer", prompt: `Footer section for: ${request.prompt}` }
|
|
352
|
-
];
|
|
423
|
+
const sectionsToGenerate = hasPlannedSections(plan) ? plan.sections : buildFallbackPlan(request.prompt).sections;
|
|
353
424
|
const metadata = DocumentMetadataSchema.parse({
|
|
354
425
|
title: plan.title || "AI Generated Page",
|
|
355
426
|
description: plan.description || "Generated by KUBUILD AI",
|
|
@@ -406,6 +477,7 @@ ${chatContext}`;
|
|
|
406
477
|
{
|
|
407
478
|
prompt: plannedSec.prompt,
|
|
408
479
|
stylePreference: request.stylePreference,
|
|
480
|
+
instructions: request.instructions,
|
|
409
481
|
targetSectionType: plannedSec.type,
|
|
410
482
|
parentContext: `Website: ${plan.title}. Previous sections: ${sectionsToGenerate.slice(0, i).map((s) => s.title).join(", ")}`
|
|
411
483
|
},
|
|
@@ -440,7 +512,7 @@ ${chatContext}`;
|
|
|
440
512
|
}
|
|
441
513
|
const finalDocument = {
|
|
442
514
|
schema: "stora.page",
|
|
443
|
-
version:
|
|
515
|
+
version: CURRENT_SCHEMA_VERSION,
|
|
444
516
|
metadata,
|
|
445
517
|
document: {
|
|
446
518
|
...rootPageNode,
|
|
@@ -484,11 +556,6 @@ ${this.catalog.map((c) => `- **${c.type}** (${c.category}): ${c.label}${c.descri
|
|
|
484
556
|
systemPrompt = `${this.options.systemPromptPrefix}
|
|
485
557
|
|
|
486
558
|
${systemPrompt}`;
|
|
487
|
-
}
|
|
488
|
-
if (request.systemPrompt) {
|
|
489
|
-
systemPrompt += `
|
|
490
|
-
Additional Context:
|
|
491
|
-
${request.systemPrompt}`;
|
|
492
559
|
}
|
|
493
560
|
if (request.currentDocument) {
|
|
494
561
|
const doc = request.currentDocument;
|
|
@@ -507,6 +574,10 @@ ${sectionSummary || "(Canvas is currently empty)"}
|
|
|
507
574
|
systemPrompt += `
|
|
508
575
|
Currently Selected Component Node ID: "${request.selectedNodeId}"`;
|
|
509
576
|
}
|
|
577
|
+
systemPrompt = appendClientInstructions(
|
|
578
|
+
systemPrompt,
|
|
579
|
+
joinInstructions(request.instructions, request.systemPrompt)
|
|
580
|
+
);
|
|
510
581
|
const lastUserMsg = [...request.messages].reverse().find((m) => m.role === "user");
|
|
511
582
|
const userPrompt = lastUserMsg ? getMessageText(lastUserMsg) || "Hello" : "Hello";
|
|
512
583
|
return { systemPrompt, userPrompt };
|
|
@@ -695,7 +766,7 @@ function resolveNode(document, nodeId, toolName) {
|
|
|
695
766
|
if (!node) {
|
|
696
767
|
return {
|
|
697
768
|
error: fail(
|
|
698
|
-
`${toolName}: node "${nodeId}"
|
|
769
|
+
`${toolName}: node "${nodeId}" not found`,
|
|
699
770
|
`No node with id "${nodeId}" exists in this page. Node ids must come from the outline or from a tool result \u2014 never invented.`,
|
|
700
771
|
{ suggestedNodeIds: suggestNodeIds(document, nodeId) }
|
|
701
772
|
)
|
|
@@ -789,7 +860,7 @@ var getPageOutline = {
|
|
|
789
860
|
},
|
|
790
861
|
execute(input, context) {
|
|
791
862
|
const maxDepth = typeof input.maxDepth === "number" && input.maxDepth > 0 ? Math.floor(input.maxDepth) : 3;
|
|
792
|
-
return succeed("
|
|
863
|
+
return succeed("Read page outline", {
|
|
793
864
|
outline: summarizeNodeTree(context.document.document, { maxDepth })
|
|
794
865
|
});
|
|
795
866
|
}
|
|
@@ -813,7 +884,7 @@ var readNode = {
|
|
|
813
884
|
},
|
|
814
885
|
execute(input, context) {
|
|
815
886
|
const nodeId = readString(input, "nodeId");
|
|
816
|
-
if (!nodeId) return fail("read_node: nodeId
|
|
887
|
+
if (!nodeId) return fail("read_node: nodeId missing", 'Argument "nodeId" is required.');
|
|
817
888
|
const resolved = resolveNode(context.document, nodeId, "read_node");
|
|
818
889
|
if ("error" in resolved) return resolved.error;
|
|
819
890
|
const selection = buildSelectionContext(context.document.document, nodeId);
|
|
@@ -859,7 +930,7 @@ var findNodes = {
|
|
|
859
930
|
const limit = typeof input.limit === "number" && input.limit > 0 ? Math.floor(input.limit) : 20;
|
|
860
931
|
if (!type && !textContains) {
|
|
861
932
|
return fail(
|
|
862
|
-
"find_nodes: filter
|
|
933
|
+
"find_nodes: empty filter",
|
|
863
934
|
'Provide at least one of "type" or "textContains" \u2014 an unfiltered search would just return the whole outline.'
|
|
864
935
|
);
|
|
865
936
|
}
|
|
@@ -907,7 +978,7 @@ var listComponentTypes = {
|
|
|
907
978
|
execute(input, context) {
|
|
908
979
|
const category = readString(input, "category");
|
|
909
980
|
const entries = category ? context.catalog.filter((spec) => spec.category === category) : context.catalog;
|
|
910
|
-
return succeed(`
|
|
981
|
+
return succeed(`Viewed component catalog (${entries.length})`, {
|
|
911
982
|
components: entries.map((spec) => ({
|
|
912
983
|
type: spec.type,
|
|
913
984
|
label: spec.label,
|
|
@@ -942,14 +1013,14 @@ function applyCommand(toolName, run) {
|
|
|
942
1013
|
return run();
|
|
943
1014
|
} catch (err) {
|
|
944
1015
|
const message = err instanceof Error ? err.message : String(err);
|
|
945
|
-
return { error: fail(`${toolName}
|
|
1016
|
+
return { error: fail(`${toolName} failed`, message) };
|
|
946
1017
|
}
|
|
947
1018
|
}
|
|
948
1019
|
function guardSecurity(toolName, document, context) {
|
|
949
1020
|
const violation = checkDocumentSecurity(document, context.securityLimits);
|
|
950
1021
|
if (!violation) return null;
|
|
951
1022
|
return fail(
|
|
952
|
-
`${toolName}
|
|
1023
|
+
`${toolName} rejected (security)`,
|
|
953
1024
|
`The resulting document failed the security check and was rejected: ${violation}`
|
|
954
1025
|
);
|
|
955
1026
|
}
|
|
@@ -976,11 +1047,11 @@ var updateNodeProps = {
|
|
|
976
1047
|
},
|
|
977
1048
|
execute(input, context) {
|
|
978
1049
|
const nodeId = readString(input, "nodeId");
|
|
979
|
-
if (!nodeId) return fail("update_node_props: nodeId
|
|
1050
|
+
if (!nodeId) return fail("update_node_props: nodeId missing", 'Argument "nodeId" is required.');
|
|
980
1051
|
const props = readPlainObject(input, "props");
|
|
981
1052
|
if (!props) {
|
|
982
1053
|
return fail(
|
|
983
|
-
"update_node_props: props
|
|
1054
|
+
"update_node_props: invalid props",
|
|
984
1055
|
'Argument "props" must be a JSON object of prop names to values.'
|
|
985
1056
|
);
|
|
986
1057
|
}
|
|
@@ -997,7 +1068,7 @@ var updateNodeProps = {
|
|
|
997
1068
|
const op = { kind: "update-props", nodeId, props, merge };
|
|
998
1069
|
const updated = findNodeById2(applied.document.document, nodeId);
|
|
999
1070
|
return succeed(
|
|
1000
|
-
`
|
|
1071
|
+
`Update props of ${describeNode(resolved.node)}`,
|
|
1001
1072
|
{ nodeId, props: updated?.props ?? props, changedKeys: Object.keys(props) },
|
|
1002
1073
|
{ op, document: applied.document }
|
|
1003
1074
|
);
|
|
@@ -1035,11 +1106,11 @@ var updateNodeStyles = {
|
|
|
1035
1106
|
},
|
|
1036
1107
|
execute(input, context) {
|
|
1037
1108
|
const nodeId = readString(input, "nodeId");
|
|
1038
|
-
if (!nodeId) return fail("update_node_styles: nodeId
|
|
1109
|
+
if (!nodeId) return fail("update_node_styles: nodeId missing", 'Argument "nodeId" is required.');
|
|
1039
1110
|
const styles = readPlainObject(input, "styles");
|
|
1040
1111
|
if (!styles) {
|
|
1041
1112
|
return fail(
|
|
1042
|
-
"update_node_styles: styles
|
|
1113
|
+
"update_node_styles: invalid styles",
|
|
1043
1114
|
'Argument "styles" must be a JSON object of CSS properties with primitive values.'
|
|
1044
1115
|
);
|
|
1045
1116
|
}
|
|
@@ -1048,7 +1119,7 @@ var updateNodeStyles = {
|
|
|
1048
1119
|
);
|
|
1049
1120
|
if (nested) {
|
|
1050
1121
|
return fail(
|
|
1051
|
-
"update_node_styles:
|
|
1122
|
+
"update_node_styles: nested value",
|
|
1052
1123
|
`Style property "${nested[0]}" has an object value. Style values must be primitives \u2014 use the "state" argument for pseudo-classes instead of nesting them.`
|
|
1053
1124
|
);
|
|
1054
1125
|
}
|
|
@@ -1056,13 +1127,13 @@ var updateNodeStyles = {
|
|
|
1056
1127
|
const rawBreakpoint = readString(input, "breakpoint");
|
|
1057
1128
|
if (rawState && rawBreakpoint) {
|
|
1058
1129
|
return fail(
|
|
1059
|
-
"update_node_styles:
|
|
1130
|
+
"update_node_styles: conflicting arguments",
|
|
1060
1131
|
'Pass either "breakpoint" or "state", not both \u2014 a pseudo-state layer is not per-breakpoint.'
|
|
1061
1132
|
);
|
|
1062
1133
|
}
|
|
1063
1134
|
if (rawBreakpoint && !BREAKPOINTS.includes(rawBreakpoint)) {
|
|
1064
1135
|
return fail(
|
|
1065
|
-
"update_node_styles: breakpoint
|
|
1136
|
+
"update_node_styles: unknown breakpoint",
|
|
1066
1137
|
`Unknown breakpoint "${rawBreakpoint}". Valid values: ${BREAKPOINTS.join(", ")}.`
|
|
1067
1138
|
);
|
|
1068
1139
|
}
|
|
@@ -1081,7 +1152,7 @@ var updateNodeStyles = {
|
|
|
1081
1152
|
const op = { kind: "update-styles", nodeId, styles, breakpoint, state, merge };
|
|
1082
1153
|
const layer = state ? `state ${state}` : `breakpoint ${breakpoint}`;
|
|
1083
1154
|
return succeed(
|
|
1084
|
-
`
|
|
1155
|
+
`Update styles of ${describeNode(resolved.node)} (${layer})`,
|
|
1085
1156
|
{ nodeId, layer, appliedStyles: styles },
|
|
1086
1157
|
{ op, document: applied.document }
|
|
1087
1158
|
);
|
|
@@ -1120,16 +1191,16 @@ var insertComponent = {
|
|
|
1120
1191
|
const type = readString(input, "type");
|
|
1121
1192
|
if (!parentId || !type) {
|
|
1122
1193
|
return fail(
|
|
1123
|
-
"insert_component:
|
|
1194
|
+
"insert_component: missing arguments",
|
|
1124
1195
|
'Arguments "parentId" and "type" are both required.'
|
|
1125
1196
|
);
|
|
1126
1197
|
}
|
|
1127
1198
|
const typeError = checkComponentType(context.catalog, type);
|
|
1128
|
-
if (typeError) return fail("insert_component:
|
|
1199
|
+
if (typeError) return fail("insert_component: unknown type", typeError);
|
|
1129
1200
|
const resolvedParent = resolveNode(context.document, parentId, "insert_component");
|
|
1130
1201
|
if ("error" in resolvedParent) return resolvedParent.error;
|
|
1131
1202
|
const nestingError = checkNesting(context.catalog, resolvedParent.node, type);
|
|
1132
|
-
if (nestingError) return fail("insert_component: nesting
|
|
1203
|
+
if (nestingError) return fail("insert_component: invalid nesting", nestingError);
|
|
1133
1204
|
const normalized = normalizeIncomingNode(
|
|
1134
1205
|
{
|
|
1135
1206
|
type,
|
|
@@ -1140,7 +1211,7 @@ var insertComponent = {
|
|
|
1140
1211
|
context.document
|
|
1141
1212
|
);
|
|
1142
1213
|
if ("error" in normalized) {
|
|
1143
|
-
return fail("insert_component: node
|
|
1214
|
+
return fail("insert_component: invalid node", normalized.error);
|
|
1144
1215
|
}
|
|
1145
1216
|
const index = readOptionalIndex(input, "index");
|
|
1146
1217
|
const applied = applyCommand(
|
|
@@ -1152,7 +1223,7 @@ var insertComponent = {
|
|
|
1152
1223
|
if (violation) return violation;
|
|
1153
1224
|
const op = { kind: "insert-node", parentId, index, node: normalized.node };
|
|
1154
1225
|
return succeed(
|
|
1155
|
-
`
|
|
1226
|
+
`Add ${describeNode(normalized.node)} to #${parentId}`,
|
|
1156
1227
|
{ nodeId: normalized.node.id, parentId, index: index ?? null },
|
|
1157
1228
|
{ op, document: applied.document }
|
|
1158
1229
|
);
|
|
@@ -1180,10 +1251,10 @@ var insertSection = {
|
|
|
1180
1251
|
},
|
|
1181
1252
|
async execute(input, context) {
|
|
1182
1253
|
const prompt = readString(input, "prompt");
|
|
1183
|
-
if (!prompt) return fail("insert_section: prompt
|
|
1254
|
+
if (!prompt) return fail("insert_section: prompt missing", 'Argument "prompt" is required.');
|
|
1184
1255
|
if (!context.generateSection) {
|
|
1185
1256
|
return fail(
|
|
1186
|
-
"insert_section:
|
|
1257
|
+
"insert_section: not available",
|
|
1187
1258
|
"Section generation is not available in this deployment. Build the section with insert_component instead."
|
|
1188
1259
|
);
|
|
1189
1260
|
}
|
|
@@ -1197,13 +1268,13 @@ var insertSection = {
|
|
|
1197
1268
|
});
|
|
1198
1269
|
} catch (err) {
|
|
1199
1270
|
return fail(
|
|
1200
|
-
"insert_section
|
|
1271
|
+
"insert_section failed",
|
|
1201
1272
|
`Section generation failed: ${err instanceof Error ? err.message : String(err)}`
|
|
1202
1273
|
);
|
|
1203
1274
|
}
|
|
1204
1275
|
const normalized = normalizeIncomingNode(generated, context.document);
|
|
1205
1276
|
if ("error" in normalized) {
|
|
1206
|
-
return fail("insert_section: section
|
|
1277
|
+
return fail("insert_section: invalid section", normalized.error);
|
|
1207
1278
|
}
|
|
1208
1279
|
const index = readOptionalIndex(input, "index");
|
|
1209
1280
|
const applied = applyCommand(
|
|
@@ -1215,7 +1286,7 @@ var insertSection = {
|
|
|
1215
1286
|
if (violation) return violation;
|
|
1216
1287
|
const op = { kind: "insert-node", parentId: rootId, index, node: normalized.node };
|
|
1217
1288
|
return succeed(
|
|
1218
|
-
`
|
|
1289
|
+
`Add new section (#${normalized.node.id})`,
|
|
1219
1290
|
{
|
|
1220
1291
|
nodeId: normalized.node.id,
|
|
1221
1292
|
index: index ?? null,
|
|
@@ -1245,7 +1316,7 @@ var moveNodeTool = {
|
|
|
1245
1316
|
const targetParentId = readString(input, "targetParentId");
|
|
1246
1317
|
if (!nodeId || !targetParentId) {
|
|
1247
1318
|
return fail(
|
|
1248
|
-
"move_node:
|
|
1319
|
+
"move_node: missing arguments",
|
|
1249
1320
|
'Arguments "nodeId" and "targetParentId" are both required.'
|
|
1250
1321
|
);
|
|
1251
1322
|
}
|
|
@@ -1254,7 +1325,7 @@ var moveNodeTool = {
|
|
|
1254
1325
|
const resolvedParent = resolveNode(context.document, targetParentId, "move_node");
|
|
1255
1326
|
if ("error" in resolvedParent) return resolvedParent.error;
|
|
1256
1327
|
const nestingError = checkNesting(context.catalog, resolvedParent.node, resolved.node.type);
|
|
1257
|
-
if (nestingError) return fail("move_node: nesting
|
|
1328
|
+
if (nestingError) return fail("move_node: invalid nesting", nestingError);
|
|
1258
1329
|
const index = readOptionalIndex(input, "index");
|
|
1259
1330
|
const applied = applyCommand(
|
|
1260
1331
|
"move_node",
|
|
@@ -1265,7 +1336,7 @@ var moveNodeTool = {
|
|
|
1265
1336
|
if (violation) return violation;
|
|
1266
1337
|
const op = { kind: "move-node", nodeId, targetParentId, index };
|
|
1267
1338
|
return succeed(
|
|
1268
|
-
`
|
|
1339
|
+
`Move ${describeNode(resolved.node)} to #${targetParentId}`,
|
|
1269
1340
|
{ nodeId, targetParentId, index: index ?? null },
|
|
1270
1341
|
{ op, document: applied.document }
|
|
1271
1342
|
);
|
|
@@ -1291,7 +1362,7 @@ var duplicateNodeTool = {
|
|
|
1291
1362
|
},
|
|
1292
1363
|
execute(input, context) {
|
|
1293
1364
|
const nodeId = readString(input, "nodeId");
|
|
1294
|
-
if (!nodeId) return fail("duplicate_node: nodeId
|
|
1365
|
+
if (!nodeId) return fail("duplicate_node: nodeId missing", 'Argument "nodeId" is required.');
|
|
1295
1366
|
const resolved = resolveNode(context.document, nodeId, "duplicate_node");
|
|
1296
1367
|
if ("error" in resolved) return resolved.error;
|
|
1297
1368
|
const targetParentId = readString(input, "targetParentId") ?? void 0;
|
|
@@ -1309,7 +1380,7 @@ var duplicateNodeTool = {
|
|
|
1309
1380
|
if (violation) return violation;
|
|
1310
1381
|
const op = { kind: "duplicate-node", nodeId, targetParentId, index };
|
|
1311
1382
|
return succeed(
|
|
1312
|
-
`
|
|
1383
|
+
`Duplicate ${describeNode(resolved.node)}`,
|
|
1313
1384
|
{ nodeId, targetParentId: targetParentId ?? null, index: index ?? null },
|
|
1314
1385
|
{ op, document: applied.document }
|
|
1315
1386
|
);
|
|
@@ -1335,11 +1406,11 @@ var deleteNode = {
|
|
|
1335
1406
|
},
|
|
1336
1407
|
execute(input, context) {
|
|
1337
1408
|
const nodeId = readString(input, "nodeId");
|
|
1338
|
-
if (!nodeId) return fail("delete_node: nodeId
|
|
1409
|
+
if (!nodeId) return fail("delete_node: nodeId missing", 'Argument "nodeId" is required.');
|
|
1339
1410
|
const reason = readString(input, "reason");
|
|
1340
1411
|
if (!reason) {
|
|
1341
1412
|
return fail(
|
|
1342
|
-
"delete_node:
|
|
1413
|
+
"delete_node: reason missing",
|
|
1343
1414
|
'Argument "reason" is required for destructive actions \u2014 state what the user asked for.'
|
|
1344
1415
|
);
|
|
1345
1416
|
}
|
|
@@ -1349,7 +1420,7 @@ var deleteNode = {
|
|
|
1349
1420
|
if ("error" in applied) return applied.error;
|
|
1350
1421
|
const op = { kind: "delete-node", nodeId };
|
|
1351
1422
|
return succeed(
|
|
1352
|
-
`
|
|
1423
|
+
`Delete ${describeNode(resolved.node)} \u2014 ${reason}`,
|
|
1353
1424
|
{ nodeId, removedType: resolved.node.type },
|
|
1354
1425
|
{ op, document: applied.document }
|
|
1355
1426
|
);
|
|
@@ -1383,7 +1454,7 @@ var replaceNodeTool = {
|
|
|
1383
1454
|
const reason = readString(input, "reason");
|
|
1384
1455
|
if (!nodeId || !raw || !reason) {
|
|
1385
1456
|
return fail(
|
|
1386
|
-
"replace_node:
|
|
1457
|
+
"replace_node: missing arguments",
|
|
1387
1458
|
'Arguments "nodeId", "node" and "reason" are all required.'
|
|
1388
1459
|
);
|
|
1389
1460
|
}
|
|
@@ -1391,7 +1462,7 @@ var replaceNodeTool = {
|
|
|
1391
1462
|
if ("error" in resolved) return resolved.error;
|
|
1392
1463
|
const normalized = normalizeIncomingNode({ ...raw, id: void 0 }, context.document);
|
|
1393
1464
|
if ("error" in normalized) {
|
|
1394
|
-
return fail("replace_node: node
|
|
1465
|
+
return fail("replace_node: invalid node", normalized.error);
|
|
1395
1466
|
}
|
|
1396
1467
|
const replacement = { ...normalized.node, id: nodeId, type: resolved.node.type };
|
|
1397
1468
|
const applied = applyCommand(
|
|
@@ -1403,7 +1474,7 @@ var replaceNodeTool = {
|
|
|
1403
1474
|
if (violation) return violation;
|
|
1404
1475
|
const op = { kind: "replace-node", nodeId, node: replacement };
|
|
1405
1476
|
return succeed(
|
|
1406
|
-
`
|
|
1477
|
+
`Replace structure of ${describeNode(resolved.node)} \u2014 ${reason}`,
|
|
1407
1478
|
{ nodeId, childCount: replacement.children?.length ?? 0 },
|
|
1408
1479
|
{ op, document: applied.document }
|
|
1409
1480
|
);
|
|
@@ -1482,7 +1553,7 @@ var KubuildAiAgent = class {
|
|
|
1482
1553
|
const available = this.tools.map((t) => t.definition.name).join(", ");
|
|
1483
1554
|
return {
|
|
1484
1555
|
ok: false,
|
|
1485
|
-
summary: `Tool "${call.name}"
|
|
1556
|
+
summary: `Tool "${call.name}" is unknown`,
|
|
1486
1557
|
snapshot,
|
|
1487
1558
|
block: {
|
|
1488
1559
|
type: "tool_result",
|
|
@@ -1579,7 +1650,7 @@ var KubuildAiAgent = class {
|
|
|
1579
1650
|
selectedNodeId: request.selectedNodeId,
|
|
1580
1651
|
prefix: this.options.systemPromptPrefix,
|
|
1581
1652
|
stylePreference: request.stylePreference,
|
|
1582
|
-
additionalContext: request.systemPrompt
|
|
1653
|
+
additionalContext: joinInstructions(request.instructions, request.systemPrompt)
|
|
1583
1654
|
});
|
|
1584
1655
|
const toolDefinitions = toToolDefinitions(this.tools);
|
|
1585
1656
|
const messages = [...request.messages];
|
|
@@ -1658,11 +1729,11 @@ var KubuildAiAgent = class {
|
|
|
1658
1729
|
}
|
|
1659
1730
|
if (stoppedBy === "complete" && step >= maxSteps && !summary) {
|
|
1660
1731
|
stoppedBy = "max-steps";
|
|
1661
|
-
summary = `
|
|
1732
|
+
summary = `Stopped after ${maxSteps} steps. ${ops.length} change(s) prepared \u2014 review them and ask to continue if needed.`;
|
|
1662
1733
|
this.log("warn", `[AGENT] hit maxSteps (${maxSteps}) with ${ops.length} op(s)`);
|
|
1663
1734
|
}
|
|
1664
1735
|
if (stoppedBy === "aborted" && !summary) {
|
|
1665
|
-
summary = `
|
|
1736
|
+
summary = `Stopped. ${ops.length} change(s) were prepared before stopping.`;
|
|
1666
1737
|
}
|
|
1667
1738
|
yield {
|
|
1668
1739
|
type: "agent-complete",
|
|
@@ -1681,7 +1752,7 @@ var KubuildAiAgent = class {
|
|
|
1681
1752
|
type: "agent-complete",
|
|
1682
1753
|
result: {
|
|
1683
1754
|
ops,
|
|
1684
|
-
summary: summary || `
|
|
1755
|
+
summary: summary || `An error occurred: ${message}`,
|
|
1685
1756
|
stepsUsed: step,
|
|
1686
1757
|
stoppedBy: "error",
|
|
1687
1758
|
usage: { promptTokens, completionTokens }
|
|
@@ -1709,7 +1780,20 @@ var KubuildAiAgent = class {
|
|
|
1709
1780
|
};
|
|
1710
1781
|
|
|
1711
1782
|
// src/server/handler.ts
|
|
1712
|
-
|
|
1783
|
+
var DEFAULT_MAX_CLIENT_INSTRUCTIONS_LENGTH = 4e3;
|
|
1784
|
+
function resolveClientInstructions(payload, options) {
|
|
1785
|
+
if (options?.allowClientInstructions === false) return void 0;
|
|
1786
|
+
const text = joinInstructions(
|
|
1787
|
+
typeof payload.instructions === "string" ? payload.instructions : void 0,
|
|
1788
|
+
typeof payload.systemPrompt === "string" ? payload.systemPrompt : void 0
|
|
1789
|
+
);
|
|
1790
|
+
if (!text) return void 0;
|
|
1791
|
+
const rawMax = options?.maxClientInstructionsLength;
|
|
1792
|
+
const max = typeof rawMax === "number" && Number.isFinite(rawMax) && rawMax >= 0 ? Math.floor(rawMax) : DEFAULT_MAX_CLIENT_INSTRUCTIONS_LENGTH;
|
|
1793
|
+
if (max === 0) return void 0;
|
|
1794
|
+
return text.length > max ? text.slice(0, max) : text;
|
|
1795
|
+
}
|
|
1796
|
+
async function processAiRequest(engine, body, signal, agent, instructionsOptions) {
|
|
1713
1797
|
if (!body || typeof body !== "object") {
|
|
1714
1798
|
return {
|
|
1715
1799
|
status: 400,
|
|
@@ -1724,6 +1808,7 @@ async function processAiRequest(engine, body, signal, agent) {
|
|
|
1724
1808
|
}
|
|
1725
1809
|
const payload = body;
|
|
1726
1810
|
const mode = payload.mode || "full-page";
|
|
1811
|
+
const instructions = resolveClientInstructions(payload, instructionsOptions);
|
|
1727
1812
|
if (mode === "full-page") {
|
|
1728
1813
|
if (!payload.prompt || typeof payload.prompt !== "string") {
|
|
1729
1814
|
return {
|
|
@@ -1746,7 +1831,8 @@ async function processAiRequest(engine, body, signal, agent) {
|
|
|
1746
1831
|
metadata: payload.metadata,
|
|
1747
1832
|
conversationHistory: payload.conversationHistory ?? payload.messages,
|
|
1748
1833
|
sectionCount: payload.sectionCount,
|
|
1749
|
-
plan: payload.plan
|
|
1834
|
+
plan: payload.plan,
|
|
1835
|
+
instructions
|
|
1750
1836
|
},
|
|
1751
1837
|
{ signal }
|
|
1752
1838
|
);
|
|
@@ -1773,7 +1859,8 @@ async function processAiRequest(engine, body, signal, agent) {
|
|
|
1773
1859
|
prompt: payload.prompt,
|
|
1774
1860
|
stylePreference: payload.stylePreference,
|
|
1775
1861
|
targetSectionType: payload.targetSectionType,
|
|
1776
|
-
parentContext: payload.parentContext
|
|
1862
|
+
parentContext: payload.parentContext,
|
|
1863
|
+
instructions
|
|
1777
1864
|
},
|
|
1778
1865
|
{ signal }
|
|
1779
1866
|
);
|
|
@@ -1799,7 +1886,8 @@ async function processAiRequest(engine, body, signal, agent) {
|
|
|
1799
1886
|
{
|
|
1800
1887
|
node: payload.node,
|
|
1801
1888
|
instruction: payload.instruction,
|
|
1802
|
-
stylePreference: payload.stylePreference
|
|
1889
|
+
stylePreference: payload.stylePreference,
|
|
1890
|
+
instructions
|
|
1803
1891
|
},
|
|
1804
1892
|
{ signal }
|
|
1805
1893
|
);
|
|
@@ -1825,7 +1913,8 @@ async function processAiRequest(engine, body, signal, agent) {
|
|
|
1825
1913
|
{
|
|
1826
1914
|
messages: payload.messages,
|
|
1827
1915
|
currentDocument: payload.currentDocument,
|
|
1828
|
-
selectedNodeId: payload.selectedNodeId
|
|
1916
|
+
selectedNodeId: payload.selectedNodeId,
|
|
1917
|
+
instructions
|
|
1829
1918
|
},
|
|
1830
1919
|
{ signal }
|
|
1831
1920
|
);
|
|
@@ -1845,7 +1934,8 @@ async function processAiRequest(engine, body, signal, agent) {
|
|
|
1845
1934
|
document: payload.document,
|
|
1846
1935
|
selectedNodeId: payload.selectedNodeId,
|
|
1847
1936
|
stylePreference: payload.stylePreference,
|
|
1848
|
-
maxSteps: payload.maxSteps
|
|
1937
|
+
maxSteps: payload.maxSteps,
|
|
1938
|
+
instructions
|
|
1849
1939
|
},
|
|
1850
1940
|
{ signal }
|
|
1851
1941
|
);
|
|
@@ -1874,7 +1964,8 @@ async function processAiRequest(engine, body, signal, agent) {
|
|
|
1874
1964
|
tone: payload.tone,
|
|
1875
1965
|
locale: payload.locale,
|
|
1876
1966
|
sectionCount: payload.sectionCount,
|
|
1877
|
-
conversationHistory: payload.conversationHistory ?? payload.messages
|
|
1967
|
+
conversationHistory: payload.conversationHistory ?? payload.messages,
|
|
1968
|
+
instructions
|
|
1878
1969
|
},
|
|
1879
1970
|
{ signal }
|
|
1880
1971
|
);
|
|
@@ -1998,8 +2089,10 @@ function createAiHandler(engine, options) {
|
|
|
1998
2089
|
);
|
|
1999
2090
|
}
|
|
2000
2091
|
const body = await request.json().catch(() => null);
|
|
2001
|
-
|
|
2002
|
-
|
|
2092
|
+
const streamMode = body && typeof body === "object" ? body.mode || "full-page" : null;
|
|
2093
|
+
if (body && typeof body === "object" && body.stream === true && (streamMode === "full-page" || streamMode === "chat" || streamMode === "agent")) {
|
|
2094
|
+
const mode = streamMode;
|
|
2095
|
+
const instructions = resolveClientInstructions(body, options);
|
|
2003
2096
|
if (mode === "agent") {
|
|
2004
2097
|
const validationError = validateAgentPayload(body, options?.agent);
|
|
2005
2098
|
if (validationError) {
|
|
@@ -2015,7 +2108,8 @@ function createAiHandler(engine, options) {
|
|
|
2015
2108
|
document: body.document,
|
|
2016
2109
|
selectedNodeId: body.selectedNodeId,
|
|
2017
2110
|
stylePreference: body.stylePreference,
|
|
2018
|
-
maxSteps: body.maxSteps
|
|
2111
|
+
maxSteps: body.maxSteps,
|
|
2112
|
+
instructions
|
|
2019
2113
|
},
|
|
2020
2114
|
{ signal: request.signal }
|
|
2021
2115
|
),
|
|
@@ -2043,7 +2137,8 @@ function createAiHandler(engine, options) {
|
|
|
2043
2137
|
{
|
|
2044
2138
|
messages: body.messages,
|
|
2045
2139
|
currentDocument: body.currentDocument,
|
|
2046
|
-
selectedNodeId: body.selectedNodeId
|
|
2140
|
+
selectedNodeId: body.selectedNodeId,
|
|
2141
|
+
instructions
|
|
2047
2142
|
},
|
|
2048
2143
|
{ signal: request.signal }
|
|
2049
2144
|
),
|
|
@@ -2075,7 +2170,8 @@ function createAiHandler(engine, options) {
|
|
|
2075
2170
|
metadata: body.metadata,
|
|
2076
2171
|
conversationHistory: body.conversationHistory ?? body.messages,
|
|
2077
2172
|
sectionCount: body.sectionCount,
|
|
2078
|
-
plan: body.plan
|
|
2173
|
+
plan: body.plan,
|
|
2174
|
+
instructions
|
|
2079
2175
|
},
|
|
2080
2176
|
{ signal: request.signal }
|
|
2081
2177
|
),
|
|
@@ -2086,7 +2182,8 @@ function createAiHandler(engine, options) {
|
|
|
2086
2182
|
engine,
|
|
2087
2183
|
body,
|
|
2088
2184
|
request.signal,
|
|
2089
|
-
options?.agent
|
|
2185
|
+
options?.agent,
|
|
2186
|
+
options
|
|
2090
2187
|
);
|
|
2091
2188
|
return new Response(JSON.stringify(response), {
|
|
2092
2189
|
status,
|
|
@@ -2117,6 +2214,7 @@ function createAiHandler(engine, options) {
|
|
|
2117
2214
|
export {
|
|
2118
2215
|
AnthropicAdapter,
|
|
2119
2216
|
CustomHttpAdapter,
|
|
2217
|
+
DEFAULT_MAX_CLIENT_INSTRUCTIONS_LENGTH,
|
|
2120
2218
|
GeminiAdapter,
|
|
2121
2219
|
KubuildAiAgent,
|
|
2122
2220
|
KubuildAiEngine,
|
|
@@ -2130,6 +2228,7 @@ export {
|
|
|
2130
2228
|
createDocumentTools,
|
|
2131
2229
|
normalizeIncomingNode,
|
|
2132
2230
|
processAiRequest,
|
|
2231
|
+
resolveClientInstructions,
|
|
2133
2232
|
suggestNodeIds,
|
|
2134
2233
|
toToolDefinitions
|
|
2135
2234
|
};
|