@bohuyeshan/openagent-labforge-core 3.11.3 → 3.11.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.
- package/README.md +4 -4
- package/README.zh-cn.md +4 -4
- package/dist/cli/index.js +1 -1
- package/dist/index.js +157 -40
- package/dist/plugin/ultrawork-model-override.d.ts +1 -1
- package/dist/shared/session-model-state.d.ts +4 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -272,10 +272,10 @@ Keep reasoning depth in the OpenCode UI instead of hardcoding separate `low` / `
|
|
|
272
272
|
|
|
273
273
|
Copy and paste this prompt to your LLM agent (Claude Code, AmpCode, Cursor, etc.):
|
|
274
274
|
|
|
275
|
-
```
|
|
276
|
-
Install and configure @bohuyeshan/openagent-labforge-core by following the instructions here:
|
|
277
|
-
https://raw.githubusercontent.com/code-yeongyu/openagent-labforge/refs/heads/dev/docs/guide/installation.md
|
|
278
|
-
```
|
|
275
|
+
```
|
|
276
|
+
Install and configure @bohuyeshan/openagent-labforge-core by following the instructions here:
|
|
277
|
+
https://raw.githubusercontent.com/code-yeongyu/openagent-labforge/refs/heads/dev/docs/guide/installation.md
|
|
278
|
+
```
|
|
279
279
|
|
|
280
280
|
Or read the [Installation Guide](docs/guide/installation.md), but seriously, let an agent do it. Humans fat-finger configs.
|
|
281
281
|
|
package/README.zh-cn.md
CHANGED
|
@@ -273,10 +273,10 @@ npm install --prefix ~/.config/opencode /absolute/path/to/openagent-labforge-cor
|
|
|
273
273
|
|
|
274
274
|
复制并粘贴以下提示词到你的 LLM Agent (Claude Code, AmpCode, Cursor 等):
|
|
275
275
|
|
|
276
|
-
```
|
|
277
|
-
Install and configure @bohuyeshan/openagent-labforge-core by following the instructions here:
|
|
278
|
-
https://raw.githubusercontent.com/code-yeongyu/openagent-labforge/refs/heads/dev/docs/guide/installation.md
|
|
279
|
-
```
|
|
276
|
+
```
|
|
277
|
+
Install and configure @bohuyeshan/openagent-labforge-core by following the instructions here:
|
|
278
|
+
https://raw.githubusercontent.com/code-yeongyu/openagent-labforge/refs/heads/dev/docs/guide/installation.md
|
|
279
|
+
```
|
|
280
280
|
|
|
281
281
|
或者你可以直接去读 [安装指南](docs/guide/installation.md),但说真的,让 Agent 去干吧。人类配环境总是容易敲错字母。
|
|
282
282
|
|
package/dist/cli/index.js
CHANGED
|
@@ -9195,7 +9195,7 @@ var {
|
|
|
9195
9195
|
// package.json
|
|
9196
9196
|
var package_default = {
|
|
9197
9197
|
name: "@bohuyeshan/openagent-labforge-core",
|
|
9198
|
-
version: "3.11.
|
|
9198
|
+
version: "3.11.5",
|
|
9199
9199
|
description: "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
|
|
9200
9200
|
main: "dist/index.js",
|
|
9201
9201
|
types: "dist/index.d.ts",
|
package/dist/index.js
CHANGED
|
@@ -20225,9 +20225,32 @@ function hasUnansweredQuestion(messages) {
|
|
|
20225
20225
|
/\u662F\u5426\u8981/u,
|
|
20226
20226
|
/\u4F60\u5E0C\u671B/u,
|
|
20227
20227
|
/\u4F60\u60F3\u8981/u,
|
|
20228
|
+
/\u4F60\u89C9\u5F97/u,
|
|
20229
|
+
/\u4F60\u600E\u4E48\u770B/u,
|
|
20230
|
+
/\u8BF7\u7ED9(?:\u6211)?\u610F\u89C1/u,
|
|
20231
|
+
/\u8BF7\u53CD\u9988/u,
|
|
20232
|
+
/\u6D4B\u8BD5\u540E(?:\u544A\u8BC9\u6211|\u53CD\u9988)/u,
|
|
20233
|
+
/\u8DD1\u5B8C\u6D4B\u8BD5(?:\u544A\u8BC9\u6211|\u53CD\u9988)/u,
|
|
20234
|
+
/\u786E\u8BA4\u540E(?:\u544A\u8BC9\u6211|\u56DE\u590D\u6211|\u6211\u518D\u7EE7\u7EED)/u,
|
|
20235
|
+
/\u4F60\u6765\u51B3\u5B9A/u,
|
|
20236
|
+
/\u4F60\u51B3\u5B9A/u,
|
|
20237
|
+
/\u8BF7(?:\u9009\u62E9|\u9009\u4E00\u4E2A)/u,
|
|
20228
20238
|
/\u5B8C\u6210\u540E\u56DE\u6211/u,
|
|
20229
20239
|
/\u91CD\u542F\u540E\u544A\u8BC9\u6211/u,
|
|
20230
20240
|
/\u56DE\u6211\u4E00\u53E5/u,
|
|
20241
|
+
/\u9700\u8981\u4F60\u786E\u8BA4/u,
|
|
20242
|
+
/\u7B49\u5F85(?:\u4F60\u7684|\u7528\u6237)(?:\u786E\u8BA4|\u53CD\u9988|\u51B3\u5B9A|\u56DE\u590D|\u610F\u89C1)/u,
|
|
20243
|
+
/what do you think/iu,
|
|
20244
|
+
/any preference/iu,
|
|
20245
|
+
/your (?:feedback|input|decision|opinion)/iu,
|
|
20246
|
+
/after you (?:test|review)/iu,
|
|
20247
|
+
/once you (?:test|review)/iu,
|
|
20248
|
+
/please review/iu,
|
|
20249
|
+
/review and confirm/iu,
|
|
20250
|
+
/should i proceed/iu,
|
|
20251
|
+
/would you like me to continue/iu,
|
|
20252
|
+
/do you want me to continue/iu,
|
|
20253
|
+
/let me know when/iu,
|
|
20231
20254
|
/which (one|option|path|approach)/iu,
|
|
20232
20255
|
/would you like/iu,
|
|
20233
20256
|
/please provide/iu,
|
|
@@ -20249,7 +20272,7 @@ function hasUnansweredQuestion(messages) {
|
|
|
20249
20272
|
`);
|
|
20250
20273
|
if (combinedText.length > 0) {
|
|
20251
20274
|
const normalized = combinedText.trim();
|
|
20252
|
-
const looksLikeQuestion = /[?\uFF1F]
|
|
20275
|
+
const looksLikeQuestion = /[?\uFF1F]/.test(normalized) || waitPatterns.some((pattern) => pattern.test(normalized));
|
|
20253
20276
|
if (looksLikeQuestion) {
|
|
20254
20277
|
log(`[${HOOK_NAME}] Detected textual prompt awaiting user response`);
|
|
20255
20278
|
return true;
|
|
@@ -52474,6 +52497,7 @@ init_logger();
|
|
|
52474
52497
|
var sessionModels = new Map;
|
|
52475
52498
|
var sessionModelLocks = new Map;
|
|
52476
52499
|
var sessionForcedModels = new Map;
|
|
52500
|
+
var sessionAutoModelRouting = new Map;
|
|
52477
52501
|
function setSessionModel(sessionID, model) {
|
|
52478
52502
|
sessionModels.set(sessionID, model);
|
|
52479
52503
|
}
|
|
@@ -52484,6 +52508,7 @@ function clearSessionModel(sessionID) {
|
|
|
52484
52508
|
sessionModels.delete(sessionID);
|
|
52485
52509
|
sessionModelLocks.delete(sessionID);
|
|
52486
52510
|
sessionForcedModels.delete(sessionID);
|
|
52511
|
+
sessionAutoModelRouting.delete(sessionID);
|
|
52487
52512
|
}
|
|
52488
52513
|
function setSessionModelLock(sessionID, model) {
|
|
52489
52514
|
sessionModelLocks.set(sessionID, model);
|
|
@@ -52503,6 +52528,12 @@ function getSessionForcedModel(sessionID) {
|
|
|
52503
52528
|
function clearSessionForcedModel(sessionID) {
|
|
52504
52529
|
sessionForcedModels.delete(sessionID);
|
|
52505
52530
|
}
|
|
52531
|
+
function setSessionAutoModelRouting(sessionID, enabled) {
|
|
52532
|
+
sessionAutoModelRouting.set(sessionID, enabled);
|
|
52533
|
+
}
|
|
52534
|
+
function isSessionAutoModelRoutingEnabled(sessionID) {
|
|
52535
|
+
return sessionAutoModelRouting.get(sessionID) === true;
|
|
52536
|
+
}
|
|
52506
52537
|
|
|
52507
52538
|
// src/hooks/compaction-context-injector/session-id.ts
|
|
52508
52539
|
function isCompactionAgent(agent) {
|
|
@@ -54181,6 +54212,8 @@ function createSessionStatusHandler(deps, helpers, sessionStatusRetryKeys) {
|
|
|
54181
54212
|
const model = props?.model;
|
|
54182
54213
|
if (!sessionID || status?.type !== "retry")
|
|
54183
54214
|
return;
|
|
54215
|
+
if (!isSessionAutoModelRoutingEnabled(sessionID))
|
|
54216
|
+
return;
|
|
54184
54217
|
const retryMessage = typeof status.message === "string" ? status.message : "";
|
|
54185
54218
|
const retrySignal = extractAutoRetrySignal({ status: retryMessage, message: retryMessage });
|
|
54186
54219
|
if (!retrySignal)
|
|
@@ -54316,6 +54349,10 @@ function createEventHandler(deps, helpers) {
|
|
|
54316
54349
|
log(`[${HOOK_NAME12}] session.error without sessionID, skipping`);
|
|
54317
54350
|
return;
|
|
54318
54351
|
}
|
|
54352
|
+
if (!isSessionAutoModelRoutingEnabled(sessionID)) {
|
|
54353
|
+
log(`[${HOOK_NAME12}] session.error fallback skipped - auto model routing disabled`, { sessionID });
|
|
54354
|
+
return;
|
|
54355
|
+
}
|
|
54319
54356
|
const resolvedAgent = await helpers.resolveAgentForSessionFromContext(sessionID, agent);
|
|
54320
54357
|
if (sessionRetryInFlight.has(sessionID)) {
|
|
54321
54358
|
log(`[${HOOK_NAME12}] session.error skipped \u2014 retry in flight`, {
|
|
@@ -54516,6 +54553,9 @@ function createMessageUpdateHandler(deps, helpers) {
|
|
|
54516
54553
|
return;
|
|
54517
54554
|
}
|
|
54518
54555
|
if (sessionID && role === "assistant" && error48) {
|
|
54556
|
+
if (!isSessionAutoModelRoutingEnabled(sessionID)) {
|
|
54557
|
+
return;
|
|
54558
|
+
}
|
|
54519
54559
|
sessionAwaitingFallbackResult.delete(sessionID);
|
|
54520
54560
|
if (sessionRetryInFlight.has(sessionID) && !retrySignal) {
|
|
54521
54561
|
log(`[${HOOK_NAME12}] message.updated fallback skipped (retry in flight)`, { sessionID });
|
|
@@ -54617,6 +54657,8 @@ function createChatMessageHandler2(deps) {
|
|
|
54617
54657
|
let state3 = sessionStates.get(sessionID);
|
|
54618
54658
|
if (!state3)
|
|
54619
54659
|
return;
|
|
54660
|
+
if (!isSessionAutoModelRoutingEnabled(sessionID))
|
|
54661
|
+
return;
|
|
54620
54662
|
sessionLastAccess.set(sessionID, Date.now());
|
|
54621
54663
|
const requestedModel = input.model ? `${input.model.providerID}/${input.model.modelID}` : undefined;
|
|
54622
54664
|
if (requestedModel && requestedModel !== state3.currentModel) {
|
|
@@ -77872,7 +77914,7 @@ function createSessionHooks(args) {
|
|
|
77872
77914
|
fallbackTitleState.delete(oldestKey);
|
|
77873
77915
|
}
|
|
77874
77916
|
};
|
|
77875
|
-
const isModelFallbackConfigEnabled = pluginConfig.model_fallback ??
|
|
77917
|
+
const isModelFallbackConfigEnabled = pluginConfig.model_fallback ?? false;
|
|
77876
77918
|
const modelFallback = isModelFallbackConfigEnabled && isHookEnabled("model-fallback") ? safeHook("model-fallback", () => createModelFallbackHook({
|
|
77877
77919
|
toast: async ({ title, message, variant, duration: duration5 }) => {
|
|
77878
77920
|
await ctx.client.tui.showToast({
|
|
@@ -97821,7 +97863,18 @@ function applyResolvedUltraworkOverride(args) {
|
|
|
97821
97863
|
});
|
|
97822
97864
|
showToast3(tui, "Ultrawork Model Override", `${fromModel} \u2192 ${override.modelID}. Maximum precision engaged.`);
|
|
97823
97865
|
}
|
|
97824
|
-
function applyUltraworkModelOverrideOnMessage(pluginConfig, inputAgentName, output, tui, sessionID,
|
|
97866
|
+
function applyUltraworkModelOverrideOnMessage(pluginConfig, inputAgentName, output, tui, sessionID, manualModelChangeDetectedOrClient = false, client2, allowAutomaticModelOverride = true) {
|
|
97867
|
+
let manualModelChangeDetected = false;
|
|
97868
|
+
let resolvedClient = client2;
|
|
97869
|
+
if (typeof manualModelChangeDetectedOrClient === "boolean") {
|
|
97870
|
+
manualModelChangeDetected = manualModelChangeDetectedOrClient;
|
|
97871
|
+
} else if (manualModelChangeDetectedOrClient !== undefined && manualModelChangeDetectedOrClient !== null) {
|
|
97872
|
+
resolvedClient = manualModelChangeDetectedOrClient;
|
|
97873
|
+
}
|
|
97874
|
+
if (!allowAutomaticModelOverride) {
|
|
97875
|
+
log("[ultrawork-model-override] Skip override; auto model routing disabled for session");
|
|
97876
|
+
return;
|
|
97877
|
+
}
|
|
97825
97878
|
if (manualModelChangeDetected) {
|
|
97826
97879
|
log("[ultrawork-model-override] Skip override; manual model change detected");
|
|
97827
97880
|
return;
|
|
@@ -97831,7 +97884,7 @@ function applyUltraworkModelOverrideOnMessage(pluginConfig, inputAgentName, outp
|
|
|
97831
97884
|
return;
|
|
97832
97885
|
const currentModel = getMessageModel(output.message.model);
|
|
97833
97886
|
const variantTargetModel = override.providerID && override.modelID ? { providerID: override.providerID, modelID: override.modelID } : currentModel;
|
|
97834
|
-
if (!
|
|
97887
|
+
if (!resolvedClient || typeof resolvedClient.provider?.list !== "function") {
|
|
97835
97888
|
if (override.variant) {
|
|
97836
97889
|
log("[ultrawork-model-override] SDK validation unavailable, skipping variant override", {
|
|
97837
97890
|
variant: override.variant
|
|
@@ -97840,7 +97893,7 @@ function applyUltraworkModelOverrideOnMessage(pluginConfig, inputAgentName, outp
|
|
|
97840
97893
|
applyResolvedUltraworkOverride({ override, validatedVariant: undefined, output, inputAgentName, tui });
|
|
97841
97894
|
return;
|
|
97842
97895
|
}
|
|
97843
|
-
return resolveValidUltraworkVariant(
|
|
97896
|
+
return resolveValidUltraworkVariant(resolvedClient, variantTargetModel, override.variant).then((validatedVariant) => {
|
|
97844
97897
|
if (override.variant && !validatedVariant) {
|
|
97845
97898
|
log("[ultrawork-model-override] Skip invalid ultrawork variant override", {
|
|
97846
97899
|
variant: override.variant,
|
|
@@ -97901,9 +97954,10 @@ function createChatMessageHandler3(args) {
|
|
|
97901
97954
|
const pluginContext = ctx;
|
|
97902
97955
|
const isRuntimeFallbackEnabled = hooks2.runtimeFallback !== null && hooks2.runtimeFallback !== undefined && (typeof pluginConfig.runtime_fallback === "boolean" ? pluginConfig.runtime_fallback : pluginConfig.runtime_fallback?.enabled ?? false);
|
|
97903
97956
|
return async (input, output) => {
|
|
97957
|
+
const isInternalInitiatedPrompt = hasInternalInitiatorMarker(output.parts);
|
|
97904
97958
|
const previousSessionModel = getSessionModel(input.sessionID);
|
|
97905
97959
|
const currentInputModel = input.model;
|
|
97906
|
-
const manualModelChangeDetected = currentInputModel !== undefined && previousSessionModel !== undefined && (currentInputModel.providerID !== previousSessionModel.providerID || currentInputModel.modelID !== previousSessionModel.modelID);
|
|
97960
|
+
const manualModelChangeDetected = !isInternalInitiatedPrompt && currentInputModel !== undefined && previousSessionModel !== undefined && (currentInputModel.providerID !== previousSessionModel.providerID || currentInputModel.modelID !== previousSessionModel.modelID);
|
|
97907
97961
|
if (manualModelChangeDetected) {
|
|
97908
97962
|
clearPendingModelFallback(input.sessionID);
|
|
97909
97963
|
clearSessionFallbackChain(input.sessionID);
|
|
@@ -97913,8 +97967,14 @@ function createChatMessageHandler3(args) {
|
|
|
97913
97967
|
const forcedModel = getSessionForcedModel(input.sessionID);
|
|
97914
97968
|
const rawInputModel = input.model;
|
|
97915
97969
|
const rawInputModelId = modelToString(rawInputModel);
|
|
97970
|
+
if (!isInternalInitiatedPrompt && rawInputModel !== undefined) {
|
|
97971
|
+
setSessionAutoModelRouting(input.sessionID, isAutoModelSelection(rawInputModelId));
|
|
97972
|
+
}
|
|
97973
|
+
const autoModelRoutingEnabled = isSessionAutoModelRoutingEnabled(input.sessionID);
|
|
97916
97974
|
if (strictUserModelPriority && lockedModel) {
|
|
97917
|
-
if (
|
|
97975
|
+
if (isInternalInitiatedPrompt) {
|
|
97976
|
+
input.model = lockedModel;
|
|
97977
|
+
} else if (!rawInputModel) {
|
|
97918
97978
|
input.model = lockedModel;
|
|
97919
97979
|
} else if (isAutoModelSelection(rawInputModelId)) {
|
|
97920
97980
|
clearSessionModelLock(input.sessionID);
|
|
@@ -97925,7 +97985,10 @@ function createChatMessageHandler3(args) {
|
|
|
97925
97985
|
}
|
|
97926
97986
|
}
|
|
97927
97987
|
}
|
|
97928
|
-
const soulRules = loadSoulRules({
|
|
97988
|
+
const soulRules = loadSoulRules({
|
|
97989
|
+
directory: typeof ctx.directory === "string" ? ctx.directory : "",
|
|
97990
|
+
pluginConfig
|
|
97991
|
+
});
|
|
97929
97992
|
const injectOnce = pluginConfig.soul?.inject_once ?? true;
|
|
97930
97993
|
const alreadyInjected = soulInjectedSessions.has(input.sessionID);
|
|
97931
97994
|
if (soulRules.content && (!injectOnce || !alreadyInjected)) {
|
|
@@ -97960,12 +98023,14 @@ function createChatMessageHandler3(args) {
|
|
|
97960
98023
|
if (firstMessageVariantGate.shouldOverride(input.sessionID)) {
|
|
97961
98024
|
firstMessageVariantGate.markApplied(input.sessionID);
|
|
97962
98025
|
}
|
|
97963
|
-
if (!isRuntimeFallbackEnabled) {
|
|
98026
|
+
if (!isRuntimeFallbackEnabled && autoModelRoutingEnabled) {
|
|
97964
98027
|
await hooks2.modelFallback?.["chat.message"]?.(input, output);
|
|
97965
98028
|
}
|
|
97966
98029
|
await hooks2.stopContinuationGuard?.["chat.message"]?.(input);
|
|
97967
98030
|
await hooks2.backgroundNotificationHook?.["chat.message"]?.(input, output);
|
|
97968
|
-
|
|
98031
|
+
if (autoModelRoutingEnabled) {
|
|
98032
|
+
await hooks2.runtimeFallback?.["chat.message"]?.(input, output);
|
|
98033
|
+
}
|
|
97969
98034
|
await hooks2.keywordDetector?.["chat.message"]?.(input, output);
|
|
97970
98035
|
await hooks2.thinkMode?.["chat.message"]?.(input, output);
|
|
97971
98036
|
await hooks2.claudeCodeHooks?.["chat.message"]?.(input, output);
|
|
@@ -98008,7 +98073,7 @@ function createChatMessageHandler3(args) {
|
|
|
98008
98073
|
hooks2.ralphLoop.cancelLoop(input.sessionID);
|
|
98009
98074
|
}
|
|
98010
98075
|
}
|
|
98011
|
-
await applyUltraworkModelOverrideOnMessage(pluginConfig, input.agent, output, pluginContext.client.tui, input.sessionID, manualModelChangeDetected, pluginContext.client);
|
|
98076
|
+
await applyUltraworkModelOverrideOnMessage(pluginConfig, input.agent, output, pluginContext.client.tui, input.sessionID, manualModelChangeDetected, pluginContext.client, autoModelRoutingEnabled);
|
|
98012
98077
|
const requestedModel = input.model;
|
|
98013
98078
|
const requestedModelId = modelToString(requestedModel);
|
|
98014
98079
|
const shouldLockToRequestedModel = strictUserModelPriority && requestedModel !== undefined && !isAutoModelSelection(requestedModelId);
|
|
@@ -98016,29 +98081,33 @@ function createChatMessageHandler3(args) {
|
|
|
98016
98081
|
providerID: output.message["model"].providerID ?? "",
|
|
98017
98082
|
modelID: output.message["model"].modelID ?? ""
|
|
98018
98083
|
} : undefined;
|
|
98019
|
-
if (
|
|
98020
|
-
|
|
98021
|
-
|
|
98022
|
-
} else if (shouldLockToRequestedModel) {
|
|
98023
|
-
setSessionModelLock(input.sessionID, requestedModel);
|
|
98024
|
-
if (modelBeforeUserLock && modelBeforeUserLock.providerID.length > 0 && modelBeforeUserLock.modelID.length > 0 && !sameModel(modelBeforeUserLock, requestedModel)) {
|
|
98025
|
-
setSessionForcedModel(input.sessionID, modelBeforeUserLock);
|
|
98026
|
-
} else {
|
|
98084
|
+
if (!isInternalInitiatedPrompt) {
|
|
98085
|
+
if (requestedModel !== undefined && isAutoModelSelection(requestedModelId)) {
|
|
98086
|
+
clearSessionModelLock(input.sessionID);
|
|
98027
98087
|
clearSessionForcedModel(input.sessionID);
|
|
98088
|
+
} else if (shouldLockToRequestedModel) {
|
|
98089
|
+
setSessionModelLock(input.sessionID, requestedModel);
|
|
98090
|
+
if (modelBeforeUserLock && modelBeforeUserLock.providerID.length > 0 && modelBeforeUserLock.modelID.length > 0 && !sameModel(modelBeforeUserLock, requestedModel)) {
|
|
98091
|
+
setSessionForcedModel(input.sessionID, modelBeforeUserLock);
|
|
98092
|
+
} else {
|
|
98093
|
+
clearSessionForcedModel(input.sessionID);
|
|
98094
|
+
}
|
|
98028
98095
|
}
|
|
98029
98096
|
}
|
|
98030
|
-
if (shouldLockToRequestedModel) {
|
|
98097
|
+
if (!isInternalInitiatedPrompt && shouldLockToRequestedModel) {
|
|
98031
98098
|
output.message["model"] = requestedModel;
|
|
98032
98099
|
}
|
|
98033
|
-
|
|
98034
|
-
|
|
98035
|
-
|
|
98036
|
-
|
|
98037
|
-
|
|
98038
|
-
|
|
98100
|
+
if (!isInternalInitiatedPrompt) {
|
|
98101
|
+
const finalOutputModel = output.message["model"];
|
|
98102
|
+
if (finalOutputModel && typeof finalOutputModel === "object" && "providerID" in finalOutputModel && "modelID" in finalOutputModel) {
|
|
98103
|
+
const providerID = finalOutputModel.providerID;
|
|
98104
|
+
const modelID = finalOutputModel.modelID;
|
|
98105
|
+
if (typeof providerID === "string" && typeof modelID === "string") {
|
|
98106
|
+
setSessionModel(input.sessionID, { providerID, modelID });
|
|
98107
|
+
}
|
|
98108
|
+
} else if (requestedModel) {
|
|
98109
|
+
setSessionModel(input.sessionID, requestedModel);
|
|
98039
98110
|
}
|
|
98040
|
-
} else if (requestedModel) {
|
|
98041
|
-
setSessionModel(input.sessionID, requestedModel);
|
|
98042
98111
|
}
|
|
98043
98112
|
};
|
|
98044
98113
|
}
|
|
@@ -98052,6 +98121,9 @@ function sameModel(left, right) {
|
|
|
98052
98121
|
return false;
|
|
98053
98122
|
return left.providerID === right.providerID && left.modelID === right.modelID;
|
|
98054
98123
|
}
|
|
98124
|
+
function hasInternalInitiatorMarker(parts) {
|
|
98125
|
+
return parts.some((part) => part.type === "text" && typeof part.text === "string" && part.text.includes(OMO_INTERNAL_INITIATOR_MARKER));
|
|
98126
|
+
}
|
|
98055
98127
|
|
|
98056
98128
|
// src/plugin/messages-transform.ts
|
|
98057
98129
|
function createMessagesTransformHandler(args) {
|
|
@@ -98109,6 +98181,11 @@ function normalizeSessionStatusToIdle(input) {
|
|
|
98109
98181
|
function isRecord12(value) {
|
|
98110
98182
|
return typeof value === "object" && value !== null;
|
|
98111
98183
|
}
|
|
98184
|
+
function hasInternalInitiatorMarker2(parts) {
|
|
98185
|
+
if (!Array.isArray(parts))
|
|
98186
|
+
return false;
|
|
98187
|
+
return parts.some((part) => isRecord12(part) && part.type === "text" && typeof part.text === "string" && part.text.includes(OMO_INTERNAL_INITIATOR_MARKER));
|
|
98188
|
+
}
|
|
98112
98189
|
function normalizeFallbackModelID(modelID) {
|
|
98113
98190
|
return modelID.replace(/-thinking$/i, "").replace(/-max$/i, "").replace(/-high$/i, "");
|
|
98114
98191
|
}
|
|
@@ -98184,6 +98261,43 @@ function createEventHandler2(args) {
|
|
|
98184
98261
|
const lastHandledModelErrorMessageID = new Map;
|
|
98185
98262
|
const lastHandledRetryStatusKey = new Map;
|
|
98186
98263
|
const lastKnownModelBySession = new Map;
|
|
98264
|
+
const internalMarkerCache2 = new Map;
|
|
98265
|
+
const INTERNAL_MARKER_CACHE_LIMIT2 = 1000;
|
|
98266
|
+
const rememberInternalMarker = (cacheKey, hasMarker) => {
|
|
98267
|
+
internalMarkerCache2.set(cacheKey, hasMarker);
|
|
98268
|
+
if (internalMarkerCache2.size > INTERNAL_MARKER_CACHE_LIMIT2) {
|
|
98269
|
+
internalMarkerCache2.clear();
|
|
98270
|
+
}
|
|
98271
|
+
};
|
|
98272
|
+
const isInternalInitiatedUserMessage = async (sessionID, props, info) => {
|
|
98273
|
+
if (hasInternalInitiatorMarker2(props?.parts))
|
|
98274
|
+
return true;
|
|
98275
|
+
if (hasInternalInitiatorMarker2(info?.parts))
|
|
98276
|
+
return true;
|
|
98277
|
+
if (hasInternalInitiatorMarker2(info?.content))
|
|
98278
|
+
return true;
|
|
98279
|
+
const messageID = typeof info?.id === "string" ? info.id : undefined;
|
|
98280
|
+
if (!messageID)
|
|
98281
|
+
return false;
|
|
98282
|
+
const cacheKey = `${sessionID}:${messageID}`;
|
|
98283
|
+
const cached3 = internalMarkerCache2.get(cacheKey);
|
|
98284
|
+
if (cached3 !== undefined)
|
|
98285
|
+
return cached3;
|
|
98286
|
+
const loadMessage = pluginContext.client.session.message;
|
|
98287
|
+
if (typeof loadMessage !== "function")
|
|
98288
|
+
return false;
|
|
98289
|
+
try {
|
|
98290
|
+
const response = await loadMessage({
|
|
98291
|
+
path: { id: sessionID, messageID }
|
|
98292
|
+
});
|
|
98293
|
+
const hasMarker = hasInternalInitiatorMarker2(response.data?.parts);
|
|
98294
|
+
rememberInternalMarker(cacheKey, hasMarker);
|
|
98295
|
+
return hasMarker;
|
|
98296
|
+
} catch {
|
|
98297
|
+
rememberInternalMarker(cacheKey, false);
|
|
98298
|
+
return false;
|
|
98299
|
+
}
|
|
98300
|
+
};
|
|
98187
98301
|
const resolveFallbackProviderID = (sessionID, providerHint) => {
|
|
98188
98302
|
const sessionModel = getSessionModel(sessionID);
|
|
98189
98303
|
if (sessionModel?.providerID) {
|
|
@@ -98335,18 +98449,21 @@ function createEventHandler2(args) {
|
|
|
98335
98449
|
const agent = info?.agent;
|
|
98336
98450
|
const role = info?.role;
|
|
98337
98451
|
if (sessionID && role === "user") {
|
|
98338
|
-
const
|
|
98339
|
-
if (
|
|
98340
|
-
|
|
98341
|
-
|
|
98342
|
-
|
|
98343
|
-
|
|
98344
|
-
|
|
98345
|
-
|
|
98346
|
-
|
|
98452
|
+
const isInternalUserMessage = await isInternalInitiatedUserMessage(sessionID, props, info);
|
|
98453
|
+
if (!isInternalUserMessage) {
|
|
98454
|
+
const isCompactionMessage = agent ? isCompactionAgent4(agent) : false;
|
|
98455
|
+
if (agent && !isCompactionMessage) {
|
|
98456
|
+
updateSessionAgent(sessionID, agent);
|
|
98457
|
+
}
|
|
98458
|
+
const providerID = info?.providerID;
|
|
98459
|
+
const modelID = info?.modelID;
|
|
98460
|
+
if (providerID && modelID && !isCompactionMessage) {
|
|
98461
|
+
lastKnownModelBySession.set(sessionID, { providerID, modelID });
|
|
98462
|
+
setSessionModel(sessionID, { providerID, modelID });
|
|
98463
|
+
}
|
|
98347
98464
|
}
|
|
98348
98465
|
}
|
|
98349
|
-
if (sessionID && role === "assistant" && !isRuntimeFallbackEnabled && isModelFallbackEnabled) {
|
|
98466
|
+
if (sessionID && role === "assistant" && !isRuntimeFallbackEnabled && isModelFallbackEnabled && isSessionAutoModelRoutingEnabled(sessionID)) {
|
|
98350
98467
|
try {
|
|
98351
98468
|
const assistantMessageID = info?.id;
|
|
98352
98469
|
const assistantError = info?.error;
|
|
@@ -98390,7 +98507,7 @@ function createEventHandler2(args) {
|
|
|
98390
98507
|
if (event.type === "session.status") {
|
|
98391
98508
|
const sessionID = props?.sessionID;
|
|
98392
98509
|
const status = props?.status;
|
|
98393
|
-
if (sessionID && status?.type === "retry" && isModelFallbackEnabled && !isRuntimeFallbackEnabled) {
|
|
98510
|
+
if (sessionID && status?.type === "retry" && isModelFallbackEnabled && !isRuntimeFallbackEnabled && isSessionAutoModelRoutingEnabled(sessionID)) {
|
|
98394
98511
|
try {
|
|
98395
98512
|
const retryMessage = typeof status.message === "string" ? status.message : "";
|
|
98396
98513
|
const parsedForKey = extractProviderModelFromErrorMessage(retryMessage);
|
|
@@ -98452,7 +98569,7 @@ function createEventHandler2(args) {
|
|
|
98452
98569
|
query: { directory: pluginContext.directory }
|
|
98453
98570
|
}).catch(() => {});
|
|
98454
98571
|
}
|
|
98455
|
-
} else if (sessionID && shouldRetryError(errorInfo) && !isRuntimeFallbackEnabled && isModelFallbackEnabled) {
|
|
98572
|
+
} else if (sessionID && shouldRetryError(errorInfo) && !isRuntimeFallbackEnabled && isModelFallbackEnabled && isSessionAutoModelRoutingEnabled(sessionID)) {
|
|
98456
98573
|
let agentName = getSessionAgent(sessionID);
|
|
98457
98574
|
if (!agentName && sessionID === getMainSessionID()) {
|
|
98458
98575
|
if (errorMessage.includes("claude-opus") || errorMessage.includes("opus")) {
|
|
@@ -20,4 +20,4 @@ export declare function applyUltraworkModelOverrideOnMessage(pluginConfig: OhMyO
|
|
|
20
20
|
text?: string;
|
|
21
21
|
[key: string]: unknown;
|
|
22
22
|
}>;
|
|
23
|
-
}, tui: unknown, sessionID?: string,
|
|
23
|
+
}, tui: unknown, sessionID?: string, manualModelChangeDetectedOrClient?: unknown, client?: unknown, allowAutomaticModelOverride?: boolean): void | Promise<void>;
|
|
@@ -11,3 +11,7 @@ export declare function clearSessionModelLock(sessionID: string): void;
|
|
|
11
11
|
export declare function setSessionForcedModel(sessionID: string, model: SessionModel): void;
|
|
12
12
|
export declare function getSessionForcedModel(sessionID: string): SessionModel | undefined;
|
|
13
13
|
export declare function clearSessionForcedModel(sessionID: string): void;
|
|
14
|
+
export declare function setSessionAutoModelRouting(sessionID: string, enabled: boolean): void;
|
|
15
|
+
export declare function getSessionAutoModelRouting(sessionID: string): boolean | undefined;
|
|
16
|
+
export declare function isSessionAutoModelRoutingEnabled(sessionID: string): boolean;
|
|
17
|
+
export declare function clearSessionAutoModelRouting(sessionID: string): void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bohuyeshan/openagent-labforge-core",
|
|
3
|
-
"version": "3.11.
|
|
3
|
+
"version": "3.11.5",
|
|
4
4
|
"description": "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|