opencode-swarm 7.125.3 → 7.125.5

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.
Files changed (51) hide show
  1. package/.opencode/skills/swarm-pr-feedback/SKILL.md +15 -0
  2. package/.opencode/skills/swarm-pr-review/SKILL.md +34 -0
  3. package/dist/cli/{config-doctor-rm1m07gz.js → config-doctor-akxywx0c.js} +2 -2
  4. package/dist/cli/{curation-policy-7pgdjt5w.js → curation-policy-62w2pwfz.js} +2 -2
  5. package/dist/cli/{curator-llm-factory-yq5vf298.js → curator-llm-factory-av2tcfy9.js} +12 -12
  6. package/dist/cli/{curator-arwm18td.js → curator-mhhvx2pw.js} +12 -12
  7. package/dist/cli/{guardrail-explain-mscq3veq.js → guardrail-explain-kqx2bczn.js} +13 -13
  8. package/dist/cli/{guardrail-log-6a2zxvtx.js → guardrail-log-222xyxfp.js} +3 -3
  9. package/dist/cli/{hive-promoter-q79naynh.js → hive-promoter-6mhnhrbx.js} +12 -12
  10. package/dist/cli/{index-7p6jkkat.js → index-0cdq55k0.js} +14 -14
  11. package/dist/cli/{index-vdfewvn5.js → index-0f45t7xy.js} +5 -5
  12. package/dist/cli/{index-45mvd5q7.js → index-1012f47p.js} +4 -4
  13. package/dist/cli/{index-rp5msv7n.js → index-1htanqp1.js} +1 -1
  14. package/dist/cli/{index-emzes7sj.js → index-4b1e5m0d.js} +2 -2
  15. package/dist/cli/{index-ambnwnmt.js → index-74xejn4v.js} +1 -1
  16. package/dist/cli/{index-x8entmky.js → index-ccfkfrew.js} +2 -2
  17. package/dist/cli/{index-xezv6tdw.js → index-dezgmvtw.js} +1 -1
  18. package/dist/cli/{index-8tjbq2ej.js → index-e315gwc9.js} +1 -1
  19. package/dist/cli/{index-fm4zfxnr.js → index-gbnpz7rh.js} +1 -1
  20. package/dist/cli/{index-01n43w2p.js → index-gd5w3ef8.js} +3 -3
  21. package/dist/cli/{index-pk099nqv.js → index-jt7hnr7q.js} +1 -1
  22. package/dist/cli/{index-4ycq2mrp.js → index-qzkcy22e.js} +1 -1
  23. package/dist/cli/{index-414r47r7.js → index-r1gdkn2d.js} +4 -0
  24. package/dist/cli/{index-m5e00g9s.js → index-s6hskqg6.js} +231 -98
  25. package/dist/cli/{index-sa3dgpmc.js → index-yq4s3q43.js} +2 -2
  26. package/dist/cli/index.js +12 -12
  27. package/dist/cli/{knowledge-escalator-gr8qd7kz.js → knowledge-escalator-h3hg7ek7.js} +3 -3
  28. package/dist/cli/{knowledge-events-q83g3f8z.js → knowledge-events-jtr66wxz.js} +1 -1
  29. package/dist/cli/{knowledge-store-qq3w5yt8.js → knowledge-store-69ttjjjs.js} +1 -1
  30. package/dist/cli/{knowledge-validator-7jhq8yam.js → knowledge-validator-yn06rh13.js} +4 -4
  31. package/dist/cli/{scan-cursor-fa5sy36q.js → scan-cursor-r0w2p5gz.js} +2 -2
  32. package/dist/cli/{schema-bw68my66.js → schema-69z8w1ka.js} +1 -1
  33. package/dist/cli/{skill-generator-ffc1agyw.js → skill-generator-a7xfyddq.js} +5 -5
  34. package/dist/commands/abort-pr-workflow.d.ts +17 -0
  35. package/dist/commands/registry.d.ts +8 -0
  36. package/dist/hooks/delegation-gate.d.ts +35 -0
  37. package/dist/hooks/pr-workflow-gate.d.ts +32 -0
  38. package/dist/hooks/pr-workflow-response-gate.d.ts +48 -0
  39. package/dist/hooks/shell-write-detect.d.ts +1 -1
  40. package/dist/index.js +100 -84
  41. package/dist/session/snapshot-writer.d.ts +9 -0
  42. package/dist/state.d.ts +15 -0
  43. package/dist/tools/abort-pr-workflow.d.ts +5 -0
  44. package/dist/tools/index.d.ts +1 -0
  45. package/dist/tools/manifest.d.ts +1 -0
  46. package/dist/tools/tool-metadata.d.ts +4 -0
  47. package/dist/turbo/lean/reviewer.d.ts +2 -1
  48. package/dist/turbo/lean/runner.d.ts +2 -1
  49. package/dist/utils/model-dispatch-fallback.d.ts +71 -0
  50. package/dist/utils/provider-error-classification.d.ts +52 -0
  51. package/package.json +1 -1
@@ -76,6 +76,15 @@ export interface SerializedAgentSession {
76
76
  * so older snapshots deserialize cleanly; the reader defaults to undefined.
77
77
  */
78
78
  cachedCohortId?: string;
79
+ /**
80
+ * Last observed `provider/model` for this (architect) session (#1896). Omitted
81
+ * when undefined for additive-only schema. MUST survive rehydration (it is NOT
82
+ * a transient-reset field) so a silent cross-interrupt model switch is
83
+ * detectable on resume.
84
+ */
85
+ lastObservedModel?: string;
86
+ /** Provider id paired with lastObservedModel (#1896). Omitted when undefined. */
87
+ lastObservedProviderID?: string;
79
88
  }
80
89
  /**
81
90
  * Minimal interface for serialized InvocationWindow
package/dist/state.d.ts CHANGED
@@ -271,6 +271,21 @@ export interface AgentSessionState {
271
271
  * failed); callers must handle the miss with a bounded fallback.
272
272
  */
273
273
  cachedCohortId?: string;
274
+ /**
275
+ * The `provider/model` most recently OBSERVED on this (architect/primary)
276
+ * session's assistant turns (e.g. "anthropic/claude"). Persisted through
277
+ * snapshots and deliberately NOT reset on rehydration, so a silent model
278
+ * switch across an interrupt can be detected on resume by comparing the
279
+ * pre-interrupt observation with the first post-resume one. `undefined` until
280
+ * first observed.
281
+ */
282
+ lastObservedModel?: string;
283
+ /** Provider id paired with `lastObservedModel` (#1896). */
284
+ lastObservedProviderID?: string;
285
+ /** One-shot guard: the resume model-change advisory has fired for this rehydration (#1896). */
286
+ resumeModelAdvisoryDone?: boolean;
287
+ /** One-shot guard: the config-vs-UI model advisory has fired for this session (#1896). */
288
+ configModelAdvisoryDone?: boolean;
274
289
  }
275
290
  export type NonTransientErrorCategory = 'shell_parse_error' | 'command_not_found' | 'sandbox_wrapper_failure' | 'general_permanent';
276
291
  export interface NonTransientCircuitState {
@@ -0,0 +1,5 @@
1
+ import { createSwarmTool } from './create-tool.js';
2
+ export declare function executeAbortPrWorkflow(args: unknown, directory: string, context?: {
3
+ sessionID?: string;
4
+ }): Promise<string>;
5
+ export declare const abort_pr_workflow: ReturnType<typeof createSwarmTool>;
@@ -86,6 +86,7 @@ export type { ClassifiedFailure, FailureClassification, FailureCluster, } from '
86
86
  export { classifyAndCluster, classifyFailure, clusterFailures, } from '../test-impact/failure-classifier.js';
87
87
  export type { FlakyTestEntry } from '../test-impact/flaky-detector.js';
88
88
  export { computeFlakyScore, detectFlakyTests, isTestQuarantined, } from '../test-impact/flaky-detector.js';
89
+ export { abort_pr_workflow, executeAbortPrWorkflow, } from './abort-pr-workflow';
89
90
  export { complete_pr_workflow, executeCompletePrWorkflow, } from './complete-pr-workflow';
90
91
  export { epic_plan_waves } from './epic-plan-waves';
91
92
  export { epic_record_divergence } from './epic-record-divergence';
@@ -43,6 +43,7 @@ export declare const TOOL_MANIFEST: {
43
43
  check_gate_status: () => ToolDefinition;
44
44
  completion_verify: () => ToolDefinition;
45
45
  complete_pr_workflow: () => ToolDefinition;
46
+ abort_pr_workflow: () => ToolDefinition;
46
47
  run_pr_feedback_stage_a: () => ToolDefinition;
47
48
  submit_council_verdicts: () => ToolDefinition;
48
49
  submit_phase_council_verdicts: () => ToolDefinition;
@@ -103,6 +103,10 @@ export declare const TOOL_METADATA: {
103
103
  description: string;
104
104
  agents: "architect"[];
105
105
  };
106
+ abort_pr_workflow: {
107
+ description: string;
108
+ agents: "architect"[];
109
+ };
106
110
  run_pr_feedback_stage_a: {
107
111
  description: string;
108
112
  agents: "architect"[];
@@ -1,3 +1,4 @@
1
+ import { type ModelOverride } from '../../utils/model-dispatch-fallback';
1
2
  import { type LaneEvidence, listLaneEvidence, readPhaseEvidence, type ValidationArtifact } from './evidence';
2
3
  import { readPersisted } from './state';
3
4
  /**
@@ -102,7 +103,7 @@ export declare const _internals: {
102
103
  compileReviewPackage: typeof compileReviewPackage;
103
104
  parseReviewerVerdict: typeof parseReviewerVerdict;
104
105
  writeReviewerEvidence: typeof writeReviewerEvidence;
105
- dispatchReviewerAgent: (directory: string, pkg: ReviewPackage, agentName: string, timeoutMs: number, parentSessionId?: string) => Promise<string>;
106
+ dispatchReviewerAgent: (directory: string, pkg: ReviewPackage, agentName: string, timeoutMs: number, parentSessionId?: string, model?: ModelOverride) => Promise<string>;
106
107
  resolveDefaultReviewerAgent: typeof resolveDefaultReviewerAgent;
107
108
  listLaneEvidence: typeof listLaneEvidence;
108
109
  readPhaseEvidence: typeof readPhaseEvidence;
@@ -21,6 +21,7 @@ import { loadFullAutoRunState } from '../../full-auto/state';
21
21
  import { acquireLaneLocks, releaseLaneLocks } from '../../parallel/file-locks';
22
22
  import { loadPlanJsonOnly } from '../../plan/manager';
23
23
  import { ensureAgentSession, hasActiveFullAuto } from '../../state';
24
+ import { type ModelOverride } from '../../utils/model-dispatch-fallback';
24
25
  import { writeLaneEvidence, writePhaseEvidence } from './evidence';
25
26
  import { attemptMergeBackFromDirty, getMergeStrategy, mergeLaneBranch, postMergeCleanup, startupOrphanRecovery } from './merge-back';
26
27
  import { planLeanTurboLanes } from './planner';
@@ -263,7 +264,7 @@ export declare class LeanTurboRunner {
263
264
  * @param lane - Lane to dispatch
264
265
  * @param agentName - Agent name to dispatch to
265
266
  */
266
- dispatchLane(lane: LeanTurboLane, agentName: string, worktreeDirectory?: string): Promise<LaneDispatchResult>;
267
+ dispatchLane(lane: LeanTurboLane, agentName: string, worktreeDirectory?: string, model?: ModelOverride): Promise<LaneDispatchResult>;
267
268
  /**
268
269
  * Internal dispatch implementation (separated for timeout wrapping).
269
270
  */
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Issue #1896 (sub-issue 3): shared model-fallback dispatch helper.
3
+ *
4
+ * Before this, the ONLY place a role failed over to its configured
5
+ * `fallback_models` was the guardrails `toolAfter` hook (which fires on
6
+ * tool-result payloads). Every direct model-dispatch stage — critic oversight,
7
+ * lean-turbo reviewer, lane runner — called the provider directly and never
8
+ * failed over, so a role that hit its quota mid-run failed the stage outright.
9
+ *
10
+ * All those stages dispatch via `client.session.prompt({ body: { agent, model }})`,
11
+ * which accepts a per-call `model: {providerID, modelID}` override. This helper
12
+ * wraps such a dispatch with (a) bounded, per-model transient retry and (b)
13
+ * model-fallback advance — kept INDEPENDENT per AGENTS.md invariant #9. The
14
+ * fallback index is owned LOCALLY here: every stage dispatches into an ephemeral
15
+ * child session, so the only reachable `session.model_fallback_index` belongs to
16
+ * the parent orchestrator (a different agent) and must not be reused.
17
+ *
18
+ * The helper does NOT import `src/agents/index.ts` (avoids a heavy import cycle);
19
+ * the caller injects a `resolveFallback(index)` closure that wraps
20
+ * `resolveFallbackModel(baseRole, index, getSwarmAgents(swarmId))`.
21
+ */
22
+ /** Per-call model override shape accepted by `client.session.prompt` body. */
23
+ export interface ModelOverride {
24
+ providerID: string;
25
+ modelID: string;
26
+ }
27
+ /**
28
+ * Parse a `provider/model` string into the per-call override shape. Returns
29
+ * undefined for empty/blank input. Throws on a value with no provider or no
30
+ * model segment.
31
+ */
32
+ export declare function parseModelString(model: string): ModelOverride | undefined;
33
+ export interface ModelFallbackResult<T> {
34
+ result: T;
35
+ /** undefined = the agent's registered/primary model; otherwise the `provider/model` string used. */
36
+ modelUsed?: string;
37
+ /** 0 = primary; 1.. = which configured fallback landed. */
38
+ fallbackIndex: number;
39
+ /** total dispatch attempts made (across models + same-model retries). */
40
+ attempts: number;
41
+ }
42
+ export interface DispatchWithModelFallbackOptions<T> {
43
+ /** Dispatch using `model` (undefined = the agent's registered/primary model). */
44
+ dispatch: (model: ModelOverride | undefined) => Promise<T>;
45
+ /**
46
+ * Resolve the 1-based fallback model as a `provider/model` string, or null
47
+ * when the fallback chain is exhausted. Typically wraps
48
+ * `resolveFallbackModel(baseRole, index, getSwarmAgents(swarmId))`.
49
+ */
50
+ resolveFallback: (fallbackIndex: number) => string | null;
51
+ /** Classify a dispatch error: 'transient' → retry/failover; 'permanent' → throw immediately. */
52
+ classify: (error: unknown) => 'transient' | 'permanent';
53
+ /** Bounded transient retries on the SAME model before advancing (invariant #9 — independent of fallback). Default 1. */
54
+ maxTransientRetriesPerModel?: number;
55
+ /** Backoff before a same-model retry (NOT before a fallback advance). Default 2**(n-1)*1000 ms. */
56
+ backoffMs?: (retryAttempt: number) => number;
57
+ /** Notified when advancing to a fallback model (for advisory/telemetry). */
58
+ onFallback?: (info: {
59
+ toModel: string;
60
+ fallbackIndex: number;
61
+ }) => void;
62
+ /** DI for tests (avoid real waits). */
63
+ sleep?: (ms: number) => Promise<void>;
64
+ }
65
+ /**
66
+ * Try the primary model, then each configured fallback, retrying transient
67
+ * failures a bounded number of times per model. A permanent failure throws
68
+ * immediately (no retry, no advance). When every model is exhausted transiently,
69
+ * the last error is rethrown.
70
+ */
71
+ export declare function dispatchWithModelFallback<T>(opts: DispatchWithModelFallbackOptions<T>): Promise<ModelFallbackResult<T>>;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Issue #1896 (sub-issue 3): single source of truth for provider/model
3
+ * transient-error classification.
4
+ *
5
+ * Previously the same `TRANSIENT_MODEL_ERROR_PATTERN` + transient-status-code set
6
+ * was duplicated across `src/hooks/guardrails/index.ts`,
7
+ * `src/hooks/guardrails/messages-transform.ts`, and `src/full-auto/oversight.ts`,
8
+ * and NONE recognized provider quota / usage-limit exhaustion — so a role whose
9
+ * model hit its quota mid-run failed the stage outright instead of failing over
10
+ * to a configured fallback model.
11
+ *
12
+ * Design (see the plan critic's M1): QUOTA is a SEPARATE pattern and is combined
13
+ * ONLY inside {@link isTransientProviderError}, which is consumed exclusively by
14
+ * the model-DISPATCH classifiers (the failover helper + oversight/reviewer/runner
15
+ * dispatch paths). The narrow {@link TRANSIENT_MODEL_ERROR_PATTERN} (no quota) is
16
+ * what the guardrails tool-OUTPUT classifier keeps using, so a bash
17
+ * `Disk quota exceeded` (EDQUOT) in tool stdout can never be misread as a
18
+ * transient provider error and trigger a bogus model fallback.
19
+ */
20
+ /** v6.33: Known HTTP status codes that indicate transient provider errors. */
21
+ export declare const TRANSIENT_STATUS_CODES: Set<number>;
22
+ /** Extracts a transient HTTP status code from an error message string. */
23
+ export declare function extractStatusCode(errorMsg: string): number | null;
24
+ /**
25
+ * v6.33: Regex for transient model/provider errors that should trigger bounded
26
+ * retry (and, in the dispatch paths, model fallback). Content is UNCHANGED from
27
+ * the historical duplicated definition — quota is intentionally NOT here (see the
28
+ * module doc + {@link QUOTA_ERROR_PATTERN}), so tool-output classifiers that
29
+ * import this keep byte-identical behavior.
30
+ */
31
+ export declare const TRANSIENT_MODEL_ERROR_PATTERN: RegExp;
32
+ /**
33
+ * Issue #1896: provider quota / usage-limit / billing exhaustion — a class
34
+ * distinct from a transient blip. It is retryable after a wait AND fallback-
35
+ * eligible (a different configured model may have its own quota). Used ONLY on
36
+ * model-DISPATCH error strings via {@link isTransientProviderError}, never on
37
+ * tool stdout, so `Disk quota exceeded` shell output cannot false-trigger it.
38
+ */
39
+ export declare const QUOTA_ERROR_PATTERN: RegExp;
40
+ /**
41
+ * True when a model-DISPATCH error is a transient provider failure OR a
42
+ * quota/rate-limit exhaustion — both are retry + model-fallback eligible.
43
+ * Do NOT use this on arbitrary tool output; use `TRANSIENT_MODEL_ERROR_PATTERN`
44
+ * directly there (quota tokens would false-positive on shell stdout).
45
+ */
46
+ export declare function isTransientProviderError(signal: string): boolean;
47
+ /**
48
+ * True when the dispatch error specifically indicates quota/usage-limit
49
+ * exhaustion. Used to tag the fallback advisory / telemetry reason as `'quota'`
50
+ * vs a generic transient failure.
51
+ */
52
+ export declare function isQuotaError(signal: string): boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "7.125.3",
3
+ "version": "7.125.5",
4
4
  "description": "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",