mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-23 20:21:11 +00:00
New grouped sessions tool (patch: label/pin/archive/model/thinking; group CRUD; owner-gated; no reset/delete/compact). sessions_spawn gains visible + worktree via sessions.create with admission reservation and abort-confirmed rollback; a started run with no run id is aborted and deleted rather than left orphaned. subagents tool reads the unified task_runs ledger tree-scoped (subagent/acp/media/cron) and cancels detached runs, enforcing the controlScope gate for leaf callers. session_status gains a cost line. Agent-origin model patches record a fallback marker; runs failing on auth/billing/model_not_found revert to the last working model (transient errors never revert), and an independent thinkingLevel change realigns the marker so revert cannot clobber it. Refs #107237
62 lines
2.1 KiB
TypeScript
62 lines
2.1 KiB
TypeScript
import { AsyncLocalStorage } from "node:async_hooks";
|
|
import {
|
|
normalizeOptionalLowercaseString,
|
|
normalizeOptionalString,
|
|
} from "@openclaw/normalization-core/string-coerce";
|
|
import { resolveProviderIdForAuth } from "../agents/provider-auth-aliases.js";
|
|
import { resolveSessionModelRef } from "../agents/session-model-ref.js";
|
|
import type { SessionEntry } from "../config/sessions.js";
|
|
import { createAgentPatchedSessionModelFallback } from "../config/sessions/session-model-fallback.js";
|
|
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
|
|
|
const agentSessionModelPatch = new AsyncLocalStorage<boolean>();
|
|
|
|
export function withAgentSessionModelPatchOrigin<T>(run: () => T): T {
|
|
return agentSessionModelPatch.run(true, run);
|
|
}
|
|
|
|
export function isAgentSessionModelPatchOrigin(): boolean {
|
|
return agentSessionModelPatch.getStore() === true;
|
|
}
|
|
|
|
export function shouldPreserveSessionAuthProfileOverride(params: {
|
|
cfg: OpenClawConfig;
|
|
entry: SessionEntry;
|
|
currentProvider: string;
|
|
provider: string;
|
|
}): boolean {
|
|
const profileOverride = normalizeOptionalString(params.entry.authProfileOverride);
|
|
const provider = normalizeOptionalLowercaseString(params.provider);
|
|
if (!profileOverride || !provider) {
|
|
return false;
|
|
}
|
|
const resolvesToTargetProvider = (rawProvider: string | undefined): boolean => {
|
|
const candidate = normalizeOptionalLowercaseString(rawProvider);
|
|
return Boolean(
|
|
candidate &&
|
|
resolveProviderIdForAuth(candidate, { config: params.cfg }) ===
|
|
resolveProviderIdForAuth(provider, { config: params.cfg }),
|
|
);
|
|
};
|
|
const delimiterIndex = profileOverride.indexOf(":");
|
|
if (delimiterIndex < 0) {
|
|
return resolvesToTargetProvider(params.currentProvider);
|
|
}
|
|
return resolvesToTargetProvider(profileOverride.slice(0, delimiterIndex));
|
|
}
|
|
|
|
export function snapshotAgentModelFallback(
|
|
cfg: OpenClawConfig,
|
|
entry: SessionEntry,
|
|
agentId: string,
|
|
now: number,
|
|
): NonNullable<SessionEntry["modelFallback"]> {
|
|
const prior = resolveSessionModelRef(cfg, entry, agentId);
|
|
return createAgentPatchedSessionModelFallback({
|
|
model: prior.model,
|
|
provider: prior.provider,
|
|
entry,
|
|
ts: now,
|
|
});
|
|
}
|