vidspotai-shared 1.0.85 → 1.0.86
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/lib/globals/aiModels/providers/runway.d.ts.map +1 -1
- package/lib/globals/aiModels/providers/runway.js +12 -7
- package/lib/globals/types.d.ts +10 -0
- package/lib/globals/types.d.ts.map +1 -1
- package/lib/globals/types.js +11 -0
- package/lib/models/agent.model.d.ts +129 -1
- package/lib/models/agent.model.d.ts.map +1 -1
- package/lib/schemas/agentRunJob.schema.d.ts +21 -0
- package/lib/schemas/agentRunJob.schema.d.ts.map +1 -1
- package/lib/schemas/agentRunJob.schema.js +35 -3
- package/lib/services/agent/executor/core.d.ts.map +1 -1
- package/lib/services/agent/executor/core.js +21 -1
- package/lib/services/agent/executor/types.d.ts +10 -0
- package/lib/services/agent/executor/types.d.ts.map +1 -1
- package/lib/services/agent/index.d.ts +3 -0
- package/lib/services/agent/index.d.ts.map +1 -1
- package/lib/services/agent/index.js +3 -0
- package/lib/services/agent/providerFallback/chains.d.ts +2 -0
- package/lib/services/agent/providerFallback/chains.d.ts.map +1 -1
- package/lib/services/agent/providerFallback/chains.js +1 -0
- package/lib/services/agent/recovery/degradeLadder.d.ts +74 -0
- package/lib/services/agent/recovery/degradeLadder.d.ts.map +1 -0
- package/lib/services/agent/recovery/degradeLadder.js +133 -0
- package/lib/services/agent/repair/engine.d.ts +38 -0
- package/lib/services/agent/repair/engine.d.ts.map +1 -0
- package/lib/services/agent/repair/engine.js +175 -0
- package/lib/services/agent/repair/index.d.ts +20 -0
- package/lib/services/agent/repair/index.d.ts.map +1 -0
- package/lib/services/agent/repair/index.js +49 -0
- package/lib/services/agent/repair/strategies/llmRepair.strategy.d.ts +6 -0
- package/lib/services/agent/repair/strategies/llmRepair.strategy.d.ts.map +1 -0
- package/lib/services/agent/repair/strategies/llmRepair.strategy.js +210 -0
- package/lib/services/agent/repair/strategies/paramRepair.strategy.d.ts +3 -0
- package/lib/services/agent/repair/strategies/paramRepair.strategy.d.ts.map +1 -0
- package/lib/services/agent/repair/strategies/paramRepair.strategy.js +151 -0
- package/lib/services/agent/repair/types.d.ts +92 -0
- package/lib/services/agent/repair/types.d.ts.map +1 -0
- package/lib/services/agent/repair/types.js +2 -0
- package/lib/services/agent/runPlanning.d.ts +96 -0
- package/lib/services/agent/runPlanning.d.ts.map +1 -0
- package/lib/services/agent/runPlanning.js +233 -0
- package/lib/services/aiGen/providers/runway/types.d.ts +14 -0
- package/lib/services/aiGen/providers/runway/types.d.ts.map +1 -1
- package/lib/services/aiGen/providers/runway/types.js +22 -1
- package/lib/services/firestore.service.d.ts +7 -1
- package/lib/services/firestore.service.d.ts.map +1 -1
- package/lib/services/firestore.service.js +8 -0
- package/package.json +1 -1
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { SceneAssetStrategy, VideoPlan } from "../../../schemas/videoPlan.schema";
|
|
2
|
+
import { FailureClass } from "../repair/types";
|
|
3
|
+
export declare function isStockStrategy(strategy: SceneAssetStrategy): boolean;
|
|
4
|
+
/**
|
|
5
|
+
* The ordered list of fallback strategies to try for a scene that failed, most
|
|
6
|
+
* intent-preserving first. Empty when nothing sensible exists (already stock /
|
|
7
|
+
* avatar).
|
|
8
|
+
*
|
|
9
|
+
* Failure-class aware: a `safety` (content-moderation) block came from the
|
|
10
|
+
* GENERATIVE step, so any remaining AI rung would just be blocked again — skip
|
|
11
|
+
* straight to the non-generative stock rungs (stock search has no prompt to
|
|
12
|
+
* moderate). All other classes step down the full ladder.
|
|
13
|
+
*/
|
|
14
|
+
export declare function degradeLadderFor(strategy: SceneAssetStrategy, failureClass: FailureClass | undefined): SceneAssetStrategy[];
|
|
15
|
+
/**
|
|
16
|
+
* Produce a copy of `plan` with exactly one scene's strategy changed. Pure — no
|
|
17
|
+
* mutation of the input. The rest of the scene (prompt, duration, bible refs) is
|
|
18
|
+
* preserved so the degraded render still reflects the planned content.
|
|
19
|
+
*/
|
|
20
|
+
export declare function planWithDegradedScene(plan: VideoPlan, sceneIndex: number, newStrategy: SceneAssetStrategy): VideoPlan;
|
|
21
|
+
/**
|
|
22
|
+
* Phase 2b — a proposed scene-recovery, computed WITHOUT executing it. The
|
|
23
|
+
* autonomous path (`recoverFailedScenes`) walks the ladder and re-runs each
|
|
24
|
+
* rung; in `manual` autonomy we instead surface this proposal on the approval
|
|
25
|
+
* card and pause. `toStrategy` is the most intent-preserving rung; `ladder`
|
|
26
|
+
* is the full remaining fallback chain (shown as "what happens if this also
|
|
27
|
+
* fails").
|
|
28
|
+
*/
|
|
29
|
+
export interface RecoveryProposal {
|
|
30
|
+
sceneIndex: number;
|
|
31
|
+
fromStrategy: SceneAssetStrategy;
|
|
32
|
+
toStrategy: SceneAssetStrategy;
|
|
33
|
+
ladder: SceneAssetStrategy[];
|
|
34
|
+
failureClass: FailureClass | undefined;
|
|
35
|
+
reason: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Minimal structural view of a failed scene outcome. Kept structural (rather
|
|
39
|
+
* than importing `SceneOutcome` from the executor) so this pure module stays
|
|
40
|
+
* free of the executor import graph — `SceneOutcome` is assignable to it.
|
|
41
|
+
*/
|
|
42
|
+
export interface FailedSceneLike {
|
|
43
|
+
scene: {
|
|
44
|
+
sceneIndex: number;
|
|
45
|
+
strategy: SceneAssetStrategy;
|
|
46
|
+
};
|
|
47
|
+
error?: {
|
|
48
|
+
classification?: FailureClass;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* PURE — compute the recovery proposal for each failed scene without running
|
|
53
|
+
* anything. One proposal per scene that HAS a (failure-class-aware) degrade
|
|
54
|
+
* path; scenes whose ladder is empty (already stock / avatar / terminal) are
|
|
55
|
+
* omitted — there is nothing to approve, so the run just hard-fails them.
|
|
56
|
+
*
|
|
57
|
+
* This is the data the worker persists onto `run.pendingApproval` when it
|
|
58
|
+
* pauses for sign-off, and the basis the approve path mutates the plan with.
|
|
59
|
+
*/
|
|
60
|
+
export declare function planSceneRecovery(failed: FailedSceneLike[]): RecoveryProposal[];
|
|
61
|
+
/**
|
|
62
|
+
* PURE — apply a set of approved recovery proposals to a plan, returning a new
|
|
63
|
+
* plan with each proposal's scene degraded to its `toStrategy`. Used on the
|
|
64
|
+
* approval-resume pass: the resumed executor then regenerates exactly those
|
|
65
|
+
* scenes with the new strategy while every already-succeeded scene replays
|
|
66
|
+
* from the providerTaskCache. No mutation of the input.
|
|
67
|
+
*/
|
|
68
|
+
export declare function applyRecoveryProposals(plan: VideoPlan, proposals: Array<{
|
|
69
|
+
sceneIndex: number;
|
|
70
|
+
toStrategy: string;
|
|
71
|
+
}>): VideoPlan;
|
|
72
|
+
/** Human-readable one-liner for trace + the approval card. */
|
|
73
|
+
export declare function describeDegrade(sceneIndex: number, from: SceneAssetStrategy, to: SceneAssetStrategy, failureClass: FailureClass | undefined): string;
|
|
74
|
+
//# sourceMappingURL=degradeLadder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"degradeLadder.d.ts","sourceRoot":"","sources":["../../../../src/services/agent/recovery/degradeLadder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AAClF,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AA4C/C,wBAAgB,eAAe,CAAC,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAErE;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,kBAAkB,EAC5B,YAAY,EAAE,YAAY,GAAG,SAAS,GACrC,kBAAkB,EAAE,CAItB;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,SAAS,EACf,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,kBAAkB,GAC9B,SAAS,CAOX;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,kBAAkB,CAAC;IACjC,UAAU,EAAE,kBAAkB,CAAC;IAC/B,MAAM,EAAE,kBAAkB,EAAE,CAAC;IAC7B,YAAY,EAAE,YAAY,GAAG,SAAS,CAAC;IACvC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,kBAAkB,CAAA;KAAE,CAAC;IAC5D,KAAK,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,YAAY,CAAA;KAAE,CAAC;CAC3C;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,gBAAgB,EAAE,CAkB/E;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,SAAS,EACf,SAAS,EAAE,KAAK,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,GAC3D,SAAS,CASX;AAED,8DAA8D;AAC9D,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,kBAAkB,EACxB,EAAE,EAAE,kBAAkB,EACtB,YAAY,EAAE,YAAY,GAAG,SAAS,GACrC,MAAM,CAUR"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isStockStrategy = isStockStrategy;
|
|
4
|
+
exports.degradeLadderFor = degradeLadderFor;
|
|
5
|
+
exports.planWithDegradedScene = planWithDegradedScene;
|
|
6
|
+
exports.planSceneRecovery = planSceneRecovery;
|
|
7
|
+
exports.applyRecoveryProposals = applyRecoveryProposals;
|
|
8
|
+
exports.describeDegrade = describeDegrade;
|
|
9
|
+
/**
|
|
10
|
+
* PLAN-LEVEL recovery — scene-strategy degrade.
|
|
11
|
+
*
|
|
12
|
+
* The tool-level repair engine reworks a single tool's INPUT (param/prompt/model)
|
|
13
|
+
* and re-runs the SAME tool. When that's exhausted — every video model failed,
|
|
14
|
+
* the prompt is unfixably blocked, the provider can't do it at all — the only
|
|
15
|
+
* remaining move is to change the scene's STRATEGY: render it a cheaper way that
|
|
16
|
+
* still fills the slot (AI video → stock footage → ken-burns still) rather than
|
|
17
|
+
* letting one scene fail the whole video.
|
|
18
|
+
*
|
|
19
|
+
* This is intentionally a PLAN mutation, not a tool-input repair, so it lives at
|
|
20
|
+
* the orchestrator layer (the worker), not inside the per-tool repair loop. A
|
|
21
|
+
* strategy change always materially alters the scene, so it is classified as a
|
|
22
|
+
* `significant` decision — exactly the kind the human-in-the-loop approval gate
|
|
23
|
+
* (Phase 2b) pauses on when autonomy is set to manual.
|
|
24
|
+
*/
|
|
25
|
+
/** Ordered fallbacks for each strategy, most-intent-preserving first. */
|
|
26
|
+
const DEGRADE_LADDER = {
|
|
27
|
+
// Pure text-to-video has no source still to fall back on → go to motion stock,
|
|
28
|
+
// then a static stock image with ken-burns motion.
|
|
29
|
+
"ai-text-to-video": ["stock-video", "stock-image-ken-burns"],
|
|
30
|
+
// Image-to-video: first drop the (failed) animation but keep the AI still,
|
|
31
|
+
// then fall back to stock footage, then a stock still.
|
|
32
|
+
"ai-image-to-video": ["ai-image-static", "stock-video", "stock-image-ken-burns"],
|
|
33
|
+
"ai-image-motion": ["ai-image-static", "stock-image-ken-burns", "stock-video"],
|
|
34
|
+
"ai-image-static": ["stock-image-ken-burns", "stock-video"],
|
|
35
|
+
"stock-video": ["stock-image-ken-burns"],
|
|
36
|
+
// Already the cheapest visual — nothing left to degrade to.
|
|
37
|
+
"stock-image-ken-burns": [],
|
|
38
|
+
// The executor already self-falls-back user-asset → stock; mirror it here.
|
|
39
|
+
"user-asset": ["stock-video", "stock-image-ken-burns"],
|
|
40
|
+
// Avatar needs a face + VO; there is no sensible automatic substitute.
|
|
41
|
+
"talking-head-avatar": [],
|
|
42
|
+
};
|
|
43
|
+
const STOCK_STRATEGIES = new Set([
|
|
44
|
+
"stock-video",
|
|
45
|
+
"stock-image-ken-burns",
|
|
46
|
+
"user-asset",
|
|
47
|
+
]);
|
|
48
|
+
function isStockStrategy(strategy) {
|
|
49
|
+
return STOCK_STRATEGIES.has(strategy);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* The ordered list of fallback strategies to try for a scene that failed, most
|
|
53
|
+
* intent-preserving first. Empty when nothing sensible exists (already stock /
|
|
54
|
+
* avatar).
|
|
55
|
+
*
|
|
56
|
+
* Failure-class aware: a `safety` (content-moderation) block came from the
|
|
57
|
+
* GENERATIVE step, so any remaining AI rung would just be blocked again — skip
|
|
58
|
+
* straight to the non-generative stock rungs (stock search has no prompt to
|
|
59
|
+
* moderate). All other classes step down the full ladder.
|
|
60
|
+
*/
|
|
61
|
+
function degradeLadderFor(strategy, failureClass) {
|
|
62
|
+
const base = DEGRADE_LADDER[strategy] ?? [];
|
|
63
|
+
if (failureClass === "safety")
|
|
64
|
+
return base.filter(isStockStrategy);
|
|
65
|
+
return base;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Produce a copy of `plan` with exactly one scene's strategy changed. Pure — no
|
|
69
|
+
* mutation of the input. The rest of the scene (prompt, duration, bible refs) is
|
|
70
|
+
* preserved so the degraded render still reflects the planned content.
|
|
71
|
+
*/
|
|
72
|
+
function planWithDegradedScene(plan, sceneIndex, newStrategy) {
|
|
73
|
+
return {
|
|
74
|
+
...plan,
|
|
75
|
+
scenes: plan.scenes.map((s) => s.sceneIndex === sceneIndex ? { ...s, strategy: newStrategy } : s),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* PURE — compute the recovery proposal for each failed scene without running
|
|
80
|
+
* anything. One proposal per scene that HAS a (failure-class-aware) degrade
|
|
81
|
+
* path; scenes whose ladder is empty (already stock / avatar / terminal) are
|
|
82
|
+
* omitted — there is nothing to approve, so the run just hard-fails them.
|
|
83
|
+
*
|
|
84
|
+
* This is the data the worker persists onto `run.pendingApproval` when it
|
|
85
|
+
* pauses for sign-off, and the basis the approve path mutates the plan with.
|
|
86
|
+
*/
|
|
87
|
+
function planSceneRecovery(failed) {
|
|
88
|
+
const proposals = [];
|
|
89
|
+
for (const outcome of failed) {
|
|
90
|
+
const fromStrategy = outcome.scene.strategy;
|
|
91
|
+
const failureClass = outcome.error?.classification;
|
|
92
|
+
const ladder = degradeLadderFor(fromStrategy, failureClass);
|
|
93
|
+
if (!ladder.length)
|
|
94
|
+
continue; // terminal — nothing to propose
|
|
95
|
+
const toStrategy = ladder[0];
|
|
96
|
+
proposals.push({
|
|
97
|
+
sceneIndex: outcome.scene.sceneIndex,
|
|
98
|
+
fromStrategy,
|
|
99
|
+
toStrategy,
|
|
100
|
+
ladder,
|
|
101
|
+
failureClass,
|
|
102
|
+
reason: describeDegrade(outcome.scene.sceneIndex, fromStrategy, toStrategy, failureClass),
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
return proposals;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* PURE — apply a set of approved recovery proposals to a plan, returning a new
|
|
109
|
+
* plan with each proposal's scene degraded to its `toStrategy`. Used on the
|
|
110
|
+
* approval-resume pass: the resumed executor then regenerates exactly those
|
|
111
|
+
* scenes with the new strategy while every already-succeeded scene replays
|
|
112
|
+
* from the providerTaskCache. No mutation of the input.
|
|
113
|
+
*/
|
|
114
|
+
function applyRecoveryProposals(plan, proposals) {
|
|
115
|
+
if (!proposals.length)
|
|
116
|
+
return plan;
|
|
117
|
+
const target = new Map(proposals.map((p) => [p.sceneIndex, p.toStrategy]));
|
|
118
|
+
return {
|
|
119
|
+
...plan,
|
|
120
|
+
scenes: plan.scenes.map((s) => target.has(s.sceneIndex) ? { ...s, strategy: target.get(s.sceneIndex) } : s),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
/** Human-readable one-liner for trace + the approval card. */
|
|
124
|
+
function describeDegrade(sceneIndex, from, to, failureClass) {
|
|
125
|
+
const why = failureClass === "safety"
|
|
126
|
+
? "content was blocked by the provider's moderation"
|
|
127
|
+
: failureClass === "capability"
|
|
128
|
+
? "no available model could generate it"
|
|
129
|
+
: failureClass === "quota"
|
|
130
|
+
? "provider quota was exhausted"
|
|
131
|
+
: "generation failed after retries";
|
|
132
|
+
return `Scene ${sceneIndex}: ${why} — fall back from "${from}" to "${to}".`;
|
|
133
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ToolContext, ToolOutcome } from "../toolRegistry";
|
|
2
|
+
import { RepairContext, RepairProposal, RepairStrategy, RepairableRunToolFn, RunWithRepairOptions } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* RepairEngine — the generic, reactive, escalating retry brain.
|
|
5
|
+
*
|
|
6
|
+
* It owns an ordered set of strategies and a single loop, `runWithRepair`,
|
|
7
|
+
* that the executor uses in place of a raw `runTool`. The loop:
|
|
8
|
+
*
|
|
9
|
+
* run tool → ok? return it.
|
|
10
|
+
* else → ask strategies (narrowest first) for a repaired input → retry.
|
|
11
|
+
* repeat until ok, no strategy can help, or the retry budget is spent.
|
|
12
|
+
*
|
|
13
|
+
* Everything specific (which field to snap, whether moderation is fixable,
|
|
14
|
+
* whether to swap models) lives in the strategies. The engine only sequences
|
|
15
|
+
* them, guards against repeating an input, and records history.
|
|
16
|
+
*/
|
|
17
|
+
export declare class RepairEngine {
|
|
18
|
+
private readonly strategies;
|
|
19
|
+
constructor(strategies: RepairStrategy[]);
|
|
20
|
+
/** Strategies, narrowest-first (read-only view, for trace/introspection). */
|
|
21
|
+
get strategyNames(): string[];
|
|
22
|
+
/**
|
|
23
|
+
* Walk strategies in ascending rank; the first that `applies` and returns a
|
|
24
|
+
* non-null proposal wins. A strategy that throws is logged and skipped (a
|
|
25
|
+
* broken strategy must never sink the whole repair — the next one still runs).
|
|
26
|
+
*/
|
|
27
|
+
diagnose(rc: RepairContext): Promise<RepairProposal | null>;
|
|
28
|
+
/**
|
|
29
|
+
* Reactive bounded retry loop. Runs the tool; on failure, escalates through
|
|
30
|
+
* the strategies and retries with the repaired input. Returns the first OK
|
|
31
|
+
* outcome, or the LAST failure once the budget is spent / nothing can help.
|
|
32
|
+
*
|
|
33
|
+
* Terminal `auth` failures short-circuit immediately — a missing/invalid key
|
|
34
|
+
* is a deploy bug, not something a different input can fix.
|
|
35
|
+
*/
|
|
36
|
+
runWithRepair<O = unknown>(runTool: RepairableRunToolFn, toolName: string, input: Record<string, unknown>, ctx: ToolContext, opts?: RunWithRepairOptions): Promise<ToolOutcome<O>>;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../../src/services/agent/repair/engine.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE3D,OAAO,EAEL,aAAa,EAEb,cAAc,EACd,cAAc,EACd,mBAAmB,EACnB,oBAAoB,EACrB,MAAM,SAAS,CAAC;AAEjB;;;;;;;;;;;;;GAaG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAmB;gBAElC,UAAU,EAAE,cAAc,EAAE;IAKxC,6EAA6E;IAC7E,IAAI,aAAa,IAAI,MAAM,EAAE,CAE5B;IAED;;;;OAIG;IACG,QAAQ,CAAC,EAAE,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IA2BjE;;;;;;;OAOG;IACG,aAAa,CAAC,CAAC,GAAG,OAAO,EAC7B,OAAO,EAAE,mBAAmB,EAC5B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,GAAG,EAAE,WAAW,EAChB,IAAI,GAAE,oBAAyB,GAC9B,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;CAyF3B"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RepairEngine = void 0;
|
|
4
|
+
const logger_1 = require("../../../utils/logger");
|
|
5
|
+
const providerTaskCache_1 = require("../providerTaskCache");
|
|
6
|
+
/**
|
|
7
|
+
* RepairEngine — the generic, reactive, escalating retry brain.
|
|
8
|
+
*
|
|
9
|
+
* It owns an ordered set of strategies and a single loop, `runWithRepair`,
|
|
10
|
+
* that the executor uses in place of a raw `runTool`. The loop:
|
|
11
|
+
*
|
|
12
|
+
* run tool → ok? return it.
|
|
13
|
+
* else → ask strategies (narrowest first) for a repaired input → retry.
|
|
14
|
+
* repeat until ok, no strategy can help, or the retry budget is spent.
|
|
15
|
+
*
|
|
16
|
+
* Everything specific (which field to snap, whether moderation is fixable,
|
|
17
|
+
* whether to swap models) lives in the strategies. The engine only sequences
|
|
18
|
+
* them, guards against repeating an input, and records history.
|
|
19
|
+
*/
|
|
20
|
+
class RepairEngine {
|
|
21
|
+
constructor(strategies) {
|
|
22
|
+
// Ascending invasiveness — narrowest fix consulted first.
|
|
23
|
+
this.strategies = [...strategies].sort((a, b) => a.rank - b.rank);
|
|
24
|
+
}
|
|
25
|
+
/** Strategies, narrowest-first (read-only view, for trace/introspection). */
|
|
26
|
+
get strategyNames() {
|
|
27
|
+
return this.strategies.map((s) => s.name);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Walk strategies in ascending rank; the first that `applies` and returns a
|
|
31
|
+
* non-null proposal wins. A strategy that throws is logged and skipped (a
|
|
32
|
+
* broken strategy must never sink the whole repair — the next one still runs).
|
|
33
|
+
*/
|
|
34
|
+
async diagnose(rc) {
|
|
35
|
+
for (const strategy of this.strategies) {
|
|
36
|
+
let relevant = false;
|
|
37
|
+
try {
|
|
38
|
+
relevant = strategy.applies(rc);
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
logger_1.logger.warn("repair: strategy.applies threw — skipping", {
|
|
42
|
+
strategy: strategy.name,
|
|
43
|
+
err: err instanceof Error ? err.message : String(err),
|
|
44
|
+
});
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (!relevant)
|
|
48
|
+
continue;
|
|
49
|
+
try {
|
|
50
|
+
const proposal = await strategy.propose(rc);
|
|
51
|
+
if (proposal)
|
|
52
|
+
return proposal;
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
logger_1.logger.warn("repair: strategy.propose threw — escalating to next", {
|
|
56
|
+
strategy: strategy.name,
|
|
57
|
+
toolName: rc.toolName,
|
|
58
|
+
err: err instanceof Error ? err.message : String(err),
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Reactive bounded retry loop. Runs the tool; on failure, escalates through
|
|
66
|
+
* the strategies and retries with the repaired input. Returns the first OK
|
|
67
|
+
* outcome, or the LAST failure once the budget is spent / nothing can help.
|
|
68
|
+
*
|
|
69
|
+
* Terminal `auth` failures short-circuit immediately — a missing/invalid key
|
|
70
|
+
* is a deploy bug, not something a different input can fix.
|
|
71
|
+
*/
|
|
72
|
+
async runWithRepair(runTool, toolName, input, ctx, opts = {}) {
|
|
73
|
+
const maxRepairs = opts.maxRepairs ?? 3;
|
|
74
|
+
const log = ctx.log ?? (() => { });
|
|
75
|
+
let currentInput = input;
|
|
76
|
+
let outcome = await runTool(toolName, currentInput, ctx);
|
|
77
|
+
if (outcome.ok)
|
|
78
|
+
return outcome;
|
|
79
|
+
const history = [];
|
|
80
|
+
// Guard against proposing an input we've already run (incl. the original).
|
|
81
|
+
const tried = new Set([safeHash(currentInput)]);
|
|
82
|
+
for (let attempt = 1; attempt <= maxRepairs; attempt++) {
|
|
83
|
+
const failure = toRepairFailure(outcome);
|
|
84
|
+
// Unfixable-by-input class — bail without burning the LLM budget.
|
|
85
|
+
if (failure.classification === "auth") {
|
|
86
|
+
log("repair_skip", { reason: "auth_class_terminal", toolName });
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
const rc = {
|
|
90
|
+
toolName,
|
|
91
|
+
input: currentInput,
|
|
92
|
+
failure,
|
|
93
|
+
attempt,
|
|
94
|
+
history: [...history],
|
|
95
|
+
ctx,
|
|
96
|
+
};
|
|
97
|
+
const proposal = await this.diagnose(rc);
|
|
98
|
+
if (!proposal) {
|
|
99
|
+
log("repair_exhausted", {
|
|
100
|
+
toolName,
|
|
101
|
+
attempt,
|
|
102
|
+
classification: failure.classification,
|
|
103
|
+
reason: "no_strategy_could_repair",
|
|
104
|
+
});
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
const proposedHash = safeHash(proposal.repairedInput);
|
|
108
|
+
if (tried.has(proposedHash)) {
|
|
109
|
+
// A strategy re-proposed something already attempted — stop rather than
|
|
110
|
+
// spin. (Distinct from maxRepairs: this catches a 2-cycle early.)
|
|
111
|
+
log("repair_loop_guard", {
|
|
112
|
+
toolName,
|
|
113
|
+
attempt,
|
|
114
|
+
strategy: proposal.strategy,
|
|
115
|
+
reason: "duplicate_input_proposed",
|
|
116
|
+
});
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
tried.add(proposedHash);
|
|
120
|
+
history.push({ strategy: "original", input: currentInput, failure });
|
|
121
|
+
logger_1.logger.info("repair: retrying with repaired input", {
|
|
122
|
+
toolName,
|
|
123
|
+
attempt,
|
|
124
|
+
strategy: proposal.strategy,
|
|
125
|
+
qualityImpact: proposal.qualityImpact,
|
|
126
|
+
rationale: proposal.rationale,
|
|
127
|
+
priorClassification: failure.classification,
|
|
128
|
+
agentRunId: ctx.agentRunId,
|
|
129
|
+
});
|
|
130
|
+
log("repair_attempt", {
|
|
131
|
+
toolName,
|
|
132
|
+
attempt,
|
|
133
|
+
strategy: proposal.strategy,
|
|
134
|
+
qualityImpact: proposal.qualityImpact,
|
|
135
|
+
rationale: proposal.rationale,
|
|
136
|
+
});
|
|
137
|
+
currentInput = proposal.repairedInput;
|
|
138
|
+
outcome = await runTool(toolName, currentInput, ctx);
|
|
139
|
+
if (outcome.ok) {
|
|
140
|
+
logger_1.logger.info("repair: succeeded", {
|
|
141
|
+
toolName,
|
|
142
|
+
attempt,
|
|
143
|
+
strategy: proposal.strategy,
|
|
144
|
+
agentRunId: ctx.agentRunId,
|
|
145
|
+
});
|
|
146
|
+
log("repair_success", { toolName, attempt, strategy: proposal.strategy });
|
|
147
|
+
return outcome;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return outcome;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
exports.RepairEngine = RepairEngine;
|
|
154
|
+
function toRepairFailure(outcome) {
|
|
155
|
+
if (outcome.ok) {
|
|
156
|
+
// Defensive — callers only pass failures here.
|
|
157
|
+
return { code: "UNKNOWN", message: "no error" };
|
|
158
|
+
}
|
|
159
|
+
return {
|
|
160
|
+
code: outcome.error.code,
|
|
161
|
+
message: outcome.error.message,
|
|
162
|
+
classification: outcome.error.classification,
|
|
163
|
+
attemptedProviders: outcome.error.attemptedProviders,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
function safeHash(input) {
|
|
167
|
+
try {
|
|
168
|
+
return (0, providerTaskCache_1.hashTaskInputs)(input);
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
// Non-canonicalizable input (shouldn't happen for tool inputs) — fall back
|
|
172
|
+
// to a best-effort string so the loop guard still functions.
|
|
173
|
+
return JSON.stringify(input).slice(0, 64);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { RepairEngine } from "./engine";
|
|
2
|
+
export * from "./types";
|
|
3
|
+
export { RepairEngine } from "./engine";
|
|
4
|
+
export { paramRepairStrategy } from "./strategies/paramRepair.strategy";
|
|
5
|
+
export { llmNarrowRepairStrategy, llmWideRepairStrategy, } from "./strategies/llmRepair.strategy";
|
|
6
|
+
/**
|
|
7
|
+
* The default escalation ladder, narrowest-first:
|
|
8
|
+
* rank 0 param-repair — deterministic single-field snap (free, instant)
|
|
9
|
+
* rank 10 llm-repair-narrow — agentic, fix the offending field only
|
|
10
|
+
* rank 20 llm-repair-wide — agentic, may swap model / restructure
|
|
11
|
+
*
|
|
12
|
+
* Engine sorts by rank, so registration order here is cosmetic.
|
|
13
|
+
*/
|
|
14
|
+
export declare function createDefaultRepairEngine(): RepairEngine;
|
|
15
|
+
/**
|
|
16
|
+
* Process-wide default engine. The Executor uses this when the host doesn't
|
|
17
|
+
* inject its own, so self-healing is on by default everywhere the executor runs.
|
|
18
|
+
*/
|
|
19
|
+
export declare const defaultRepairEngine: RepairEngine;
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/services/agent/repair/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAOxC,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,EACL,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,iCAAiC,CAAC;AAEzC;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,IAAI,YAAY,CAMxD;AAED;;;GAGG;AACH,eAAO,MAAM,mBAAmB,EAAE,YAA0C,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.defaultRepairEngine = exports.llmWideRepairStrategy = exports.llmNarrowRepairStrategy = exports.paramRepairStrategy = exports.RepairEngine = void 0;
|
|
18
|
+
exports.createDefaultRepairEngine = createDefaultRepairEngine;
|
|
19
|
+
const engine_1 = require("./engine");
|
|
20
|
+
const paramRepair_strategy_1 = require("./strategies/paramRepair.strategy");
|
|
21
|
+
const llmRepair_strategy_1 = require("./strategies/llmRepair.strategy");
|
|
22
|
+
__exportStar(require("./types"), exports);
|
|
23
|
+
var engine_2 = require("./engine");
|
|
24
|
+
Object.defineProperty(exports, "RepairEngine", { enumerable: true, get: function () { return engine_2.RepairEngine; } });
|
|
25
|
+
var paramRepair_strategy_2 = require("./strategies/paramRepair.strategy");
|
|
26
|
+
Object.defineProperty(exports, "paramRepairStrategy", { enumerable: true, get: function () { return paramRepair_strategy_2.paramRepairStrategy; } });
|
|
27
|
+
var llmRepair_strategy_2 = require("./strategies/llmRepair.strategy");
|
|
28
|
+
Object.defineProperty(exports, "llmNarrowRepairStrategy", { enumerable: true, get: function () { return llmRepair_strategy_2.llmNarrowRepairStrategy; } });
|
|
29
|
+
Object.defineProperty(exports, "llmWideRepairStrategy", { enumerable: true, get: function () { return llmRepair_strategy_2.llmWideRepairStrategy; } });
|
|
30
|
+
/**
|
|
31
|
+
* The default escalation ladder, narrowest-first:
|
|
32
|
+
* rank 0 param-repair — deterministic single-field snap (free, instant)
|
|
33
|
+
* rank 10 llm-repair-narrow — agentic, fix the offending field only
|
|
34
|
+
* rank 20 llm-repair-wide — agentic, may swap model / restructure
|
|
35
|
+
*
|
|
36
|
+
* Engine sorts by rank, so registration order here is cosmetic.
|
|
37
|
+
*/
|
|
38
|
+
function createDefaultRepairEngine() {
|
|
39
|
+
return new engine_1.RepairEngine([
|
|
40
|
+
paramRepair_strategy_1.paramRepairStrategy,
|
|
41
|
+
llmRepair_strategy_1.llmNarrowRepairStrategy,
|
|
42
|
+
llmRepair_strategy_1.llmWideRepairStrategy,
|
|
43
|
+
]);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Process-wide default engine. The Executor uses this when the host doesn't
|
|
47
|
+
* inject its own, so self-healing is on by default everywhere the executor runs.
|
|
48
|
+
*/
|
|
49
|
+
exports.defaultRepairEngine = createDefaultRepairEngine();
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { RepairStrategy } from "../types";
|
|
2
|
+
/** Tier 1 — narrow agentic fix (offending field only, no model change). */
|
|
3
|
+
export declare const llmNarrowRepairStrategy: RepairStrategy;
|
|
4
|
+
/** Tier 2 — wide agentic fix (may swap model / restructure). */
|
|
5
|
+
export declare const llmWideRepairStrategy: RepairStrategy;
|
|
6
|
+
//# sourceMappingURL=llmRepair.strategy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llmRepair.strategy.d.ts","sourceRoot":"","sources":["../../../../../src/services/agent/repair/strategies/llmRepair.strategy.ts"],"names":[],"mappings":"AAOA,OAAO,EAAiC,cAAc,EAAE,MAAM,UAAU,CAAC;AAwOzE,2EAA2E;AAC3E,eAAO,MAAM,uBAAuB,gBAAsC,CAAC;AAC3E,gEAAgE;AAChE,eAAO,MAAM,qBAAqB,gBAAoC,CAAC"}
|