open-multi-agent-kit 0.96.2 → 0.97.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/CHANGELOG.md +16 -0
- package/README.md +4 -2
- package/dist/core/agent-session.d.ts +9 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +84 -7
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/attachment-store.d.ts +39 -0
- package/dist/core/attachment-store.d.ts.map +1 -0
- package/dist/core/attachment-store.js +81 -0
- package/dist/core/attachment-store.js.map +1 -0
- package/dist/core/command-safety.d.ts +8 -0
- package/dist/core/command-safety.d.ts.map +1 -1
- package/dist/core/command-safety.js +140 -14
- package/dist/core/command-safety.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +6 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +35 -1
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/context-budget-governor-v2.d.ts +1 -1
- package/dist/core/context-budget-governor-v2.d.ts.map +1 -1
- package/dist/core/context-budget-governor-v2.js +1 -1
- package/dist/core/context-budget-governor-v2.js.map +1 -1
- package/dist/core/context-budget-v2-cache-keys.d.ts +3 -0
- package/dist/core/context-budget-v2-cache-keys.d.ts.map +1 -1
- package/dist/core/context-budget-v2-cache-keys.js +2 -0
- package/dist/core/context-budget-v2-cache-keys.js.map +1 -1
- package/dist/core/context-budget-v2-plan-cache-keys.d.ts.map +1 -1
- package/dist/core/context-budget-v2-plan-cache-keys.js +3 -0
- package/dist/core/context-budget-v2-plan-cache-keys.js.map +1 -1
- package/dist/core/context-budget-v2-planner.d.ts.map +1 -1
- package/dist/core/context-budget-v2-planner.js +2 -1
- package/dist/core/context-budget-v2-planner.js.map +1 -1
- package/dist/core/context-budget-v2-scoring.d.ts +17 -0
- package/dist/core/context-budget-v2-scoring.d.ts.map +1 -1
- package/dist/core/context-budget-v2-scoring.js +25 -8
- package/dist/core/context-budget-v2-scoring.js.map +1 -1
- package/dist/core/context-budget-v2-selection.d.ts +2 -2
- package/dist/core/context-budget-v2-selection.d.ts.map +1 -1
- package/dist/core/context-budget-v2-selection.js +18 -1
- package/dist/core/context-budget-v2-selection.js.map +1 -1
- package/dist/core/context-budget-v2-types.d.ts +17 -0
- package/dist/core/context-budget-v2-types.d.ts.map +1 -1
- package/dist/core/context-budget-v2-types.js +15 -0
- package/dist/core/context-budget-v2-types.js.map +1 -1
- package/dist/core/extensions/builtin/command-safety-gate.d.ts +3 -1
- package/dist/core/extensions/builtin/command-safety-gate.d.ts.map +1 -1
- package/dist/core/extensions/builtin/command-safety-gate.js +7 -0
- package/dist/core/extensions/builtin/command-safety-gate.js.map +1 -1
- package/dist/core/extensions/types.d.ts +12 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/model-registry.d.ts +8 -3
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +71 -1
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/package-doctor-source-scan.d.ts +9 -0
- package/dist/core/package-doctor-source-scan.d.ts.map +1 -1
- package/dist/core/package-doctor-source-scan.js +77 -4
- package/dist/core/package-doctor-source-scan.js.map +1 -1
- package/dist/core/prompt-attachment.d.ts +51 -0
- package/dist/core/prompt-attachment.d.ts.map +1 -0
- package/dist/core/prompt-attachment.js +186 -0
- package/dist/core/prompt-attachment.js.map +1 -0
- package/dist/core/provider-resilience.d.ts +28 -0
- package/dist/core/provider-resilience.d.ts.map +1 -1
- package/dist/core/provider-resilience.js +50 -0
- package/dist/core/provider-resilience.js.map +1 -1
- package/dist/core/provider-retry.d.ts +1 -1
- package/dist/core/provider-retry.d.ts.map +1 -1
- package/dist/core/provider-retry.js +1 -1
- package/dist/core/provider-retry.js.map +1 -1
- package/dist/core/provider-usage.d.ts.map +1 -1
- package/dist/core/provider-usage.js +68 -2
- package/dist/core/provider-usage.js.map +1 -1
- package/dist/core/reasoning-router-promotion.d.ts +84 -0
- package/dist/core/reasoning-router-promotion.d.ts.map +1 -0
- package/dist/core/reasoning-router-promotion.js +92 -0
- package/dist/core/reasoning-router-promotion.js.map +1 -0
- package/dist/core/session-bash-service.d.ts.map +1 -1
- package/dist/core/session-bash-service.js +4 -3
- package/dist/core/session-bash-service.js.map +1 -1
- package/dist/core/session-termination.d.ts +1 -1
- package/dist/core/session-termination.d.ts.map +1 -1
- package/dist/core/session-termination.js +11 -2
- package/dist/core/session-termination.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +3 -7
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +13 -48
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +1 -34
- package/dist/core/tools/read.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/components/attachment-strip.d.ts +21 -0
- package/dist/modes/interactive/components/attachment-strip.d.ts.map +1 -0
- package/dist/modes/interactive/components/attachment-strip.js +136 -0
- package/dist/modes/interactive/components/attachment-strip.js.map +1 -0
- package/dist/modes/interactive/components/footer.d.ts +6 -0
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +26 -1
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/status-sidebar.d.ts.map +1 -1
- package/dist/modes/interactive/components/status-sidebar.js +12 -1
- package/dist/modes/interactive/components/status-sidebar.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +23 -4
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +174 -53
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/docs/compaction.md +1 -1
- package/docs/extensions.md +12 -3
- package/docs/index.md +4 -1
- package/docs/metrics.md +74 -2
- package/docs/provider-resilience.md +11 -0
- package/docs/usage.md +1 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +18 -18
- package/package.json +7 -7
- package/dist/core/tools/omp-pure-seams.d.ts +0 -41
- package/dist/core/tools/omp-pure-seams.d.ts.map +0 -1
- package/dist/core/tools/omp-pure-seams.js +0 -142
- package/dist/core/tools/omp-pure-seams.js.map +0 -1
- package/dist/core/tools/omp-seam-runtime.d.ts +0 -100
- package/dist/core/tools/omp-seam-runtime.d.ts.map +0 -1
- package/dist/core/tools/omp-seam-runtime.js +0 -40
- package/dist/core/tools/omp-seam-runtime.js.map +0 -1
|
@@ -79,7 +79,7 @@ import { computePromptTokenBudget } from "./prompt-budget.js";
|
|
|
79
79
|
import { classifyPromptCacheTransition } from "./prompt-cache.js";
|
|
80
80
|
import { createPromptSettlementState, reducePromptSettlement, settlePromptIfReady, } from "./prompt-settlement.js";
|
|
81
81
|
import { expandPromptTemplate } from "./prompt-templates.js";
|
|
82
|
-
import { isQuotaExhaustionMessage, isStickySafetyModel, pickFailoverCandidate, resolveProviderResilience, shouldEjectStickySafetyModel, shouldHonorSafetyFailover, stickySafetyBlockMessage, } from "./provider-resilience.js";
|
|
82
|
+
import { isQuotaExhaustionMessage, isStickySafetyModel, isUpstreamUnavailableMessage, pickFailoverCandidate, resolveFailoverCandidates, resolveProviderResilience, sameModelRouteCandidates, shouldEjectStickySafetyModel, shouldHonorSafetyFailover, stickySafetyBlockMessage, } from "./provider-resilience.js";
|
|
83
83
|
import { computeRetryDelayMs, failoverModelKey, isFailoverTriggerError, isRetryableAssistantError, nextRetryAttempt, retryBudgetForAssistantError, } from "./provider-retry.js";
|
|
84
84
|
import { getBiasStepsForCell, parseRouterBiasSnapshot } from "./reasoning-router-bias.js";
|
|
85
85
|
import { classifyTaskV4, deriveRouterFeedbackFeaturesV4, resolveThinkingLevelV4WithUncertainty, TASK_CLASS_THINKING_LEVELS_V4, } from "./reasoning-router-v4.js";
|
|
@@ -624,6 +624,12 @@ export class AgentSession {
|
|
|
624
624
|
if (/auth|unauthori[sz]ed|forbidden|invalid.?api.?key|no api key|401|403|\/login/i.test(text)) {
|
|
625
625
|
return { area: "provider", code: "auth" };
|
|
626
626
|
}
|
|
627
|
+
// Gateway/upstream 5xx and dropped streams are transport failures, not
|
|
628
|
+
// transcript-shape problems. Classify as network so the guidance points to
|
|
629
|
+
// retry/model-switch instead of the protocol sanitize path.
|
|
630
|
+
if (isUpstreamUnavailableMessage(text)) {
|
|
631
|
+
return { area: "provider", code: "network" };
|
|
632
|
+
}
|
|
627
633
|
// Kimi/K3 + OpenAI-compat: orphan tool results after dropped error assistants.
|
|
628
634
|
// Sanitize-and-retry (transform-messages drops orphans), not a hard tool fatal.
|
|
629
635
|
if (/tool_call_id\s+is\s+not\s+found|tool_call_id\s+not\s+found|unknown\s+tool_call_id/i.test(text)) {
|
|
@@ -648,6 +654,9 @@ export class AgentSession {
|
|
|
648
654
|
if (/auth|api key|unauthori[sz]ed|forbidden|401|403|\/login/i.test(message)) {
|
|
649
655
|
return { area: "provider", code: "auth" };
|
|
650
656
|
}
|
|
657
|
+
if (isUpstreamUnavailableMessage(message)) {
|
|
658
|
+
return { area: "provider", code: "network" };
|
|
659
|
+
}
|
|
651
660
|
if (/context.+overflow|context window|too many tokens/i.test(message)) {
|
|
652
661
|
return { area: "provider", code: "context_overflow" };
|
|
653
662
|
}
|
|
@@ -1130,6 +1139,11 @@ export class AgentSession {
|
|
|
1130
1139
|
}
|
|
1131
1140
|
else if (event.type === "agent_end") {
|
|
1132
1141
|
await this._extensionRunner.emit({ type: "agent_end", messages: event.messages });
|
|
1142
|
+
// `agent_end` fires once per attempt. Extensions that release per-run
|
|
1143
|
+
// state need the boundary no retry follows, so mark it explicitly.
|
|
1144
|
+
if (!this._willRetryAfterAgentEnd(event)) {
|
|
1145
|
+
await this._extensionRunner.emit({ type: "agent_settled", messages: event.messages });
|
|
1146
|
+
}
|
|
1133
1147
|
}
|
|
1134
1148
|
else if (event.type === "turn_start") {
|
|
1135
1149
|
this._turnMetricsState = {
|
|
@@ -2986,6 +3000,25 @@ export class AgentSession {
|
|
|
2986
3000
|
});
|
|
2987
3001
|
return model;
|
|
2988
3002
|
}
|
|
3003
|
+
/**
|
|
3004
|
+
* Authenticated failover candidates for compaction summarization, in
|
|
3005
|
+
* resilience-chain order, excluding the primary compaction model itself.
|
|
3006
|
+
* Used when the primary model's quota is exhausted (same-model retry is
|
|
3007
|
+
* useless until reset; another provider can still save the compaction).
|
|
3008
|
+
*/
|
|
3009
|
+
_compactionFailoverModels(primary) {
|
|
3010
|
+
const candidates = resolveFailoverCandidates(this.settingsManager.getProviderResilienceSettings());
|
|
3011
|
+
const available = this._modelRegistry.getAvailable();
|
|
3012
|
+
const models = [];
|
|
3013
|
+
for (const candidate of candidates) {
|
|
3014
|
+
if (candidate.provider === primary.provider && candidate.id === primary.id)
|
|
3015
|
+
continue;
|
|
3016
|
+
const resolved = available.find((m) => m.provider === candidate.provider && m.id === candidate.id);
|
|
3017
|
+
if (resolved)
|
|
3018
|
+
models.push(resolved);
|
|
3019
|
+
}
|
|
3020
|
+
return models;
|
|
3021
|
+
}
|
|
2989
3022
|
/**
|
|
2990
3023
|
* Manually compact the session context.
|
|
2991
3024
|
* Aborts current agent operation first.
|
|
@@ -3046,7 +3079,7 @@ export class AgentSession {
|
|
|
3046
3079
|
}
|
|
3047
3080
|
else {
|
|
3048
3081
|
// Generate compaction result
|
|
3049
|
-
const result = await compact(preparation, compactionModel, apiKey, headers, customInstructions, this._compactionAbortController.signal, this.thinkingLevel, this.agent.streamFn, this.settingsManager.getRetrySettings(), this._summarizationRetryCallbacks({ source: "compaction", reason: "manual" }));
|
|
3082
|
+
const result = await compact(preparation, compactionModel, apiKey, headers, customInstructions, this._compactionAbortController.signal, this.thinkingLevel, this.agent.streamFn, this.settingsManager.getRetrySettings(), this._summarizationRetryCallbacks({ source: "compaction", reason: "manual" }), this._compactionFailoverModels(compactionModel));
|
|
3050
3083
|
summary = result.summary;
|
|
3051
3084
|
firstKeptEntryId = result.firstKeptEntryId;
|
|
3052
3085
|
tokensBefore = result.tokensBefore;
|
|
@@ -3089,6 +3122,8 @@ export class AgentSession {
|
|
|
3089
3122
|
compactionCode = "aborted";
|
|
3090
3123
|
else if (stale)
|
|
3091
3124
|
compactionCode = "stale";
|
|
3125
|
+
else if (isQuotaExhaustionMessage(message))
|
|
3126
|
+
compactionCode = "quota_exhausted";
|
|
3092
3127
|
const timestamp = new Date().toISOString();
|
|
3093
3128
|
this._publishTermination(classifySessionTermination({
|
|
3094
3129
|
sessionId: this.sessionId,
|
|
@@ -3142,7 +3177,7 @@ export class AgentSession {
|
|
|
3142
3177
|
/**
|
|
3143
3178
|
* Effective context window for the upcoming turn.
|
|
3144
3179
|
* Image-bearing turns with a text-only session model are auto-routed to the
|
|
3145
|
-
* vision model (gpt-5.6-luna,
|
|
3180
|
+
* vision model (gpt-5.6-luna, 1M) — that window is the real limit. Text-only
|
|
3146
3181
|
* turns keep the session model's (typically much larger) window.
|
|
3147
3182
|
*/
|
|
3148
3183
|
_effectiveTurnContextWindow(pendingMessages, sessionWindow) {
|
|
@@ -3377,7 +3412,7 @@ export class AgentSession {
|
|
|
3377
3412
|
}
|
|
3378
3413
|
else {
|
|
3379
3414
|
// Generate compaction result
|
|
3380
|
-
const compactResult = await compact(preparation, compactionModel, apiKey, headers, undefined, this._autoCompactionAbortController.signal, this.thinkingLevel, this.agent.streamFn, this.settingsManager.getRetrySettings(), this._summarizationRetryCallbacks({ source: "compaction", reason }));
|
|
3415
|
+
const compactResult = await compact(preparation, compactionModel, apiKey, headers, undefined, this._autoCompactionAbortController.signal, this.thinkingLevel, this.agent.streamFn, this.settingsManager.getRetrySettings(), this._summarizationRetryCallbacks({ source: "compaction", reason }), this._compactionFailoverModels(compactionModel));
|
|
3381
3416
|
summary = compactResult.summary;
|
|
3382
3417
|
firstKeptEntryId = compactResult.firstKeptEntryId;
|
|
3383
3418
|
tokensBefore = compactResult.tokensBefore;
|
|
@@ -3992,6 +4027,41 @@ export class AgentSession {
|
|
|
3992
4027
|
// setModel itself blocks sticky targets, not sources — safe.
|
|
3993
4028
|
await this.setModel(next);
|
|
3994
4029
|
}
|
|
4030
|
+
/**
|
|
4031
|
+
* Rotate to another authenticated provider route serving the SAME model
|
|
4032
|
+
* family (e.g. openrouter/stealth/ox-alpha ↔ opencode-go/ox-alpha-free ↔
|
|
4033
|
+
* opencode/x-preview-f-free). Used when the current route fails with an
|
|
4034
|
+
* upstream availability error — same-model retry would hammer a dead
|
|
4035
|
+
* endpoint while the identical model is one route away. Visited and
|
|
4036
|
+
* unauthenticated routes are marked in {@link _refusedModels} so repeat
|
|
4037
|
+
* failures advance the rotation within the turn.
|
|
4038
|
+
*/
|
|
4039
|
+
async _maybeRotateModelRoutes() {
|
|
4040
|
+
const current = this.model;
|
|
4041
|
+
if (!current)
|
|
4042
|
+
return undefined;
|
|
4043
|
+
const candidates = sameModelRouteCandidates(current, this._modelRegistry.getAvailable());
|
|
4044
|
+
for (const candidate of candidates) {
|
|
4045
|
+
const key = failoverModelKey(candidate.provider, candidate.id);
|
|
4046
|
+
if (this._refusedModels.has(key))
|
|
4047
|
+
continue;
|
|
4048
|
+
const next = this._modelRegistry.find(candidate.provider, candidate.id);
|
|
4049
|
+
if (!next || !this._modelRegistry.hasConfiguredAuth(next)) {
|
|
4050
|
+
this._refusedModels.add(key);
|
|
4051
|
+
continue;
|
|
4052
|
+
}
|
|
4053
|
+
try {
|
|
4054
|
+
await this.setModel(next);
|
|
4055
|
+
// The old route just failed upstream — keep it out of this turn's retries.
|
|
4056
|
+
this._refusedModels.add(failoverModelKey(current.provider, current.id));
|
|
4057
|
+
return `${next.provider}/${next.id}`;
|
|
4058
|
+
}
|
|
4059
|
+
catch {
|
|
4060
|
+
this._refusedModels.add(key);
|
|
4061
|
+
}
|
|
4062
|
+
}
|
|
4063
|
+
return undefined;
|
|
4064
|
+
}
|
|
3995
4065
|
/**
|
|
3996
4066
|
* Content/safety stops (stop_reason=refusal) are often false positives on coding turns
|
|
3997
4067
|
* for Fable AND Claude Opus/Sonnet. Retrying the same model usually reprints the refusal —
|
|
@@ -4053,12 +4123,19 @@ export class AgentSession {
|
|
|
4053
4123
|
if (attempt === undefined)
|
|
4054
4124
|
return false;
|
|
4055
4125
|
this._retryAttempt = attempt;
|
|
4126
|
+
// Upstream-unavailable (gateway 5xx / dropped stream): rotate to another
|
|
4127
|
+
// authenticated route of the SAME model family so the retry lands on a
|
|
4128
|
+
// live endpoint instead of hammering the dead one.
|
|
4129
|
+
const rotatedTo = isUpstreamUnavailableMessage(message.errorMessage)
|
|
4130
|
+
? await this._maybeRotateModelRoutes()
|
|
4131
|
+
: undefined;
|
|
4056
4132
|
// Content/safety stop (Fable/Opus/Sonnet): switch model BEFORE delay so retry is not same-model refusal.
|
|
4057
4133
|
const failoverTo = await this._maybeFailoverFromSafetyStop(message);
|
|
4134
|
+
const switchedVia = failoverTo ? `failover ${failoverTo}` : rotatedTo ? `route ${rotatedTo}` : undefined;
|
|
4058
4135
|
// Safety stops are usually immediate false positives — short delay after failover, full backoff otherwise.
|
|
4059
|
-
const delayMs = computeRetryDelayMs(settings.baseDelayMs, attempt,
|
|
4060
|
-
const errorMessage =
|
|
4061
|
-
? `${message.errorMessage || "content/safety stop"} →
|
|
4136
|
+
const delayMs = computeRetryDelayMs(settings.baseDelayMs, attempt, switchedVia !== undefined);
|
|
4137
|
+
const errorMessage = switchedVia
|
|
4138
|
+
? `${message.errorMessage || "content/safety stop"} → ${switchedVia}`
|
|
4062
4139
|
: message.errorMessage || "Unknown error";
|
|
4063
4140
|
this._emit({
|
|
4064
4141
|
type: "auto_retry_start",
|