@ggui-ai/ui-gen 0.27.0 → 0.29.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/{adapter-h4_V69LI.d.ts → adapter-DLQ-5COm.d.ts} +1 -1
- package/dist/adapters/base.js +2 -27
- package/dist/adapters/base.js.map +1 -1
- package/dist/adapters/generation-dispatch.d.ts +14 -6
- package/dist/adapters/generation-dispatch.js +40 -19095
- package/dist/adapters/generation-dispatch.js.map +1 -1
- package/dist/adapters/index.d.ts +1 -1
- package/dist/adapters/index.js +25 -3561
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/types.js +2 -9
- package/dist/adapters/types.js.map +1 -1
- package/dist/advanced/index.d.ts +13 -12
- package/dist/advanced/index.js +63 -21789
- package/dist/advanced/index.js.map +1 -1
- package/dist/{bank-Ctdp3FUA.d.ts → bank-LWaiAtaA.d.ts} +1 -1
- package/dist/blueprint-validator.js +6 -2301
- package/dist/blueprint-validator.js.map +1 -1
- package/dist/boilerplate.d.ts +3 -2
- package/dist/boilerplate.js +6 -1867
- package/dist/boilerplate.js.map +1 -1
- package/dist/check/index.d.ts +3 -2
- package/dist/check/index.js +6 -1923
- package/dist/check/index.js.map +1 -1
- package/dist/chunk-33B3BAWS.js +24 -0
- package/dist/chunk-33B3BAWS.js.map +1 -0
- package/dist/chunk-3HSGA6NI.js +591 -0
- package/dist/chunk-3HSGA6NI.js.map +1 -0
- package/dist/chunk-3NNNGNTO.js +1707 -0
- package/dist/chunk-3NNNGNTO.js.map +1 -0
- package/dist/chunk-3T2HMTON.js +79 -0
- package/dist/chunk-3T2HMTON.js.map +1 -0
- package/dist/chunk-3ZSSDV3L.js +123 -0
- package/dist/chunk-3ZSSDV3L.js.map +1 -0
- package/dist/chunk-4MBR5GA3.js +99 -0
- package/dist/chunk-4MBR5GA3.js.map +1 -0
- package/dist/chunk-56NJFD55.js +337 -0
- package/dist/chunk-56NJFD55.js.map +1 -0
- package/dist/chunk-5AGTY555.js +26 -0
- package/dist/chunk-5AGTY555.js.map +1 -0
- package/dist/chunk-5EJM7EGY.js +115 -0
- package/dist/chunk-5EJM7EGY.js.map +1 -0
- package/dist/chunk-5KXCQLLR.js +529 -0
- package/dist/chunk-5KXCQLLR.js.map +1 -0
- package/dist/chunk-5VBXHVEH.js +171 -0
- package/dist/chunk-5VBXHVEH.js.map +1 -0
- package/dist/chunk-6KDDEING.js +515 -0
- package/dist/chunk-6KDDEING.js.map +1 -0
- package/dist/chunk-6VDRWAP6.js +123 -0
- package/dist/chunk-6VDRWAP6.js.map +1 -0
- package/dist/chunk-732IBFEJ.js +2400 -0
- package/dist/chunk-732IBFEJ.js.map +1 -0
- package/dist/chunk-73AURS3I.js +46 -0
- package/dist/chunk-73AURS3I.js.map +1 -0
- package/dist/chunk-77H5SKLX.js +8 -0
- package/dist/chunk-77H5SKLX.js.map +1 -0
- package/dist/chunk-7QE3AHLE.js +35 -0
- package/dist/chunk-7QE3AHLE.js.map +1 -0
- package/dist/chunk-A375NNWN.js +11 -0
- package/dist/chunk-A375NNWN.js.map +1 -0
- package/dist/chunk-AOU33EFS.js +140 -0
- package/dist/chunk-AOU33EFS.js.map +1 -0
- package/dist/chunk-BA4QYA6E.js +461 -0
- package/dist/chunk-BA4QYA6E.js.map +1 -0
- package/dist/chunk-DBP764GL.js +3 -0
- package/dist/chunk-DBP764GL.js.map +1 -0
- package/dist/chunk-DUU3ZJDQ.js +41 -0
- package/dist/chunk-DUU3ZJDQ.js.map +1 -0
- package/dist/chunk-DXKRBXNU.js +30 -0
- package/dist/chunk-DXKRBXNU.js.map +1 -0
- package/dist/chunk-FB7OEEAH.js +1467 -0
- package/dist/chunk-FB7OEEAH.js.map +1 -0
- package/dist/chunk-FLRNMZV2.js +18 -0
- package/dist/chunk-FLRNMZV2.js.map +1 -0
- package/dist/chunk-FWJIMKFZ.js +2032 -0
- package/dist/chunk-FWJIMKFZ.js.map +1 -0
- package/dist/chunk-FXRHWYIQ.js +163 -0
- package/dist/chunk-FXRHWYIQ.js.map +1 -0
- package/dist/chunk-G3PMV62Z.js +33 -0
- package/dist/chunk-G3PMV62Z.js.map +1 -0
- package/dist/chunk-GAJI7Y3P.js +13 -0
- package/dist/chunk-GAJI7Y3P.js.map +1 -0
- package/dist/chunk-GYINWMPR.js +2052 -0
- package/dist/chunk-GYINWMPR.js.map +1 -0
- package/dist/chunk-HD6ABIK7.js +484 -0
- package/dist/chunk-HD6ABIK7.js.map +1 -0
- package/dist/chunk-HDQVHYO6.js +100 -0
- package/dist/chunk-HDQVHYO6.js.map +1 -0
- package/dist/chunk-IHUT3SIW.js +7 -0
- package/dist/chunk-IHUT3SIW.js.map +1 -0
- package/dist/chunk-JDH5EGNZ.js +126 -0
- package/dist/chunk-JDH5EGNZ.js.map +1 -0
- package/dist/chunk-JMD4RGSV.js +37 -0
- package/dist/chunk-JMD4RGSV.js.map +1 -0
- package/dist/chunk-KJWGZL5B.js +33 -0
- package/dist/chunk-KJWGZL5B.js.map +1 -0
- package/dist/chunk-MKMDQFZ7.js +86 -0
- package/dist/chunk-MKMDQFZ7.js.map +1 -0
- package/dist/chunk-NF6JUZWF.js +85 -0
- package/dist/chunk-NF6JUZWF.js.map +1 -0
- package/dist/chunk-O2YC6XDC.js +1933 -0
- package/dist/chunk-O2YC6XDC.js.map +1 -0
- package/dist/chunk-OVLH5ICV.js +29 -0
- package/dist/chunk-OVLH5ICV.js.map +1 -0
- package/dist/chunk-PBOYHGSD.js +106 -0
- package/dist/chunk-PBOYHGSD.js.map +1 -0
- package/dist/chunk-PJFH7QWA.js +81 -0
- package/dist/chunk-PJFH7QWA.js.map +1 -0
- package/dist/chunk-PUH4CXGZ.js +284 -0
- package/dist/chunk-PUH4CXGZ.js.map +1 -0
- package/dist/chunk-QLXXPGTV.js +18 -0
- package/dist/chunk-QLXXPGTV.js.map +1 -0
- package/dist/chunk-R5GIGPW2.js +2845 -0
- package/dist/chunk-R5GIGPW2.js.map +1 -0
- package/dist/chunk-RH4IUSTO.js +83 -0
- package/dist/chunk-RH4IUSTO.js.map +1 -0
- package/dist/chunk-S2GVXKKY.js +153 -0
- package/dist/chunk-S2GVXKKY.js.map +1 -0
- package/dist/chunk-TVHGKFJS.js +58 -0
- package/dist/chunk-TVHGKFJS.js.map +1 -0
- package/dist/chunk-U7GALWLG.js +66 -0
- package/dist/chunk-U7GALWLG.js.map +1 -0
- package/dist/chunk-VTC263LT.js +256 -0
- package/dist/chunk-VTC263LT.js.map +1 -0
- package/dist/chunk-WEOXFEVE.js +739 -0
- package/dist/chunk-WEOXFEVE.js.map +1 -0
- package/dist/chunk-WYHP46LT.js +28 -0
- package/dist/chunk-WYHP46LT.js.map +1 -0
- package/dist/chunk-XGLO5LGG.js +274 -0
- package/dist/chunk-XGLO5LGG.js.map +1 -0
- package/dist/chunk-XRBCRKA2.js +29 -0
- package/dist/chunk-XRBCRKA2.js.map +1 -0
- package/dist/chunk-XW7ADFFV.js +340 -0
- package/dist/chunk-XW7ADFFV.js.map +1 -0
- package/dist/chunk-YIQ42IUX.js +34 -0
- package/dist/chunk-YIQ42IUX.js.map +1 -0
- package/dist/chunk-YJZTUY7B.js +101 -0
- package/dist/chunk-YJZTUY7B.js.map +1 -0
- package/dist/chunk-Z3CXME3K.js +107 -0
- package/dist/chunk-Z3CXME3K.js.map +1 -0
- package/dist/classifier/index.js +2 -527
- package/dist/classifier/index.js.map +1 -1
- package/dist/client-JBPCXU7W.js +4 -0
- package/dist/client-JBPCXU7W.js.map +1 -0
- package/dist/compose.js +3 -367
- package/dist/compose.js.map +1 -1
- package/dist/cost-tracker-HHGQ4FTW.js +67 -0
- package/dist/cost-tracker-HHGQ4FTW.js.map +1 -0
- package/dist/{create-ui-generator-BrZHF0cf.d.ts → create-ui-generator-BY-WeaPi.d.ts} +3 -3
- package/dist/{design-mode-DGWN_Gkm.d.ts → design-mode-XyOQmzE0.d.ts} +4 -3
- package/dist/{dispatch-B07TI30d.d.ts → dispatch-8LzTddKw.d.ts} +3 -2
- package/dist/dist-UALN6ZVB.js +543 -0
- package/dist/dist-UALN6ZVB.js.map +1 -0
- package/dist/dupe-break-X6K7QFIS.js +4 -0
- package/dist/dupe-break-X6K7QFIS.js.map +1 -0
- package/dist/evaluation/axis-checks/index.d.ts +5 -4
- package/dist/evaluation/axis-checks/index.js +6 -1818
- package/dist/evaluation/axis-checks/index.js.map +1 -1
- package/dist/evaluation/axis-checks/registry.d.ts +3 -2
- package/dist/evaluation/axis-checks/registry.js +3 -1748
- package/dist/evaluation/axis-checks/registry.js.map +1 -1
- package/dist/evaluation/index.d.ts +49 -132
- package/dist/evaluation/index.js +302 -6368
- package/dist/evaluation/index.js.map +1 -1
- package/dist/evaluation/types.d.ts +3 -2
- package/dist/evaluation/types.js +2 -5
- package/dist/evaluation/types.js.map +1 -1
- package/dist/fragments/index.js +2 -338
- package/dist/fragments/index.js.map +1 -1
- package/dist/{generate-tSO_shQ0.d.ts → generate-DQ4ci90s.d.ts} +1 -1
- package/dist/harness/check/runtime-render/index.d.ts +35 -15
- package/dist/harness/check/runtime-render/index.js +6 -2390
- package/dist/harness/check/runtime-render/index.js.map +1 -1
- package/dist/harness/check/runtime-render/render-check-worker.js +4 -1739
- package/dist/harness/check/runtime-render/render-check-worker.js.map +1 -1
- package/dist/harness/index.d.ts +3 -2
- package/dist/harness/index.js +23 -5124
- package/dist/harness/index.js.map +1 -1
- package/dist/harness/llm-trace-sink.js +2 -24
- package/dist/harness/llm-trace-sink.js.map +1 -1
- package/dist/harness/prompts.d.ts +2 -2
- package/dist/harness/prompts.js +8 -324
- package/dist/harness/prompts.js.map +1 -1
- package/dist/harness/result-types.d.ts +18 -6
- package/dist/harness/result-types.js +2 -0
- package/dist/harness/result-types.js.map +1 -1
- package/dist/harness/runtime.d.ts +22 -5
- package/dist/harness/runtime.js +10 -2313
- package/dist/harness/runtime.js.map +1 -1
- package/dist/harness/types-public.d.ts +3 -2
- package/dist/harness/types-public.js +16 -2954
- package/dist/harness/types-public.js.map +1 -1
- package/dist/harness/validator-trace-sink.d.ts +3 -2
- package/dist/harness/validator-trace-sink.js +2 -26
- package/dist/harness/validator-trace-sink.js.map +1 -1
- package/dist/hash.js +2 -39
- package/dist/hash.js.map +1 -1
- package/dist/hashline-5OKREIRM.js +4 -0
- package/dist/hashline-5OKREIRM.js.map +1 -0
- package/dist/index.d.ts +51 -12
- package/dist/index.js +57 -21850
- package/dist/index.js.map +1 -1
- package/dist/llm-evaluator-PN3WFCS4.js +653 -0
- package/dist/llm-evaluator-PN3WFCS4.js.map +1 -0
- package/dist/magic-string.es-2NZTC4GZ.js +1307 -0
- package/dist/magic-string.es-2NZTC4GZ.js.map +1 -0
- package/dist/patch.d.ts +3 -2
- package/dist/patch.js +2 -56
- package/dist/patch.js.map +1 -1
- package/dist/policy-VCYKGSAC.js +5 -0
- package/dist/policy-VCYKGSAC.js.map +1 -0
- package/dist/policy.js +2 -35
- package/dist/policy.js.map +1 -1
- package/dist/primitive-index-2OF6F4TZ.js +131 -0
- package/dist/primitive-index-2OF6F4TZ.js.map +1 -0
- package/dist/primitive-slice-WTMBLYFJ.js +235 -0
- package/dist/primitive-slice-WTMBLYFJ.js.map +1 -0
- package/dist/{prompts-BhNUuRoZ.d.ts → prompts-CLZGywMP.d.ts} +1 -1
- package/dist/provider-adapter-contract.js +10407 -14204
- package/dist/provider-adapter-contract.js.map +1 -1
- package/dist/provider-adapter.js +2 -44
- package/dist/provider-adapter.js.map +1 -1
- package/dist/providers/index.d.ts +89 -1
- package/dist/providers/index.js +115 -44
- package/dist/providers/index.js.map +1 -1
- package/dist/raw-C6KBH5I3.js +141 -0
- package/dist/raw-C6KBH5I3.js.map +1 -0
- package/dist/raw-FXSBXQTZ.js +7 -0
- package/dist/raw-FXSBXQTZ.js.map +1 -0
- package/dist/raw-MURDUPGK.js +8 -0
- package/dist/raw-MURDUPGK.js.map +1 -0
- package/dist/raw-T3GW3UVX.js +8 -0
- package/dist/raw-T3GW3UVX.js.map +1 -0
- package/dist/render-check-host-ZNIS6BJ5.js +5 -0
- package/dist/render-check-host-ZNIS6BJ5.js.map +1 -0
- package/dist/sdk-4JNSDNSR.js +6 -0
- package/dist/sdk-4JNSDNSR.js.map +1 -0
- package/dist/sdk-DIVJMHCX.js +7 -0
- package/dist/sdk-DIVJMHCX.js.map +1 -0
- package/dist/sdk-QRJOCRTS.js +7 -0
- package/dist/sdk-QRJOCRTS.js.map +1 -0
- package/dist/tag-balance-CTHCTRJ7.js +123 -0
- package/dist/tag-balance-CTHCTRJ7.js.map +1 -0
- package/dist/tools/get-primitives-ts.d.ts +1 -1
- package/dist/tools/get-primitives-ts.js +3 -1
- package/dist/tools/get-primitives-ts.js.map +1 -1
- package/dist/tools/render-check-worker.js +3 -40
- package/dist/tools/render-check-worker.js.map +1 -1
- package/dist/{types-public-h8IMnYuh.d.ts → types-public-hYlrerZh.d.ts} +35 -2
- package/dist/validation/index.d.ts +2 -2
- package/dist/validation/index.js +3 -498
- package/dist/validation/index.js.map +1 -1
- package/dist/{visual-evaluator-C2strxqD.d.ts → visual-evaluator-KskajxD5.d.ts} +14 -4
- package/dist/visual-evaluator-TGEXYQTP.js +12 -0
- package/dist/visual-evaluator-TGEXYQTP.js.map +1 -0
- package/dist/workflows.d.ts +3 -2
- package/dist/workflows.js +2 -151
- package/dist/workflows.js.map +1 -1
- package/package.json +21 -17
- package/src/adapters/claude/sdk.ts +4 -2
- package/src/adapters/claude/tool-bridge.ts +2 -1
- package/src/adapters/generation-dispatch.ts +9 -0
- package/src/adapters/openai/raw.ts +4 -0
- package/src/adapters/openai/sdk.ts +6 -1
- package/src/adapters/openai/tokens.ts +21 -7
- package/src/adapters/provider-router.ts +1 -0
- package/src/adapters/tool-bridge.ts +1 -1
- package/src/adapters/tools.ts +1 -1
- package/src/advanced/feedback.ts +1 -2
- package/src/advanced/generator.ts +4 -3
- package/src/boilerplate/free-design-prompt.ts +7 -0
- package/src/boilerplate/generate.ts +18 -5
- package/src/boilerplate/hard-sections.ts +8 -3
- package/src/boilerplate/react-hooks.ts +56 -0
- package/src/boilerplate/system-prompt.ts +12 -3
- package/src/check/run-tier0.ts +233 -8
- package/src/check/type-checker.ts +128 -16
- package/src/coding-agent/tools.ts +26 -3
- package/src/create-ui-generator.ts +4 -2
- package/src/design-mode.ts +4 -9
- package/src/evaluation/axis-checks/checks/state-merge.ts +3 -5
- package/src/evaluation/axis-checks/checks/state-payload.ts +1 -28
- package/src/evaluation/axis-checks/checks/tint.ts +197 -0
- package/src/evaluation/axis-checks/helpers.ts +246 -0
- package/src/evaluation/axis-checks/registry.ts +2 -0
- package/src/evaluation/criteria/__fixtures__/edge-v2-draw2.json +4629 -0
- package/src/evaluation/criteria/bank.ts +1 -1
- package/src/evaluation/criteria/edge-instruments.ts +14 -0
- package/src/evaluation/criteria/edge-probe-v2.ts +352 -0
- package/src/evaluation/criteria/edge-v2.ts +242 -0
- package/src/evaluation/criteria/resolve.ts +24 -5
- package/src/evaluation/evaluator.ts +2 -2
- package/src/evaluation/index.ts +3 -5
- package/src/evaluation/llm-evaluator.ts +2 -2
- package/src/evaluation/mcp-server.ts +0 -50
- package/src/evaluation/types-public.ts +6 -1
- package/src/evaluation/visual-evaluator.ts +162 -31
- package/src/harness/check/runtime-render/index.ts +28 -4
- package/src/harness/check/runtime-render/render-check.ts +20 -21
- package/src/harness/claude-agent-sdk-loader.ts +93 -0
- package/src/harness/claude-code-login-query.ts +1 -1
- package/src/harness/coding/assemble-result.ts +1 -0
- package/src/harness/coding/dupe-break.ts +70 -0
- package/src/harness/coding/generate-task-runner.ts +6 -1
- package/src/harness/coding/run-coding-turn.ts +59 -1
- package/src/harness/coding/run-eval-round.ts +9 -0
- package/src/harness/llm-router.ts +50 -2
- package/src/harness/result-types.ts +12 -0
- package/src/harness/runtime.ts +17 -0
- package/src/index.ts +10 -1
- package/src/providers/anthropic-tool-call.ts +263 -0
- package/src/providers/index.ts +13 -0
- package/src/tools/get-primitives-ts.ts +1 -1
- package/src/tools/render-check.ts +4 -4
- package/src/validation/primitives.ts +2 -1
- package/src/evaluation/loop.ts +0 -218
|
@@ -21,6 +21,20 @@ import type { DataContract, JsonObject, PropsSpec } from "@ggui-ai/protocol";
|
|
|
21
21
|
import { HOOK_NAME_RE, listContractGadgets } from "@ggui-ai/protocol";
|
|
22
22
|
import { createProbe, createProbeWireConfig, type ActionFiredEvent, type Probe } from "./probe.js";
|
|
23
23
|
import { loadComponent } from "./load-component.js";
|
|
24
|
+
import { ASSET_SHIM_FOR_SPECIFIER } from "@ggui-ai/design/rendering";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* ggui#1934 — the design specifiers production's import rewrite serves, each paired with the module
|
|
28
|
+
* that backs it here. `templates` is backed by the barrel: the renderer's templates shim serves every
|
|
29
|
+
* layer (compositions, then primitives and components). `app-components` is the operator's own registry, never a design-package module, so it is not
|
|
30
|
+
* pre-resolved; a card importing it fails with the sandbox's "not available" reason.
|
|
31
|
+
*/
|
|
32
|
+
export function sandboxDesignModules(): ReadonlyArray<readonly [specifier: string, moduleId: string]> {
|
|
33
|
+
return Object.keys(ASSET_SHIM_FOR_SPECIFIER)
|
|
34
|
+
.filter((id) => id === "@ggui-ai/design" || id.startsWith("@ggui-ai/design/"))
|
|
35
|
+
.filter((id) => id !== "@ggui-ai/design/app-components")
|
|
36
|
+
.map((id) => [id, id === "@ggui-ai/design/templates" ? "@ggui-ai/design" : id] as const);
|
|
37
|
+
}
|
|
24
38
|
import { findWiring, type WiringDetection } from "./find-wiring.js";
|
|
25
39
|
import { installProductionActShim } from "./production-act-shim.js";
|
|
26
40
|
// All happy-dom / RTL / user-event narrowing flows through the typed
|
|
@@ -290,27 +304,12 @@ export async function runRenderCheckInProcess(
|
|
|
290
304
|
"@ggui-ai/wire": Wire,
|
|
291
305
|
};
|
|
292
306
|
|
|
293
|
-
// Pre-load
|
|
294
|
-
//
|
|
295
|
-
//
|
|
296
|
-
//
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
// Per-specifier failures are swallowed — the sandbox throws its own
|
|
300
|
-
// clear error if the component actually needs a missing one.
|
|
301
|
-
const designSpecifiers = [
|
|
302
|
-
"@ggui-ai/design",
|
|
303
|
-
"@ggui-ai/design/primitives",
|
|
304
|
-
"@ggui-ai/design/components",
|
|
305
|
-
"@ggui-ai/design/compositions",
|
|
306
|
-
"@ggui-ai/design/interact",
|
|
307
|
-
];
|
|
308
|
-
for (const id of designSpecifiers) {
|
|
309
|
-
try {
|
|
310
|
-
moduleResolutions[id] = await import(id);
|
|
311
|
-
} catch {
|
|
312
|
-
/* skip — sandbox will report a clear error if the component imports it */
|
|
313
|
-
}
|
|
307
|
+
// Pre-load every @ggui-ai/design specifier production serves (ggui#1934). The package is ESM-only
|
|
308
|
+
// with no `require` export condition, so `loadComponent`'s `createRequire` fallback can load none
|
|
309
|
+
// of them: a specifier missing here fails the probe while the served card renders. The list is
|
|
310
|
+
// the renderer's own map, so a subpath production starts serving is served here too.
|
|
311
|
+
for (const [id, moduleId] of sandboxDesignModules()) {
|
|
312
|
+
moduleResolutions[id] = await import(moduleId);
|
|
314
313
|
}
|
|
315
314
|
|
|
316
315
|
// Pre-load `@ggui-ai/gadgets` for components that declare
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one runtime load of `@anthropic-ai/claude-agent-sdk` (ggui#1951).
|
|
3
|
+
*
|
|
4
|
+
* The SDK is an OPTIONAL peer of this package, not a dependency. Its
|
|
5
|
+
* per-platform native binary is about 300 MB, and only the Claude Code
|
|
6
|
+
* login route (`routeOverride.claudeCodeLogin`, `ggui serve
|
|
7
|
+
* --local-cli-login`), the `sdk`-mode Claude adapter and the
|
|
8
|
+
* `./evaluation` loop run it. A plain install therefore does not carry
|
|
9
|
+
* it, and every one of those paths loads it through
|
|
10
|
+
* {@link loadClaudeAgentSdk}: a missing SDK fails with one
|
|
11
|
+
* {@link ClaudeAgentSdkMissingError} that names the install line for
|
|
12
|
+
* each way of installing ggui, and every other failure keeps its own
|
|
13
|
+
* shape.
|
|
14
|
+
*
|
|
15
|
+
* `preloadProviderSdks` (in `./llm-router.ts`) imports the SDK directly
|
|
16
|
+
* on purpose: it reports a missing SDK in its `missing` list and never
|
|
17
|
+
* throws.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/** The package specifier, as it is imported and installed. */
|
|
21
|
+
export const CLAUDE_AGENT_SDK_SPECIFIER = '@anthropic-ai/claude-agent-sdk';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The exact version this package's `peerDependencies` names. The install
|
|
25
|
+
* lines in {@link ClaudeAgentSdkMissingError} use it; a test pins it to
|
|
26
|
+
* `package.json`.
|
|
27
|
+
*/
|
|
28
|
+
export const CLAUDE_AGENT_SDK_VERSION = '0.3.229';
|
|
29
|
+
|
|
30
|
+
export type ClaudeAgentSdk = typeof import('@anthropic-ai/claude-agent-sdk');
|
|
31
|
+
|
|
32
|
+
/** The SDK is not installed where this package can import it. */
|
|
33
|
+
export class ClaudeAgentSdkMissingError extends Error {
|
|
34
|
+
constructor(cause: Error) {
|
|
35
|
+
const pin = `${CLAUDE_AGENT_SDK_SPECIFIER}@${CLAUDE_AGENT_SDK_VERSION}`;
|
|
36
|
+
super(
|
|
37
|
+
`${CLAUDE_AGENT_SDK_SPECIFIER} is not installed. It is an optional peer of @ggui-ai/ui-gen, ` +
|
|
38
|
+
`needed only to generate with the Claude Code login (and by the Agent SDK adapter and evaluation loop). ` +
|
|
39
|
+
`Install it beside ggui:\n` +
|
|
40
|
+
` npm install ${pin} (ggui installed in a project)\n` +
|
|
41
|
+
` npm install -g ${pin} (ggui installed with -g)\n` +
|
|
42
|
+
` npx -p @ggui-ai/cli -p ${pin} ggui serve --local-cli-login (ggui run with npx)`,
|
|
43
|
+
{ cause },
|
|
44
|
+
);
|
|
45
|
+
this.name = 'ClaudeAgentSdkMissingError';
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function isMissingSdk(err: unknown): err is Error {
|
|
50
|
+
if (!(err instanceof Error)) return false;
|
|
51
|
+
const code: unknown = Reflect.get(err, 'code');
|
|
52
|
+
if (code !== 'ERR_MODULE_NOT_FOUND' && code !== 'MODULE_NOT_FOUND') return false;
|
|
53
|
+
// A package the SDK itself imports can be missing too; that failure names
|
|
54
|
+
// its own package and is not this one.
|
|
55
|
+
return err.message.includes(`'${CLAUDE_AGENT_SDK_SPECIFIER}'`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function missingOrRethrow(err: unknown): never {
|
|
59
|
+
if (isMissingSdk(err)) throw new ClaudeAgentSdkMissingError(err);
|
|
60
|
+
throw err;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Import the Claude Agent SDK. A missing SDK rejects with
|
|
65
|
+
* {@link ClaudeAgentSdkMissingError}; any other failure rejects unchanged.
|
|
66
|
+
* `importer` is for tests. Package-internal: its return type names the
|
|
67
|
+
* SDK's types, which a consumer without the SDK cannot resolve.
|
|
68
|
+
*/
|
|
69
|
+
export async function loadClaudeAgentSdk(
|
|
70
|
+
importer: () => Promise<ClaudeAgentSdk> = () => import('@anthropic-ai/claude-agent-sdk'),
|
|
71
|
+
): Promise<ClaudeAgentSdk> {
|
|
72
|
+
try {
|
|
73
|
+
return await importer();
|
|
74
|
+
} catch (err) {
|
|
75
|
+
return missingOrRethrow(err);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Check that the Claude Agent SDK loads, with the same errors as
|
|
81
|
+
* {@link loadClaudeAgentSdk}, for a host that wants to say so at boot
|
|
82
|
+
* (`ggui serve --local-cli-login`). Its signature names none of the SDK's
|
|
83
|
+
* types, so the package's main entry can export it. `importer` is for tests.
|
|
84
|
+
*/
|
|
85
|
+
export async function ensureClaudeAgentSdk(
|
|
86
|
+
importer: () => Promise<unknown> = () => import('@anthropic-ai/claude-agent-sdk'),
|
|
87
|
+
): Promise<void> {
|
|
88
|
+
try {
|
|
89
|
+
await importer();
|
|
90
|
+
} catch (err) {
|
|
91
|
+
missingOrRethrow(err);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -39,7 +39,7 @@ import type {
|
|
|
39
39
|
} from "@anthropic-ai/claude-agent-sdk";
|
|
40
40
|
import type { MessageParam } from "@anthropic-ai/sdk/resources";
|
|
41
41
|
import { isRecord, type JsonObject, type JsonValue } from "@ggui-ai/protocol";
|
|
42
|
-
import
|
|
42
|
+
import * as z from "zod";
|
|
43
43
|
import type { LLMToolDef } from "../llm.js";
|
|
44
44
|
import {
|
|
45
45
|
claudeCodeLoginQueryOptions,
|
|
@@ -132,6 +132,7 @@ export async function assembleGenerationResult(
|
|
|
132
132
|
: telemetry.evalResult,
|
|
133
133
|
// ggui#404 — present only when the same-exchange guard ended the run.
|
|
134
134
|
...(telemetry.sameExchangeBreak !== undefined ? { sameExchangeBreak: telemetry.sameExchangeBreak } : {}),
|
|
135
|
+
...(telemetry.sameFailureBreak !== undefined ? { sameFailureBreak: telemetry.sameFailureBreak } : {}),
|
|
135
136
|
needsBackgroundImprovement,
|
|
136
137
|
selfCheckPassed: telemetry.selfCheckPassed,
|
|
137
138
|
timing,
|
|
@@ -102,6 +102,11 @@ export interface DupeBreakState {
|
|
|
102
102
|
* information-free — the model learned nothing it didn't already
|
|
103
103
|
* have. 1 = first occurrence; 2 = one repeat (nudge); 3 = break. */
|
|
104
104
|
consecutiveIdenticalExchanges: number;
|
|
105
|
+
/** ggui#1791 — for each failure signature ({@link failureSignatures}), how
|
|
106
|
+
* many failed writes (`apply_changes` / `rewrite`) have reported it since
|
|
107
|
+
* the last write that passed, whatever the patch and whatever failed in
|
|
108
|
+
* between. Cleared when a write passes. */
|
|
109
|
+
failureCounts: Map<string, number>;
|
|
105
110
|
}
|
|
106
111
|
|
|
107
112
|
/**
|
|
@@ -147,6 +152,70 @@ export const SAME_EXCHANGE_NUDGE =
|
|
|
147
152
|
"you already have and emit an apply_changes (or scoped) call now; one " +
|
|
148
153
|
"more identical repeat terminates the run.";
|
|
149
154
|
|
|
155
|
+
/**
|
|
156
|
+
* ggui#1791 — the failures a failed write reported, one signature per failing
|
|
157
|
+
* check, with what changes between two identical failures removed: every
|
|
158
|
+
* digit (line and column numbers, counts) and runs of whitespace.
|
|
159
|
+
*
|
|
160
|
+
* A self-check result lists its violations as `[category] description` lines;
|
|
161
|
+
* each one is its own signature, so a check that fails on every turn reads as
|
|
162
|
+
* the same failure whether or not another check fails beside it. A result with
|
|
163
|
+
* no violation line (a build error, a rejected patch) is one signature: its
|
|
164
|
+
* text without the `Committed <oid>: "<message>"` line, which carries a fresh
|
|
165
|
+
* oid and the model's own message every turn.
|
|
166
|
+
*
|
|
167
|
+
* The patch fingerprint above keys on the PATCH, so the same failure under a
|
|
168
|
+
* different patch each turn (a reworded comment, a moved line) never reads as
|
|
169
|
+
* stuck, and a run goes to the turn cap. These key on the FAILURE.
|
|
170
|
+
*/
|
|
171
|
+
export function failureSignatures(resultText: string): string[] {
|
|
172
|
+
const norm = (text: string): string => text.replace(/[0-9]+/g, "#").replace(/\s+/g, " ").trim();
|
|
173
|
+
const violations = [...resultText.matchAll(/^\[[^\]\n]+\] [^\n]+/gm)].map((m) => norm(m[0]));
|
|
174
|
+
if (violations.length > 0) return [...new Set(violations)];
|
|
175
|
+
const rest = norm(resultText.replace(/^Committed [^\n]*\n/, ""));
|
|
176
|
+
return rest.length > 0 ? [rest] : [];
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** The failure a write has reported most often since the last pass, and how often. */
|
|
180
|
+
export interface RepeatedFailure {
|
|
181
|
+
readonly signature: string;
|
|
182
|
+
readonly repeats: number;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* ggui#1791 — record one failed write: count each of its signatures once, and
|
|
187
|
+
* return the one now reported most often since the last passing write
|
|
188
|
+
* (undefined when the result carried no recognisable failure).
|
|
189
|
+
*/
|
|
190
|
+
export function recordWriteFailure(state: DupeBreakState, resultText: string): RepeatedFailure | undefined {
|
|
191
|
+
let top: RepeatedFailure | undefined;
|
|
192
|
+
for (const signature of failureSignatures(resultText)) {
|
|
193
|
+
const repeats = (state.failureCounts.get(signature) ?? 0) + 1;
|
|
194
|
+
state.failureCounts.set(signature, repeats);
|
|
195
|
+
if (top === undefined || repeats > top.repeats) top = { signature, repeats };
|
|
196
|
+
}
|
|
197
|
+
return top;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** ggui#1791 — a write passed: every count starts over. */
|
|
201
|
+
export function clearWriteFailures(state: DupeBreakState): void {
|
|
202
|
+
state.failureCounts.clear();
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** A failure reported for the third time since the last pass ⇒ one explicit nudge. */
|
|
206
|
+
export const SAME_FAILURE_NUDGE_AT = 3;
|
|
207
|
+
|
|
208
|
+
/** A failure reported for the fifth time since the last pass ⇒ the loop is not
|
|
209
|
+
* converging; the caller ends the run, which ships what the turn cap would
|
|
210
|
+
* have shipped. */
|
|
211
|
+
export const SAME_FAILURE_BREAK_AT = 5;
|
|
212
|
+
|
|
213
|
+
/** Appended to the tool result of the {@link SAME_FAILURE_NUDGE_AT}th identical failure. */
|
|
214
|
+
export const SAME_FAILURE_NUDGE =
|
|
215
|
+
"\n\n[harness] This same failure has now been reported for three of your " +
|
|
216
|
+
"patches. Changing other code does not clear it: re-read that check above and " +
|
|
217
|
+
"change exactly what it names. Two more reports of it end the run.";
|
|
218
|
+
|
|
150
219
|
export function createDupeBreakState(): DupeBreakState {
|
|
151
220
|
return {
|
|
152
221
|
lastFailedPatchFingerprint: null,
|
|
@@ -164,6 +233,7 @@ export function createDupeBreakState(): DupeBreakState {
|
|
|
164
233
|
consecutiveNoToolCalls: 0,
|
|
165
234
|
lastExchangeKey: null,
|
|
166
235
|
consecutiveIdenticalExchanges: 0,
|
|
236
|
+
failureCounts: new Map(),
|
|
167
237
|
};
|
|
168
238
|
}
|
|
169
239
|
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
import { runEvalRound } from "./run-eval-round.js";
|
|
26
26
|
import type { TokenUsage } from "./run-eval-round.js";
|
|
27
27
|
import type { VisualLegTokens } from "../../evaluation/visual-evaluator.js";
|
|
28
|
-
import type { SameExchangeBreak } from "../result-types.js";
|
|
28
|
+
import type { SameExchangeBreak, SameFailureBreak } from "../result-types.js";
|
|
29
29
|
|
|
30
30
|
type PreWarmedEvalContext =
|
|
31
31
|
import("../../evaluation/llm-evaluator.js").PreWarmedEvalContext;
|
|
@@ -105,6 +105,8 @@ export interface GenerateTelemetry {
|
|
|
105
105
|
* undefined unless that guard is what stopped the loop.
|
|
106
106
|
*/
|
|
107
107
|
sameExchangeBreak: SameExchangeBreak | undefined;
|
|
108
|
+
/** ggui#1791 — set when the same-failure guard ended the run. */
|
|
109
|
+
sameFailureBreak: SameFailureBreak | undefined;
|
|
108
110
|
/** Latest compiled code — empty string until the first self-check pass. */
|
|
109
111
|
compiledCode: string;
|
|
110
112
|
/**
|
|
@@ -147,6 +149,7 @@ export function createTelemetry(): GenerateTelemetry {
|
|
|
147
149
|
probeRepairTrigger: undefined,
|
|
148
150
|
contractFeedback: undefined,
|
|
149
151
|
sameExchangeBreak: undefined,
|
|
152
|
+
sameFailureBreak: undefined,
|
|
150
153
|
compiledCode: "",
|
|
151
154
|
pairedSource: "",
|
|
152
155
|
selfCheckPassed: false,
|
|
@@ -223,6 +226,7 @@ export function absorbTurn(telemetry: GenerateTelemetry, turn: CodingTurnResult)
|
|
|
223
226
|
else telemetry.counters.outcomes.selfCheckFail++;
|
|
224
227
|
}
|
|
225
228
|
if (turn.sameExchangeBreak !== undefined) telemetry.sameExchangeBreak = turn.sameExchangeBreak;
|
|
229
|
+
if (turn.sameFailureBreak !== undefined) telemetry.sameFailureBreak = turn.sameFailureBreak;
|
|
226
230
|
}
|
|
227
231
|
|
|
228
232
|
export interface CreateGenerateRunnerInput {
|
|
@@ -297,6 +301,7 @@ export function createGenerateTaskRunner(input: CreateGenerateRunnerInput): Task
|
|
|
297
301
|
// place (fingerprint + cooldown + forceEscape +
|
|
298
302
|
// scopedEscapeUsedCount).
|
|
299
303
|
dupeBreak: session.dupeBreak,
|
|
304
|
+
...(params.onCodingTurnPrompt !== undefined ? { onPrompt: params.onCodingTurnPrompt } : {}),
|
|
300
305
|
},
|
|
301
306
|
{
|
|
302
307
|
turnsUsed: telemetry.turnsUsed,
|
|
@@ -21,7 +21,7 @@ import { executeTool } from "../../coding-agent/tools.js";
|
|
|
21
21
|
import type { CostTracker } from "../../evaluation/cost-tracker.js";
|
|
22
22
|
import type { LLMAgent } from "../llm-router.js";
|
|
23
23
|
import type { Harness } from "../types-public.js";
|
|
24
|
-
import type { SameExchangeBreak } from "../result-types.js";
|
|
24
|
+
import type { SameExchangeBreak, SameFailureBreak } from "../result-types.js";
|
|
25
25
|
import {
|
|
26
26
|
APPLY_CHANGES_HASHLINE_TOOL,
|
|
27
27
|
APPLY_CHANGES_HASHLINE_TOOL_FLAT,
|
|
@@ -38,10 +38,16 @@ import {
|
|
|
38
38
|
import { LUCIDE_ICON_NAMES } from "@ggui-ai/design";
|
|
39
39
|
import { formatWithHashlines } from "../hashline.js";
|
|
40
40
|
import {
|
|
41
|
+
clearWriteFailures,
|
|
41
42
|
recordToolExchange,
|
|
43
|
+
recordWriteFailure,
|
|
42
44
|
SAME_EXCHANGE_BREAK_AT,
|
|
43
45
|
SAME_EXCHANGE_NUDGE,
|
|
46
|
+
SAME_FAILURE_BREAK_AT,
|
|
47
|
+
SAME_FAILURE_NUDGE,
|
|
48
|
+
SAME_FAILURE_NUDGE_AT,
|
|
44
49
|
} from "./dupe-break.js";
|
|
50
|
+
import type { RepeatedFailure } from "./dupe-break.js";
|
|
45
51
|
|
|
46
52
|
/** Staged process-mode phase machine — also defined in runtime.ts. */
|
|
47
53
|
export type A1Phase = "scaffold" | "fill" | "post";
|
|
@@ -183,6 +189,8 @@ export interface CodingTurnContext {
|
|
|
183
189
|
* `breakDuplicatePatch` policy flag gates whether this turn reads it.
|
|
184
190
|
*/
|
|
185
191
|
readonly dupeBreak?: import("./dupe-break.js").DupeBreakState;
|
|
192
|
+
/** Told the system prompt and user message this turn hands the coding agent, just before the call. */
|
|
193
|
+
readonly onPrompt?: (sent: import("../runtime.js").CodingTurnPrompt) => void;
|
|
186
194
|
}
|
|
187
195
|
|
|
188
196
|
/**
|
|
@@ -254,6 +262,11 @@ export interface CodingTurnResult {
|
|
|
254
262
|
* control value many exits share. No key on any other turn.
|
|
255
263
|
*/
|
|
256
264
|
readonly sameExchangeBreak?: SameExchangeBreak;
|
|
265
|
+
/**
|
|
266
|
+
* Set only on the `break` the same-failure guard returns (ggui#1791). No
|
|
267
|
+
* key on any other turn.
|
|
268
|
+
*/
|
|
269
|
+
readonly sameFailureBreak?: SameFailureBreak;
|
|
257
270
|
}
|
|
258
271
|
|
|
259
272
|
/**
|
|
@@ -533,6 +546,7 @@ ${closingInstruction}`;
|
|
|
533
546
|
planFirstTurn,
|
|
534
547
|
codeFormat,
|
|
535
548
|
);
|
|
549
|
+
ctx.onPrompt?.({ turn: turnsUsed, systemPrompt, userPrompt });
|
|
536
550
|
const llmStart = Date.now();
|
|
537
551
|
const response = await codingAgent.callTools(
|
|
538
552
|
codingModel,
|
|
@@ -952,6 +966,26 @@ ${closingInstruction}`;
|
|
|
952
966
|
}
|
|
953
967
|
}
|
|
954
968
|
|
|
969
|
+
// ggui#1791 same-failure guard — the patch fingerprint above keys on the
|
|
970
|
+
// PATCH, so the same failure under a different patch each turn (a reworded
|
|
971
|
+
// comment, a moved line) never counts as stuck. This keys on the FAILURE:
|
|
972
|
+
// each failing check a write reports is counted since the last passing
|
|
973
|
+
// write, whatever failed in between. The third report of one gets a nudge,
|
|
974
|
+
// the fifth ends the run. A passing write clears the counts; a non-write
|
|
975
|
+
// tool (cat, icons) changes nothing and leaves them as they were.
|
|
976
|
+
const isWrite = call.name === "apply_changes" || call.name === "rewrite";
|
|
977
|
+
let repeatedFailure: RepeatedFailure | undefined;
|
|
978
|
+
if (ctx.dupeBreak && isWrite) {
|
|
979
|
+
if (result.done) {
|
|
980
|
+
clearWriteFailures(ctx.dupeBreak);
|
|
981
|
+
} else {
|
|
982
|
+
repeatedFailure = recordWriteFailure(ctx.dupeBreak, result.result);
|
|
983
|
+
if (repeatedFailure?.repeats === SAME_FAILURE_NUDGE_AT) {
|
|
984
|
+
augmentedResultText += SAME_FAILURE_NUDGE;
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
|
|
955
989
|
// Send tool result back to close the API contract (Google/OpenAI/OpenRouter)
|
|
956
990
|
// This enables proper session chaining on the next callTools() invocation.
|
|
957
991
|
await codingAgent.sendToolResult([{
|
|
@@ -984,6 +1018,30 @@ ${closingInstruction}`;
|
|
|
984
1018
|
};
|
|
985
1019
|
}
|
|
986
1020
|
|
|
1021
|
+
if (repeatedFailure !== undefined && repeatedFailure.repeats >= SAME_FAILURE_BREAK_AT) {
|
|
1022
|
+
const signature = repeatedFailure.signature.slice(0, 160);
|
|
1023
|
+
console.log(
|
|
1024
|
+
`[coding-agent] SAME_FAILURE_BREAK | tool=${call.name} | repeats=${repeatedFailure.repeats} | failure=${JSON.stringify(signature.slice(0, 80))} — terminating run (ggui#1791)`,
|
|
1025
|
+
);
|
|
1026
|
+
return {
|
|
1027
|
+
control: "break",
|
|
1028
|
+
compiledCode: "",
|
|
1029
|
+
selfCheckPassed: false,
|
|
1030
|
+
outcome: undefined,
|
|
1031
|
+
phase: undefined,
|
|
1032
|
+
tokens,
|
|
1033
|
+
...cacheTokens,
|
|
1034
|
+
llmMs,
|
|
1035
|
+
toolMs,
|
|
1036
|
+
lastResultText: augmentedResultText,
|
|
1037
|
+
lastDiffFailed: false,
|
|
1038
|
+
isEvalFeedback: false,
|
|
1039
|
+
iconNamesCache,
|
|
1040
|
+
preWarmedContext,
|
|
1041
|
+
sameFailureBreak: { signature, repeats: repeatedFailure.repeats },
|
|
1042
|
+
};
|
|
1043
|
+
}
|
|
1044
|
+
|
|
987
1045
|
// Track whether the diff itself failed to apply (vs applied but had violations)
|
|
988
1046
|
const turnDiffFailed = !!result.error && result.result.includes("DIFF");
|
|
989
1047
|
|
|
@@ -1462,6 +1462,15 @@ export async function runEvalRound(
|
|
|
1462
1462
|
console.log(
|
|
1463
1463
|
`[simple] eval round ${evalRoundsUsed}: ${allActionable.length} issues (${blocking.length} fail, ${warns.length} warn) → feeding back to coding loop`,
|
|
1464
1464
|
);
|
|
1465
|
+
// ggui#1981 — one line per deterministic (tier-0) finding on a feedback round, and whether it took one of the
|
|
1466
|
+
// MAX_FEEDBACK_ISSUES slots, so a bench read can count a warn that displaced a repair instead of inferring it.
|
|
1467
|
+
for (const issue of evalResult.issues) {
|
|
1468
|
+
if (issue.tier !== 0 || (issue.result !== "fail" && issue.result !== "warn")) continue;
|
|
1469
|
+
console.log(
|
|
1470
|
+
`[simple] eval round ${evalRoundsUsed}: tier0 ${issue.result} ${issue.subcategory ?? issue.category} ` +
|
|
1471
|
+
`delivered=${allActionable.includes(issue)}`,
|
|
1472
|
+
);
|
|
1473
|
+
}
|
|
1465
1474
|
// ggui#1542 — WHY this round continued, for a caller that set `actOn`: the manipulation check of an experiment on
|
|
1466
1475
|
// the setting reads this line. `visual majors acted` counts the judge's majors only (fit's are never acted on).
|
|
1467
1476
|
if (visualEvaluation?.actOn !== undefined) {
|
|
@@ -36,6 +36,7 @@ import { createAnthropicClient } from '../adapters/claude/client.js';
|
|
|
36
36
|
import { getBedrockModelId } from '../adapters/provider-router.js';
|
|
37
37
|
import { toolArgsToJsonObject } from '../adapters/tool-bridge.js';
|
|
38
38
|
import { splitCacheInclusiveUsage, splitOpenAiUsage } from '../adapters/openai/tokens.js';
|
|
39
|
+
import { loadClaudeAgentSdk } from './claude-agent-sdk-loader.js';
|
|
39
40
|
import {
|
|
40
41
|
emitLlmTraceEvent,
|
|
41
42
|
newLlmTraceId,
|
|
@@ -252,6 +253,8 @@ export interface LLMWithToolsResponse {
|
|
|
252
253
|
turnsUsed: number;
|
|
253
254
|
/** Prompt-cache reads summed over the loop's turns, when the provider reports them (absent = unreported, never zero). */
|
|
254
255
|
cacheReadTokens?: number;
|
|
256
|
+
/** ggui#1957 — prompt-cache writes summed over the loop's turns, when the provider reports them (absent = unreported). */
|
|
257
|
+
cacheCreationTokens?: number;
|
|
255
258
|
}
|
|
256
259
|
|
|
257
260
|
export interface LLMToolCall {
|
|
@@ -1169,7 +1172,7 @@ export class ClaudeCodeLoginAgent extends LLMAgent implements VisionAgent {
|
|
|
1169
1172
|
}
|
|
1170
1173
|
|
|
1171
1174
|
protected async createClient(): Promise<LoginSdk> {
|
|
1172
|
-
const { query, tool, createSdkMcpServer } = await
|
|
1175
|
+
const { query, tool, createSdkMcpServer } = await loadClaudeAgentSdk();
|
|
1173
1176
|
return { query, tool, createSdkMcpServer };
|
|
1174
1177
|
}
|
|
1175
1178
|
|
|
@@ -1428,11 +1431,14 @@ export class OpenAIAgent extends LLMAgent {
|
|
|
1428
1431
|
// ggui#1186 (second site): `input_tokens` INCLUDES the cached prefix on the
|
|
1429
1432
|
// Responses API — report the NON-cached input like every other provider.
|
|
1430
1433
|
// The text response carries no cache field, so the cached count is
|
|
1431
|
-
// dropped here rather than double-counted.
|
|
1434
|
+
// dropped here rather than double-counted. Cache writes (ggui#1957) stay
|
|
1435
|
+
// inside `inputTokens` on this path for the same reason: with no
|
|
1436
|
+
// cache-write term to carry them, subtracting them would drop them.
|
|
1432
1437
|
const textUsage = splitOpenAiUsage(
|
|
1433
1438
|
response.usage?.input_tokens ?? 0,
|
|
1434
1439
|
response.usage?.output_tokens ?? 0,
|
|
1435
1440
|
response.usage?.input_tokens_details?.cached_tokens ?? 0,
|
|
1441
|
+
0,
|
|
1436
1442
|
);
|
|
1437
1443
|
return {
|
|
1438
1444
|
text,
|
|
@@ -1509,6 +1515,7 @@ export class OpenAIAgent extends LLMAgent {
|
|
|
1509
1515
|
response.usage?.input_tokens ?? 0,
|
|
1510
1516
|
response.usage?.output_tokens ?? 0,
|
|
1511
1517
|
response.usage?.input_tokens_details?.cached_tokens ?? 0,
|
|
1518
|
+
response.usage?.input_tokens_details?.cache_write_tokens ?? 0,
|
|
1512
1519
|
);
|
|
1513
1520
|
return {
|
|
1514
1521
|
toolCalls: functionCalls.map((fc) => ({
|
|
@@ -1519,6 +1526,7 @@ export class OpenAIAgent extends LLMAgent {
|
|
|
1519
1526
|
inputTokens: toolsUsage.tokens.input,
|
|
1520
1527
|
outputTokens: toolsUsage.tokens.output,
|
|
1521
1528
|
cacheReadTokens: toolsUsage.cacheReadTokens,
|
|
1529
|
+
cacheCreationTokens: toolsUsage.cacheCreationTokens,
|
|
1522
1530
|
};
|
|
1523
1531
|
}
|
|
1524
1532
|
|
|
@@ -1558,6 +1566,7 @@ export class OpenAIAgent extends LLMAgent {
|
|
|
1558
1566
|
let totalIn = 0;
|
|
1559
1567
|
let totalOut = 0;
|
|
1560
1568
|
let totalCacheRead = 0;
|
|
1569
|
+
let totalCacheWrite = 0;
|
|
1561
1570
|
let allText = '';
|
|
1562
1571
|
|
|
1563
1572
|
for (let turn = 0; turn < maxTurns; turn++) {
|
|
@@ -1574,10 +1583,12 @@ export class OpenAIAgent extends LLMAgent {
|
|
|
1574
1583
|
response.usage?.input_tokens ?? 0,
|
|
1575
1584
|
response.usage?.output_tokens ?? 0,
|
|
1576
1585
|
response.usage?.input_tokens_details?.cached_tokens ?? 0,
|
|
1586
|
+
response.usage?.input_tokens_details?.cache_write_tokens ?? 0,
|
|
1577
1587
|
);
|
|
1578
1588
|
totalIn += turnUsage.tokens.input;
|
|
1579
1589
|
totalOut += turnUsage.tokens.output;
|
|
1580
1590
|
totalCacheRead += turnUsage.cacheReadTokens;
|
|
1591
|
+
totalCacheWrite += turnUsage.cacheCreationTokens;
|
|
1581
1592
|
|
|
1582
1593
|
const functionCalls = response.output.filter(
|
|
1583
1594
|
(o): o is ResponseFunctionToolCall => o.type === 'function_call',
|
|
@@ -1615,6 +1626,7 @@ export class OpenAIAgent extends LLMAgent {
|
|
|
1615
1626
|
inputTokens: totalIn,
|
|
1616
1627
|
outputTokens: totalOut,
|
|
1617
1628
|
cacheReadTokens: totalCacheRead,
|
|
1629
|
+
cacheCreationTokens: totalCacheWrite,
|
|
1618
1630
|
turnsUsed: input.length,
|
|
1619
1631
|
};
|
|
1620
1632
|
}
|
|
@@ -2435,3 +2447,39 @@ export async function callLLMWithTools(
|
|
|
2435
2447
|
return result;
|
|
2436
2448
|
}
|
|
2437
2449
|
|
|
2450
|
+
|
|
2451
|
+
/** What {@link preloadProviderSdks} loaded, and what it could not, by specifier. */
|
|
2452
|
+
export interface ProviderSdkPreload {
|
|
2453
|
+
readonly ms: number;
|
|
2454
|
+
readonly loaded: readonly string[];
|
|
2455
|
+
readonly missing: ReadonlyArray<{ readonly specifier: string; readonly reason: string }>;
|
|
2456
|
+
}
|
|
2457
|
+
|
|
2458
|
+
/**
|
|
2459
|
+
* ggui#1769 — load the provider SDKs this router imports lazily, once, before a long-lived host takes traffic.
|
|
2460
|
+
*
|
|
2461
|
+
* Each agent imports its SDK on first use. Cold, `@anthropic-ai/claude-agent-sdk` alone compiles for ~0.9 s
|
|
2462
|
+
* synchronously, so a host's first generation stalls the event loop for that long mid-request. A host awaits
|
|
2463
|
+
* this at boot instead; afterwards every `import()` below resolves from the module cache.
|
|
2464
|
+
*
|
|
2465
|
+
* Never rejects: an SDK that is not installed (an optional provider a deployment does not use) is reported in
|
|
2466
|
+
* `missing` with its reason, and its agent fails on first use exactly as it would without the preload.
|
|
2467
|
+
*/
|
|
2468
|
+
export async function preloadProviderSdks(): Promise<ProviderSdkPreload> {
|
|
2469
|
+
const start = Date.now();
|
|
2470
|
+
const attempts: ReadonlyArray<readonly [string, () => Promise<object>]> = [
|
|
2471
|
+
['@anthropic-ai/claude-agent-sdk', () => import('@anthropic-ai/claude-agent-sdk')],
|
|
2472
|
+
['openai', () => import('openai')],
|
|
2473
|
+
['@google/genai', () => import('@google/genai')],
|
|
2474
|
+
['@anthropic-ai/bedrock-sdk', () => import('@anthropic-ai/bedrock-sdk')],
|
|
2475
|
+
];
|
|
2476
|
+
const settled = await Promise.allSettled(attempts.map(([, load]) => load()));
|
|
2477
|
+
const loaded: string[] = [];
|
|
2478
|
+
const missing: { specifier: string; reason: string }[] = [];
|
|
2479
|
+
settled.forEach((r, i) => {
|
|
2480
|
+
const specifier = attempts[i]?.[0] ?? '';
|
|
2481
|
+
if (r.status === 'fulfilled') loaded.push(specifier);
|
|
2482
|
+
else missing.push({ specifier, reason: r.reason instanceof Error ? r.reason.message : String(r.reason) });
|
|
2483
|
+
});
|
|
2484
|
+
return { ms: Date.now() - start, loaded, missing };
|
|
2485
|
+
}
|
|
@@ -62,6 +62,16 @@ export interface SameExchangeBreak {
|
|
|
62
62
|
readonly repeats: number;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
/**
|
|
66
|
+
* ggui#1791 — the same-failure guard ended the run: one failing check
|
|
67
|
+
* (`signature`, its first 160 characters) was reported by this many failed
|
|
68
|
+
* writes since the last passing one, whatever the patch.
|
|
69
|
+
*/
|
|
70
|
+
export interface SameFailureBreak {
|
|
71
|
+
readonly signature: string;
|
|
72
|
+
readonly repeats: number;
|
|
73
|
+
}
|
|
74
|
+
|
|
65
75
|
export interface GenerationResult extends AdapterResult {
|
|
66
76
|
/** Number of generation passes the harness performed */
|
|
67
77
|
passesUsed: number;
|
|
@@ -77,6 +87,8 @@ export interface GenerationResult extends AdapterResult {
|
|
|
77
87
|
inLoopVisualTokens?: VisualLegTokens;
|
|
78
88
|
/** Set only when the same-exchange guard ended the run (ggui#404); no key otherwise. */
|
|
79
89
|
sameExchangeBreak?: SameExchangeBreak;
|
|
90
|
+
/** ggui#1791 — set only when the same-failure guard ended the run. */
|
|
91
|
+
sameFailureBreak?: SameFailureBreak;
|
|
80
92
|
/** Whether background improvement should be spawned (auto-improve mode) */
|
|
81
93
|
needsBackgroundImprovement?: boolean;
|
|
82
94
|
/** Whether at least one commit passed the self-check (compile + type check + lint) */
|
package/src/harness/runtime.ts
CHANGED
|
@@ -66,6 +66,18 @@ export interface AgentSpec {
|
|
|
66
66
|
onRetry?: AgentConfig["onRetry"];
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
/**
|
|
70
|
+
* One coding turn's prompt, exactly as handed to the coding agent's tool call: the system prompt (after every
|
|
71
|
+
* policy swap, e.g. the condensed component reference) and the turn's user message. Lets a caller audit the
|
|
72
|
+
* prompt a generation actually sent rather than the templates it was built from.
|
|
73
|
+
*/
|
|
74
|
+
export interface CodingTurnPrompt {
|
|
75
|
+
/** 1-indexed coding turn. */
|
|
76
|
+
readonly turn: number;
|
|
77
|
+
readonly systemPrompt: string;
|
|
78
|
+
readonly userPrompt: string;
|
|
79
|
+
}
|
|
80
|
+
|
|
69
81
|
export interface SingleComponentParams {
|
|
70
82
|
userPrompt: string;
|
|
71
83
|
contract?: DataContract;
|
|
@@ -119,6 +131,11 @@ export interface SingleComponentParams {
|
|
|
119
131
|
actOn?: "critical" | "major";
|
|
120
132
|
};
|
|
121
133
|
onProgress?: (event: unknown) => void;
|
|
134
|
+
/**
|
|
135
|
+
* Observer of what each coding turn sends the model — see {@link CodingTurnPrompt}. Read-only: the generation is
|
|
136
|
+
* byte-identical with or without it. Absent = nothing reported.
|
|
137
|
+
*/
|
|
138
|
+
onCodingTurnPrompt?: (sent: CodingTurnPrompt) => void;
|
|
122
139
|
onInitialResult?: (result: {
|
|
123
140
|
componentCode: string;
|
|
124
141
|
sourceCode?: string;
|
package/src/index.ts
CHANGED
|
@@ -22,7 +22,16 @@ export {
|
|
|
22
22
|
export type { CreateUiGeneratorOptions } from './create-ui-generator.js';
|
|
23
23
|
export type { RuntimeRenderProbeConfig } from './harness/check/runtime-render/adapter.js';
|
|
24
24
|
export type { ProviderRetryInfo } from './harness/llm-router.js';
|
|
25
|
-
export
|
|
25
|
+
export { preloadProviderSdks, type ProviderSdkPreload } from './harness/llm-router.js';
|
|
26
|
+
// ggui#1951: the Agent SDK is an optional peer. Only what names none of
|
|
27
|
+
// its types is exported here, so this entry type-checks without it.
|
|
28
|
+
export {
|
|
29
|
+
CLAUDE_AGENT_SDK_SPECIFIER,
|
|
30
|
+
CLAUDE_AGENT_SDK_VERSION,
|
|
31
|
+
ClaudeAgentSdkMissingError,
|
|
32
|
+
ensureClaudeAgentSdk,
|
|
33
|
+
} from './harness/claude-agent-sdk-loader.js';
|
|
34
|
+
export type { GenerationResult, SameExchangeBreak, SameFailureBreak } from './harness/result-types.js';
|
|
26
35
|
// The build identity a stamp outside this package can name: the same
|
|
27
36
|
// digests `createUiGenerator` puts on every result's `metadata.build`, for
|
|
28
37
|
// either design mode — so a harness definition can carry both modes' digests
|