@agent-native/core 0.80.10 → 0.80.11
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 +6 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/production-agent.ts +108 -15
- package/corpus/core/src/client/AssistantChat.tsx +123 -26
- package/corpus/core/src/client/sse-event-processor.ts +9 -0
- package/corpus/templates/assets/.agents/skills/image-generation/SKILL.md +9 -2
- package/corpus/templates/assets/AGENTS.md +4 -0
- package/corpus/templates/assets/actions/_tool-activity.ts +46 -0
- package/corpus/templates/assets/actions/generate-image-batch.ts +26 -5
- package/corpus/templates/assets/actions/generate-image.ts +118 -67
- package/corpus/templates/assets/actions/list-draft-assets.ts +50 -0
- package/corpus/templates/assets/actions/rerun-generation-run.ts +52 -31
- package/corpus/templates/assets/app/components/create/RecentDraftsSection.tsx +100 -0
- package/corpus/templates/assets/app/i18n/zh-TW.ts +7 -0
- package/corpus/templates/assets/app/i18n-data.ts +61 -0
- package/corpus/templates/assets/app/routes/_index.tsx +4 -0
- package/corpus/templates/assets/app/routes/library.tsx +145 -38
- package/corpus/templates/assets/changelog/2026-06-29-image-generation-can-now-render-requested-text-and-respect-b.md +6 -0
- package/corpus/templates/assets/changelog/2026-06-30-image-generation-no-longer-looks-stuck-while-the-provider-is-still-working.md +6 -0
- package/corpus/templates/assets/changelog/2026-06-30-tagged-presets-now-control-the-image-aspect-ratio.md +6 -0
- package/corpus/templates/assets/server/lib/generation.ts +135 -11
- package/corpus/templates/assets/shared/api.ts +4 -0
- package/corpus/templates/clips/actions/list-ai-requests.ts +60 -0
- package/corpus/templates/clips/app/hooks/use-auto-title.ts +24 -25
- package/corpus/templates/design/actions/apply-component-prop-edit.ts +13 -5
- package/corpus/templates/design/actions/apply-design-state.ts +17 -4
- package/corpus/templates/design/actions/apply-motion-edit.ts +9 -46
- package/corpus/templates/design/actions/delete-design.ts +20 -0
- package/corpus/templates/design/actions/get-component-details.ts +16 -7
- package/corpus/templates/design/actions/index-design-tokens.ts +8 -4
- package/corpus/templates/design/actions/list-design-states.ts +19 -1
- package/corpus/templates/design/actions/open-component-source.ts +7 -2
- package/corpus/templates/design/actions/preview-component-prop-edit.ts +32 -26
- package/corpus/templates/design/actions/preview-shader-fill.ts +9 -11
- package/corpus/templates/design/actions/run-design-audit.ts +21 -6
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +139 -14
- package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +20 -3
- package/corpus/templates/design/app/components/design/EditPanel.tsx +428 -31
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +110 -30
- package/corpus/templates/design/app/components/design/MotionDock.tsx +9 -0
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +1 -1
- package/corpus/templates/design/app/components/design/ReviewPanel.tsx +12 -5
- package/corpus/templates/design/app/components/design/StatesPanel.tsx +4 -2
- package/corpus/templates/design/app/components/design/TokensPanel.tsx +13 -8
- package/corpus/templates/design/app/i18n/zh-TW.ts +1 -0
- package/corpus/templates/design/app/i18n-data.ts +11 -0
- package/corpus/templates/design/app/pages/DesignEditor.tsx +684 -179
- package/corpus/templates/design/changelog/2026-06-30-design-token-edits-now-stay-visible-in-previews-and-token-li.md +6 -0
- package/corpus/templates/design/e2e/global-setup.ts +94 -2
- package/corpus/templates/design/shared/component-model.ts +35 -0
- package/corpus/templates/design/shared/motion-compiler.ts +79 -8
- package/corpus/templates/design/shared/resolve-tweaks.ts +32 -9
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +94 -10
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +14 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +115 -22
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +10 -0
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/observability/routes.d.ts +3 -3
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
|
|
4
|
+
import { createClient } from "@libsql/client";
|
|
4
5
|
import { chromium, type FullConfig } from "@playwright/test";
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -19,6 +20,12 @@ const AUTH_DIR = path.join(import.meta.dirname, ".auth");
|
|
|
19
20
|
const STATE_PATH = path.join(AUTH_DIR, "state.json");
|
|
20
21
|
const SEED_PATH = path.join(AUTH_DIR, "seed.json");
|
|
21
22
|
const BROWSER_CHANNEL = process.env.E2E_BROWSER_CHANNEL;
|
|
23
|
+
const E2E_DATABASE_URL = `file:${path.join(
|
|
24
|
+
import.meta.dirname,
|
|
25
|
+
"..",
|
|
26
|
+
"data",
|
|
27
|
+
"e2e.db",
|
|
28
|
+
)}`;
|
|
22
29
|
|
|
23
30
|
/**
|
|
24
31
|
* Fixture HTML with distinct, text-identifiable elements. Plain inline styles
|
|
@@ -31,6 +38,12 @@ export const FIXTURE_HTML = `<!doctype html>
|
|
|
31
38
|
<meta charset="utf-8" />
|
|
32
39
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
33
40
|
<title>E2E Fixture</title>
|
|
41
|
+
<style>
|
|
42
|
+
:root {
|
|
43
|
+
--e2e-accent-color: #6366f1;
|
|
44
|
+
--e2e-radius: 14px;
|
|
45
|
+
}
|
|
46
|
+
</style>
|
|
34
47
|
</head>
|
|
35
48
|
<body style="margin:0;font-family:system-ui,sans-serif;background:#0f1115;color:#f4f4f5">
|
|
36
49
|
<main style="max-width:720px;margin:0 auto;padding:48px 32px;display:flex;flex-direction:column;gap:24px">
|
|
@@ -38,8 +51,26 @@ export const FIXTURE_HTML = `<!doctype html>
|
|
|
38
51
|
<p style="font-size:18px;line-height:1.6;margin:0;color:#a1a1aa">First fixture paragraph for selection tests.</p>
|
|
39
52
|
<p style="font-size:18px;line-height:1.6;margin:0;color:#a1a1aa">Second fixture paragraph for selection tests.</p>
|
|
40
53
|
<div style="display:flex;flex-direction:row;gap:16px">
|
|
41
|
-
<button style="padding:14px 28px;border-radius:10px;border:0;background:#6366f1;color:#fff;font-size:16px">Alpha Button</button>
|
|
42
|
-
<button style="padding:14px 28px;border-radius:10px;border:0;background:#22c55e;color:#06240f;font-size:16px">Beta Button</button>
|
|
54
|
+
<button data-agent-native-node-id="e2e-alpha-button" data-agent-native-layer-name="Alpha Button" style="padding:14px 28px;border-radius:10px;border:0;background:#6366f1;color:#fff;font-size:16px">Alpha Button</button>
|
|
55
|
+
<button data-agent-native-node-id="e2e-beta-button" data-agent-native-layer-name="Beta Button" style="padding:14px 28px;border-radius:10px;border:0;background:#22c55e;color:#06240f;font-size:16px">Beta Button</button>
|
|
56
|
+
</div>
|
|
57
|
+
<button
|
|
58
|
+
data-agent-native-node-id="e2e-component-button"
|
|
59
|
+
data-agent-native-layer-name="E2E Component Button"
|
|
60
|
+
data-agent-native-component="E2EButton"
|
|
61
|
+
data-agent-native-prop-variant="primary"
|
|
62
|
+
data-agent-native-prop-size="md"
|
|
63
|
+
style="align-self:flex-start;padding:14px 28px;border-radius:var(--e2e-radius);border:0;background:var(--e2e-accent-color);color:#fff;font-size:16px"
|
|
64
|
+
>Variant CTA</button>
|
|
65
|
+
<div
|
|
66
|
+
data-agent-native-node-id="e2e-token-sample"
|
|
67
|
+
data-agent-native-layer-name="E2E Token Sample"
|
|
68
|
+
style="padding:18px 20px;border-radius:var(--e2e-radius);background:var(--e2e-accent-color);color:#fff;font-weight:700"
|
|
69
|
+
>Token swatch sample</div>
|
|
70
|
+
<div style="display:flex;align-items:center;gap:12px">
|
|
71
|
+
<img data-agent-native-node-id="e2e-audit-image" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==" style="width:32px;height:32px;border-radius:8px;background:#27272a" />
|
|
72
|
+
<input data-agent-native-node-id="e2e-audit-input" placeholder="Email" style="height:32px;border-radius:8px;border:1px solid #3f3f46;background:#18181b;color:#fff;padding:0 10px" />
|
|
73
|
+
<button data-agent-native-node-id="e2e-audit-focus-button" class="outline-none" style="height:32px;border-radius:8px;border:1px solid #3f3f46;background:#27272a;color:#fff;padding:0 10px">Focus me</button>
|
|
43
74
|
</div>
|
|
44
75
|
<div style="padding:8px;border:1px solid #27272a;border-radius:12px">
|
|
45
76
|
<div style="padding:8px;border:1px solid #3f3f46;border-radius:10px">
|
|
@@ -76,6 +107,63 @@ async function postAction(
|
|
|
76
107
|
return res.json();
|
|
77
108
|
}
|
|
78
109
|
|
|
110
|
+
function componentIndexId(designId: string, name: string): string {
|
|
111
|
+
return `ci_${designId}_${name.toLowerCase().replace(/[^a-z0-9]/g, "_")}`;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export async function seedComponentVariantMetadata(
|
|
115
|
+
designId: string,
|
|
116
|
+
): Promise<void> {
|
|
117
|
+
const client = createClient({ url: E2E_DATABASE_URL });
|
|
118
|
+
const name = "E2EButton";
|
|
119
|
+
const now = new Date().toISOString();
|
|
120
|
+
const variants = JSON.stringify({
|
|
121
|
+
variant: ["primary", "secondary", "ghost"],
|
|
122
|
+
size: ["sm", "md", "lg"],
|
|
123
|
+
});
|
|
124
|
+
const props = JSON.stringify([
|
|
125
|
+
{ name: "variant", type: "primary | secondary | ghost" },
|
|
126
|
+
{ name: "size", type: "sm | md | lg" },
|
|
127
|
+
]);
|
|
128
|
+
|
|
129
|
+
try {
|
|
130
|
+
const result = await client.execute({
|
|
131
|
+
sql: `
|
|
132
|
+
UPDATE component_index
|
|
133
|
+
SET variants = ?, props = ?, file_path = ?, export_name = ?, updated_at = ?
|
|
134
|
+
WHERE design_id = ? AND name = ?
|
|
135
|
+
`,
|
|
136
|
+
args: [variants, props, "index.html", name, now, designId, name],
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
if (result.rowsAffected > 0) return;
|
|
140
|
+
|
|
141
|
+
await client.execute({
|
|
142
|
+
sql: `
|
|
143
|
+
INSERT INTO component_index (
|
|
144
|
+
id, design_id, name, file_path, export_name, props, variants,
|
|
145
|
+
runtime_selectors, owner_email, created_at, updated_at
|
|
146
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
147
|
+
`,
|
|
148
|
+
args: [
|
|
149
|
+
componentIndexId(designId, name),
|
|
150
|
+
designId,
|
|
151
|
+
name,
|
|
152
|
+
"index.html",
|
|
153
|
+
name,
|
|
154
|
+
props,
|
|
155
|
+
variants,
|
|
156
|
+
JSON.stringify(['[data-agent-native-node-id="e2e-component-button"]']),
|
|
157
|
+
E2E_EMAIL,
|
|
158
|
+
now,
|
|
159
|
+
now,
|
|
160
|
+
],
|
|
161
|
+
});
|
|
162
|
+
} finally {
|
|
163
|
+
client.close();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
79
167
|
export default async function globalSetup(config: FullConfig) {
|
|
80
168
|
const baseURL =
|
|
81
169
|
(config.projects[0]?.use?.baseURL as string | undefined) ??
|
|
@@ -148,6 +236,10 @@ export default async function globalSetup(config: FullConfig) {
|
|
|
148
236
|
content: FIXTURE_HTML,
|
|
149
237
|
fileType: "html",
|
|
150
238
|
});
|
|
239
|
+
await postAction(context.request, baseURL, "index-components", {
|
|
240
|
+
designId,
|
|
241
|
+
});
|
|
242
|
+
await seedComponentVariantMetadata(designId);
|
|
151
243
|
|
|
152
244
|
await writeFile(SEED_PATH, JSON.stringify({ designId }, null, 2));
|
|
153
245
|
// eslint-disable-next-line no-console
|
|
@@ -40,6 +40,22 @@ export interface ComponentPropValue {
|
|
|
40
40
|
value: string;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Convert a JavaScript/React prop name to the `data-agent-native-prop-*`
|
|
45
|
+
* attribute name used in rendered HTML.
|
|
46
|
+
*
|
|
47
|
+
* HTML attribute names are lower-cased by parsers, so camelCase must be written
|
|
48
|
+
* as kebab-case to round-trip through {@link extractProps}.
|
|
49
|
+
*/
|
|
50
|
+
export function propNameToDataAttribute(propName: string): string {
|
|
51
|
+
const suffix = propName
|
|
52
|
+
.trim()
|
|
53
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1-$2")
|
|
54
|
+
.replace(/[\s_]+/g, "-")
|
|
55
|
+
.toLowerCase();
|
|
56
|
+
return `${COMPONENT_PROP_PREFIX}${suffix}`;
|
|
57
|
+
}
|
|
58
|
+
|
|
43
59
|
// ─── Component instance ───────────────────────────────────────────────────────
|
|
44
60
|
|
|
45
61
|
/**
|
|
@@ -118,6 +134,25 @@ export function componentNameFor(node: CodeLayerNode): string | null {
|
|
|
118
134
|
return raw.trim();
|
|
119
135
|
}
|
|
120
136
|
|
|
137
|
+
/**
|
|
138
|
+
* Match a selected component handle against both generated code-layer ids and
|
|
139
|
+
* durable runtime/source ids stamped into the rendered DOM.
|
|
140
|
+
*/
|
|
141
|
+
export function componentNodeIdMatches(
|
|
142
|
+
node: CodeLayerNode,
|
|
143
|
+
nodeId: string,
|
|
144
|
+
): boolean {
|
|
145
|
+
return (
|
|
146
|
+
node.id === nodeId ||
|
|
147
|
+
node.dataAttributes["data-agent-native-node-id"] === nodeId ||
|
|
148
|
+
node.dataAttributes["data-code-layer-id"] === nodeId ||
|
|
149
|
+
node.dataAttributes["data-layer-id"] === nodeId ||
|
|
150
|
+
node.dataAttributes["data-builder-id"] === nodeId ||
|
|
151
|
+
node.dataAttributes["data-loc"] === nodeId ||
|
|
152
|
+
node.attributes.id === nodeId
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
121
156
|
/**
|
|
122
157
|
* Extract simple prop values from `data-agent-native-prop-*` attributes on a
|
|
123
158
|
* code-layer node.
|
|
@@ -47,6 +47,7 @@ export interface CompileResult {
|
|
|
47
47
|
*/
|
|
48
48
|
export function compile(timeline: MotionTimeline): CompileResult {
|
|
49
49
|
const { tracks, durationMs, defaultEase } = timeline;
|
|
50
|
+
assertSafeMotionCssToken(defaultEase, "defaultEase");
|
|
50
51
|
|
|
51
52
|
if (!tracks || tracks.length === 0) {
|
|
52
53
|
const css = reducedMotionBlock([]);
|
|
@@ -55,7 +56,15 @@ export function compile(timeline: MotionTimeline): CompileResult {
|
|
|
55
56
|
|
|
56
57
|
const animNames: string[] = [];
|
|
57
58
|
const kfBlocks: string[] = [];
|
|
58
|
-
const
|
|
59
|
+
const rulesByTarget = new Map<
|
|
60
|
+
string,
|
|
61
|
+
{
|
|
62
|
+
names: string[];
|
|
63
|
+
durations: string[];
|
|
64
|
+
timings: string[];
|
|
65
|
+
fillModes: string[];
|
|
66
|
+
}
|
|
67
|
+
>();
|
|
59
68
|
|
|
60
69
|
// Sort tracks for determinism: targetNodeId ASC, property ASC.
|
|
61
70
|
const sorted = [...tracks].sort((a, b) => {
|
|
@@ -66,6 +75,7 @@ export function compile(timeline: MotionTimeline): CompileResult {
|
|
|
66
75
|
for (const track of sorted) {
|
|
67
76
|
const { targetNodeId, property, keyframes } = track;
|
|
68
77
|
if (!keyframes || keyframes.length === 0) continue;
|
|
78
|
+
assertSafeMotionCssProperty(property, "track.property");
|
|
69
79
|
|
|
70
80
|
const name = animationName(targetNodeId, property);
|
|
71
81
|
animNames.push(name);
|
|
@@ -73,15 +83,31 @@ export function compile(timeline: MotionTimeline): CompileResult {
|
|
|
73
83
|
|
|
74
84
|
const dur = formatDuration(durationMs);
|
|
75
85
|
const ease = keyframes[0]?.ease ?? defaultEase;
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
86
|
+
assertSafeMotionCssToken(ease, "track ease");
|
|
87
|
+
const targetRule = rulesByTarget.get(targetNodeId) ?? {
|
|
88
|
+
names: [],
|
|
89
|
+
durations: [],
|
|
90
|
+
timings: [],
|
|
91
|
+
fillModes: [],
|
|
92
|
+
};
|
|
93
|
+
targetRule.names.push(name);
|
|
94
|
+
targetRule.durations.push(dur);
|
|
95
|
+
targetRule.timings.push(ease);
|
|
96
|
+
targetRule.fillModes.push("both");
|
|
97
|
+
rulesByTarget.set(targetNodeId, targetRule);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const ruleBlocks = [...rulesByTarget.entries()]
|
|
101
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
102
|
+
.map(
|
|
103
|
+
([targetNodeId, rule]) =>
|
|
104
|
+
`[data-agent-native-node-id="${escAttr(targetNodeId)}"] {\n` +
|
|
105
|
+
` animation-name: ${rule.names.join(", ")};\n` +
|
|
106
|
+
` animation-duration: ${rule.durations.join(", ")};\n` +
|
|
107
|
+
` animation-timing-function: ${rule.timings.join(", ")};\n` +
|
|
108
|
+
` animation-fill-mode: ${rule.fillModes.join(", ")};\n` +
|
|
82
109
|
`}`,
|
|
83
110
|
);
|
|
84
|
-
}
|
|
85
111
|
|
|
86
112
|
const css = [...kfBlocks, ...ruleBlocks, reducedMotionBlock(animNames)].join(
|
|
87
113
|
"\n\n",
|
|
@@ -129,8 +155,51 @@ export function hashCss(css: string): string {
|
|
|
129
155
|
return djb2(css);
|
|
130
156
|
}
|
|
131
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Reject caller-supplied CSS declaration values before interpolation into the
|
|
160
|
+
* managed motion stylesheet. Motion values still allow useful CSS functions
|
|
161
|
+
* such as `translateY(...)`, `calc(...)`, `cubic-bezier(...)`, and `var(...)`,
|
|
162
|
+
* but block declaration/rule/style breakouts and remote-resource hooks.
|
|
163
|
+
*/
|
|
164
|
+
export function assertSafeMotionCssToken(value: string, field: string): string {
|
|
165
|
+
if (typeof value !== "string") {
|
|
166
|
+
throw new Error(`Invalid ${field}: expected a CSS string value.`);
|
|
167
|
+
}
|
|
168
|
+
if (value.trim().length === 0) {
|
|
169
|
+
throw new Error(`Invalid ${field}: motion CSS values cannot be empty.`);
|
|
170
|
+
}
|
|
171
|
+
if (CSS_TOKEN_CONTROL_RE.test(value) || CSS_TOKEN_BREAKOUT_RE.test(value)) {
|
|
172
|
+
throw new Error(
|
|
173
|
+
`Invalid ${field}: semicolons, braces, comments, angle brackets, control characters, and url(...) are not allowed in motion CSS values.`,
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
return value;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Validate that a CSS property name is a safe CSS identifier.
|
|
181
|
+
*
|
|
182
|
+
* Accepts standard and vendor-prefixed property names (e.g. "opacity",
|
|
183
|
+
* "transform", "-webkit-transform") and nothing else.
|
|
184
|
+
*/
|
|
185
|
+
export function assertSafeMotionCssProperty(
|
|
186
|
+
property: string,
|
|
187
|
+
field: string,
|
|
188
|
+
): string {
|
|
189
|
+
if (!/^-?[a-zA-Z][a-zA-Z0-9-]*$/.test(property)) {
|
|
190
|
+
throw new Error(
|
|
191
|
+
`Invalid ${field}: "${property}" is not a valid CSS property identifier. ` +
|
|
192
|
+
"Only ASCII letters, digits, hyphens, and an optional leading hyphen are allowed.",
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
return property;
|
|
196
|
+
}
|
|
197
|
+
|
|
132
198
|
// ─── Internal helpers ─────────────────────────────────────────────────────────
|
|
133
199
|
|
|
200
|
+
const CSS_TOKEN_BREAKOUT_RE = /[;{}<>]|\/\*|\*\/|\burl\s*\(/i;
|
|
201
|
+
const CSS_TOKEN_CONTROL_RE = /[\u0000-\u001f\u007f]/;
|
|
202
|
+
|
|
134
203
|
/**
|
|
135
204
|
* Build a deterministic CSS animation name from a node id and CSS property.
|
|
136
205
|
* Non-ident characters are replaced with `_`.
|
|
@@ -169,6 +238,8 @@ function keyframesBlock(
|
|
|
169
238
|
const stops = sorted.map((kf) => {
|
|
170
239
|
const pct = formatPercent(kf.t);
|
|
171
240
|
const ease = kf.ease ?? defaultEase;
|
|
241
|
+
assertSafeMotionCssToken(kf.value, "keyframe value");
|
|
242
|
+
assertSafeMotionCssToken(ease, "keyframe ease");
|
|
172
243
|
return (
|
|
173
244
|
` ${pct} {\n` +
|
|
174
245
|
` ${property}: ${kf.value};\n` +
|
|
@@ -30,7 +30,12 @@ export type TweakSelections = Record<string, string | number | boolean>;
|
|
|
30
30
|
*
|
|
31
31
|
* Tweaks without a `cssVar` are skipped (they don't map to a property).
|
|
32
32
|
* A missing selection falls back to the tweak's `defaultValue`.
|
|
33
|
+
* Selection keys that are themselves safe CSS custom properties are also
|
|
34
|
+
* emitted directly, which lets token edits persist vars that were not part of
|
|
35
|
+
* the generated tweak definition list.
|
|
33
36
|
*/
|
|
37
|
+
const CSS_CUSTOM_PROPERTY_NAME = /^--[-_a-zA-Z0-9]+$/;
|
|
38
|
+
|
|
34
39
|
export function resolveTweaksToCssVars(
|
|
35
40
|
tweaks: TweakDefinition[],
|
|
36
41
|
selections: TweakSelections,
|
|
@@ -39,19 +44,37 @@ export function resolveTweaksToCssVars(
|
|
|
39
44
|
for (const t of tweaks) {
|
|
40
45
|
if (!t.cssVar) continue;
|
|
41
46
|
const v = selections[t.id] ?? t.defaultValue;
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
} else {
|
|
49
|
-
out[t.cssVar] = String(v);
|
|
50
|
-
}
|
|
47
|
+
out[t.cssVar] = stringifyCssVarValue(t.cssVar, v, t.unit);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
for (const [key, value] of Object.entries(selections)) {
|
|
51
|
+
if (!isDirectCssVarSelectionKey(key)) continue;
|
|
52
|
+
out[key] = stringifyCssVarValue(key, value);
|
|
51
53
|
}
|
|
54
|
+
|
|
52
55
|
return out;
|
|
53
56
|
}
|
|
54
57
|
|
|
58
|
+
export function isDirectCssVarSelectionKey(key: string): boolean {
|
|
59
|
+
return CSS_CUSTOM_PROPERTY_NAME.test(key);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function stringifyCssVarValue(
|
|
63
|
+
cssVar: string,
|
|
64
|
+
value: string | number | boolean,
|
|
65
|
+
unit?: string,
|
|
66
|
+
): string {
|
|
67
|
+
if (typeof value === "boolean") {
|
|
68
|
+
return value ? "1" : "0";
|
|
69
|
+
}
|
|
70
|
+
if (typeof value === "number") {
|
|
71
|
+
const resolvedUnit =
|
|
72
|
+
unit ?? (cssVar.toLowerCase().includes("radius") ? "px" : "");
|
|
73
|
+
return `${value}${resolvedUnit}`;
|
|
74
|
+
}
|
|
75
|
+
return String(value);
|
|
76
|
+
}
|
|
77
|
+
|
|
55
78
|
/**
|
|
56
79
|
* Render resolved CSS vars as a `:root { ... }` block. Used by the
|
|
57
80
|
* coding-handoff bundle so external agents inherit the user's tuned tokens
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"production-agent.d.ts","sourceRoot":"","sources":["../../src/agent/production-agent.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"production-agent.d.ts","sourceRoot":"","sources":["../../src/agent/production-agent.ts"],"names":[],"mappings":"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"}
|
|
@@ -1516,6 +1516,53 @@ function stableStringify(value) {
|
|
|
1516
1516
|
function toolCallCacheKey(toolName, input) {
|
|
1517
1517
|
return `${toolName}:${stableStringify(normalizeToolCallInputForHistory(input))}`;
|
|
1518
1518
|
}
|
|
1519
|
+
const INTERRUPTED_TOOL_LEDGER_POLL_MS = process.env.NODE_ENV === "test" ? 0 : 2_000;
|
|
1520
|
+
async function waitForInterruptedToolLedgerEntry(opts) {
|
|
1521
|
+
const pollMs = INTERRUPTED_TOOL_LEDGER_POLL_MS;
|
|
1522
|
+
// Wait up to the tool's OWN declared timeout — the abandoned zombie can keep
|
|
1523
|
+
// running that long (e.g. a 12-minute image generation, whose provider keeps
|
|
1524
|
+
// generating after the run aborts), and giving up early re-runs the same
|
|
1525
|
+
// write tool while the original is still in flight, duplicating work and
|
|
1526
|
+
// double-charging. A flat sub-tool-timeout cap (previously 5 min) silently
|
|
1527
|
+
// truncated long tools. The run's AbortSignal still bounds this to the run's
|
|
1528
|
+
// remaining budget: when the run is cut off, the poll returns null and the
|
|
1529
|
+
// re-dispatch hits the already-aborted signal instead of launching a real
|
|
1530
|
+
// second call, so the wait never outlives the run.
|
|
1531
|
+
const maxWaitMs = process.env.NODE_ENV === "test" ? 1 : Math.max(0, opts.timeoutMs);
|
|
1532
|
+
const maxPolls = process.env.NODE_ENV === "test"
|
|
1533
|
+
? 3
|
|
1534
|
+
: Math.max(1, Math.ceil(maxWaitMs / Math.max(1, pollMs)) + 1);
|
|
1535
|
+
for (let attempt = 0; attempt < maxPolls; attempt++) {
|
|
1536
|
+
if (opts.signal.aborted)
|
|
1537
|
+
return null;
|
|
1538
|
+
const ledgerResult = await readLedgerEntry(opts.threadId, opts.toolKey);
|
|
1539
|
+
if (ledgerResult !== null)
|
|
1540
|
+
return ledgerResult;
|
|
1541
|
+
if (attempt >= maxPolls - 1)
|
|
1542
|
+
break;
|
|
1543
|
+
opts.send({
|
|
1544
|
+
type: "activity",
|
|
1545
|
+
tool: opts.toolName,
|
|
1546
|
+
label: `Waiting for previous ${opts.toolName} result.`,
|
|
1547
|
+
});
|
|
1548
|
+
if (pollMs <= 0)
|
|
1549
|
+
continue;
|
|
1550
|
+
await new Promise((resolve) => {
|
|
1551
|
+
let settled = false;
|
|
1552
|
+
const done = () => {
|
|
1553
|
+
if (settled)
|
|
1554
|
+
return;
|
|
1555
|
+
settled = true;
|
|
1556
|
+
clearTimeout(timer);
|
|
1557
|
+
opts.signal.removeEventListener("abort", done);
|
|
1558
|
+
resolve();
|
|
1559
|
+
};
|
|
1560
|
+
const timer = setTimeout(done, pollMs);
|
|
1561
|
+
opts.signal.addEventListener("abort", done, { once: true });
|
|
1562
|
+
});
|
|
1563
|
+
}
|
|
1564
|
+
return null;
|
|
1565
|
+
}
|
|
1519
1566
|
function normalizeToolErrorForBreaker(error) {
|
|
1520
1567
|
return error.replace(/\s+/g, " ").trim();
|
|
1521
1568
|
}
|
|
@@ -2376,6 +2423,14 @@ export async function runAgentLoop(opts) {
|
|
|
2376
2423
|
content: result,
|
|
2377
2424
|
};
|
|
2378
2425
|
}
|
|
2426
|
+
const DEFAULT_TOOL_RESULT_CHARS = 50_000;
|
|
2427
|
+
const DEFAULT_TOOL_TIMEOUT_MS = 60_000;
|
|
2428
|
+
const toolTimeoutMs = actionEntry.timeoutMs ??
|
|
2429
|
+
opts.toolLimits?.timeoutMs ??
|
|
2430
|
+
DEFAULT_TOOL_TIMEOUT_MS;
|
|
2431
|
+
const toolMaxResultChars = actionEntry.maxResultChars ??
|
|
2432
|
+
opts.toolLimits?.maxResultChars ??
|
|
2433
|
+
DEFAULT_TOOL_RESULT_CHARS;
|
|
2379
2434
|
// TOOL-CALL JOURNAL HARD-BLOCK (resume safety, tool-layer enforcement).
|
|
2380
2435
|
// The prompt-level resume journal already TELLS a resuming model not to
|
|
2381
2436
|
// re-run completed tool calls; this enforces it at the tool layer so a
|
|
@@ -2419,12 +2474,21 @@ export async function runAgentLoop(opts) {
|
|
|
2419
2474
|
// previous invocation's zombie actually completed and wrote its result to
|
|
2420
2475
|
// the durable ledger. If so, return the ledger result without re-executing
|
|
2421
2476
|
// (prevents the duplicate side effect) and skip counting it toward the
|
|
2422
|
-
// interruption budget.
|
|
2477
|
+
// interruption budget. A just-abandoned long tool may need a short grace
|
|
2478
|
+
// period before its detached promise writes the ledger, so wait while the
|
|
2479
|
+
// current run still has budget instead of immediately re-running it.
|
|
2423
2480
|
if (!actionEntry.readOnly) {
|
|
2424
2481
|
const writeCacheKey = toolCallCacheKey(toolCall.name, toolCall.input);
|
|
2425
2482
|
const priorInterruptions = writeToolInterruptions.get(writeCacheKey) ?? 0;
|
|
2426
2483
|
if (priorInterruptions > 0 && opts.threadId) {
|
|
2427
|
-
const ledgerResult = await
|
|
2484
|
+
const ledgerResult = await waitForInterruptedToolLedgerEntry({
|
|
2485
|
+
threadId: opts.threadId,
|
|
2486
|
+
toolKey: writeCacheKey,
|
|
2487
|
+
toolName: toolCall.name,
|
|
2488
|
+
timeoutMs: toolTimeoutMs,
|
|
2489
|
+
signal,
|
|
2490
|
+
send,
|
|
2491
|
+
});
|
|
2428
2492
|
if (ledgerResult !== null) {
|
|
2429
2493
|
// Zombie completed — recover the real result without re-executing.
|
|
2430
2494
|
const result = `(Recovered from prior interrupted chunk — action already completed.)\n\n` +
|
|
@@ -2477,6 +2541,24 @@ export async function runAgentLoop(opts) {
|
|
|
2477
2541
|
};
|
|
2478
2542
|
}
|
|
2479
2543
|
}
|
|
2544
|
+
// Stop BEFORE emitting tool_start if the run was already aborted —
|
|
2545
|
+
// typically because the ledger wait above polled for minutes and the soft
|
|
2546
|
+
// timeout fired meanwhile. Emitting tool_start/tool_done here would leave a
|
|
2547
|
+
// bogus interrupted pair in the transcript for a tool that never re-ran,
|
|
2548
|
+
// and re-invoking would spawn a duplicate zombie. Return the interrupted
|
|
2549
|
+
// marker (no events) so the next continuation recovers via the ledger.
|
|
2550
|
+
// (A second guard inside the try below still covers an abort that lands in
|
|
2551
|
+
// the tiny sync window between here and the action invocation.)
|
|
2552
|
+
if (signal.aborted) {
|
|
2553
|
+
recordToolResult(INTERRUPTED_TOOL_RESULT_MARKER, false);
|
|
2554
|
+
return {
|
|
2555
|
+
type: "tool-result",
|
|
2556
|
+
toolCallId: toolCall.id,
|
|
2557
|
+
toolName: toolCall.name,
|
|
2558
|
+
toolInput: wireToolInput,
|
|
2559
|
+
content: INTERRUPTED_TOOL_RESULT_MARKER,
|
|
2560
|
+
};
|
|
2561
|
+
}
|
|
2480
2562
|
send({
|
|
2481
2563
|
type: "tool_start",
|
|
2482
2564
|
tool: toolCall.name,
|
|
@@ -2524,18 +2606,20 @@ export async function runAgentLoop(opts) {
|
|
|
2524
2606
|
isError: true,
|
|
2525
2607
|
};
|
|
2526
2608
|
}
|
|
2527
|
-
const DEFAULT_TOOL_RESULT_CHARS = 50_000;
|
|
2528
|
-
const DEFAULT_TOOL_TIMEOUT_MS = 60_000;
|
|
2529
|
-
const toolTimeoutMs = actionEntry.timeoutMs ??
|
|
2530
|
-
opts.toolLimits?.timeoutMs ??
|
|
2531
|
-
DEFAULT_TOOL_TIMEOUT_MS;
|
|
2532
|
-
const toolMaxResultChars = actionEntry.maxResultChars ??
|
|
2533
|
-
opts.toolLimits?.maxResultChars ??
|
|
2534
|
-
DEFAULT_TOOL_RESULT_CHARS;
|
|
2535
2609
|
let result;
|
|
2536
2610
|
let isError = false;
|
|
2537
2611
|
let mcpApp;
|
|
2538
2612
|
try {
|
|
2613
|
+
// The run may have been aborted while we waited above for an
|
|
2614
|
+
// interrupted tool's ledger result (the wait can poll for minutes).
|
|
2615
|
+
// Re-check before invoking the action: starting it now would spawn a
|
|
2616
|
+
// fresh zombie execution — a duplicate side effect / double charge —
|
|
2617
|
+
// which the ledger-recovery path exists to prevent. The Promise.race
|
|
2618
|
+
// "Run aborted" leg below only rejects AFTER the action is invoked, so
|
|
2619
|
+
// it cannot guard this. Throw here instead, handled like any abort.
|
|
2620
|
+
if (signal.aborted) {
|
|
2621
|
+
throw new Error("Run aborted");
|
|
2622
|
+
}
|
|
2539
2623
|
const timeoutSignal = AbortSignal.timeout(toolTimeoutMs);
|
|
2540
2624
|
const actionUserEmail = opts.ownerEmail ?? getRequestUserEmail();
|
|
2541
2625
|
const actionOrgId = opts.orgId ?? getRequestOrgId() ?? null;
|