@zhixuan92/multi-model-agent-core 4.5.4 → 4.6.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/README.md +8 -3
- package/dist/escalation/delegate-with-escalation.d.ts +2 -2
- package/dist/escalation/delegate-with-escalation.d.ts.map +1 -1
- package/dist/escalation/delegate-with-escalation.js +11 -17
- package/dist/escalation/delegate-with-escalation.js.map +1 -1
- package/dist/escalation/fallback-helpers.d.ts +5 -5
- package/dist/escalation/fallback-helpers.d.ts.map +1 -1
- package/dist/escalation/fallback-helpers.js +5 -3
- package/dist/escalation/fallback-helpers.js.map +1 -1
- package/dist/events/event-builder.d.ts +36 -5
- package/dist/events/event-builder.d.ts.map +1 -1
- package/dist/events/event-builder.js +173 -31
- package/dist/events/event-builder.js.map +1 -1
- package/dist/events/observability-events.d.ts +6 -0
- package/dist/events/observability-events.d.ts.map +1 -1
- package/dist/events/observability-events.js +5 -0
- package/dist/events/observability-events.js.map +1 -1
- package/dist/events/telemetry-types.d.ts +10 -0
- package/dist/events/telemetry-types.d.ts.map +1 -1
- package/dist/events/verbose-log-channel.d.ts +7 -7
- package/dist/events/verbose-log-channel.js +10 -10
- package/dist/index.d.ts +9 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -2
- package/dist/index.js.map +1 -1
- package/dist/lifecycle/annotate-parser.d.ts +9 -0
- package/dist/lifecycle/annotate-parser.d.ts.map +1 -0
- package/dist/lifecycle/annotate-parser.js +83 -0
- package/dist/lifecycle/annotate-parser.js.map +1 -0
- package/dist/lifecycle/annotate-prompts.d.ts +9 -0
- package/dist/lifecycle/annotate-prompts.d.ts.map +1 -0
- package/dist/lifecycle/annotate-prompts.js +86 -0
- package/dist/lifecycle/annotate-prompts.js.map +1 -0
- package/dist/lifecycle/auto-register-context-block.d.ts +2 -2
- package/dist/lifecycle/auto-register-context-block.d.ts.map +1 -1
- package/dist/lifecycle/auto-register-context-block.js.map +1 -1
- package/dist/lifecycle/build-cancelled-result.d.ts +11 -0
- package/dist/lifecycle/build-cancelled-result.d.ts.map +1 -0
- package/dist/lifecycle/build-cancelled-result.js +27 -0
- package/dist/lifecycle/build-cancelled-result.js.map +1 -0
- package/dist/lifecycle/executor-output-types.d.ts +2 -2
- package/dist/lifecycle/executor-output-types.d.ts.map +1 -1
- package/dist/lifecycle/fallback-report.d.ts +2 -2
- package/dist/lifecycle/fallback-report.d.ts.map +1 -1
- package/dist/lifecycle/fallback-report.js.map +1 -1
- package/dist/lifecycle/findings-parser.d.ts +2 -0
- package/dist/lifecycle/findings-parser.d.ts.map +1 -1
- package/dist/lifecycle/findings-parser.js +9 -4
- package/dist/lifecycle/findings-parser.js.map +1 -1
- package/dist/lifecycle/git-toplevel.d.ts +12 -0
- package/dist/lifecycle/git-toplevel.d.ts.map +1 -0
- package/dist/lifecycle/git-toplevel.js +49 -0
- package/dist/lifecycle/git-toplevel.js.map +1 -0
- package/dist/lifecycle/handlers/annotator.d.ts +2 -1
- package/dist/lifecycle/handlers/annotator.d.ts.map +1 -1
- package/dist/lifecycle/handlers/annotator.js +225 -7
- package/dist/lifecycle/handlers/annotator.js.map +1 -1
- package/dist/lifecycle/handlers/baseline-handlers.d.ts +10 -5
- package/dist/lifecycle/handlers/baseline-handlers.d.ts.map +1 -1
- package/dist/lifecycle/handlers/baseline-handlers.js +206 -316
- package/dist/lifecycle/handlers/baseline-handlers.js.map +1 -1
- package/dist/lifecycle/handlers/enrich-runtime-result.d.ts +3 -0
- package/dist/lifecycle/handlers/enrich-runtime-result.d.ts.map +1 -0
- package/dist/lifecycle/handlers/enrich-runtime-result.js +191 -0
- package/dist/lifecycle/handlers/enrich-runtime-result.js.map +1 -0
- package/dist/lifecycle/handlers/git-commit-handler.d.ts +3 -2
- package/dist/lifecycle/handlers/git-commit-handler.d.ts.map +1 -1
- package/dist/lifecycle/handlers/git-commit-handler.js +139 -110
- package/dist/lifecycle/handlers/git-commit-handler.js.map +1 -1
- package/dist/lifecycle/handlers/prepare-execution-context-handler.d.ts +7 -13
- package/dist/lifecycle/handlers/prepare-execution-context-handler.d.ts.map +1 -1
- package/dist/lifecycle/handlers/prepare-execution-context-handler.js +72 -49
- package/dist/lifecycle/handlers/prepare-execution-context-handler.js.map +1 -1
- package/dist/lifecycle/handlers/register-context-block-handlers.d.ts +2 -1
- package/dist/lifecycle/handlers/register-context-block-handlers.d.ts.map +1 -1
- package/dist/lifecycle/handlers/register-context-block-handlers.js +35 -14
- package/dist/lifecycle/handlers/register-context-block-handlers.js.map +1 -1
- package/dist/lifecycle/handlers/review-handler.d.ts +2 -1
- package/dist/lifecycle/handlers/review-handler.d.ts.map +1 -1
- package/dist/lifecycle/handlers/review-handler.js +152 -154
- package/dist/lifecycle/handlers/review-handler.js.map +1 -1
- package/dist/lifecycle/handlers/rework-handler.d.ts +2 -1
- package/dist/lifecycle/handlers/rework-handler.d.ts.map +1 -1
- package/dist/lifecycle/handlers/rework-handler.js +62 -14
- package/dist/lifecycle/handlers/rework-handler.js.map +1 -1
- package/dist/lifecycle/handlers/task-executor.d.ts +5 -4
- package/dist/lifecycle/handlers/task-executor.d.ts.map +1 -1
- package/dist/lifecycle/handlers/task-executor.js +153 -74
- package/dist/lifecycle/handlers/task-executor.js.map +1 -1
- package/dist/lifecycle/handlers/terminal-handlers.d.ts +22 -0
- package/dist/lifecycle/handlers/terminal-handlers.d.ts.map +1 -1
- package/dist/lifecycle/handlers/terminal-handlers.js +86 -5
- package/dist/lifecycle/handlers/terminal-handlers.js.map +1 -1
- package/dist/lifecycle/lifecycle-context.d.ts +31 -3
- package/dist/lifecycle/lifecycle-context.d.ts.map +1 -1
- package/dist/lifecycle/lifecycle-dispatcher.d.ts +18 -19
- package/dist/lifecycle/lifecycle-dispatcher.d.ts.map +1 -1
- package/dist/lifecycle/lifecycle-dispatcher.js +38 -22
- package/dist/lifecycle/lifecycle-dispatcher.js.map +1 -1
- package/dist/lifecycle/lifecycle-driver.d.ts +15 -8
- package/dist/lifecycle/lifecycle-driver.d.ts.map +1 -1
- package/dist/lifecycle/lifecycle-driver.js +110 -29
- package/dist/lifecycle/lifecycle-driver.js.map +1 -1
- package/dist/lifecycle/merge-stage-stats.d.ts +3 -3
- package/dist/lifecycle/merge-stage-stats.d.ts.map +1 -1
- package/dist/lifecycle/merge-stage-stats.js +2 -2
- package/dist/lifecycle/merge-stage-stats.js.map +1 -1
- package/dist/lifecycle/perform-implementation.d.ts +3 -0
- package/dist/lifecycle/perform-implementation.d.ts.map +1 -0
- package/dist/lifecycle/perform-implementation.js +264 -0
- package/dist/lifecycle/perform-implementation.js.map +1 -0
- package/dist/lifecycle/repo-hygiene.d.ts +14 -0
- package/dist/lifecycle/repo-hygiene.d.ts.map +1 -0
- package/dist/lifecycle/repo-hygiene.js +71 -0
- package/dist/lifecycle/repo-hygiene.js.map +1 -0
- package/dist/lifecycle/shared-compute.d.ts +4 -4
- package/dist/lifecycle/shared-compute.d.ts.map +1 -1
- package/dist/lifecycle/shared-compute.js +1 -1
- package/dist/lifecycle/shared-compute.js.map +1 -1
- package/dist/lifecycle/stage-io.d.ts +139 -0
- package/dist/lifecycle/stage-io.d.ts.map +1 -0
- package/dist/lifecycle/stage-io.js +20 -0
- package/dist/lifecycle/stage-io.js.map +1 -0
- package/dist/lifecycle/stage-plan-builder.d.ts +3 -3
- package/dist/lifecycle/stage-plan-builder.d.ts.map +1 -1
- package/dist/lifecycle/stage-plan-builder.js +157 -128
- package/dist/lifecycle/stage-plan-builder.js.map +1 -1
- package/dist/lifecycle/stage-plan-types.d.ts +5 -21
- package/dist/lifecycle/stage-plan-types.d.ts.map +1 -1
- package/dist/lifecycle/stage-progression.d.ts +3 -15
- package/dist/lifecycle/stage-progression.d.ts.map +1 -1
- package/dist/lifecycle/stage-progression.js +48 -91
- package/dist/lifecycle/stage-progression.js.map +1 -1
- package/dist/lifecycle/task-completion-summary.d.ts +2 -2
- package/dist/lifecycle/task-completion-summary.d.ts.map +1 -1
- package/dist/lifecycle/task-completion-summary.js +0 -6
- package/dist/lifecycle/task-completion-summary.js.map +1 -1
- package/dist/lifecycle/task-executor.d.ts +23 -0
- package/dist/lifecycle/task-executor.d.ts.map +1 -1
- package/dist/lifecycle/task-executor.js +77 -5
- package/dist/lifecycle/task-executor.js.map +1 -1
- package/dist/lifecycle/task-grouping.d.ts +19 -0
- package/dist/lifecycle/task-grouping.d.ts.map +1 -0
- package/dist/lifecycle/task-grouping.js +48 -0
- package/dist/lifecycle/task-grouping.js.map +1 -0
- package/dist/lifecycle/task-runner.d.ts +20 -7
- package/dist/lifecycle/task-runner.d.ts.map +1 -1
- package/dist/lifecycle/task-runner.js +42 -278
- package/dist/lifecycle/task-runner.js.map +1 -1
- package/dist/lifecycle/tool-config-types.d.ts +9 -0
- package/dist/lifecycle/tool-config-types.d.ts.map +1 -1
- package/dist/lifecycle/worker-output-contract.d.ts +9 -15
- package/dist/lifecycle/worker-output-contract.d.ts.map +1 -1
- package/dist/lifecycle/worker-output-contract.js +45 -30
- package/dist/lifecycle/worker-output-contract.js.map +1 -1
- package/dist/providers/assemble-run-result.d.ts +3 -3
- package/dist/providers/assemble-run-result.d.ts.map +1 -1
- package/dist/providers/assemble-run-result.js +20 -9
- package/dist/providers/assemble-run-result.js.map +1 -1
- package/dist/providers/claude-session.d.ts.map +1 -1
- package/dist/providers/claude-session.js +1 -0
- package/dist/providers/claude-session.js.map +1 -1
- package/dist/providers/claude.js.map +1 -1
- package/dist/providers/codex-cli-launch.js +1 -1
- package/dist/providers/codex-cli-launch.js.map +1 -1
- package/dist/providers/codex-cli-session.d.ts +4 -1
- package/dist/providers/codex-cli-session.d.ts.map +1 -1
- package/dist/providers/codex-cli-session.js +73 -46
- package/dist/providers/codex-cli-session.js.map +1 -1
- package/dist/providers/codex.js.map +1 -1
- package/dist/providers/index.d.ts +1 -0
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +1 -0
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/normalize-claude.d.ts +2 -0
- package/dist/providers/normalize-claude.d.ts.map +1 -1
- package/dist/providers/normalize-claude.js +1 -0
- package/dist/providers/normalize-claude.js.map +1 -1
- package/dist/providers/run-annotator-turn.d.ts +24 -0
- package/dist/providers/run-annotator-turn.d.ts.map +1 -0
- package/dist/providers/run-annotator-turn.js +43 -0
- package/dist/providers/run-annotator-turn.js.map +1 -0
- package/dist/providers/run-worker-turn.d.ts +26 -0
- package/dist/providers/run-worker-turn.d.ts.map +1 -0
- package/dist/providers/run-worker-turn.js +58 -0
- package/dist/providers/run-worker-turn.js.map +1 -0
- package/dist/providers/runner-types.d.ts +1 -1
- package/dist/providers/runner-types.d.ts.map +1 -1
- package/dist/reporting/headline-composer.d.ts +3 -3
- package/dist/reporting/headline-composer.d.ts.map +1 -1
- package/dist/review/index.d.ts +4 -3
- package/dist/review/index.d.ts.map +1 -1
- package/dist/review/index.js +7 -4
- package/dist/review/index.js.map +1 -1
- package/dist/review/parse-review-report.d.ts +7 -1
- package/dist/review/parse-review-report.d.ts.map +1 -1
- package/dist/review/parse-review-report.js +13 -21
- package/dist/review/parse-review-report.js.map +1 -1
- package/dist/review/review-verdict-mapping.d.ts +3 -3
- package/dist/review/review-verdict-mapping.d.ts.map +1 -1
- package/dist/review/review-verdict-mapping.js +1 -1
- package/dist/review/review-verdict-mapping.js.map +1 -1
- package/dist/review/run-reviewer.d.ts +40 -0
- package/dist/review/run-reviewer.d.ts.map +1 -0
- package/dist/review/run-reviewer.js +54 -0
- package/dist/review/run-reviewer.js.map +1 -0
- package/dist/review/templates/quality-review.d.ts +5 -0
- package/dist/review/templates/quality-review.d.ts.map +1 -1
- package/dist/review/templates/quality-review.js +35 -25
- package/dist/review/templates/quality-review.js.map +1 -1
- package/dist/review/templates/spec-review.d.ts +6 -0
- package/dist/review/templates/spec-review.d.ts.map +1 -1
- package/dist/review/templates/spec-review.js +36 -8
- package/dist/review/templates/spec-review.js.map +1 -1
- package/dist/stores/batch-cache.d.ts +3 -3
- package/dist/stores/batch-cache.d.ts.map +1 -1
- package/dist/stores/batch-cache.js.map +1 -1
- package/dist/stores/batch-registry.d.ts +31 -0
- package/dist/stores/batch-registry.d.ts.map +1 -1
- package/dist/stores/batch-registry.js +12 -0
- package/dist/stores/batch-registry.js.map +1 -1
- package/dist/tools/debug/tool-config.js +1 -1
- package/dist/tools/debug/tool-config.js.map +1 -1
- package/dist/tools/delegate/tool-config.d.ts.map +1 -1
- package/dist/tools/delegate/tool-config.js +3 -1
- package/dist/tools/delegate/tool-config.js.map +1 -1
- package/dist/tools/execute-plan/tool-config.d.ts.map +1 -1
- package/dist/tools/execute-plan/tool-config.js +3 -1
- package/dist/tools/execute-plan/tool-config.js.map +1 -1
- package/dist/tools/investigate/tool-config.js +1 -1
- package/dist/tools/investigate/tool-config.js.map +1 -1
- package/dist/tools/retry/tool-config.js.map +1 -1
- package/dist/types/run-result.d.ts +164 -213
- package/dist/types/run-result.d.ts.map +1 -1
- package/dist/types/run-result.js +17 -0
- package/dist/types/run-result.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/lifecycle/handlers/derive-terminal-status.d.ts +0 -10
- package/dist/lifecycle/handlers/derive-terminal-status.d.ts.map +0 -1
- package/dist/lifecycle/handlers/derive-terminal-status.js +0 -35
- package/dist/lifecycle/handlers/derive-terminal-status.js.map +0 -1
- package/dist/lifecycle/handlers/files-written-cross-check.d.ts +0 -27
- package/dist/lifecycle/handlers/files-written-cross-check.d.ts.map +0 -1
- package/dist/lifecycle/handlers/files-written-cross-check.js +0 -91
- package/dist/lifecycle/handlers/files-written-cross-check.js.map +0 -1
- package/dist/lifecycle/handlers/verify-stage.d.ts +0 -37
- package/dist/lifecycle/handlers/verify-stage.d.ts.map +0 -1
- package/dist/lifecycle/handlers/verify-stage.js +0 -208
- package/dist/lifecycle/handlers/verify-stage.js.map +0 -1
- package/dist/review/default-engines.d.ts +0 -3
- package/dist/review/default-engines.d.ts.map +0 -1
- package/dist/review/default-engines.js +0 -22
- package/dist/review/default-engines.js.map +0 -1
- package/dist/review/reviewer-engine.d.ts +0 -53
- package/dist/review/reviewer-engine.d.ts.map +0 -1
- package/dist/review/reviewer-engine.js +0 -47
- package/dist/review/reviewer-engine.js.map +0 -1
- package/dist/review/reviewer-output-parser.d.ts +0 -12
- package/dist/review/reviewer-output-parser.d.ts.map +0 -1
- package/dist/review/reviewer-output-parser.js +0 -213
- package/dist/review/reviewer-output-parser.js.map +0 -1
- package/dist/review/reviewer-prompt-builder.d.ts +0 -21
- package/dist/review/reviewer-prompt-builder.d.ts.map +0 -1
- package/dist/review/reviewer-prompt-builder.js +0 -22
- package/dist/review/reviewer-prompt-builder.js.map +0 -1
- package/dist/review/templates/annotate-completion.d.ts +0 -12
- package/dist/review/templates/annotate-completion.d.ts.map +0 -1
- package/dist/review/templates/annotate-completion.js +0 -72
- package/dist/review/templates/annotate-completion.js.map +0 -1
package/README.md
CHANGED
|
@@ -228,9 +228,14 @@ mmagent logs --follow --batch=<id> # tail + filter
|
|
|
228
228
|
|
|
229
229
|
As of 3.4.0 every task-execution event the worker emits to the verbose stderr stream is also written to the JSONL log via a single `emit(TaskEvent)` writer — schema parity across both sinks. Crash/disconnect events (`startup`, `request_start`, `request_complete`, `shutdown`, `error`) are written unconditionally; per-task events (`heartbeat`, `stage_change`, `tool_call`, `turn_complete`, etc.) flow through the same writer.
|
|
230
230
|
|
|
231
|
-
## What's new in 4.
|
|
232
|
-
|
|
233
|
-
- **`
|
|
231
|
+
## What's new in 4.6.0
|
|
232
|
+
|
|
233
|
+
- **`isLlmStage: boolean` on the internal `StageEntryInternal` shape** (required, no default — compile-time enforced). `rollupByTier` filters out non-LLM stages (synthetic review, commit) before computing tier rollup, so synthetic placeholders no longer corrupt `tierUsage.<tier>.model` under last-seen semantics.
|
|
234
|
+
- **`StageModelMissingError` + `safeBuild` wrapper** around stage builders. Missing-model errors drop the offending stage with a `validation_warnings` diagnostic; the rest of the event ships.
|
|
235
|
+
- **Tier-uniformity invariant.** Two LLM stages on the same tier with different models trigger an `R-TIER-MODEL-DIVERGENCE` diagnostic and the tier is omitted from `tierUsage`.
|
|
236
|
+
- **`RunAnnotatorResult` and `RunReviewerResult` carry full token attribution** (`inputTokens`, `outputTokens`, `cachedReadTokens`, `cachedNonReadTokens`) plus `model` — read from `turn.usage` and `turn.model` on the `Session.send` return.
|
|
237
|
+
- **Cross-tier reviewer policy** via `invertedReviewerTier()` helper exported from `review/run-reviewer.ts`. Single-tier deployments fall back to the implementer tier.
|
|
238
|
+
- **`buildSyntheticReviewStage(findings)`** continues to emit `costUSD: 0` and `model: 'custom'` with `isLlmStage: false`.
|
|
234
239
|
|
|
235
240
|
Full history: [CHANGELOG](https://github.com/zhixuan312/multi-model-agent/blob/master/CHANGELOG.md).
|
|
236
241
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TaskSpec,
|
|
1
|
+
import type { TaskSpec, RuntimeRunResult, Provider, AgentType } from '../types.js';
|
|
2
2
|
import type { InternalRunnerEvent } from '../providers/runner-types.js';
|
|
3
3
|
import type { EventEmitter } from '../events/event-emitter.js';
|
|
4
4
|
export interface DelegateOptions {
|
|
@@ -48,5 +48,5 @@ export interface DelegateOptions {
|
|
|
48
48
|
*/
|
|
49
49
|
stageLabel?: string;
|
|
50
50
|
}
|
|
51
|
-
export declare function delegateWithEscalation(task: TaskSpec, chain: Provider[], options?: DelegateOptions): Promise<
|
|
51
|
+
export declare function delegateWithEscalation(task: TaskSpec, chain: Provider[], options?: DelegateOptions): Promise<RuntimeRunResult>;
|
|
52
52
|
//# sourceMappingURL=delegate-with-escalation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delegate-with-escalation.d.ts","sourceRoot":"","sources":["../../src/escalation/delegate-with-escalation.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,
|
|
1
|
+
{"version":3,"file":"delegate-with-escalation.d.ts","sourceRoot":"","sources":["../../src/escalation/delegate-with-escalation.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACnF,OAAO,KAAK,EAEV,mBAAmB,EAGpB,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAe/D,MAAM,WAAW,eAAe;IAC9B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAClD;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;;;OAIG;IACH,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB;;;;;OAKG;IACH,GAAG,CAAC,EAAE,YAAY,CAAC;IACnB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAiBD,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,QAAQ,EAAE,EACjB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,gBAAgB,CAAC,CAmL3B"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// lifecycle review-chain handlers. This function only handles transient
|
|
5
5
|
// retries (api_error / network_error).
|
|
6
6
|
import { retryableFor } from '../error-codes.js';
|
|
7
|
-
import {
|
|
7
|
+
import { extractToolName } from '../providers/stall-detector.js';
|
|
8
8
|
import { assembleRunResult } from '../providers/assemble-run-result.js';
|
|
9
9
|
import { HUMAN_LABEL } from '../lifecycle/stage-labels.js';
|
|
10
10
|
function deriveCause(status, errorCode) {
|
|
@@ -73,11 +73,12 @@ export async function delegateWithEscalation(task, chain, options = {}) {
|
|
|
73
73
|
: remainingClamped;
|
|
74
74
|
}
|
|
75
75
|
// v4.4: ProviderConfig.type is one of: 'claude' | 'codex'.
|
|
76
|
-
const
|
|
76
|
+
const cfg = provider.config;
|
|
77
|
+
const cfgType = cfg.type ?? 'codex';
|
|
77
78
|
const providerTypeName = cfgType === 'claude' ? 'claude' : 'codex';
|
|
78
79
|
safeSink?.({
|
|
79
80
|
kind: 'worker_start',
|
|
80
|
-
model:
|
|
81
|
+
model: cfg.model ?? 'unknown',
|
|
81
82
|
providerType: providerTypeName,
|
|
82
83
|
tier: options.assignedTier ?? 'standard',
|
|
83
84
|
});
|
|
@@ -175,25 +176,18 @@ export async function delegateWithEscalation(task, chain, options = {}) {
|
|
|
175
176
|
best = a.result;
|
|
176
177
|
}
|
|
177
178
|
}
|
|
178
|
-
|
|
179
|
-
//
|
|
180
|
-
//
|
|
181
|
-
|
|
182
|
-
const
|
|
183
|
-
const finalStatus = baseStatus === 'incomplete' &&
|
|
184
|
-
best.workerStatus === 'done' &&
|
|
185
|
-
outputIsSubstantive &&
|
|
186
|
-
(best.filesWritten.length > 0 || hasCompletedWork(best.toolCalls) || hasShellVerification || task.skipCompletionHeuristic === true)
|
|
187
|
-
? 'ok'
|
|
188
|
-
: baseStatus;
|
|
189
|
-
const wasPromoted = finalStatus === 'ok' && baseStatus === 'incomplete';
|
|
179
|
+
// v5: escalation no longer gates on workerSelfAssessment. Annotate is the
|
|
180
|
+
// single point of truth for `completed` (spec §5.7 + §9 M1/M3 fixes).
|
|
181
|
+
// Escalation only records attempts and selects the best one; status flows
|
|
182
|
+
// through unchanged to annotate which makes the final verdict.
|
|
183
|
+
const finalStatus = best.status === 'ok' ? 'incomplete' : best.status;
|
|
190
184
|
const terminationReason = {
|
|
191
185
|
cause: deriveCause(finalStatus, best.errorCode),
|
|
192
186
|
turnsUsed: best.turns,
|
|
193
187
|
hasFileArtifacts: best.filesWritten.length > 0,
|
|
194
188
|
usedShell: best.toolCalls.some(tc => extractToolName(tc) === 'runShell'),
|
|
195
|
-
workerSelfAssessment: best.workerStatus ?? null,
|
|
196
|
-
wasPromoted,
|
|
189
|
+
workerSelfAssessment: best.workerStatus ?? null, // truthful read; NOT stamped (M3 fix)
|
|
190
|
+
wasPromoted: false,
|
|
197
191
|
};
|
|
198
192
|
return {
|
|
199
193
|
...best,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delegate-with-escalation.js","sourceRoot":"","sources":["../../src/escalation/delegate-with-escalation.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,mEAAmE;AACnE,iEAAiE;AACjE,wEAAwE;AACxE,uCAAuC;AAWvC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,
|
|
1
|
+
{"version":3,"file":"delegate-with-escalation.js","sourceRoot":"","sources":["../../src/escalation/delegate-with-escalation.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import type { Provider, AgentType,
|
|
1
|
+
import type { Provider, AgentType, RuntimeRunResult } from '../types.js';
|
|
2
2
|
/** Two providers are "identical" iff they resolve to the same effective backend
|
|
3
3
|
* (type + model + baseUrl + apiKey wiring). When an operator points both tiers
|
|
4
4
|
* at the same backend (one-provider deployment), cross-tier fallback is
|
|
5
5
|
* structurally pointless — alt would just hit the same place. Comparing the
|
|
6
6
|
* serialized config catches this without a new operator-facing flag. */
|
|
7
7
|
export declare function providersIdentical(a: Provider, b: Provider): boolean;
|
|
8
|
-
/** Lifecycle helper: builds the synthetic
|
|
8
|
+
/** Lifecycle helper: builds the synthetic RuntimeRunResult expected when both tiers are
|
|
9
9
|
* unavailable. Status is the new 'unavailable' value (NOT 'api_error') so
|
|
10
10
|
* re-passing the synthetic into runWithFallback's isTransportFailure cannot
|
|
11
11
|
* retrigger fallback.
|
|
12
12
|
*
|
|
13
|
-
* IMPORTANT: This shape MUST satisfy `
|
|
13
|
+
* IMPORTANT: This shape MUST satisfy `RuntimeRunResult` (see types.ts). Confirmed
|
|
14
14
|
* required fields: output, status, usage, turns, filesRead, filesWritten,
|
|
15
|
-
* toolCalls, outputIsDiagnostic, escalationLog. All other
|
|
15
|
+
* toolCalls, outputIsDiagnostic, escalationLog. All other RuntimeRunResult fields
|
|
16
16
|
* are optional. */
|
|
17
|
-
export declare function makeSyntheticRunResult(assigned: AgentType, errorCode: string):
|
|
17
|
+
export declare function makeSyntheticRunResult(assigned: AgentType, errorCode: string): RuntimeRunResult;
|
|
18
18
|
export declare function isReviewTransportFailure(r: {
|
|
19
19
|
status?: string;
|
|
20
20
|
}): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fallback-helpers.d.ts","sourceRoot":"","sources":["../../src/escalation/fallback-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"fallback-helpers.d.ts","sourceRoot":"","sources":["../../src/escalation/fallback-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEzE;;;;yEAIyE;AACzE,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAEpE;AAED;;;;;;;;oBAQoB;AACpB,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,gBAAgB,CAiB/F;AAED,wBAAgB,wBAAwB,CACtC,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GACrB,OAAO,CAET;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,SAAS,GAAG,MAAM,CAMrD"}
|
|
@@ -6,14 +6,14 @@
|
|
|
6
6
|
export function providersIdentical(a, b) {
|
|
7
7
|
return JSON.stringify(a.config) === JSON.stringify(b.config);
|
|
8
8
|
}
|
|
9
|
-
/** Lifecycle helper: builds the synthetic
|
|
9
|
+
/** Lifecycle helper: builds the synthetic RuntimeRunResult expected when both tiers are
|
|
10
10
|
* unavailable. Status is the new 'unavailable' value (NOT 'api_error') so
|
|
11
11
|
* re-passing the synthetic into runWithFallback's isTransportFailure cannot
|
|
12
12
|
* retrigger fallback.
|
|
13
13
|
*
|
|
14
|
-
* IMPORTANT: This shape MUST satisfy `
|
|
14
|
+
* IMPORTANT: This shape MUST satisfy `RuntimeRunResult` (see types.ts). Confirmed
|
|
15
15
|
* required fields: output, status, usage, turns, filesRead, filesWritten,
|
|
16
|
-
* toolCalls, outputIsDiagnostic, escalationLog. All other
|
|
16
|
+
* toolCalls, outputIsDiagnostic, escalationLog. All other RuntimeRunResult fields
|
|
17
17
|
* are optional. */
|
|
18
18
|
export function makeSyntheticRunResult(assigned, errorCode) {
|
|
19
19
|
return {
|
|
@@ -29,6 +29,8 @@ export function makeSyntheticRunResult(assigned, errorCode) {
|
|
|
29
29
|
filesWritten: [],
|
|
30
30
|
toolCalls: [],
|
|
31
31
|
escalationLog: [],
|
|
32
|
+
actualCostUSD: 0,
|
|
33
|
+
directoriesListed: [],
|
|
32
34
|
};
|
|
33
35
|
}
|
|
34
36
|
export function isReviewTransportFailure(r) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fallback-helpers.js","sourceRoot":"","sources":["../../src/escalation/fallback-helpers.ts"],"names":[],"mappings":"AAEA;;;;yEAIyE;AACzE,MAAM,UAAU,kBAAkB,CAAC,CAAW,EAAE,CAAW;IACzD,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AAC/D,CAAC;AAED;;;;;;;;oBAQoB;AACpB,MAAM,UAAU,sBAAsB,CAAC,QAAmB,EAAE,SAAiB;IAC3E,OAAO;QACL,MAAM,EAAE,aAAa;QACrB,MAAM,EAAE,EAAE;QACV,kBAAkB,EAAE,IAAI;QACxB,KAAK,EAAE,qDAAqD,QAAQ,GAAG;QACvE,SAAS;QACT,SAAS,EAAE,KAAK;QAChB,KAAK,EAAE,CAAC;QACR,KAAK,EAAE,EAAE,WAAW,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,mBAAmB,EAAE,CAAC,EAAE;QACvF,SAAS,EAAE,EAAE;QACb,YAAY,EAAE,EAAE;QAChB,SAAS,EAAE,EAAE;QACb,aAAa,EAAE,EAAE;
|
|
1
|
+
{"version":3,"file":"fallback-helpers.js","sourceRoot":"","sources":["../../src/escalation/fallback-helpers.ts"],"names":[],"mappings":"AAEA;;;;yEAIyE;AACzE,MAAM,UAAU,kBAAkB,CAAC,CAAW,EAAE,CAAW;IACzD,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AAC/D,CAAC;AAED;;;;;;;;oBAQoB;AACpB,MAAM,UAAU,sBAAsB,CAAC,QAAmB,EAAE,SAAiB;IAC3E,OAAO;QACL,MAAM,EAAE,aAAa;QACrB,MAAM,EAAE,EAAE;QACV,kBAAkB,EAAE,IAAI;QACxB,KAAK,EAAE,qDAAqD,QAAQ,GAAG;QACvE,SAAS;QACT,SAAS,EAAE,KAAK;QAChB,KAAK,EAAE,CAAC;QACR,KAAK,EAAE,EAAE,WAAW,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,mBAAmB,EAAE,CAAC,EAAE;QACvF,SAAS,EAAE,EAAE;QACb,YAAY,EAAE,EAAE;QAChB,SAAS,EAAE,EAAE;QACb,aAAa,EAAE,EAAE;QACjB,aAAa,EAAE,CAAC;QAChB,iBAAiB,EAAE,EAAE;KACtB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,wBAAwB,CACtC,CAAsB;IAEtB,OAAO,CAAC,CAAC,MAAM,KAAK,WAAW,IAAI,CAAC,CAAC,MAAM,KAAK,4BAA4B,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC;AACzG,CAAC;AAED,MAAM,UAAU,SAAS,CAAI,CAAgB;IAC3C,IAAI,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC;IACjB,MAAM,KAAK,GAAI,CAA0C,CAAC,KAAK,IAAI,EAAE,CAAC;IACtE,MAAM,KAAK,GAAI,CAAwB,CAAC,KAAK,IAAI,CAAC,CAAC;IACnD,MAAM,YAAY,GAAG,CAAE,CAAkC,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC;IAC1F,OAAO,KAAK,GAAG,YAAY,GAAG,CAAC,KAAK,CAAC,WAAW,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC;AAChE,CAAC"}
|
|
@@ -1,24 +1,55 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { RuntimeRunResult } from '../types.js';
|
|
2
|
+
import type { StageGate } from '../lifecycle/stage-io.js';
|
|
2
3
|
import { type WireTelemetryRecord } from './telemetry-types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Thrown when a stage marked `isLlmStage: true` arrives at the builder
|
|
6
|
+
* with no model identifier. Caught one level up by the stage-build loop
|
|
7
|
+
* (Task A5b) and converted into a `validation_warnings` diagnostic; the
|
|
8
|
+
* offending stage is dropped from the emitted event but the rest of the
|
|
9
|
+
* event still ships. Per spec D5 + §6.
|
|
10
|
+
*/
|
|
11
|
+
export declare class StageModelMissingError extends Error {
|
|
12
|
+
readonly stageName: string;
|
|
13
|
+
constructor(stageName: string);
|
|
14
|
+
}
|
|
3
15
|
export interface BuildContext {
|
|
4
16
|
route: 'delegate' | 'audit' | 'review' | 'debug' | 'execute-plan' | 'retry' | 'investigate' | 'research' | 'register-context-block';
|
|
5
17
|
taskSpec: {
|
|
6
18
|
filePaths?: string[];
|
|
7
19
|
subtype?: string;
|
|
8
20
|
};
|
|
9
|
-
runResult:
|
|
21
|
+
runResult: RuntimeRunResult;
|
|
10
22
|
realFilesChanged: string[];
|
|
11
23
|
client: string;
|
|
12
24
|
mainModel: string | null;
|
|
13
25
|
reviewPolicy?: 'full' | 'quality_only' | 'diff_only' | 'none';
|
|
14
26
|
verifyCommandPresent?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* v5 — per-stage gates from LifecycleState. When present, the wire builder
|
|
29
|
+
* cross-checks each stage's runResult.stageStats against gates[name].telemetry
|
|
30
|
+
* and prefers the gate's values for `costUSD`, `durationMs`, `turnsUsed`,
|
|
31
|
+
* `stopReason` (the canonical v5 source). stageStats supplies the remaining
|
|
32
|
+
* fields (tokens, tool calls, files read/written) because they're not on the
|
|
33
|
+
* gate's telemetry block.
|
|
34
|
+
*/
|
|
35
|
+
gates?: Record<string, StageGate<unknown>>;
|
|
15
36
|
}
|
|
16
37
|
export declare function buildTaskCompletedEvent(ctx: BuildContext): WireTelemetryRecord;
|
|
17
38
|
/**
|
|
18
39
|
* Wire payload builder. Internal record fields match the wire schema 1:1
|
|
19
40
|
* after the v4.0.3 rename (mainModel/mainModelFamily everywhere — DB column
|
|
20
|
-
* is `main_model`, header is `X-MMA-Main-Model
|
|
21
|
-
*
|
|
41
|
+
* is `main_model`, header is `X-MMA-Main-Model`).
|
|
42
|
+
*
|
|
43
|
+
* v5 — this used to be a `as unknown as WireTelemetryRecord` passthrough.
|
|
44
|
+
* The translator is now real: the internal record is passed through Zod
|
|
45
|
+
* (`WireTelemetryRecordSchema`) so the wire payload is schema-validated at
|
|
46
|
+
* the egress boundary. When the schema rejects, we fall back to the
|
|
47
|
+
* passthrough to preserve "best-effort telemetry" semantics — but the
|
|
48
|
+
* validation failure is observable on bus emits so backend can detect drift
|
|
49
|
+
* before the warehouse 400s. Callers that need strict validation should
|
|
50
|
+
* call `WireTelemetryRecordSchema.parse` directly.
|
|
22
51
|
*/
|
|
23
|
-
export declare function buildWirePayload(internalRecord: Record<string, unknown
|
|
52
|
+
export declare function buildWirePayload(internalRecord: Record<string, unknown>, opts?: {
|
|
53
|
+
onValidationError?: (err: unknown) => void;
|
|
54
|
+
}): WireTelemetryRecord;
|
|
24
55
|
//# sourceMappingURL=event-builder.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-builder.d.ts","sourceRoot":"","sources":["../../src/events/event-builder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"event-builder.d.ts","sourceRoot":"","sources":["../../src/events/event-builder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAiB,MAAM,aAAa,CAAC;AAEnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAG1D,OAAO,EAAkH,KAAK,mBAAmB,EAA6B,MAAM,sBAAsB,CAAC;AAmB3M;;;;;;GAMG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;aACnB,SAAS,EAAE,MAAM;gBAAjB,SAAS,EAAE,MAAM;CAI9C;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,cAAc,GAAG,OAAO,GAAG,aAAa,GAAG,UAAU,GAAG,wBAAwB,CAAC;IACpI,QAAQ,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACrD,SAAS,EAAE,gBAAgB,CAAC;IAC5B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,GAAG,cAAc,GAAG,WAAW,GAAG,MAAM,CAAC;IAC9D,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;CAC5C;AA0ED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,YAAY,GAAG,mBAAmB,CAuL9E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAC9B,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACvC,IAAI,CAAC,EAAE;IAAE,iBAAiB,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAA;CAAE,GACpD,mBAAmB,CAcrB"}
|
|
@@ -1,13 +1,45 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
2
|
import { normalizeModel } from './normalize.js';
|
|
3
3
|
import { classifyConcern } from './concern-classifier.js';
|
|
4
|
-
import { ErrorCode } from './telemetry-types.js';
|
|
4
|
+
import { ErrorCode, WireTelemetryRecordSchema } from './telemetry-types.js';
|
|
5
5
|
import { bucketFindingsBySeverity } from '../reporting/severity.js';
|
|
6
6
|
import { rollupByTier, sumTokens } from '../bounded-execution/cost-rollup.js';
|
|
7
7
|
import { priceTokens, resolveRateCard } from '../bounded-execution/cost-compute.js';
|
|
8
8
|
import { clampStageCost, clampTaskCost, clampInputTokens, clampOutputTokens, clampCachedTokens, clampToolCallCount, clampFilesReadCount, clampFilesWrittenCount, clampTurnCount, clampDurationMsStage, clampDurationMsTotal, } from './clamp.js';
|
|
9
|
+
/**
|
|
10
|
+
* Thrown when a stage marked `isLlmStage: true` arrives at the builder
|
|
11
|
+
* with no model identifier. Caught one level up by the stage-build loop
|
|
12
|
+
* (Task A5b) and converted into a `validation_warnings` diagnostic; the
|
|
13
|
+
* offending stage is dropped from the emitted event but the rest of the
|
|
14
|
+
* event still ships. Per spec D5 + §6.
|
|
15
|
+
*/
|
|
16
|
+
export class StageModelMissingError extends Error {
|
|
17
|
+
stageName;
|
|
18
|
+
constructor(stageName) {
|
|
19
|
+
super(`Stage '${stageName}' is marked isLlmStage:true but raw.model is null.`);
|
|
20
|
+
this.stageName = stageName;
|
|
21
|
+
this.name = 'StageModelMissingError';
|
|
22
|
+
}
|
|
23
|
+
}
|
|
9
24
|
const REVIEWED_ROUTES = new Set(['delegate', 'audit', 'review', 'debug', 'execute-plan', 'investigate']);
|
|
10
25
|
const QUALITY_ONLY_ROUTES = new Set(['audit', 'review', 'debug', 'investigate']);
|
|
26
|
+
/**
|
|
27
|
+
* Catches StageModelMissingError thrown by LLM stage builders and converts
|
|
28
|
+
* it into a validation warning. The stage is dropped from the emitted event,
|
|
29
|
+
* but the rest of the event still ships. Per spec §6 + task A5b.
|
|
30
|
+
*/
|
|
31
|
+
function safeBuild(name, fn, validationWarnings) {
|
|
32
|
+
try {
|
|
33
|
+
return fn();
|
|
34
|
+
}
|
|
35
|
+
catch (e) {
|
|
36
|
+
if (e instanceof StageModelMissingError) {
|
|
37
|
+
validationWarnings.push({ path: `stages.${name}`, rule: 'StageModelMissingError' });
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
throw e;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
11
43
|
/** Read findings from the v4.4 lifecycle sources:
|
|
12
44
|
* - structuredReport.findings → read-only routes (audit/review/debug/investigate/research/explore)
|
|
13
45
|
* - structuredReport.reviewConcerns → reviewed write routes (delegate/execute-plan)
|
|
@@ -41,7 +73,8 @@ function normalizeSeverity(s) {
|
|
|
41
73
|
}
|
|
42
74
|
export function buildTaskCompletedEvent(ctx) {
|
|
43
75
|
const { route, runResult, client, mainModel } = ctx;
|
|
44
|
-
const
|
|
76
|
+
const validationWarnings = [];
|
|
77
|
+
const stages = buildStages(route, runResult, ctx.gates, validationWarnings);
|
|
45
78
|
// Compute per-stage main-model-equivalent cost using the resolved rate card.
|
|
46
79
|
// Plugs into StageEntryBase.mainEquivalentCostUSD so the schema stays valid
|
|
47
80
|
// without weakening the field to optional.
|
|
@@ -52,6 +85,12 @@ export function buildTaskCompletedEvent(ctx) {
|
|
|
52
85
|
cachedReadTokens: st.cachedReadTokens ?? 0, cachedNonReadTokens: st.cachedNonReadTokens ?? 0 }, mainCard)
|
|
53
86
|
: null;
|
|
54
87
|
}
|
|
88
|
+
// Spec D11: when the implementing or rework stage was dropped due to
|
|
89
|
+
// StageModelMissingError, omit tierUsage.<tier> entirely — do not let
|
|
90
|
+
// another stage's model become the tier attribution.
|
|
91
|
+
const droppedImpl = validationWarnings.some(w => w.rule === 'StageModelMissingError'
|
|
92
|
+
&& (w.path === 'stages.implementing' || w.path === 'stages.rework'));
|
|
93
|
+
const droppedTier = (runResult.stageStats?.implementing?.agentTier === 'complex') ? 'complex' : 'standard';
|
|
55
94
|
// Gap 3 fix (4.0.3+): R4 invariant `totalDurationMs >= Σ stage.durationMs`
|
|
56
95
|
// is satisfied by Math.max-ing the executor wall-clock against the stage
|
|
57
96
|
// sum. Pre-fix, runResult.durationMs only covered the implementer's
|
|
@@ -75,7 +114,34 @@ export function buildTaskCompletedEvent(ctx) {
|
|
|
75
114
|
const rawTotal = Math.max(runResult.durationMs ?? 0, stageDurationsSum);
|
|
76
115
|
const totalDurationMs = clampDurationMsTotal(rawTotal);
|
|
77
116
|
// ── Tier-level rollup (§3.2, §3.3) ───────────────────────────────────
|
|
78
|
-
|
|
117
|
+
// Filter to LLM-billable stages only — synthetic stages (annotated
|
|
118
|
+
// placeholder review on read-only routes, the commit stage) carry
|
|
119
|
+
// model: 'custom' and would corrupt tier rollup under last-seen
|
|
120
|
+
// semantics. Per spec §4.1.1 and §4.1.2.
|
|
121
|
+
const llmStages = stages.filter(s => s.isLlmStage);
|
|
122
|
+
// Tier-uniformity invariant (spec D9). Every LLM-billable stage at
|
|
123
|
+
// a given tier must share the same canonical model id. If violated,
|
|
124
|
+
// omit that tier from tierUsage and record a diagnostic — better
|
|
125
|
+
// honest-null than silent-wrong attribution.
|
|
126
|
+
const tierModels = {};
|
|
127
|
+
for (const s of llmStages) {
|
|
128
|
+
const tier = s.tier;
|
|
129
|
+
const set = tierModels[tier] ?? new Set();
|
|
130
|
+
set.add(s.model);
|
|
131
|
+
tierModels[tier] = set;
|
|
132
|
+
}
|
|
133
|
+
const divergentTiers = new Set();
|
|
134
|
+
for (const tier of ['standard', 'complex']) {
|
|
135
|
+
if ((tierModels[tier]?.size ?? 0) > 1) {
|
|
136
|
+
divergentTiers.add(tier);
|
|
137
|
+
validationWarnings.push({ path: `tierUsage.${tier}`, rule: 'R-TIER-MODEL-DIVERGENCE' });
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (droppedImpl) {
|
|
141
|
+
divergentTiers.add(droppedTier);
|
|
142
|
+
}
|
|
143
|
+
const rollupInput = llmStages.filter(s => !divergentTiers.has(s.tier));
|
|
144
|
+
const tierUsage = rollupByTier(rollupInput.map(s => ({
|
|
79
145
|
tier: s.tier,
|
|
80
146
|
model: s.model,
|
|
81
147
|
costUSD: s.costUSD,
|
|
@@ -114,6 +180,13 @@ export function buildTaskCompletedEvent(ctx) {
|
|
|
114
180
|
const escalationLog = runResult.escalationLog ?? [];
|
|
115
181
|
const distinctProviders = new Set(escalationLog.map(a => a.provider)).size;
|
|
116
182
|
const escalationCount = Math.max(0, distinctProviders - 1);
|
|
183
|
+
// Strip producer-internal isLlmStage before wire emission. Wire schema
|
|
184
|
+
// (telemetry-types.ts) does not include this field; backend transformer
|
|
185
|
+
// does not read it. Per spec D2.
|
|
186
|
+
const wireStages = stages.map(s => {
|
|
187
|
+
const { isLlmStage: _drop, ...rest } = s;
|
|
188
|
+
return rest;
|
|
189
|
+
});
|
|
117
190
|
const internalRecord = {
|
|
118
191
|
eventId: randomUUID(),
|
|
119
192
|
route,
|
|
@@ -149,29 +222,51 @@ export function buildTaskCompletedEvent(ctx) {
|
|
|
149
222
|
taskMaxIdleMs: runResult.taskMaxIdleMs ?? 0,
|
|
150
223
|
sandboxViolationCount: Math.min(runResult.sandboxViolationCount ?? 0, 100),
|
|
151
224
|
filesWrittenCount: (ctx.realFilesChanged ?? []).length,
|
|
152
|
-
stages,
|
|
225
|
+
stages: wireStages,
|
|
226
|
+
validation_warnings: validationWarnings.length > 0 ? validationWarnings : undefined,
|
|
153
227
|
};
|
|
154
228
|
return buildWirePayload(internalRecord);
|
|
155
229
|
}
|
|
156
230
|
/**
|
|
157
231
|
* Wire payload builder. Internal record fields match the wire schema 1:1
|
|
158
232
|
* after the v4.0.3 rename (mainModel/mainModelFamily everywhere — DB column
|
|
159
|
-
* is `main_model`, header is `X-MMA-Main-Model
|
|
160
|
-
*
|
|
233
|
+
* is `main_model`, header is `X-MMA-Main-Model`).
|
|
234
|
+
*
|
|
235
|
+
* v5 — this used to be a `as unknown as WireTelemetryRecord` passthrough.
|
|
236
|
+
* The translator is now real: the internal record is passed through Zod
|
|
237
|
+
* (`WireTelemetryRecordSchema`) so the wire payload is schema-validated at
|
|
238
|
+
* the egress boundary. When the schema rejects, we fall back to the
|
|
239
|
+
* passthrough to preserve "best-effort telemetry" semantics — but the
|
|
240
|
+
* validation failure is observable on bus emits so backend can detect drift
|
|
241
|
+
* before the warehouse 400s. Callers that need strict validation should
|
|
242
|
+
* call `WireTelemetryRecordSchema.parse` directly.
|
|
161
243
|
*/
|
|
162
|
-
export function buildWirePayload(internalRecord) {
|
|
244
|
+
export function buildWirePayload(internalRecord, opts) {
|
|
245
|
+
const parsed = WireTelemetryRecordSchema.safeParse(internalRecord);
|
|
246
|
+
if (parsed.success) {
|
|
247
|
+
// Schema-strip: drop unknown fields by returning the parsed record. This
|
|
248
|
+
// is the v5 contract guarantee — only wire-schema fields cross the
|
|
249
|
+
// boundary.
|
|
250
|
+
return parsed.data;
|
|
251
|
+
}
|
|
252
|
+
// Schema rejected — surface the error to the caller and fall back to the
|
|
253
|
+
// passthrough so we never silently drop a telemetry row. Backend will
|
|
254
|
+
// 400 on schema mismatch; the bus event makes the drift discoverable
|
|
255
|
+
// before that point.
|
|
256
|
+
opts?.onValidationError?.(parsed.error);
|
|
163
257
|
return internalRecord;
|
|
164
258
|
}
|
|
165
|
-
function buildStages(route, rr) {
|
|
259
|
+
function buildStages(route, rr, gates, validationWarnings) {
|
|
260
|
+
const warnings = validationWarnings ?? [];
|
|
166
261
|
const result = [];
|
|
167
|
-
const impl = buildImplStage(rr);
|
|
262
|
+
const impl = safeBuild('implementing', () => buildImplStage(rr, gates?.['implement']), warnings);
|
|
168
263
|
if (impl)
|
|
169
264
|
result.push(impl);
|
|
170
265
|
if (REVIEWED_ROUTES.has(route)) {
|
|
171
266
|
const status = rr.reviewVerdict ?? rr.qualityReviewStatus ?? rr.specReviewStatus ?? null;
|
|
172
267
|
const stageRounds = rr.stageStats?.review?.roundsUsed;
|
|
173
268
|
const rounds = stageRounds ?? (Math.max(rr.reviewRounds?.spec ?? 0, rr.reviewRounds?.quality ?? 0) || null);
|
|
174
|
-
const rev = buildReviewStage(rr, status, rounds);
|
|
269
|
+
const rev = safeBuild('review', () => buildReviewStage(rr, status, rounds, gates?.['review']), warnings);
|
|
175
270
|
if (rev) {
|
|
176
271
|
result.push(rev);
|
|
177
272
|
}
|
|
@@ -190,23 +285,43 @@ function buildStages(route, rr) {
|
|
|
190
285
|
}
|
|
191
286
|
}
|
|
192
287
|
if (REVIEWED_ROUTES.has(route) && !QUALITY_ONLY_ROUTES.has(route)) {
|
|
193
|
-
const rw = buildReworkStage(rr);
|
|
288
|
+
const rw = safeBuild('rework', () => buildReworkStage(rr, gates?.['rework']), warnings);
|
|
194
289
|
if (rw)
|
|
195
290
|
result.push(rw);
|
|
196
291
|
}
|
|
197
|
-
const an = buildAnnotatingStage(rr);
|
|
292
|
+
const an = safeBuild('annotating', () => buildAnnotatingStage(rr, gates?.['annotate']), warnings);
|
|
198
293
|
if (an)
|
|
199
294
|
result.push(an);
|
|
200
|
-
const cm = buildCommitStage(rr);
|
|
295
|
+
const cm = safeBuild('committing', () => buildCommitStage(rr, gates?.['commit']), warnings);
|
|
201
296
|
if (cm)
|
|
202
297
|
result.push(cm);
|
|
203
298
|
return result.slice(0, 8);
|
|
204
299
|
}
|
|
300
|
+
/**
|
|
301
|
+
* Overlay gate telemetry onto an extracted-stage base. Gates are the v5
|
|
302
|
+
* canonical source for `durationMs`, `costUSD`, `turnsUsed`. When both
|
|
303
|
+
* sources have a value, the gate wins (intentional: the gate is what the
|
|
304
|
+
* lifecycle actually produced; stageStats is the legacy mirror that the
|
|
305
|
+
* runner-shell and per-stage tracker fill in). Tokens, tool calls, and
|
|
306
|
+
* files-read/written remain on stageStats because the gate telemetry block
|
|
307
|
+
* doesn't carry them.
|
|
308
|
+
*/
|
|
309
|
+
function applyGateOverlay(base, gate) {
|
|
310
|
+
if (!gate)
|
|
311
|
+
return base;
|
|
312
|
+
const t = gate.telemetry;
|
|
313
|
+
return {
|
|
314
|
+
...base,
|
|
315
|
+
durationMs: clampDurationMsStage(t.durationMs ?? base.durationMs),
|
|
316
|
+
costUSD: clampStageCost(t.costUSD ?? base.costUSD),
|
|
317
|
+
turnCount: clampTurnCount(t.turnsUsed ?? base.turnCount),
|
|
318
|
+
};
|
|
319
|
+
}
|
|
205
320
|
function extractStageData(raw, _rr, _stageName) {
|
|
206
321
|
if (!raw || !raw.entered)
|
|
207
322
|
return null;
|
|
208
323
|
return {
|
|
209
|
-
model: raw.model ? normalizeModel(raw.model).canonical ?? raw.model :
|
|
324
|
+
model: raw.model ? (normalizeModel(raw.model).canonical ?? raw.model) : null,
|
|
210
325
|
tier: raw.agentTier ?? 'standard',
|
|
211
326
|
round: raw.round ?? 0,
|
|
212
327
|
durationMs: clampDurationMsStage(raw.durationMs ?? 0),
|
|
@@ -223,12 +338,16 @@ function extractStageData(raw, _rr, _stageName) {
|
|
|
223
338
|
totalIdleMs: raw.totalIdleMs ?? 0,
|
|
224
339
|
};
|
|
225
340
|
}
|
|
226
|
-
function buildImplStage(rr) {
|
|
341
|
+
function buildImplStage(rr, gate) {
|
|
227
342
|
const ss = rr.stageStats?.implementing;
|
|
228
|
-
|
|
343
|
+
let base = extractStageData(ss, rr, 'implementing');
|
|
229
344
|
if (!base)
|
|
230
345
|
return null;
|
|
231
|
-
|
|
346
|
+
base = applyGateOverlay(base, gate);
|
|
347
|
+
if (base.model === null) {
|
|
348
|
+
throw new StageModelMissingError('implementing');
|
|
349
|
+
}
|
|
350
|
+
return { name: 'implementing', ...base, model: base.model, mainEquivalentCostUSD: null, isLlmStage: true };
|
|
232
351
|
}
|
|
233
352
|
/** Synthetic review stage entry for read-only routes that hardcode
|
|
234
353
|
* reviewPolicy: 'none'. The implementer is the finding producer; v5
|
|
@@ -268,13 +387,18 @@ function buildSyntheticReviewStage(findings) {
|
|
|
268
387
|
roundsUsed: 1,
|
|
269
388
|
concernCategories: categories.slice(0, 9),
|
|
270
389
|
findingsBySeverity,
|
|
390
|
+
isLlmStage: false,
|
|
271
391
|
};
|
|
272
392
|
}
|
|
273
|
-
function buildReviewStage(rr, status, rounds) {
|
|
393
|
+
function buildReviewStage(rr, status, rounds, gate) {
|
|
274
394
|
const ss = rr.stageStats?.review;
|
|
275
|
-
|
|
395
|
+
let base = extractStageData(ss, rr, 'review');
|
|
276
396
|
if (!base)
|
|
277
397
|
return null;
|
|
398
|
+
base = applyGateOverlay(base, gate);
|
|
399
|
+
if (base.model === null) {
|
|
400
|
+
throw new StageModelMissingError('review');
|
|
401
|
+
}
|
|
278
402
|
// v4.4.x: projectFindings reads from structuredReport.findings (read-only
|
|
279
403
|
// routes) and structuredReport.reviewConcerns (reviewed write routes). The
|
|
280
404
|
// pre-v4.4 rr.concerns field is no longer populated by the lifecycle, so
|
|
@@ -300,42 +424,63 @@ function buildReviewStage(rr, status, rounds) {
|
|
|
300
424
|
return {
|
|
301
425
|
name: 'review',
|
|
302
426
|
...base,
|
|
427
|
+
model: base.model,
|
|
303
428
|
verdict,
|
|
304
429
|
roundsUsed: Math.min(rounds ?? 1, 10),
|
|
305
430
|
concernCategories: categories.slice(0, 9),
|
|
306
431
|
findingsBySeverity,
|
|
432
|
+
mainEquivalentCostUSD: null,
|
|
433
|
+
isLlmStage: true,
|
|
307
434
|
};
|
|
308
435
|
}
|
|
309
|
-
function buildReworkStage(rr) {
|
|
436
|
+
function buildReworkStage(rr, gate) {
|
|
310
437
|
const ss = rr.stageStats?.rework;
|
|
311
|
-
|
|
438
|
+
let base = extractStageData(ss, rr, 'rework');
|
|
312
439
|
if (!base)
|
|
313
440
|
return null;
|
|
441
|
+
base = applyGateOverlay(base, gate);
|
|
442
|
+
if (base.model === null) {
|
|
443
|
+
throw new StageModelMissingError('rework');
|
|
444
|
+
}
|
|
314
445
|
const stageConcerns = projectFindings(rr).filter(c => c.source === 'spec_review' || c.source === 'quality_review' || c.source === 'review' || c.source === 'implementer');
|
|
315
446
|
const triggeringCategories = [...new Set(stageConcerns.map(c => classifyConcern(c)))];
|
|
316
447
|
return {
|
|
317
448
|
name: 'rework',
|
|
318
449
|
...base,
|
|
450
|
+
model: base.model,
|
|
319
451
|
triggeringConcernCategories: triggeringCategories.slice(0, 9),
|
|
452
|
+
mainEquivalentCostUSD: null,
|
|
453
|
+
isLlmStage: true,
|
|
320
454
|
};
|
|
321
455
|
}
|
|
322
|
-
function buildAnnotatingStage(rr) {
|
|
456
|
+
function buildAnnotatingStage(rr, gate) {
|
|
323
457
|
const ss = rr.stageStats?.annotating;
|
|
324
|
-
|
|
458
|
+
let base = extractStageData(ss, rr, 'annotating');
|
|
325
459
|
if (!base)
|
|
326
460
|
return null;
|
|
461
|
+
base = applyGateOverlay(base, gate);
|
|
462
|
+
// Annotator is an LLM stage iff the runtime actually invoked a model.
|
|
463
|
+
// Per spec §4.1.3, the observable signal is whether stageStats.annotating.model
|
|
464
|
+
// was populated. Task A6 fixes the upstream so this is always populated when
|
|
465
|
+
// the LLM was called. When null (degraded pure-transform path), the stage
|
|
466
|
+
// appears in wire stages[] but is excluded from tier rollup.
|
|
467
|
+
const isLlmStage = base.model !== null && base.model !== 'custom';
|
|
327
468
|
return {
|
|
328
469
|
name: 'annotating',
|
|
329
470
|
...base,
|
|
471
|
+
model: base.model || 'custom',
|
|
472
|
+
isLlmStage,
|
|
473
|
+
mainEquivalentCostUSD: null,
|
|
330
474
|
outcome: ss?.outcome ?? 'not_applicable',
|
|
331
475
|
skipReason: ss?.outcome === 'skipped' ? (ss?.skipReason ?? 'other') : null,
|
|
332
476
|
};
|
|
333
477
|
}
|
|
334
|
-
function buildCommitStage(rr) {
|
|
478
|
+
function buildCommitStage(rr, gate) {
|
|
335
479
|
const ss = rr.stageStats?.committing;
|
|
336
|
-
|
|
480
|
+
let base = extractStageData(ss, rr, 'committing');
|
|
337
481
|
if (!base)
|
|
338
482
|
return null;
|
|
483
|
+
base = applyGateOverlay(base, gate);
|
|
339
484
|
const commits = Array.isArray(rr.commits) ? rr.commits : [];
|
|
340
485
|
const allFiles = commits.flatMap((c) => Array.isArray(c?.filesChanged)
|
|
341
486
|
? c.filesChanged.filter((f) => typeof f === 'string')
|
|
@@ -344,23 +489,20 @@ function buildCommitStage(rr) {
|
|
|
344
489
|
return {
|
|
345
490
|
name: 'committing',
|
|
346
491
|
...base,
|
|
492
|
+
model: base.model || 'custom',
|
|
347
493
|
filesCommittedCount,
|
|
348
494
|
// CommitStageRunner does not track branch-creation directly today;
|
|
349
495
|
// name-diff against pre-commit refs is unreliable, so we report
|
|
350
496
|
// false. A future change can wire this when CommitStageRunner emits
|
|
351
497
|
// an explicit signal alongside filesCommittedCount.
|
|
352
498
|
branchCreated: false,
|
|
499
|
+
mainEquivalentCostUSD: null,
|
|
500
|
+
isLlmStage: false,
|
|
353
501
|
};
|
|
354
502
|
}
|
|
355
503
|
// ── Derivation helpers ─────────────────────────────────────────────────────
|
|
356
504
|
function deriveTerminalStatus(rr) {
|
|
357
505
|
const tr = rr.terminationReason;
|
|
358
|
-
if (tr === 'all_tiers_unavailable')
|
|
359
|
-
return 'unavailable';
|
|
360
|
-
if (tr === 'cost_ceiling')
|
|
361
|
-
return 'cost_exceeded';
|
|
362
|
-
if (tr === 'round_cap')
|
|
363
|
-
return 'incomplete';
|
|
364
506
|
if (!tr || typeof tr !== 'object')
|
|
365
507
|
return 'incomplete';
|
|
366
508
|
switch (tr.cause) {
|