@agent-native/core 0.84.53 → 0.84.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +13 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/cli/skills.ts +34 -16
- package/corpus/core/src/client/AssistantChat.tsx +198 -146
- package/corpus/core/src/client/agent-chat-adapter.ts +14 -4
- package/corpus/core/src/client/blocks/library/diagram.config.ts +13 -2
- package/corpus/core/src/client/blocks/library/diagram.tsx +27 -3
- package/corpus/core/src/client/blocks/library/server-specs.ts +2 -2
- package/corpus/core/src/client/blocks/library/wireframe.config.ts +7 -1
- package/corpus/core/src/client/blocks/library/wireframe.tsx +42 -3
- package/corpus/core/src/client/blocks/types.ts +9 -0
- package/corpus/core/src/client/chat/message-components.tsx +6 -2
- package/corpus/core/src/client/sse-event-processor.ts +11 -4
- package/corpus/core/src/client/use-agent-engine-configured.ts +54 -12
- package/corpus/core/src/server/agent-chat-plugin.ts +9 -5
- package/corpus/core/src/styles/agent-native.css +44 -0
- package/corpus/core/src/styles/blocks.css +18 -0
- package/corpus/templates/plan/.agents/skills/visual-plan/references/document-quality.md +10 -6
- package/corpus/templates/plan/.agents/skills/visual-plan/references/wireframe.md +20 -9
- package/corpus/templates/plan/.agents/skills/visual-recap/SKILL.md +4 -1
- package/corpus/templates/plan/.agents/skills/visual-recap/references/wireframe.md +20 -9
- package/corpus/templates/plan/actions/create-ui-plan.ts +1 -1
- package/corpus/templates/plan/actions/create-visual-plan.ts +1 -1
- package/corpus/templates/plan/actions/create-visual-recap.ts +1 -1
- package/corpus/templates/plan/actions/get-plan-blocks.ts +2 -0
- package/corpus/templates/plan/app/components/plan/planBlocks.tsx +2 -0
- package/corpus/templates/plan/app/components/plan/wireframe/Wireframe.tsx +38 -4
- package/corpus/templates/plan/app/components/plan/wireframe/html-artboard.css +18 -0
- package/corpus/templates/plan/app/global.css +1 -2
- package/corpus/templates/plan/changelog/2026-07-02-plan-chat-keeps-the-composer-anchored-when-connect-ai-appears.md +6 -0
- package/corpus/templates/plan/changelog/2026-07-02-wireframe-and-diagram-blocks-can-now-show-or-hide-their-outer-frame.md +6 -0
- package/corpus/templates/plan/server/plan-mdx.ts +3 -0
- package/corpus/templates/plan/shared/plan-content.ts +8 -0
- package/dist/cli/skills.d.ts +3 -3
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +34 -16
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +65 -45
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +12 -2
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/blocks/library/diagram.config.d.ts +3 -1
- package/dist/client/blocks/library/diagram.config.d.ts.map +1 -1
- package/dist/client/blocks/library/diagram.config.js +10 -1
- package/dist/client/blocks/library/diagram.config.js.map +1 -1
- package/dist/client/blocks/library/diagram.d.ts.map +1 -1
- package/dist/client/blocks/library/diagram.js +13 -7
- package/dist/client/blocks/library/diagram.js.map +1 -1
- package/dist/client/blocks/library/server-specs.js +2 -2
- package/dist/client/blocks/library/server-specs.js.map +1 -1
- package/dist/client/blocks/library/wireframe.config.d.ts +3 -1
- package/dist/client/blocks/library/wireframe.config.d.ts.map +1 -1
- package/dist/client/blocks/library/wireframe.config.js +4 -0
- package/dist/client/blocks/library/wireframe.config.js.map +1 -1
- package/dist/client/blocks/library/wireframe.d.ts.map +1 -1
- package/dist/client/blocks/library/wireframe.js +20 -9
- package/dist/client/blocks/library/wireframe.js.map +1 -1
- package/dist/client/blocks/types.d.ts +8 -0
- package/dist/client/blocks/types.d.ts.map +1 -1
- package/dist/client/blocks/types.js.map +1 -1
- package/dist/client/chat/message-components.d.ts.map +1 -1
- package/dist/client/chat/message-components.js +6 -2
- package/dist/client/chat/message-components.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +9 -4
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/client/use-agent-engine-configured.d.ts +10 -1
- package/dist/client/use-agent-engine-configured.d.ts.map +1 -1
- package/dist/client/use-agent-engine-configured.js +35 -10
- package/dist/client/use-agent-engine-configured.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +2 -2
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +4 -4
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +9 -2
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/styles/agent-native.css +44 -0
- package/dist/styles/blocks.css +18 -0
- package/package.json +1 -1
|
@@ -89,6 +89,7 @@ function HtmlDiagram({
|
|
|
89
89
|
const ref = useRef<HTMLDivElement>(null);
|
|
90
90
|
const isDark = useIsDark();
|
|
91
91
|
const style = useWireframeStyle();
|
|
92
|
+
const showFrame = resolveVisualFrame(data.frame, ctx);
|
|
92
93
|
const scopeId = useId().replace(/[^a-zA-Z0-9_-]/g, "");
|
|
93
94
|
// Sanitize author HTML/CSS at the render point (defense-in-depth against
|
|
94
95
|
// stored XSS). Self-contained in core via the shared block sanitizer (DOM-based
|
|
@@ -114,6 +115,7 @@ function HtmlDiagram({
|
|
|
114
115
|
dir={ctx.textDirection}
|
|
115
116
|
data-theme={isDark ? "dark" : "light"}
|
|
116
117
|
data-style={style}
|
|
118
|
+
data-frame={showFrame ? "show" : "hide"}
|
|
117
119
|
data-text-direction={ctx.textDirection}
|
|
118
120
|
data-plan-diagram-scope={scopeId}
|
|
119
121
|
>
|
|
@@ -126,7 +128,7 @@ function HtmlDiagram({
|
|
|
126
128
|
<RoughOverlay
|
|
127
129
|
scopeRef={ref}
|
|
128
130
|
enabled={style === "sketchy"}
|
|
129
|
-
drawFrame={
|
|
131
|
+
drawFrame={showFrame}
|
|
130
132
|
selector={DIAGRAM_ROUGH_SELECTOR}
|
|
131
133
|
/>
|
|
132
134
|
{data.caption && !compact && (
|
|
@@ -138,6 +140,15 @@ function HtmlDiagram({
|
|
|
138
140
|
);
|
|
139
141
|
}
|
|
140
142
|
|
|
143
|
+
function resolveVisualFrame(
|
|
144
|
+
frame: DiagramData["frame"],
|
|
145
|
+
ctx: BlockRenderContext,
|
|
146
|
+
): boolean {
|
|
147
|
+
const resolved =
|
|
148
|
+
frame && frame !== "auto" ? frame : (ctx.visualFrame ?? "show");
|
|
149
|
+
return resolved !== "hide";
|
|
150
|
+
}
|
|
151
|
+
|
|
141
152
|
/* -------------------------------------------------------------------------- */
|
|
142
153
|
/* Legacy node-graph paths */
|
|
143
154
|
/* -------------------------------------------------------------------------- */
|
|
@@ -186,11 +197,13 @@ function PositionedDiagram({
|
|
|
186
197
|
compact,
|
|
187
198
|
markerId,
|
|
188
199
|
direction,
|
|
200
|
+
showFrame,
|
|
189
201
|
}: {
|
|
190
202
|
data: DiagramData;
|
|
191
203
|
compact?: boolean;
|
|
192
204
|
markerId: string;
|
|
193
205
|
direction?: BlockRenderContext["textDirection"];
|
|
206
|
+
showFrame: boolean;
|
|
194
207
|
}) {
|
|
195
208
|
const nodes = (data.nodes ?? []).map((node) => ({
|
|
196
209
|
...node,
|
|
@@ -228,7 +241,10 @@ function PositionedDiagram({
|
|
|
228
241
|
|
|
229
242
|
return (
|
|
230
243
|
<div
|
|
231
|
-
className=
|
|
244
|
+
className={cn(
|
|
245
|
+
"plan-sketch",
|
|
246
|
+
showFrame ? "rounded-[16px] border border-border bg-muted p-5" : "p-0",
|
|
247
|
+
)}
|
|
232
248
|
dir={direction}
|
|
233
249
|
data-text-direction={direction}
|
|
234
250
|
>
|
|
@@ -426,10 +442,12 @@ function SequenceDiagram({
|
|
|
426
442
|
data,
|
|
427
443
|
compact,
|
|
428
444
|
direction,
|
|
445
|
+
showFrame,
|
|
429
446
|
}: {
|
|
430
447
|
data: DiagramData;
|
|
431
448
|
compact?: boolean;
|
|
432
449
|
direction?: BlockRenderContext["textDirection"];
|
|
450
|
+
showFrame: boolean;
|
|
433
451
|
}) {
|
|
434
452
|
const edges = data.edges ?? [];
|
|
435
453
|
const nodes = orderDiagramNodes(data.nodes ?? [], edges);
|
|
@@ -443,7 +461,10 @@ function SequenceDiagram({
|
|
|
443
461
|
const visualNodes = direction === "rtl" ? [...nodes].reverse() : nodes;
|
|
444
462
|
return (
|
|
445
463
|
<div
|
|
446
|
-
className=
|
|
464
|
+
className={cn(
|
|
465
|
+
"plan-sketch",
|
|
466
|
+
showFrame ? "rounded-[16px] border border-border bg-muted p-5" : "p-0",
|
|
467
|
+
)}
|
|
447
468
|
dir={direction}
|
|
448
469
|
data-text-direction={direction}
|
|
449
470
|
>
|
|
@@ -524,6 +545,7 @@ function DiagramBody({
|
|
|
524
545
|
compact?: boolean;
|
|
525
546
|
}) {
|
|
526
547
|
const markerId = useId().replace(/:/g, "");
|
|
548
|
+
const showFrame = resolveVisualFrame(data.frame, ctx);
|
|
527
549
|
if (data.html?.trim()) {
|
|
528
550
|
return <HtmlDiagram data={data} ctx={ctx} compact={compact} />;
|
|
529
551
|
}
|
|
@@ -534,6 +556,7 @@ function DiagramBody({
|
|
|
534
556
|
compact={compact}
|
|
535
557
|
markerId={markerId}
|
|
536
558
|
direction={ctx.textDirection}
|
|
559
|
+
showFrame={showFrame}
|
|
537
560
|
/>
|
|
538
561
|
);
|
|
539
562
|
}
|
|
@@ -542,6 +565,7 @@ function DiagramBody({
|
|
|
542
565
|
data={data}
|
|
543
566
|
compact={compact}
|
|
544
567
|
direction={ctx.textDirection}
|
|
568
|
+
showFrame={showFrame}
|
|
545
569
|
/>
|
|
546
570
|
);
|
|
547
571
|
}
|
|
@@ -211,7 +211,7 @@ export const libraryBlockConfigs: BlockSpec<any>[] = [
|
|
|
211
211
|
placement: ["block"],
|
|
212
212
|
label: "Diagram",
|
|
213
213
|
description:
|
|
214
|
-
"A flexible inline architecture/code diagram. Prefer html/css with SVG or semantic HTML for polished two-dimensional layouts; use .diagram-* primitives and --wf-* tokens for theme/sketch compatibility. Legacy nodes/edges are only for simple previews.",
|
|
214
|
+
"A flexible inline architecture/code diagram. Prefer html/css with SVG or semantic HTML for polished two-dimensional layouts; use .diagram-* primitives and --wf-* tokens for theme/sketch compatibility. Set frame to show for standalone artifacts that need containment, hide when surrounding docs/canvas chrome already supplies the boundary. Legacy nodes/edges are only for simple previews.",
|
|
215
215
|
}),
|
|
216
216
|
defineBlock<WireframeData>({
|
|
217
217
|
type: "wireframe",
|
|
@@ -221,7 +221,7 @@ export const libraryBlockConfigs: BlockSpec<any>[] = [
|
|
|
221
221
|
placement: ["block"],
|
|
222
222
|
label: "Wireframe",
|
|
223
223
|
description:
|
|
224
|
-
"A sketch wireframe of one screen built from kit primitives (or an HTML mockup), rendered in a chosen surface
|
|
224
|
+
"A sketch wireframe of one screen built from kit primitives (or an HTML mockup), rendered in a chosen surface (desktop/mobile/popover/panel/browser). Set frame to show for standalone screens and recap comparisons, hide only when surrounding chrome already supplies the boundary.",
|
|
225
225
|
}),
|
|
226
226
|
defineBlock<MermaidData>({
|
|
227
227
|
type: "mermaid",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
3
|
import { prop, attributeValue } from "../mdx.js";
|
|
4
|
-
import type { BlockMdxConfig } from "../types.js";
|
|
4
|
+
import type { BlockMdxConfig, BlockVisualFrame } from "../types.js";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Pure (React-free) part of the shared `wireframe` block: its data shape, zod
|
|
@@ -138,6 +138,8 @@ export interface WireframeData {
|
|
|
138
138
|
/** `design` renders full-fidelity branded HTML/CSS instead of a sketch. */
|
|
139
139
|
renderMode?: WireframeRenderMode;
|
|
140
140
|
caption?: string;
|
|
141
|
+
/** Outer surface frame. `auto` lets the host choose the right default. */
|
|
142
|
+
frame?: BlockVisualFrame;
|
|
141
143
|
/**
|
|
142
144
|
* Neutral, textless loading register. The renderer drops borders, the sketch
|
|
143
145
|
* outline, and color, rendering soft placeholder geometry only.
|
|
@@ -205,6 +207,7 @@ const elNameSchema = z.enum(
|
|
|
205
207
|
WIREFRAME_EL_NAMES as [WireframeElName, ...WireframeElName[]],
|
|
206
208
|
);
|
|
207
209
|
const idSchema = z.string().trim().min(1).max(120);
|
|
210
|
+
const visualFrameSchema = z.enum(["auto", "show", "hide"]);
|
|
208
211
|
|
|
209
212
|
/**
|
|
210
213
|
* Reject full-document HTML (html/head/body/script/style tags) in the `html` /
|
|
@@ -281,6 +284,7 @@ export const wireframeSchema = z
|
|
|
281
284
|
surface: z.enum(["desktop", "mobile", "popover", "panel", "browser"]),
|
|
282
285
|
renderMode: z.enum(["wireframe", "design"]).optional(),
|
|
283
286
|
caption: z.string().trim().max(400).optional(),
|
|
287
|
+
frame: visualFrameSchema.optional(),
|
|
284
288
|
skeleton: z.boolean().optional(),
|
|
285
289
|
html: z
|
|
286
290
|
.string()
|
|
@@ -387,6 +391,7 @@ function serializeScreen(data: WireframeData): string {
|
|
|
387
391
|
prop("surface", data.surface),
|
|
388
392
|
prop("renderMode", data.renderMode),
|
|
389
393
|
prop("caption", data.caption),
|
|
394
|
+
prop("frame", data.frame),
|
|
390
395
|
prop("html", data.html),
|
|
391
396
|
prop("css", data.css),
|
|
392
397
|
prop("skeleton", data.skeleton),
|
|
@@ -494,6 +499,7 @@ function parseScreen(node: WireframeMdxNode, idContext: string): WireframeData {
|
|
|
494
499
|
(stringAttr(node, "surface") as WireframeData["surface"]) ?? "desktop",
|
|
495
500
|
renderMode: stringAttr(node, "renderMode") as WireframeData["renderMode"],
|
|
496
501
|
caption: stringAttr(node, "caption"),
|
|
502
|
+
frame: stringAttr(node, "frame") as WireframeData["frame"],
|
|
497
503
|
html: requiredStringAttr(node, "html"),
|
|
498
504
|
css: requiredStringAttr(node, "css"),
|
|
499
505
|
skeleton: boolAttr(node, "skeleton"),
|
|
@@ -113,6 +113,7 @@ function ArtboardFrame({
|
|
|
113
113
|
skeleton,
|
|
114
114
|
renderMode,
|
|
115
115
|
roughOverlay = true,
|
|
116
|
+
showFrame = true,
|
|
116
117
|
selector,
|
|
117
118
|
caption,
|
|
118
119
|
render,
|
|
@@ -129,6 +130,7 @@ function ArtboardFrame({
|
|
|
129
130
|
skeleton?: boolean;
|
|
130
131
|
renderMode?: "wireframe" | "design";
|
|
131
132
|
roughOverlay?: boolean;
|
|
133
|
+
showFrame?: boolean;
|
|
132
134
|
selector: string;
|
|
133
135
|
caption?: string;
|
|
134
136
|
render: (ctx: {
|
|
@@ -164,6 +166,9 @@ function ArtboardFrame({
|
|
|
164
166
|
const designMode = renderMode === "design";
|
|
165
167
|
const sketchy = !designMode && style === "sketchy" && !skeleton;
|
|
166
168
|
const roughEnabled = sketchy && roughOverlay;
|
|
169
|
+
const frameBorder = skeleton
|
|
170
|
+
? "var(--plan-placeholder-line, var(--plan-line, hsl(var(--border))))"
|
|
171
|
+
: "var(--plan-line, hsl(var(--border)))";
|
|
167
172
|
|
|
168
173
|
useEffect(() => {
|
|
169
174
|
const element = fitRef.current;
|
|
@@ -231,6 +236,7 @@ function ArtboardFrame({
|
|
|
231
236
|
ref={ref}
|
|
232
237
|
className="plan-kit-artboard relative"
|
|
233
238
|
data-rough-scope="wireframe"
|
|
239
|
+
data-frame={showFrame ? "show" : "hide"}
|
|
234
240
|
style={{
|
|
235
241
|
width,
|
|
236
242
|
// Auto-height by default (content-driven, floored at `minHeight`);
|
|
@@ -259,10 +265,19 @@ function ArtboardFrame({
|
|
|
259
265
|
>
|
|
260
266
|
{render({ theme, style })}
|
|
261
267
|
</div>
|
|
268
|
+
{!roughEnabled && showFrame && (
|
|
269
|
+
<div
|
|
270
|
+
className="pointer-events-none absolute inset-0"
|
|
271
|
+
style={{
|
|
272
|
+
borderRadius: preset.radius,
|
|
273
|
+
border: `1.5px solid ${frameBorder}`,
|
|
274
|
+
}}
|
|
275
|
+
/>
|
|
276
|
+
)}
|
|
262
277
|
<RoughOverlay
|
|
263
278
|
scopeRef={ref}
|
|
264
279
|
enabled={roughEnabled}
|
|
265
|
-
drawFrame={
|
|
280
|
+
drawFrame={showFrame}
|
|
266
281
|
frameRadius={preset.radius}
|
|
267
282
|
selector={selector}
|
|
268
283
|
/>
|
|
@@ -313,10 +328,12 @@ function WireframeStyleToggleButton() {
|
|
|
313
328
|
function HtmlArtboard({
|
|
314
329
|
data,
|
|
315
330
|
ctx: _ctx,
|
|
331
|
+
showFrame,
|
|
316
332
|
compact,
|
|
317
333
|
}: {
|
|
318
334
|
data: WireframeData;
|
|
319
335
|
ctx: BlockRenderContext;
|
|
336
|
+
showFrame: boolean;
|
|
320
337
|
compact?: boolean;
|
|
321
338
|
}) {
|
|
322
339
|
const renderMode = data.renderMode ?? "wireframe";
|
|
@@ -350,6 +367,7 @@ function HtmlArtboard({
|
|
|
350
367
|
compact={compact}
|
|
351
368
|
skeleton={data.skeleton}
|
|
352
369
|
renderMode={renderMode}
|
|
370
|
+
showFrame={showFrame}
|
|
353
371
|
selector={HTML_ROUGH_SELECTOR}
|
|
354
372
|
caption={data.caption}
|
|
355
373
|
render={({ theme, style }) => (
|
|
@@ -357,6 +375,7 @@ function HtmlArtboard({
|
|
|
357
375
|
className="plan-html-frame"
|
|
358
376
|
data-theme={theme}
|
|
359
377
|
data-style={style}
|
|
378
|
+
data-frame={showFrame ? "show" : "hide"}
|
|
360
379
|
data-render-mode={renderMode}
|
|
361
380
|
data-plan-design-scope={scopeId}
|
|
362
381
|
data-skeleton={data.skeleton ? "true" : undefined}
|
|
@@ -378,9 +397,11 @@ function HtmlArtboard({
|
|
|
378
397
|
|
|
379
398
|
function KitArtboard({
|
|
380
399
|
data,
|
|
400
|
+
showFrame,
|
|
381
401
|
compact,
|
|
382
402
|
}: {
|
|
383
403
|
data: WireframeData;
|
|
404
|
+
showFrame: boolean;
|
|
384
405
|
compact?: boolean;
|
|
385
406
|
}) {
|
|
386
407
|
return (
|
|
@@ -388,6 +409,7 @@ function KitArtboard({
|
|
|
388
409
|
surface={data.surface}
|
|
389
410
|
compact={compact}
|
|
390
411
|
skeleton={data.skeleton}
|
|
412
|
+
showFrame={showFrame}
|
|
391
413
|
selector="[data-rough]"
|
|
392
414
|
caption={data.caption}
|
|
393
415
|
render={({ theme, style }) => (
|
|
@@ -430,10 +452,27 @@ function WireframeSurfaceView({
|
|
|
430
452
|
ctx: BlockRenderContext;
|
|
431
453
|
compact?: boolean;
|
|
432
454
|
}) {
|
|
455
|
+
const showFrame = resolveVisualFrame(data.frame, ctx);
|
|
433
456
|
if (isHtmlData(data)) {
|
|
434
|
-
return
|
|
457
|
+
return (
|
|
458
|
+
<HtmlArtboard
|
|
459
|
+
data={data}
|
|
460
|
+
ctx={ctx}
|
|
461
|
+
showFrame={showFrame}
|
|
462
|
+
compact={compact}
|
|
463
|
+
/>
|
|
464
|
+
);
|
|
435
465
|
}
|
|
436
|
-
return <KitArtboard data={data} compact={compact} />;
|
|
466
|
+
return <KitArtboard data={data} showFrame={showFrame} compact={compact} />;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
function resolveVisualFrame(
|
|
470
|
+
frame: WireframeData["frame"],
|
|
471
|
+
ctx: BlockRenderContext,
|
|
472
|
+
): boolean {
|
|
473
|
+
const resolved =
|
|
474
|
+
frame && frame !== "auto" ? frame : (ctx.visualFrame ?? "show");
|
|
475
|
+
return resolved !== "hide";
|
|
437
476
|
}
|
|
438
477
|
|
|
439
478
|
/* -------------------------------------------------------------------------- */
|
|
@@ -19,6 +19,9 @@ import type { ZodType } from "zod";
|
|
|
19
19
|
/** Where a block can be placed in a document. */
|
|
20
20
|
export type BlockPlacement = "block" | "inline";
|
|
21
21
|
|
|
22
|
+
/** How visual blocks decide whether to draw an outer surface frame. */
|
|
23
|
+
export type BlockVisualFrame = "auto" | "show" | "hide";
|
|
24
|
+
|
|
22
25
|
/**
|
|
23
26
|
* A serialized MDX/NFM attribute value before the shared `prop()` encoder runs.
|
|
24
27
|
* `prop()` decides string-vs-JSON encoding; this is just the value domain.
|
|
@@ -96,6 +99,12 @@ export interface BlockRenderContext {
|
|
|
96
99
|
dialect?: "gfm" | "nfm";
|
|
97
100
|
/** Document text direction inferred by the host app. */
|
|
98
101
|
textDirection?: "ltr" | "rtl";
|
|
102
|
+
/**
|
|
103
|
+
* Host default for visual wireframe/diagram frames when block data leaves
|
|
104
|
+
* `frame` unset or set to `auto`. Plans/recaps usually show a frame; docs can
|
|
105
|
+
* hide it by default and let individual blocks opt back in.
|
|
106
|
+
*/
|
|
107
|
+
visualFrame?: Exclude<BlockVisualFrame, "auto">;
|
|
99
108
|
/** Resolve an asset id → displayable URL. */
|
|
100
109
|
resolveAssetSrc?: (assetId: string) => string | undefined;
|
|
101
110
|
/** Open the shared asset picker (returns the chosen asset). */
|
|
@@ -75,7 +75,11 @@ const PENDING_SELECTION_KEY = "pending-selection-context";
|
|
|
75
75
|
// ─── displayableUserMessageText ───────────────────────────────────────────────
|
|
76
76
|
|
|
77
77
|
export function displayableUserMessageText(text: string): string {
|
|
78
|
-
return text
|
|
78
|
+
return text
|
|
79
|
+
.replace(/<context\b[^>]*>[\s\S]*?<\/context>\n?/gi, "")
|
|
80
|
+
.replace(/<context\b[^>]*>[\s\S]*$/gi, "")
|
|
81
|
+
.replace(/<\/context>/gi, "")
|
|
82
|
+
.trim();
|
|
79
83
|
}
|
|
80
84
|
|
|
81
85
|
// ─── Message timestamp helpers ────────────────────────────────────────────────
|
|
@@ -214,7 +218,7 @@ export function SelectionAttachedPill() {
|
|
|
214
218
|
if (length === null || length === 0) return null;
|
|
215
219
|
|
|
216
220
|
return (
|
|
217
|
-
<div className="shrink-0 px-3 pt-1.5 -mb-1">
|
|
221
|
+
<div className="agent-selection-attached-pill shrink-0 px-3 pt-1.5 -mb-1">
|
|
218
222
|
<div className="inline-flex items-center gap-1.5 rounded-full border border-border bg-muted/50 px-2 py-0.5 text-[11px] text-muted-foreground">
|
|
219
223
|
<IconQuote size={11} />
|
|
220
224
|
<span>{length.toLocaleString()} chars of selection attached</span>
|
|
@@ -601,6 +601,15 @@ function dispatchActivityClear(tabId: string | undefined) {
|
|
|
601
601
|
);
|
|
602
602
|
}
|
|
603
603
|
|
|
604
|
+
function dispatchMissingApiKey(tabId: string | undefined) {
|
|
605
|
+
if (typeof window === "undefined") return;
|
|
606
|
+
window.dispatchEvent(
|
|
607
|
+
new CustomEvent("agent-chat:missing-api-key", {
|
|
608
|
+
detail: { tabId },
|
|
609
|
+
}),
|
|
610
|
+
);
|
|
611
|
+
}
|
|
612
|
+
|
|
604
613
|
function pendingToolNames(content: ContentPart[]): {
|
|
605
614
|
activity: string[];
|
|
606
615
|
running: string[];
|
|
@@ -1056,7 +1065,7 @@ export function processEvent(
|
|
|
1056
1065
|
errorCode,
|
|
1057
1066
|
};
|
|
1058
1067
|
if (typeof window !== "undefined") {
|
|
1059
|
-
|
|
1068
|
+
dispatchMissingApiKey(tabId);
|
|
1060
1069
|
window.dispatchEvent(
|
|
1061
1070
|
new CustomEvent("agent-chat:run-error", {
|
|
1062
1071
|
detail: { ...runError, tabId },
|
|
@@ -1156,9 +1165,7 @@ export function processEvent(
|
|
|
1156
1165
|
}
|
|
1157
1166
|
const normalized = normalizeChatError(errMsg, ev.errorCode);
|
|
1158
1167
|
if (isMissingCredentialText(errMsg, ev.errorCode)) {
|
|
1159
|
-
|
|
1160
|
-
window.dispatchEvent(new Event("agent-chat:missing-api-key"));
|
|
1161
|
-
}
|
|
1168
|
+
dispatchMissingApiKey(tabId);
|
|
1162
1169
|
}
|
|
1163
1170
|
const runError = {
|
|
1164
1171
|
message: normalized.message,
|
|
@@ -15,10 +15,20 @@ export interface UseAgentEngineConfiguredResult {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export interface FetchAgentEngineConfiguredStateOptions {
|
|
18
|
+
/**
|
|
19
|
+
* Legacy hint from explicit missing-key stream events. Kept for API
|
|
20
|
+
* compatibility, but missing state still requires authoritative status
|
|
21
|
+
* responses so transient endpoint failures do not clobber connected state.
|
|
22
|
+
*/
|
|
18
23
|
missingFallback?: boolean;
|
|
19
24
|
timeoutMs?: number;
|
|
20
25
|
}
|
|
21
26
|
|
|
27
|
+
export interface UseAgentEngineConfiguredOptions {
|
|
28
|
+
tabId?: string | null;
|
|
29
|
+
threadId?: string | null;
|
|
30
|
+
}
|
|
31
|
+
|
|
22
32
|
const DEFAULT_STATUS_CHECK_TIMEOUT_MS = 2500;
|
|
23
33
|
|
|
24
34
|
async function fetchStatusJson(
|
|
@@ -60,6 +70,27 @@ function hasConfiguredFlag(value: unknown): value is { configured: boolean } {
|
|
|
60
70
|
);
|
|
61
71
|
}
|
|
62
72
|
|
|
73
|
+
function missingKeyEventMatchesScope(
|
|
74
|
+
event: Event,
|
|
75
|
+
options: UseAgentEngineConfiguredOptions | undefined,
|
|
76
|
+
): boolean {
|
|
77
|
+
const detail = (event as CustomEvent).detail as
|
|
78
|
+
| { tabId?: unknown; threadId?: unknown }
|
|
79
|
+
| undefined;
|
|
80
|
+
const eventTabId = typeof detail?.tabId === "string" ? detail.tabId : null;
|
|
81
|
+
const eventThreadId =
|
|
82
|
+
typeof detail?.threadId === "string" ? detail.threadId : null;
|
|
83
|
+
if (!eventTabId && !eventThreadId) return true;
|
|
84
|
+
|
|
85
|
+
const tabId = options?.tabId ?? null;
|
|
86
|
+
const threadId = options?.threadId ?? null;
|
|
87
|
+
if (!tabId && !threadId) return true;
|
|
88
|
+
return (
|
|
89
|
+
(eventTabId != null && eventTabId === tabId) ||
|
|
90
|
+
(eventThreadId != null && eventThreadId === threadId)
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
63
94
|
export async function fetchAgentEngineConfiguredState(
|
|
64
95
|
enabled = true,
|
|
65
96
|
options?: FetchAgentEngineConfiguredStateOptions,
|
|
@@ -76,22 +107,31 @@ export async function fetchAgentEngineConfiguredState(
|
|
|
76
107
|
fetchStatusJson("/_agent-native/agent-engine/status", timeoutMs),
|
|
77
108
|
]);
|
|
78
109
|
|
|
79
|
-
// All three failed — likely a flaky network; keep the caller in unknown
|
|
80
|
-
//
|
|
110
|
+
// All three failed — likely a flaky network; keep the caller in unknown.
|
|
111
|
+
// Even an explicit missing-key stream event should not pin the composer into
|
|
112
|
+
// setup without a fresh authoritative status response.
|
|
81
113
|
if (envKeys == null && builderStatus == null && engineStatus == null) {
|
|
82
|
-
return
|
|
114
|
+
return "unknown";
|
|
83
115
|
}
|
|
84
116
|
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
117
|
+
const envKeysKnown = Array.isArray(envKeys);
|
|
118
|
+
const builderStatusKnown = hasConfiguredFlag(builderStatus);
|
|
119
|
+
const engineStatusKnown = hasConfiguredFlag(engineStatus);
|
|
120
|
+
const keys = envKeysKnown
|
|
121
|
+
? (envKeys as Array<{
|
|
122
|
+
key: string;
|
|
123
|
+
configured: boolean;
|
|
124
|
+
}>)
|
|
125
|
+
: [];
|
|
89
126
|
const llmKeys = keys.filter((k) => PROVIDER_ENV_VAR_SET.has(k.key));
|
|
90
127
|
const anyConfigured =
|
|
91
128
|
llmKeys.some((k) => k.configured) ||
|
|
92
|
-
(
|
|
93
|
-
(
|
|
94
|
-
|
|
129
|
+
(builderStatusKnown && builderStatus.configured) ||
|
|
130
|
+
(engineStatusKnown && engineStatus.configured);
|
|
131
|
+
if (anyConfigured) return "configured";
|
|
132
|
+
return envKeysKnown && builderStatusKnown && engineStatusKnown
|
|
133
|
+
? "missing"
|
|
134
|
+
: "unknown";
|
|
95
135
|
}
|
|
96
136
|
|
|
97
137
|
/**
|
|
@@ -103,6 +143,7 @@ export async function fetchAgentEngineConfiguredState(
|
|
|
103
143
|
*/
|
|
104
144
|
export function useAgentEngineConfigured(
|
|
105
145
|
enabled = true,
|
|
146
|
+
options?: UseAgentEngineConfiguredOptions,
|
|
106
147
|
): UseAgentEngineConfiguredResult {
|
|
107
148
|
const [state, setState] = useState<AgentEngineConfiguredState>("unknown");
|
|
108
149
|
|
|
@@ -119,7 +160,8 @@ export function useAgentEngineConfigured(
|
|
|
119
160
|
const onConfiguredChanged = () => {
|
|
120
161
|
void check();
|
|
121
162
|
};
|
|
122
|
-
const onMissing = () => {
|
|
163
|
+
const onMissing = (event: Event) => {
|
|
164
|
+
if (!missingKeyEventMatchesScope(event, options)) return;
|
|
123
165
|
if (!enabled) {
|
|
124
166
|
setState("configured");
|
|
125
167
|
return;
|
|
@@ -143,7 +185,7 @@ export function useAgentEngineConfigured(
|
|
|
143
185
|
);
|
|
144
186
|
window.removeEventListener("agent-chat:missing-api-key", onMissing);
|
|
145
187
|
};
|
|
146
|
-
}, [enabled]);
|
|
188
|
+
}, [enabled, options?.tabId, options?.threadId]);
|
|
147
189
|
|
|
148
190
|
return { missing: state === "missing", state };
|
|
149
191
|
}
|
|
@@ -7124,11 +7124,15 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
7124
7124
|
setResponseStatus(event, 400);
|
|
7125
7125
|
return { error: "message is required" };
|
|
7126
7126
|
}
|
|
7127
|
-
// Strip mention markup
|
|
7128
|
-
|
|
7129
|
-
|
|
7130
|
-
|
|
7131
|
-
|
|
7127
|
+
// Strip hidden context and mention markup before title generation.
|
|
7128
|
+
// Fallback titles are often direct truncations, so never let injected
|
|
7129
|
+
// prompt context become a visible tab label.
|
|
7130
|
+
const cleanMessage = message
|
|
7131
|
+
.replace(/<context\b[^>]*>[\s\S]*?<\/context>\n?/gi, "")
|
|
7132
|
+
.replace(/<context\b[^>]*>[\s\S]*$/gi, "")
|
|
7133
|
+
.replace(/<\/context>/gi, "")
|
|
7134
|
+
.replace(/@\[([^\]|]+)\|[^\]]*\]/g, "@$1")
|
|
7135
|
+
.trim();
|
|
7132
7136
|
// Mirror the chat-run resolution so BYO-key users have title
|
|
7133
7137
|
// generation billed to their own key instead of the platform key.
|
|
7134
7138
|
const { getOwnerActiveApiKey } =
|
|
@@ -682,6 +682,23 @@
|
|
|
682
682
|
line-height: 1.75rem;
|
|
683
683
|
}
|
|
684
684
|
|
|
685
|
+
.agent-composer-stack {
|
|
686
|
+
position: relative;
|
|
687
|
+
flex-shrink: 0;
|
|
688
|
+
width: 100%;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
.agent-composer-stack[data-agent-composer-adjacent-ui="true"],
|
|
692
|
+
.agent-composer-stack:has(.agent-selection-attached-pill) {
|
|
693
|
+
display: flex;
|
|
694
|
+
flex-direction: column;
|
|
695
|
+
gap: 0.5rem;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
.agent-composer-setup-card {
|
|
699
|
+
width: 100%;
|
|
700
|
+
}
|
|
701
|
+
|
|
685
702
|
[data-agent-empty-state="centered"] {
|
|
686
703
|
justify-content: center;
|
|
687
704
|
}
|
|
@@ -691,6 +708,33 @@
|
|
|
691
708
|
overflow: visible;
|
|
692
709
|
}
|
|
693
710
|
|
|
711
|
+
[data-agent-empty-state="centered"]
|
|
712
|
+
> .agent-composer-stack:not([data-agent-composer-adjacent-ui="true"]):not(
|
|
713
|
+
:has(.agent-selection-attached-pill)
|
|
714
|
+
)
|
|
715
|
+
> .agent-composer-setup-card {
|
|
716
|
+
position: absolute;
|
|
717
|
+
left: 0;
|
|
718
|
+
right: 0;
|
|
719
|
+
z-index: 3;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
[data-agent-empty-state="centered"]
|
|
723
|
+
> .agent-composer-stack:not([data-agent-composer-adjacent-ui="true"]):not(
|
|
724
|
+
:has(.agent-selection-attached-pill)
|
|
725
|
+
)
|
|
726
|
+
> .agent-composer-setup-card[data-agent-composer-setup-position="above"] {
|
|
727
|
+
bottom: calc(100% + 0.5rem);
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
[data-agent-empty-state="centered"]
|
|
731
|
+
> .agent-composer-stack:not([data-agent-composer-adjacent-ui="true"]):not(
|
|
732
|
+
:has(.agent-selection-attached-pill)
|
|
733
|
+
)
|
|
734
|
+
> .agent-composer-setup-card[data-agent-composer-setup-position="below"] {
|
|
735
|
+
top: calc(100% + 0.5rem);
|
|
736
|
+
}
|
|
737
|
+
|
|
694
738
|
[data-agent-empty-state="compact-setup"] > .agent-chat-scroll {
|
|
695
739
|
flex: 0 0 auto;
|
|
696
740
|
overflow: visible;
|
|
@@ -1290,6 +1290,20 @@
|
|
|
1290
1290
|
line-height: 1.4;
|
|
1291
1291
|
}
|
|
1292
1292
|
|
|
1293
|
+
.plan-diagram-frame[data-frame="show"] {
|
|
1294
|
+
border: 1px solid var(--wf-diagram-line);
|
|
1295
|
+
padding: 10px;
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
.plan-diagram-frame[data-frame="show"][data-rough-ready] {
|
|
1299
|
+
border-color: transparent;
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
.plan-diagram-frame[data-frame="hide"] {
|
|
1303
|
+
border: 0;
|
|
1304
|
+
background: transparent;
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1293
1307
|
.plan-diagram-frame[data-theme="dark"] {
|
|
1294
1308
|
--wf-diagram-line: color-mix(in srgb, var(--wf-sketch) 72%, var(--wf-line));
|
|
1295
1309
|
}
|
|
@@ -1312,6 +1326,10 @@
|
|
|
1312
1326
|
direction: inherit;
|
|
1313
1327
|
}
|
|
1314
1328
|
|
|
1329
|
+
.plan-diagram-frame[data-frame="show"] .plan-diagram-frame-content {
|
|
1330
|
+
padding: 0;
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1315
1333
|
.plan-diagram-frame-content
|
|
1316
1334
|
> .diagram-panel:not([data-rough]):not([data-diagram-frame]) {
|
|
1317
1335
|
--rough-skip: 1;
|
|
@@ -109,12 +109,16 @@ so you never emit a block the editor cannot render or round-trip:
|
|
|
109
109
|
`--wf-paper`, `--wf-card`, `--wf-accent`, `--wf-accent-soft`, `--wf-warn`, and
|
|
110
110
|
`--wf-ok`, and switch to Excalifont plus rough.js outlines in sketchy mode. Do not
|
|
111
111
|
set `font-family` and do not hard-code hex, rgb, or hsl colors in diagram HTML
|
|
112
|
-
or CSS.
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
112
|
+
or CSS. Choose the outer `frame` intentionally: use `show` when the diagram
|
|
113
|
+
stands alone in a recap, comparison, or prose section; use `hide` when the
|
|
114
|
+
diagram sits inside docs chrome, columns, tabs, cards, a canvas surface, or
|
|
115
|
+
already has visible `.diagram-panel` / `.diagram-box` structure. Leave room
|
|
116
|
+
for the sketch font: keep labels short, give nodes generous width, and place
|
|
117
|
+
boundary/annotation labels in unused space instead of over nodes; labels must
|
|
118
|
+
not overlap nodes, connectors, or each other. For small text/SVG changes to an
|
|
119
|
+
existing HTML diagram, use `patch-diagram-html` with a unique
|
|
120
|
+
`find`/`replace` snippet instead of resending the whole `data.html` string.
|
|
121
|
+
Use legacy `nodes` / `edges` only for small previews or truly
|
|
118
122
|
sequential flows. In architecture/code plans, prefer a repeated section rhythm:
|
|
119
123
|
recommendation title, confidence and category badges, code-path evidence, a
|
|
120
124
|
local before/after or current/target spatial diagram, then concise
|