@kodrunhq/opencode-autopilot 1.18.0 → 1.19.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 +95 -13
- package/assets/commands/oc-update-docs.md +1 -1
- package/package.json +1 -1
- package/src/agents/index.ts +0 -12
- package/src/agents/pipeline/index.ts +0 -4
- package/src/autonomy/completion.ts +52 -0
- package/src/autonomy/controller.ts +144 -0
- package/src/autonomy/index.ts +25 -0
- package/src/autonomy/injector.ts +49 -0
- package/src/autonomy/state.ts +91 -0
- package/src/autonomy/types.ts +30 -0
- package/src/autonomy/verification.ts +86 -0
- package/src/background/database.ts +170 -0
- package/src/background/executor.ts +174 -0
- package/src/background/index.ts +8 -0
- package/src/background/manager.ts +232 -0
- package/src/background/repository.ts +174 -0
- package/src/background/schema.ts +24 -0
- package/src/background/sdk-runner.ts +40 -0
- package/src/background/slot-manager.ts +41 -0
- package/src/background/state-machine.ts +19 -0
- package/src/context/budget.ts +45 -0
- package/src/context/compaction-handler.ts +58 -0
- package/src/context/discovery.ts +94 -0
- package/src/context/index.ts +14 -0
- package/src/context/injector.ts +119 -0
- package/src/context/types.ts +24 -0
- package/src/health/checks.ts +145 -2
- package/src/health/index.ts +7 -1
- package/src/health/runner.ts +6 -0
- package/src/index.ts +113 -6
- package/src/installer.ts +13 -0
- package/src/kernel/index.ts +6 -0
- package/src/kernel/migrations.ts +50 -0
- package/src/kernel/retry.ts +49 -0
- package/src/kernel/schema.ts +9 -1
- package/src/kernel/transaction.ts +40 -12
- package/src/logging/forensic-writer.ts +6 -2
- package/src/logging/index.ts +2 -0
- package/src/mcp/index.ts +34 -0
- package/src/mcp/manager.ts +206 -0
- package/src/mcp/scope-filter.ts +44 -0
- package/src/mcp/types.ts +38 -0
- package/src/orchestrator/arena.ts +7 -1
- package/src/orchestrator/fallback/event-handler.ts +12 -1
- package/src/orchestrator/handlers/challenge.ts +8 -1
- package/src/orchestrator/handlers/plan.ts +8 -1
- package/src/orchestrator/handlers/recon.ts +8 -1
- package/src/orchestrator/handlers/types.ts +2 -2
- package/src/orchestrator/lesson-memory.ts +6 -1
- package/src/orchestrator/orchestration-logger.ts +15 -3
- package/src/orchestrator/skill-injection.ts +7 -1
- package/src/orchestrator/state.ts +6 -1
- package/src/recovery/classifier.ts +127 -0
- package/src/recovery/event-handler.ts +263 -0
- package/src/recovery/index.ts +20 -0
- package/src/recovery/orchestrator.ts +180 -0
- package/src/recovery/persistence.ts +87 -0
- package/src/recovery/strategies.ts +107 -0
- package/src/recovery/types.ts +31 -0
- package/src/registry/model-groups.ts +2 -19
- package/src/registry/resolver.ts +38 -9
- package/src/review/agent-catalog.ts +83 -251
- package/src/review/agents/architecture-verifier.ts +41 -0
- package/src/review/agents/code-hygiene-auditor.ts +40 -0
- package/src/review/agents/correctness-auditor.ts +41 -0
- package/src/review/agents/frontend-auditor.ts +39 -0
- package/src/review/agents/index.ts +15 -42
- package/src/review/agents/language-idioms-auditor.ts +39 -0
- package/src/review/agents/security-auditor.ts +12 -8
- package/src/review/stack-gate.ts +2 -6
- package/src/routing/categories.ts +111 -0
- package/src/routing/classifier.ts +152 -0
- package/src/routing/engine.ts +89 -0
- package/src/routing/index.ts +4 -0
- package/src/routing/types.ts +14 -0
- package/src/skills/adaptive-injector.ts +34 -3
- package/src/skills/loader.ts +4 -0
- package/src/tools/background.ts +196 -0
- package/src/tools/delegate.ts +205 -0
- package/src/tools/loop.ts +94 -0
- package/src/tools/recover.ts +172 -0
- package/src/types/recovery.ts +10 -0
- package/src/ux/context-warnings.ts +81 -0
- package/src/ux/error-hints.ts +38 -0
- package/src/ux/index.ts +7 -0
- package/src/ux/notifications.ts +67 -0
- package/src/ux/progress.ts +77 -0
- package/src/ux/session-summary.ts +67 -0
- package/src/ux/task-status.ts +109 -0
- package/src/ux/types.ts +24 -0
- package/src/agents/db-specialist.ts +0 -295
- package/src/agents/devops.ts +0 -352
- package/src/agents/documenter.ts +0 -44
- package/src/agents/frontend-engineer.ts +0 -541
- package/src/agents/pipeline/oc-explorer.ts +0 -46
- package/src/agents/pipeline/oc-retrospector.ts +0 -42
- package/src/review/agents/auth-flow-verifier.ts +0 -47
- package/src/review/agents/concurrency-checker.ts +0 -47
- package/src/review/agents/dead-code-scanner.ts +0 -47
- package/src/review/agents/go-idioms-auditor.ts +0 -46
- package/src/review/agents/python-django-auditor.ts +0 -46
- package/src/review/agents/react-patterns-auditor.ts +0 -46
- package/src/review/agents/rust-safety-auditor.ts +0 -46
- package/src/review/agents/scope-intent-verifier.ts +0 -45
- package/src/review/agents/silent-failure-hunter.ts +0 -45
- package/src/review/agents/spec-checker.ts +0 -45
- package/src/review/agents/state-mgmt-auditor.ts +0 -46
- package/src/review/agents/type-soundness.ts +0 -46
- package/src/review/agents/wiring-inspector.ts +0 -46
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { Database } from "bun:sqlite";
|
|
2
|
+
import { withTransaction } from "../kernel/transaction";
|
|
3
|
+
import type { RecoveryAttempt, RecoveryState } from "./types";
|
|
4
|
+
|
|
5
|
+
interface RecoveryStateRow {
|
|
6
|
+
readonly session_id: string;
|
|
7
|
+
readonly state_json: string;
|
|
8
|
+
readonly updated_at: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function isRecoveryAttempt(value: unknown): value is RecoveryAttempt {
|
|
12
|
+
if (value === null || typeof value !== "object") {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const candidate = value as Record<string, unknown>;
|
|
17
|
+
return (
|
|
18
|
+
typeof candidate.attemptNumber === "number" &&
|
|
19
|
+
typeof candidate.strategy === "string" &&
|
|
20
|
+
typeof candidate.errorCategory === "string" &&
|
|
21
|
+
typeof candidate.timestamp === "string" &&
|
|
22
|
+
typeof candidate.success === "boolean" &&
|
|
23
|
+
(candidate.error === undefined || typeof candidate.error === "string")
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function isRecoveryState(value: unknown): value is RecoveryState {
|
|
28
|
+
if (value === null || typeof value !== "object") {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const candidate = value as Record<string, unknown>;
|
|
33
|
+
return (
|
|
34
|
+
typeof candidate.sessionId === "string" &&
|
|
35
|
+
Array.isArray(candidate.attempts) &&
|
|
36
|
+
candidate.attempts.every(isRecoveryAttempt) &&
|
|
37
|
+
(candidate.currentStrategy === null || typeof candidate.currentStrategy === "string") &&
|
|
38
|
+
typeof candidate.maxAttempts === "number" &&
|
|
39
|
+
typeof candidate.isRecovering === "boolean" &&
|
|
40
|
+
(candidate.lastError === null || typeof candidate.lastError === "string")
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function parseState(row: RecoveryStateRow | null): RecoveryState | null {
|
|
45
|
+
if (!row) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const parsed = JSON.parse(row.state_json) as unknown;
|
|
50
|
+
return isRecoveryState(parsed) ? Object.freeze(parsed) : null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function saveRecoveryState(db: Database, state: RecoveryState): void {
|
|
54
|
+
const updatedAt = new Date().toISOString();
|
|
55
|
+
withTransaction(db, () => {
|
|
56
|
+
db.run(
|
|
57
|
+
`INSERT INTO recovery_state (session_id, state_json, updated_at)
|
|
58
|
+
VALUES (?, ?, ?)
|
|
59
|
+
ON CONFLICT(session_id) DO UPDATE SET
|
|
60
|
+
state_json = excluded.state_json,
|
|
61
|
+
updated_at = excluded.updated_at`,
|
|
62
|
+
[state.sessionId, JSON.stringify(state), updatedAt],
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function loadRecoveryState(db: Database, sessionId: string): RecoveryState | null {
|
|
68
|
+
const row = db
|
|
69
|
+
.query("SELECT session_id, state_json, updated_at FROM recovery_state WHERE session_id = ?")
|
|
70
|
+
.get(sessionId) as RecoveryStateRow | null;
|
|
71
|
+
return parseState(row);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function clearRecoveryState(db: Database, sessionId: string): void {
|
|
75
|
+
withTransaction(db, () => {
|
|
76
|
+
db.run("DELETE FROM recovery_state WHERE session_id = ?", [sessionId]);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function listRecoveryStates(db: Database): readonly RecoveryState[] {
|
|
81
|
+
const rows = db
|
|
82
|
+
.query("SELECT session_id, state_json, updated_at FROM recovery_state ORDER BY updated_at DESC")
|
|
83
|
+
.all() as RecoveryStateRow[];
|
|
84
|
+
return Object.freeze(
|
|
85
|
+
rows.map(parseState).filter((state): state is RecoveryState => state !== null),
|
|
86
|
+
);
|
|
87
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { ErrorCategory, RecoveryAction } from "../types/recovery";
|
|
2
|
+
import type { RecoveryState } from "./types";
|
|
3
|
+
|
|
4
|
+
export type RecoveryStrategyResolver = (context: RecoveryState) => RecoveryAction;
|
|
5
|
+
|
|
6
|
+
function createAction(
|
|
7
|
+
strategy: RecoveryAction["strategy"],
|
|
8
|
+
errorCategory: ErrorCategory,
|
|
9
|
+
maxAttempts: number,
|
|
10
|
+
backoffMs: number,
|
|
11
|
+
metadata: Record<string, unknown> = {},
|
|
12
|
+
): RecoveryAction {
|
|
13
|
+
return Object.freeze({
|
|
14
|
+
strategy,
|
|
15
|
+
errorCategory,
|
|
16
|
+
maxAttempts,
|
|
17
|
+
backoffMs,
|
|
18
|
+
metadata,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function getAttemptIndex(context: RecoveryState): number {
|
|
23
|
+
return context.attempts.length;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function retryWithBackoff(category: ErrorCategory): RecoveryStrategyResolver {
|
|
27
|
+
return (context) => {
|
|
28
|
+
const attemptIndex = getAttemptIndex(context);
|
|
29
|
+
return createAction("retry", category, context.maxAttempts, 1000 * 2 ** attemptIndex, {
|
|
30
|
+
retryMode: "backoff",
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function fallbackModel(category: ErrorCategory): RecoveryStrategyResolver {
|
|
36
|
+
return (context) =>
|
|
37
|
+
createAction("fallback_model", category, context.maxAttempts, 0, {
|
|
38
|
+
switchModel: true,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function compactAndRetry(category: ErrorCategory): RecoveryStrategyResolver {
|
|
43
|
+
return (context) =>
|
|
44
|
+
createAction("compact_and_retry", category, context.maxAttempts, 500, {
|
|
45
|
+
compactContext: true,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function restartSession(category: ErrorCategory): RecoveryStrategyResolver {
|
|
50
|
+
return (context) =>
|
|
51
|
+
createAction("restart_session", category, context.maxAttempts, 0, {
|
|
52
|
+
restartSession: true,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function reduceContext(category: ErrorCategory): RecoveryStrategyResolver {
|
|
57
|
+
return (context) =>
|
|
58
|
+
createAction("reduce_context", category, context.maxAttempts, 250, {
|
|
59
|
+
trimContext: true,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function skipAndContinue(category: ErrorCategory): RecoveryStrategyResolver {
|
|
64
|
+
return (context) =>
|
|
65
|
+
createAction("skip_and_continue", category, context.maxAttempts, 0, {
|
|
66
|
+
skipCurrentStep: true,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function userPrompt(category: ErrorCategory): RecoveryStrategyResolver {
|
|
71
|
+
return (context) => createAction("user_prompt", category, context.maxAttempts, 0);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function abort(category: ErrorCategory): RecoveryStrategyResolver {
|
|
75
|
+
return (context) => createAction("abort", category, context.maxAttempts, 0);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function getStrategy(category: ErrorCategory): RecoveryStrategyResolver {
|
|
79
|
+
switch (category) {
|
|
80
|
+
case "rate_limit":
|
|
81
|
+
case "timeout":
|
|
82
|
+
case "network":
|
|
83
|
+
case "service_unavailable":
|
|
84
|
+
return retryWithBackoff(category);
|
|
85
|
+
case "quota_exceeded":
|
|
86
|
+
case "empty_content":
|
|
87
|
+
case "thinking_block_error":
|
|
88
|
+
return fallbackModel(category);
|
|
89
|
+
case "tool_result_overflow":
|
|
90
|
+
return compactAndRetry(category);
|
|
91
|
+
case "context_window_exceeded":
|
|
92
|
+
return (context) =>
|
|
93
|
+
getAttemptIndex(context) > 0
|
|
94
|
+
? reduceContext(category)(context)
|
|
95
|
+
: compactAndRetry(category)(context);
|
|
96
|
+
case "session_corruption":
|
|
97
|
+
return restartSession(category);
|
|
98
|
+
case "agent_loop_stuck":
|
|
99
|
+
return skipAndContinue(category);
|
|
100
|
+
case "validation":
|
|
101
|
+
return userPrompt(category);
|
|
102
|
+
case "auth_failure":
|
|
103
|
+
return abort(category);
|
|
104
|
+
default:
|
|
105
|
+
return retryWithBackoff(category);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { ErrorCategory, RecoveryAction, RecoveryStrategy } from "../types/recovery";
|
|
2
|
+
|
|
3
|
+
export interface ClassificationResult {
|
|
4
|
+
readonly category: ErrorCategory;
|
|
5
|
+
readonly confidence: number;
|
|
6
|
+
readonly reasoning: string;
|
|
7
|
+
readonly isRecoverable: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface RecoveryAttempt {
|
|
11
|
+
readonly attemptNumber: number;
|
|
12
|
+
readonly strategy: RecoveryStrategy;
|
|
13
|
+
readonly errorCategory: ErrorCategory;
|
|
14
|
+
readonly timestamp: string;
|
|
15
|
+
readonly success: boolean;
|
|
16
|
+
readonly error?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface RecoveryState {
|
|
20
|
+
readonly sessionId: string;
|
|
21
|
+
readonly attempts: readonly RecoveryAttempt[];
|
|
22
|
+
readonly currentStrategy: RecoveryStrategy | null;
|
|
23
|
+
readonly maxAttempts: number;
|
|
24
|
+
readonly isRecovering: boolean;
|
|
25
|
+
readonly lastError: string | null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface RecoveryActionEnvelope {
|
|
29
|
+
readonly action: RecoveryAction;
|
|
30
|
+
readonly state: RecoveryState;
|
|
31
|
+
}
|
|
@@ -11,56 +11,39 @@ function deepFreeze<T extends object>(obj: T): Readonly<T> {
|
|
|
11
11
|
|
|
12
12
|
export const AGENT_REGISTRY: Readonly<Record<string, AgentEntry>> = deepFreeze({
|
|
13
13
|
// ── Architects ─────────────────────────────────────────────
|
|
14
|
-
// Deep reasoning: system design, task decomposition, orchestration
|
|
15
14
|
"oc-architect": { group: "architects" },
|
|
16
15
|
"oc-planner": { group: "architects" },
|
|
17
16
|
autopilot: { group: "architects" },
|
|
18
17
|
planner: { group: "architects" },
|
|
19
18
|
|
|
20
19
|
// ── Challengers ────────────────────────────────────────────
|
|
21
|
-
// Adversarial to Architects: critique proposals, enhance ideas
|
|
22
20
|
"oc-critic": { group: "challengers" },
|
|
23
21
|
"oc-challenger": { group: "challengers" },
|
|
24
22
|
|
|
25
23
|
// ── Builders ───────────────────────────────────────────────
|
|
26
|
-
// Code generation and debugging
|
|
27
24
|
"oc-implementer": { group: "builders" },
|
|
25
|
+
coder: { group: "builders" },
|
|
28
26
|
debugger: { group: "builders" },
|
|
29
27
|
|
|
30
28
|
// ── Reviewers ──────────────────────────────────────────────
|
|
31
|
-
// Code analysis, adversarial to Builders
|
|
32
|
-
// NOTE: The 21 internal ReviewAgent objects (logic-auditor, security-auditor,
|
|
33
|
-
// etc.) are NOT in this registry. They use the ReviewAgent type from
|
|
34
|
-
// src/review/types.ts, not AgentConfig. The review pipeline resolves their
|
|
35
|
-
// model via resolveModelForGroup("reviewers") directly.
|
|
36
29
|
"oc-reviewer": { group: "reviewers" },
|
|
37
30
|
reviewer: { group: "reviewers" },
|
|
38
31
|
|
|
39
32
|
// ── Red Team ───────────────────────────────────────────────
|
|
40
|
-
// Final adversarial pass
|
|
41
|
-
// NOTE: red-team and product-thinker are ALSO internal ReviewAgent objects
|
|
42
|
-
// in STAGE3_AGENTS (src/review/agents/index.ts). They appear here so the
|
|
43
|
-
// review pipeline can resolve their model via resolveModelForGroup("red-team")
|
|
44
|
-
// separately from the "reviewers" group.
|
|
45
33
|
"red-team": { group: "red-team" },
|
|
46
34
|
"product-thinker": { group: "red-team" },
|
|
47
35
|
|
|
48
36
|
// ── Researchers ────────────────────────────────────────────
|
|
49
|
-
// Domain research, feasibility analysis
|
|
50
37
|
"oc-researcher": { group: "researchers" },
|
|
51
38
|
researcher: { group: "researchers" },
|
|
52
39
|
|
|
53
40
|
// ── Communicators ──────────────────────────────────────────
|
|
54
|
-
// Docs, changelogs, lesson extraction
|
|
55
41
|
"oc-shipper": { group: "communicators" },
|
|
56
|
-
documenter: { group: "communicators" },
|
|
57
|
-
"oc-retrospector": { group: "communicators" },
|
|
58
42
|
|
|
59
43
|
// ── Utilities ──────────────────────────────────────────────
|
|
60
|
-
// Fast lookups, prompt tuning, PR scanning
|
|
61
|
-
"oc-explorer": { group: "utilities" },
|
|
62
44
|
metaprompter: { group: "utilities" },
|
|
63
45
|
"pr-reviewer": { group: "utilities" },
|
|
46
|
+
"security-auditor": { group: "reviewers" },
|
|
64
47
|
});
|
|
65
48
|
|
|
66
49
|
export const GROUP_DEFINITIONS: Readonly<Record<GroupId, GroupDefinition>> = deepFreeze({
|
package/src/registry/resolver.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { AGENT_REGISTRY } from "./model-groups";
|
|
2
2
|
import type { AgentOverride, GroupId, GroupModelAssignment, ResolvedModel } from "./types";
|
|
3
3
|
|
|
4
|
+
const DEPRECATED_AGENT_REMAP: Readonly<Record<string, string>> = Object.freeze({
|
|
5
|
+
documenter: "coder",
|
|
6
|
+
devops: "coder",
|
|
7
|
+
"frontend-engineer": "coder",
|
|
8
|
+
"db-specialist": "coder",
|
|
9
|
+
"oc-explorer": "oc-researcher",
|
|
10
|
+
"oc-retrospector": "oc-shipper",
|
|
11
|
+
});
|
|
12
|
+
|
|
4
13
|
/**
|
|
5
14
|
* Extract model family (provider) from a model string.
|
|
6
15
|
* "anthropic/claude-opus-4-6" → "anthropic"
|
|
@@ -17,15 +26,15 @@ export function extractFamily(model: string): string {
|
|
|
17
26
|
*
|
|
18
27
|
* Resolution order:
|
|
19
28
|
* 1. Per-agent override in overrides[agentName]
|
|
20
|
-
* 2.
|
|
21
|
-
* 3.
|
|
29
|
+
* 2. Deprecated agent remap → resolve via new agent name
|
|
30
|
+
* 3. Agent's group in AGENT_REGISTRY → groups[groupId]
|
|
31
|
+
* 4. null (agent uses OpenCode's default model)
|
|
22
32
|
*/
|
|
23
33
|
export function resolveModelForAgent(
|
|
24
34
|
agentName: string,
|
|
25
35
|
groups: Readonly<Record<string, GroupModelAssignment>>,
|
|
26
36
|
overrides: Readonly<Record<string, AgentOverride>>,
|
|
27
37
|
): ResolvedModel | null {
|
|
28
|
-
// Tier 1: per-agent override
|
|
29
38
|
const override = overrides[agentName];
|
|
30
39
|
if (override) {
|
|
31
40
|
return {
|
|
@@ -35,7 +44,30 @@ export function resolveModelForAgent(
|
|
|
35
44
|
};
|
|
36
45
|
}
|
|
37
46
|
|
|
38
|
-
|
|
47
|
+
const remappedName = DEPRECATED_AGENT_REMAP[agentName];
|
|
48
|
+
if (remappedName) {
|
|
49
|
+
const remappedOverride = overrides[remappedName];
|
|
50
|
+
if (remappedOverride) {
|
|
51
|
+
return {
|
|
52
|
+
primary: remappedOverride.primary,
|
|
53
|
+
fallbacks: remappedOverride.fallbacks ?? [],
|
|
54
|
+
source: "override",
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const remappedEntry = AGENT_REGISTRY[remappedName];
|
|
59
|
+
if (remappedEntry) {
|
|
60
|
+
const remappedGroup = groups[remappedEntry.group];
|
|
61
|
+
if (remappedGroup) {
|
|
62
|
+
return {
|
|
63
|
+
primary: remappedGroup.primary,
|
|
64
|
+
fallbacks: remappedGroup.fallbacks,
|
|
65
|
+
source: "group",
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
39
71
|
const entry = AGENT_REGISTRY[agentName];
|
|
40
72
|
if (entry) {
|
|
41
73
|
const group = groups[entry.group];
|
|
@@ -48,17 +80,12 @@ export function resolveModelForAgent(
|
|
|
48
80
|
}
|
|
49
81
|
}
|
|
50
82
|
|
|
51
|
-
// Tier 3: no assignment
|
|
52
83
|
return null;
|
|
53
84
|
}
|
|
54
85
|
|
|
55
86
|
/**
|
|
56
87
|
* Resolve model for a group directly (used by review pipeline for
|
|
57
88
|
* internal ReviewAgent objects that are not in AGENT_REGISTRY).
|
|
58
|
-
*
|
|
59
|
-
* Used by:
|
|
60
|
-
* - Review pipeline for the 19 universal+specialized agents → "reviewers"
|
|
61
|
-
* - Review pipeline for red-team + product-thinker → "red-team"
|
|
62
89
|
*/
|
|
63
90
|
export function resolveModelForGroup(
|
|
64
91
|
groupId: GroupId,
|
|
@@ -72,3 +99,5 @@ export function resolveModelForGroup(
|
|
|
72
99
|
source: "group",
|
|
73
100
|
};
|
|
74
101
|
}
|
|
102
|
+
|
|
103
|
+
export { DEPRECATED_AGENT_REMAP };
|