@bohuyeshan/openagent-labforge-core 3.11.3 → 3.11.4

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 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.3",
9198
+ version: "3.11.4",
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]$/.test(normalized) || waitPatterns.some((pattern) => pattern.test(normalized));
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 ?? true;
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, manualModelChangeDetected = false, client2) {
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 (!client2 || typeof client2.provider?.list !== "function") {
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(client2, variantTargetModel, override.variant).then((validatedVariant) => {
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,
@@ -97913,6 +97966,10 @@ function createChatMessageHandler3(args) {
97913
97966
  const forcedModel = getSessionForcedModel(input.sessionID);
97914
97967
  const rawInputModel = input.model;
97915
97968
  const rawInputModelId = modelToString(rawInputModel);
97969
+ if (rawInputModel !== undefined) {
97970
+ setSessionAutoModelRouting(input.sessionID, isAutoModelSelection(rawInputModelId));
97971
+ }
97972
+ const autoModelRoutingEnabled = isSessionAutoModelRoutingEnabled(input.sessionID);
97916
97973
  if (strictUserModelPriority && lockedModel) {
97917
97974
  if (!rawInputModel) {
97918
97975
  input.model = lockedModel;
@@ -97925,7 +97982,10 @@ function createChatMessageHandler3(args) {
97925
97982
  }
97926
97983
  }
97927
97984
  }
97928
- const soulRules = loadSoulRules({ directory: ctx.directory, pluginConfig });
97985
+ const soulRules = loadSoulRules({
97986
+ directory: typeof ctx.directory === "string" ? ctx.directory : "",
97987
+ pluginConfig
97988
+ });
97929
97989
  const injectOnce = pluginConfig.soul?.inject_once ?? true;
97930
97990
  const alreadyInjected = soulInjectedSessions.has(input.sessionID);
97931
97991
  if (soulRules.content && (!injectOnce || !alreadyInjected)) {
@@ -97960,12 +98020,14 @@ function createChatMessageHandler3(args) {
97960
98020
  if (firstMessageVariantGate.shouldOverride(input.sessionID)) {
97961
98021
  firstMessageVariantGate.markApplied(input.sessionID);
97962
98022
  }
97963
- if (!isRuntimeFallbackEnabled) {
98023
+ if (!isRuntimeFallbackEnabled && autoModelRoutingEnabled) {
97964
98024
  await hooks2.modelFallback?.["chat.message"]?.(input, output);
97965
98025
  }
97966
98026
  await hooks2.stopContinuationGuard?.["chat.message"]?.(input);
97967
98027
  await hooks2.backgroundNotificationHook?.["chat.message"]?.(input, output);
97968
- await hooks2.runtimeFallback?.["chat.message"]?.(input, output);
98028
+ if (autoModelRoutingEnabled) {
98029
+ await hooks2.runtimeFallback?.["chat.message"]?.(input, output);
98030
+ }
97969
98031
  await hooks2.keywordDetector?.["chat.message"]?.(input, output);
97970
98032
  await hooks2.thinkMode?.["chat.message"]?.(input, output);
97971
98033
  await hooks2.claudeCodeHooks?.["chat.message"]?.(input, output);
@@ -98008,7 +98070,7 @@ function createChatMessageHandler3(args) {
98008
98070
  hooks2.ralphLoop.cancelLoop(input.sessionID);
98009
98071
  }
98010
98072
  }
98011
- await applyUltraworkModelOverrideOnMessage(pluginConfig, input.agent, output, pluginContext.client.tui, input.sessionID, manualModelChangeDetected, pluginContext.client);
98073
+ await applyUltraworkModelOverrideOnMessage(pluginConfig, input.agent, output, pluginContext.client.tui, input.sessionID, manualModelChangeDetected, pluginContext.client, autoModelRoutingEnabled);
98012
98074
  const requestedModel = input.model;
98013
98075
  const requestedModelId = modelToString(requestedModel);
98014
98076
  const shouldLockToRequestedModel = strictUserModelPriority && requestedModel !== undefined && !isAutoModelSelection(requestedModelId);
@@ -98346,7 +98408,7 @@ function createEventHandler2(args) {
98346
98408
  setSessionModel(sessionID, { providerID, modelID });
98347
98409
  }
98348
98410
  }
98349
- if (sessionID && role === "assistant" && !isRuntimeFallbackEnabled && isModelFallbackEnabled) {
98411
+ if (sessionID && role === "assistant" && !isRuntimeFallbackEnabled && isModelFallbackEnabled && isSessionAutoModelRoutingEnabled(sessionID)) {
98350
98412
  try {
98351
98413
  const assistantMessageID = info?.id;
98352
98414
  const assistantError = info?.error;
@@ -98390,7 +98452,7 @@ function createEventHandler2(args) {
98390
98452
  if (event.type === "session.status") {
98391
98453
  const sessionID = props?.sessionID;
98392
98454
  const status = props?.status;
98393
- if (sessionID && status?.type === "retry" && isModelFallbackEnabled && !isRuntimeFallbackEnabled) {
98455
+ if (sessionID && status?.type === "retry" && isModelFallbackEnabled && !isRuntimeFallbackEnabled && isSessionAutoModelRoutingEnabled(sessionID)) {
98394
98456
  try {
98395
98457
  const retryMessage = typeof status.message === "string" ? status.message : "";
98396
98458
  const parsedForKey = extractProviderModelFromErrorMessage(retryMessage);
@@ -98452,7 +98514,7 @@ function createEventHandler2(args) {
98452
98514
  query: { directory: pluginContext.directory }
98453
98515
  }).catch(() => {});
98454
98516
  }
98455
- } else if (sessionID && shouldRetryError(errorInfo) && !isRuntimeFallbackEnabled && isModelFallbackEnabled) {
98517
+ } else if (sessionID && shouldRetryError(errorInfo) && !isRuntimeFallbackEnabled && isModelFallbackEnabled && isSessionAutoModelRoutingEnabled(sessionID)) {
98456
98518
  let agentName = getSessionAgent(sessionID);
98457
98519
  if (!agentName && sessionID === getMainSessionID()) {
98458
98520
  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, manualModelChangeDetected?: boolean, client?: unknown): void | Promise<void>;
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",
3
+ "version": "3.11.4",
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",