@ggui-ai/ui-gen 0.21.0 → 0.23.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/adapters/generation-dispatch.d.ts +1 -1
- package/dist/adapters/generation-dispatch.js +253 -76
- package/dist/adapters/generation-dispatch.js.map +1 -1
- package/dist/adapters/index.js +36 -11
- package/dist/adapters/index.js.map +1 -1
- package/dist/advanced/index.d.ts +3 -3
- package/dist/advanced/index.js +447 -76
- package/dist/advanced/index.js.map +1 -1
- package/dist/blueprint-validator.js +37 -7
- package/dist/blueprint-validator.js.map +1 -1
- package/dist/boilerplate.js +1 -0
- package/dist/boilerplate.js.map +1 -1
- package/dist/check/index.d.ts +1 -1
- package/dist/check/index.js.map +1 -1
- package/dist/{create-ui-generator-D7kOXNjJ.d.ts → create-ui-generator-D0kbWwln.d.ts} +1 -1
- package/dist/{dispatch-DGvhmARp.d.ts → dispatch-wxaIMwZt.d.ts} +1 -1
- package/dist/evaluation/axis-checks/index.d.ts +3 -3
- package/dist/evaluation/axis-checks/index.js +19 -4
- package/dist/evaluation/axis-checks/index.js.map +1 -1
- package/dist/evaluation/axis-checks/registry.d.ts +1 -1
- package/dist/evaluation/axis-checks/registry.js +19 -4
- package/dist/evaluation/axis-checks/registry.js.map +1 -1
- package/dist/evaluation/index.d.ts +3 -3
- package/dist/evaluation/index.js +58 -26
- package/dist/evaluation/index.js.map +1 -1
- package/dist/harness/check/runtime-render/index.d.ts +4 -4
- package/dist/harness/check/runtime-render/index.js +26 -6
- package/dist/harness/check/runtime-render/index.js.map +1 -1
- package/dist/harness/check/runtime-render/render-check-worker.js.map +1 -1
- package/dist/harness/index.d.ts +1 -1
- package/dist/harness/index.js +37 -11
- package/dist/harness/index.js.map +1 -1
- package/dist/harness/prompts.js +1 -1
- package/dist/harness/prompts.js.map +1 -1
- package/dist/harness/result-types.d.ts +15 -2
- package/dist/harness/result-types.js.map +1 -1
- package/dist/harness/runtime.d.ts +1 -1
- package/dist/harness/runtime.js +2 -1
- package/dist/harness/runtime.js.map +1 -1
- package/dist/harness/types-public.d.ts +9 -5
- package/dist/harness/types-public.js +1 -0
- package/dist/harness/types-public.js.map +1 -1
- package/dist/harness/validator-trace-sink.d.ts +1 -1
- package/dist/index.d.ts +22 -6
- package/dist/index.js +436 -75
- package/dist/index.js.map +1 -1
- package/dist/patch.d.ts +1 -1
- package/dist/{render-check-C0CqVceF.d.ts → render-check-Blwj8gB6.d.ts} +18 -0
- package/dist/tools/get-primitives-ts.d.ts +1 -1
- package/dist/tools/get-primitives-ts.js +1 -1
- package/dist/tools/get-primitives-ts.js.map +1 -1
- package/dist/{types-public-CzYqZclY.d.ts → types-public-Ow-tNtFE.d.ts} +41 -3
- package/dist/validation/index.d.ts +1 -1
- package/dist/validation/index.js +1 -1
- package/dist/validation/index.js.map +1 -1
- package/dist/workflows.d.ts +1 -1
- package/package.json +12 -12
- package/src/adapters/claude/claude-code-login.ts +62 -7
- package/src/adapters/claude/sdk.ts +6 -5
- package/src/advanced/generator.ts +16 -1
- package/src/blueprint-validator.ts +21 -6
- package/src/boilerplate/hard-sections.ts +1 -0
- package/src/boilerplate/templates/layouts/chat-mobile.tsx.tmpl +7 -3
- package/src/boilerplate/templates/layouts/chat-universal.tsx.tmpl +7 -3
- package/src/coding-agent/tools.ts +6 -1
- package/src/contract-context.ts +1 -1
- package/src/create-ui-generator.ts +30 -0
- package/src/evaluation/axis-checks/checks/state-payload.ts +29 -4
- package/src/evaluation/index.ts +1 -0
- package/src/evaluation/llm-evaluator.ts +40 -13
- package/src/evaluation/types-public.ts +42 -2
- package/src/evaluation/visual-evaluator.ts +9 -6
- package/src/generator-build.ts +158 -0
- package/src/harness/check/runtime-render/adapter.ts +19 -0
- package/src/harness/check/runtime-render/render-check-host.ts +31 -9
- package/src/harness/check/runtime-render/render-check.ts +19 -0
- package/src/harness/claude-code-login-query.ts +5 -4
- package/src/harness/coding/assemble-result.ts +8 -1
- package/src/harness/coding/generate-task-runner.ts +75 -36
- package/src/harness/coding/run-coding-turn.ts +9 -0
- package/src/harness/coding/run-eval-round.ts +162 -5
- package/src/harness/llm-router.ts +3 -3
- package/src/harness/result-types.ts +14 -0
- package/src/harness/types-public.ts +9 -5
- package/src/index.ts +2 -1
- package/src/tools/get-primitives-ts.ts +1 -1
- package/src/validation/primitives.ts +1 -1
|
@@ -22,7 +22,7 @@ import { listContractGadgets } from "@ggui-ai/protocol";
|
|
|
22
22
|
import type { Classification } from "../../classifier/index.js";
|
|
23
23
|
import type { AgentWorkspace } from "../../coding-agent/workspace.js";
|
|
24
24
|
import type { CostTracker } from "../../evaluation/cost-tracker.js";
|
|
25
|
-
import type { EvalIssue, EvalResult, RuntimeProbeMeta, VisualEvalSummary, VisualCoverage } from "../../evaluation/types-public.js";
|
|
25
|
+
import type { ContractFeedbackRecord, EvalIssue, EvalResult, RuntimeProbeMeta, VisualEvalSummary, VisualCoverage } from "../../evaluation/types-public.js";
|
|
26
26
|
import { notApplicableCoverage } from "../../evaluation/types-public.js";
|
|
27
27
|
import { mapProviderForEvaluator, visionJudgeProvider } from "../enforced-coding.js";
|
|
28
28
|
import { runCheck } from "../index.js";
|
|
@@ -40,6 +40,7 @@ import type {
|
|
|
40
40
|
type PreWarmedEvalContext =
|
|
41
41
|
import("../../evaluation/llm-evaluator.js").PreWarmedEvalContext;
|
|
42
42
|
type LlmEvalMod = typeof import("../../evaluation/llm-evaluator.js");
|
|
43
|
+
type LLMEvalTokenUsage = import("../../evaluation/llm-evaluator.js").LLMEvalTokenUsage;
|
|
43
44
|
type VisualEvalMod = typeof import("../../evaluation/visual-evaluator.js");
|
|
44
45
|
|
|
45
46
|
/**
|
|
@@ -100,6 +101,20 @@ export interface EvalRoundInput {
|
|
|
100
101
|
*/
|
|
101
102
|
export type EvalRoundControl = "break" | "feedback";
|
|
102
103
|
|
|
104
|
+
/**
|
|
105
|
+
* One call's (or one round's) token accounting. `input` is the NON-cached
|
|
106
|
+
* input; the cache counts are present only when the provider reported them —
|
|
107
|
+
* absent means unreported, never zero. The runner folds every coding turn and
|
|
108
|
+
* every eval round through the same rule (`absorbTokens`), so the published
|
|
109
|
+
* `tokens.total` holds one convention across both (ggui#1281, #1186).
|
|
110
|
+
*/
|
|
111
|
+
export interface TokenUsage {
|
|
112
|
+
readonly input: number;
|
|
113
|
+
readonly output: number;
|
|
114
|
+
readonly cacheRead?: number;
|
|
115
|
+
readonly cacheCreation?: number;
|
|
116
|
+
}
|
|
117
|
+
|
|
103
118
|
export interface EvalRoundResult {
|
|
104
119
|
readonly control: EvalRoundControl;
|
|
105
120
|
/** True only on the low-risk bypass + clean-pass paths. */
|
|
@@ -115,7 +130,7 @@ export interface EvalRoundResult {
|
|
|
115
130
|
readonly prevFailFingerprints: Set<string>;
|
|
116
131
|
readonly preWarmedContext: PreWarmedEvalContext | null | undefined;
|
|
117
132
|
/** Tokens added during this round — caller adds to its own totals. */
|
|
118
|
-
readonly evalTokens:
|
|
133
|
+
readonly evalTokens: TokenUsage;
|
|
119
134
|
/** Wall-clock of the parallel LLM + visual eval block (zero on the
|
|
120
135
|
* low-risk bypass path, which exits before `Promise.all`). Caller
|
|
121
136
|
* accumulates into its `cumulativeEvalLlmMs`. */
|
|
@@ -124,6 +139,13 @@ export interface EvalRoundResult {
|
|
|
124
139
|
readonly lastResultText: string;
|
|
125
140
|
readonly isEvalFeedback: boolean;
|
|
126
141
|
readonly lastDiffFailed: boolean;
|
|
142
|
+
/**
|
|
143
|
+
* ggui#1261 — set ONLY on the round that granted a contract-feedback round:
|
|
144
|
+
* what bought it and the source it was fed back on. The caller keeps it past
|
|
145
|
+
* this round (the next round rebuilds `evalResult`) and stamps it on the
|
|
146
|
+
* result the generation ends with.
|
|
147
|
+
*/
|
|
148
|
+
readonly contractFeedback?: ContractFeedbackRecord;
|
|
127
149
|
}
|
|
128
150
|
|
|
129
151
|
/** Cap feedback to N issues per eval-fix turn so the LLM stays surgical. */
|
|
@@ -337,6 +359,8 @@ async function runProbeAtExit(input: {
|
|
|
337
359
|
const meta: RuntimeProbeMeta = {
|
|
338
360
|
status: outcome.status,
|
|
339
361
|
...(outcome.reason !== undefined ? { reason: outcome.reason } : {}),
|
|
362
|
+
...(outcome.elapsedMs !== undefined ? { elapsedMs: outcome.elapsedMs } : {}),
|
|
363
|
+
...(outcome.hostLoad !== undefined ? { hostLoad: outcome.hostLoad } : {}),
|
|
340
364
|
};
|
|
341
365
|
if (outcome.status !== "ran") {
|
|
342
366
|
return { fired: false, recoverableFail: false, probeIssues: [], meta };
|
|
@@ -368,6 +392,42 @@ function formatRuntimeProbeFeedback(issue: EvalIssue): string {
|
|
|
368
392
|
);
|
|
369
393
|
}
|
|
370
394
|
|
|
395
|
+
/**
|
|
396
|
+
* Exit-probe checks whose FAIL buys ONE feedback round although it is not a
|
|
397
|
+
* crash: a contract defect the probe diagnoses deterministically, with a fix
|
|
398
|
+
* text the model can act on in a turn. Without the round the loop recorded the
|
|
399
|
+
* finding and shipped it — its own evaluator named the defect and the model
|
|
400
|
+
* never heard. Named, and grown only with evidence: `prop-sensitivity` (a
|
|
401
|
+
* declared prop ignored, a literal baked in its place — "You" for
|
|
402
|
+
* `currentUser`) is the class measured failing across models (ggui#1261).
|
|
403
|
+
*/
|
|
404
|
+
const FEEDBACK_PROBE_CHECKS: readonly string[] = ["prop-sensitivity"];
|
|
405
|
+
|
|
406
|
+
/** Rounds past the cap the contract-feedback round may use: one, as the fit round (ggui#1195). */
|
|
407
|
+
const CONTRACT_FEEDBACK_BONUS = 1;
|
|
408
|
+
|
|
409
|
+
/** `runtime:<check>` or `runtime:<check>:<subject>` for a named feedback check, FAIL only. */
|
|
410
|
+
function isFeedbackProbeFail(issue: EvalIssue): boolean {
|
|
411
|
+
const sub = issue.subcategory;
|
|
412
|
+
if (issue.result !== "fail" || typeof sub !== "string") return false;
|
|
413
|
+
return FEEDBACK_PROBE_CHECKS.some((check) => sub === `runtime:${check}` || sub.startsWith(`runtime:${check}:`));
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* The exit probe's feedback-worthy FAILs this generation has not been told
|
|
418
|
+
* about yet. A finding whose fingerprint already rode a feedback round and
|
|
419
|
+
* recurred is left out — one attempt per finding, then it ships as recorded.
|
|
420
|
+
*/
|
|
421
|
+
/** The round's record: the findings that bought it, and the source they were found on. */
|
|
422
|
+
function contractFeedbackRecord(fails: readonly EvalIssue[], sourceBefore: string): ContractFeedbackRecord {
|
|
423
|
+
return { firedOn: fails.flatMap((i) => (i.subcategory !== undefined ? [i.subcategory] : [])), sourceBefore };
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
function contractFeedbackFails(exitProbe: ProbeAtExitResult, alreadyFedBack: ReadonlySet<string>): EvalIssue[] {
|
|
427
|
+
if (!exitProbe.fired) return [];
|
|
428
|
+
return exitProbe.probeIssues.filter((i) => isFeedbackProbeFail(i) && !alreadyFedBack.has(fingerprintFail(i)));
|
|
429
|
+
}
|
|
430
|
+
|
|
371
431
|
/**
|
|
372
432
|
* Run one eval round. Mutates `ctx.costTracker` (records LLM eval tokens)
|
|
373
433
|
* and `ctx.workspace` is read-only from this function's POV. Returns
|
|
@@ -404,7 +464,7 @@ export async function runEvalRound(
|
|
|
404
464
|
const currentSource = workspace.read() ?? "";
|
|
405
465
|
|
|
406
466
|
let evalResult: EvalResult | undefined;
|
|
407
|
-
let evalTokens = { input: 0, output: 0 };
|
|
467
|
+
let evalTokens: TokenUsage = { input: 0, output: 0 };
|
|
408
468
|
let evalLlmMs = 0;
|
|
409
469
|
|
|
410
470
|
try {
|
|
@@ -528,7 +588,7 @@ export async function runEvalRound(
|
|
|
528
588
|
}
|
|
529
589
|
|
|
530
590
|
// ── Tier 1+2: LLM evaluation + Visual eval in parallel ──
|
|
531
|
-
let llmResult: (EvalResult &
|
|
591
|
+
let llmResult: (EvalResult & LLMEvalTokenUsage) | null = null;
|
|
532
592
|
let visualIssues: EvalIssue[] | null = null;
|
|
533
593
|
|
|
534
594
|
// The visual leg's page and frame — ONE value each, read by the judge and
|
|
@@ -629,6 +689,8 @@ export async function runEvalRound(
|
|
|
629
689
|
evalTokens = {
|
|
630
690
|
input: llmResult.inputTokens,
|
|
631
691
|
output: llmResult.outputTokens,
|
|
692
|
+
...(llmResult.cacheReadTokens !== undefined ? { cacheRead: llmResult.cacheReadTokens } : {}),
|
|
693
|
+
...(llmResult.cacheCreationTokens !== undefined ? { cacheCreation: llmResult.cacheCreationTokens } : {}),
|
|
632
694
|
};
|
|
633
695
|
}
|
|
634
696
|
|
|
@@ -748,6 +810,40 @@ export async function runEvalRound(
|
|
|
748
810
|
lastDiffFailed: false,
|
|
749
811
|
};
|
|
750
812
|
}
|
|
813
|
+
// ggui#1261 — a contract defect the probe diagnosed (a named check,
|
|
814
|
+
// FAIL) that this generation has not been told about: ONE feedback
|
|
815
|
+
// round with the probe's own diagnosis and fix. The next round re-runs
|
|
816
|
+
// the probe at its exit, so the result this generation ends with
|
|
817
|
+
// carries the post-fix stamp, never this one.
|
|
818
|
+
const contractFails = contractFeedbackFails(exitProbe, prevFailFingerprints);
|
|
819
|
+
if (contractFails.length > 0 && evalRoundsUsed < maxEvalRounds + CONTRACT_FEEDBACK_BONUS) {
|
|
820
|
+
const lines = contractFails.slice(0, MAX_FEEDBACK_ISSUES).map(formatRuntimeProbeFeedback);
|
|
821
|
+
evalResult = {
|
|
822
|
+
...evalResult,
|
|
823
|
+
issues: [...allIssues, ...exitProbe.probeIssues],
|
|
824
|
+
pass: allPass,
|
|
825
|
+
runtimeProbe: exitProbe.meta,
|
|
826
|
+
};
|
|
827
|
+
console.log(
|
|
828
|
+
`[simple] eval round ${evalRoundsUsed}: tier-1/2 clean BUT contract probe fail — granting +1 turn ` +
|
|
829
|
+
`(ggui#1261; ${contractFails.map((i) => i.subcategory).join(", ")})`,
|
|
830
|
+
);
|
|
831
|
+
return {
|
|
832
|
+
control: "feedback",
|
|
833
|
+
evalDone: false,
|
|
834
|
+
evalResult,
|
|
835
|
+
evalRoundsUsed,
|
|
836
|
+
prevModeSubcats: updatedPrevModeSubcats,
|
|
837
|
+
prevFailFingerprints: new Set([...currFailFingerprints, ...contractFails.map(fingerprintFail)]),
|
|
838
|
+
preWarmedContext,
|
|
839
|
+
evalTokens,
|
|
840
|
+
evalLlmMs,
|
|
841
|
+
lastResultText: lines.join("\n\n"),
|
|
842
|
+
isEvalFeedback: true,
|
|
843
|
+
lastDiffFailed: false,
|
|
844
|
+
contractFeedback: contractFeedbackRecord(contractFails, currentSource),
|
|
845
|
+
};
|
|
846
|
+
}
|
|
751
847
|
// Probe didn't trip a recoverable fail — fold its issues (if any)
|
|
752
848
|
// into the merged result and ALWAYS stamp its execution meta, so a
|
|
753
849
|
// did-not-run probe is visible downstream even on this clean exit.
|
|
@@ -811,7 +907,8 @@ export async function runEvalRound(
|
|
|
811
907
|
// the runtimeProbe stamp lands (Exp 48 found this exit surfacing
|
|
812
908
|
// as "SKIP — no runtimeProbe stamp" in the bench: honest, but a
|
|
813
909
|
// probe here is cheap and the shipped code deserves the signal).
|
|
814
|
-
//
|
|
910
|
+
// The RECURRING fails get no more feedback — stuck means the model
|
|
911
|
+
// saw them and stopped converging on them.
|
|
815
912
|
const stuckExitProbe = await runProbeAtExit({
|
|
816
913
|
harness,
|
|
817
914
|
sourceCode: currentSource,
|
|
@@ -824,6 +921,36 @@ export async function runEvalRound(
|
|
|
824
921
|
issues: [...evalResult.issues, ...stuckExitProbe.probeIssues],
|
|
825
922
|
runtimeProbe: stuckExitProbe.meta,
|
|
826
923
|
};
|
|
924
|
+
// ggui#1261 — a contract defect the exit probe diagnosed here was never
|
|
925
|
+
// DELIVERED: the stuck set is non-runtime by construction (runtime-only
|
|
926
|
+
// sets are exempt above), and the stuck premise is "the model saw these
|
|
927
|
+
// and did not resolve them". So it gets the same one round as at the
|
|
928
|
+
// clean-PASS and cap exits — the probe's diagnosis only, never the
|
|
929
|
+
// recurring fail; one attempt per finding; bounded at the cap + 1 (Exp
|
|
930
|
+
// 011, candidate r5: the one FAIL that shipped without a round).
|
|
931
|
+
const stuckContractFails = contractFeedbackFails(stuckExitProbe, prevFailFingerprints);
|
|
932
|
+
if (stuckContractFails.length > 0 && evalRoundsUsed < maxEvalRounds + CONTRACT_FEEDBACK_BONUS) {
|
|
933
|
+
const lines = stuckContractFails.slice(0, MAX_FEEDBACK_ISSUES).map(formatRuntimeProbeFeedback);
|
|
934
|
+
console.log(
|
|
935
|
+
`[simple] eval round ${evalRoundsUsed}: stuck BUT contract probe fail never delivered — granting +1 turn ` +
|
|
936
|
+
`(ggui#1261; ${stuckContractFails.map((i) => i.subcategory).join(", ")})`,
|
|
937
|
+
);
|
|
938
|
+
return {
|
|
939
|
+
control: "feedback",
|
|
940
|
+
evalDone: false,
|
|
941
|
+
evalResult,
|
|
942
|
+
evalRoundsUsed,
|
|
943
|
+
prevModeSubcats: updatedPrevModeSubcats,
|
|
944
|
+
prevFailFingerprints: new Set([...currFailFingerprints, ...stuckContractFails.map(fingerprintFail)]),
|
|
945
|
+
preWarmedContext,
|
|
946
|
+
evalTokens,
|
|
947
|
+
evalLlmMs,
|
|
948
|
+
lastResultText: lines.join("\n\n"),
|
|
949
|
+
isEvalFeedback: true,
|
|
950
|
+
lastDiffFailed: false,
|
|
951
|
+
contractFeedback: contractFeedbackRecord(stuckContractFails, currentSource),
|
|
952
|
+
};
|
|
953
|
+
}
|
|
827
954
|
return {
|
|
828
955
|
control: "break",
|
|
829
956
|
evalDone: false,
|
|
@@ -909,6 +1036,36 @@ export async function runEvalRound(
|
|
|
909
1036
|
lastDiffFailed: false,
|
|
910
1037
|
};
|
|
911
1038
|
}
|
|
1039
|
+
// ggui#1261 — a named contract FAIL from the exit probe active at the
|
|
1040
|
+
// cap: the same one round as at the clean exit, bounded at the cap + 1.
|
|
1041
|
+
const capContractFails = allowRuntimeExtension ? [] : contractFeedbackFails(exitProbe, prevFailFingerprints);
|
|
1042
|
+
if (capContractFails.length > 0 && evalRoundsUsed < maxEvalRounds + CONTRACT_FEEDBACK_BONUS) {
|
|
1043
|
+
const contractLines = capContractFails.slice(0, MAX_FEEDBACK_ISSUES).map(formatRuntimeProbeFeedback);
|
|
1044
|
+
evalResult = {
|
|
1045
|
+
...evalResult,
|
|
1046
|
+
issues: [...evalResult.issues, ...exitProbe.probeIssues],
|
|
1047
|
+
runtimeProbe: exitProbe.meta,
|
|
1048
|
+
};
|
|
1049
|
+
console.log(
|
|
1050
|
+
`[simple] eval round ${evalRoundsUsed}: contract probe fail active at cap — granting +1 retry ` +
|
|
1051
|
+
`(ggui#1261; ${capContractFails.map((i) => i.subcategory).join(", ")})`,
|
|
1052
|
+
);
|
|
1053
|
+
return {
|
|
1054
|
+
control: "feedback",
|
|
1055
|
+
evalDone: false,
|
|
1056
|
+
evalResult,
|
|
1057
|
+
evalRoundsUsed,
|
|
1058
|
+
prevModeSubcats: updatedPrevModeSubcats,
|
|
1059
|
+
prevFailFingerprints: new Set([...currFailFingerprints, ...capContractFails.map(fingerprintFail)]),
|
|
1060
|
+
preWarmedContext,
|
|
1061
|
+
evalTokens,
|
|
1062
|
+
evalLlmMs,
|
|
1063
|
+
lastResultText: contractLines.join("\n\n"),
|
|
1064
|
+
isEvalFeedback: true,
|
|
1065
|
+
lastDiffFailed: false,
|
|
1066
|
+
contractFeedback: contractFeedbackRecord(capContractFails, currentSource),
|
|
1067
|
+
};
|
|
1068
|
+
}
|
|
912
1069
|
if (!allowRuntimeExtension) {
|
|
913
1070
|
// Fold probe issues (if any) into evalResult for telemetry and
|
|
914
1071
|
// ALWAYS stamp the probe's execution meta, even though we're not
|
|
@@ -875,8 +875,8 @@ export class AnthropicAgent extends LLMAgent {
|
|
|
875
875
|
: toolChoice;
|
|
876
876
|
if (appliedToolChoice !== toolChoice) {
|
|
877
877
|
console.warn(
|
|
878
|
-
`[anthropic] callTools: ${normalizeAnthropicModelId(resolvedModel)}
|
|
879
|
-
`caller's 'required' downgraded to 'auto'`,
|
|
878
|
+
`[anthropic] callTools: ${normalizeAnthropicModelId(resolvedModel)} would reject a forced tool_choice (the API answers 400); ` +
|
|
879
|
+
`caller's 'required' downgraded to 'auto' before sending`,
|
|
880
880
|
);
|
|
881
881
|
}
|
|
882
882
|
const response = await this.apiCall(() =>
|
|
@@ -2128,7 +2128,7 @@ export class OpenRouterAgent extends LLMAgent {
|
|
|
2128
2128
|
requested === 'required' && anthropicRejectsForcedToolChoice(resolved) ? 'auto' : requested;
|
|
2129
2129
|
if (appliedToolChoice !== requested) {
|
|
2130
2130
|
console.warn(
|
|
2131
|
-
`[openrouter] callTools: ${resolved}
|
|
2131
|
+
`[openrouter] callTools: ${resolved} would reject a forced tool_choice (the API answers 400); caller's 'required' downgraded to 'auto' before sending`,
|
|
2132
2132
|
);
|
|
2133
2133
|
}
|
|
2134
2134
|
|
|
@@ -49,11 +49,25 @@ export type ModelRoles = Partial<Record<ModelRole, string>>;
|
|
|
49
49
|
// Generation Result
|
|
50
50
|
// =============================================================================
|
|
51
51
|
|
|
52
|
+
/**
|
|
53
|
+
* The same-exchange guard (ggui#404) ended this generation: the coding model
|
|
54
|
+
* made one identical tool exchange (same tool, same input, same result)
|
|
55
|
+
* `repeats` times, so the loop stopped instead of burning its remaining turns.
|
|
56
|
+
* Present ONLY when that guard ended the run — whether anything shipped is
|
|
57
|
+
* the compiled code's to say (the loop falls back to an earlier build).
|
|
58
|
+
*/
|
|
59
|
+
export interface SameExchangeBreak {
|
|
60
|
+
readonly tool: string;
|
|
61
|
+
readonly repeats: number;
|
|
62
|
+
}
|
|
63
|
+
|
|
52
64
|
export interface GenerationResult extends AdapterResult {
|
|
53
65
|
/** Number of generation passes the harness performed */
|
|
54
66
|
passesUsed: number;
|
|
55
67
|
/** Three-tier evaluation result (tier 0 + LLM tier 1+2 + visual) */
|
|
56
68
|
evalResult?: EvalResult;
|
|
69
|
+
/** Set only when the same-exchange guard ended the run (ggui#404); no key otherwise. */
|
|
70
|
+
sameExchangeBreak?: SameExchangeBreak;
|
|
57
71
|
/** Whether background improvement should be spawned (auto-improve mode) */
|
|
58
72
|
needsBackgroundImprovement?: boolean;
|
|
59
73
|
/** Whether at least one commit passed the self-check (compile + type check + lint) */
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
import type { GenerationProfileInput } from "../boilerplate/styling-profile.js";
|
|
22
22
|
import type { GadgetDescriptor, DataContract, JsonValue } from "@ggui-ai/protocol";
|
|
23
23
|
import type { Classification } from "../classifier/axes.js";
|
|
24
|
-
import type { EvalIssue, EvalTier, AxisCheck, RuntimeProbeStatus } from "../evaluation/types-public.js";
|
|
24
|
+
import type { EvalIssue, EvalTier, AxisCheck, ProbeHostLoad, RuntimeProbeStatus } from "../evaluation/types-public.js";
|
|
25
25
|
import type { LLMToolDef } from "../llm.js";
|
|
26
26
|
import type { CacheTier, HarnessFragment } from "../fragments/index.js";
|
|
27
27
|
import type { HarnessPolicy, ProcessMode } from "../policy.js";
|
|
@@ -140,14 +140,18 @@ export interface LLMEvaluator {
|
|
|
140
140
|
export interface RuntimeRenderOutcome {
|
|
141
141
|
/**
|
|
142
142
|
* Whether the probe actually executed. `issues` is only probe
|
|
143
|
-
* evidence when `status === "ran"` — an `infra-skipped
|
|
144
|
-
* `not-applicable` outcome carries zero evidence and
|
|
145
|
-
* scored as a pass by any consumer.
|
|
143
|
+
* evidence when `status === "ran"` — an `infra-skipped`,
|
|
144
|
+
* `not-applicable` or `timed-out` outcome carries zero evidence and
|
|
145
|
+
* MUST NOT be scored as a pass by any consumer.
|
|
146
146
|
*/
|
|
147
147
|
readonly status: RuntimeProbeStatus;
|
|
148
148
|
readonly issues: readonly EvalIssue[];
|
|
149
|
-
/** Populated for `infra-skipped` / `not-applicable` — why the probe didn't
|
|
149
|
+
/** Populated for `infra-skipped` / `not-applicable` / `timed-out` — why the probe didn't finish. */
|
|
150
150
|
readonly reason?: string;
|
|
151
|
+
/** `timed-out` only: how long the probe ran before it was stopped. */
|
|
152
|
+
readonly elapsedMs?: number;
|
|
153
|
+
/** Host load around the probe, when it ran isolated (absent for an in-process probe). */
|
|
154
|
+
readonly hostLoad?: ProbeHostLoad;
|
|
151
155
|
}
|
|
152
156
|
|
|
153
157
|
export interface RuntimeRenderCheck {
|
package/src/index.ts
CHANGED
|
@@ -21,7 +21,8 @@ export {
|
|
|
21
21
|
} from './create-ui-generator.js';
|
|
22
22
|
export type { CreateUiGeneratorOptions } from './create-ui-generator.js';
|
|
23
23
|
export type { ProviderRetryInfo } from './harness/llm-router.js';
|
|
24
|
-
export type { GenerationResult } from './harness/result-types.js';
|
|
24
|
+
export type { GenerationResult, SameExchangeBreak } from './harness/result-types.js';
|
|
25
|
+
export type { UiGenBuild } from './generator-build.js';
|
|
25
26
|
|
|
26
27
|
// Generator registry seam re-export. The interface + slug helpers live
|
|
27
28
|
// in `@ggui-ai/mcp-server-core`; the in-memory factory lives in
|