@autohq/cli 0.1.316 → 0.1.318

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.
@@ -23431,7 +23431,7 @@ Object.assign(lookup, {
23431
23431
  // package.json
23432
23432
  var package_default = {
23433
23433
  name: "@autohq/cli",
23434
- version: "0.1.316",
23434
+ version: "0.1.318",
23435
23435
  license: "SEE LICENSE IN README.md",
23436
23436
  publishConfig: {
23437
23437
  access: "public"
@@ -25285,6 +25285,12 @@ var AgentModelSelectionSchema = external_exports.object({
25285
25285
  var ResolvedAgentModelSelectionSchema = AgentModelSelectionSchema.extend({
25286
25286
  provider: ModelApiTokenProviderSchema
25287
25287
  });
25288
+ var InvalidModelSelectionError = class extends Error {
25289
+ constructor(message) {
25290
+ super(message);
25291
+ this.name = "InvalidModelSelectionError";
25292
+ }
25293
+ };
25288
25294
  var HARNESS_MODEL_RULES = {
25289
25295
  "claude-code": {
25290
25296
  defaultProvider: "anthropic",
@@ -25335,7 +25341,7 @@ function validateReasoningEffortForHarness(input) {
25335
25341
  }
25336
25342
  const rules = modelRulesForHarness(input.harness);
25337
25343
  if (!rules.reasoningEfforts.includes(input.reasoningEffort)) {
25338
- throw new Error(
25344
+ throw new InvalidModelSelectionError(
25339
25345
  `${input.harness} does not support reasoning effort "${input.reasoningEffort}"`
25340
25346
  );
25341
25347
  }
@@ -25372,7 +25378,9 @@ function validateAgentModelFieldsForHarness(spec, context) {
25372
25378
  function validateModelProviderForHarness(harness, provider) {
25373
25379
  const rules = modelRulesForHarness(harness);
25374
25380
  if (!rules.providers.includes(provider)) {
25375
- throw new Error(`${harness} does not support ${provider} models`);
25381
+ throw new InvalidModelSelectionError(
25382
+ `${harness} does not support ${provider} models`
25383
+ );
25376
25384
  }
25377
25385
  }
25378
25386
  function validateModelIdForProvider(input) {
@@ -25386,11 +25394,11 @@ function validateModelIdForProvider(input) {
25386
25394
  return;
25387
25395
  }
25388
25396
  if (curated) {
25389
- throw new Error(
25397
+ throw new InvalidModelSelectionError(
25390
25398
  `${input.provider} model "${input.id}" is not available for ${input.harness}`
25391
25399
  );
25392
25400
  }
25393
- throw new Error(
25401
+ throw new InvalidModelSelectionError(
25394
25402
  `${input.provider} model ids are not open for ${input.harness}`
25395
25403
  );
25396
25404
  }
@@ -61678,7 +61686,8 @@ function claudeAgentOptions(config2, input = {}) {
61678
61686
  includePartialMessages: true,
61679
61687
  thinking: { type: "adaptive", display: "summarized" },
61680
61688
  settings: { showThinkingSummaries: true },
61681
- model: CLAUDE_CODE_DEFAULT_MODEL,
61689
+ model: config2.model?.id ?? CLAUDE_CODE_DEFAULT_MODEL,
61690
+ ...config2.reasoningEffort ? { effort: config2.reasoningEffort } : {},
61682
61691
  permissionMode: "bypassPermissions",
61683
61692
  allowDangerouslySkipPermissions: true,
61684
61693
  pathToClaudeCodeExecutable: claudeCodeExecutablePath(),
@@ -62420,7 +62429,10 @@ var ClaudeAgentBridgeSessionImpl = class {
62420
62429
  );
62421
62430
  return { outcome: "timeout" };
62422
62431
  }
62423
- await delay(CLAUDE_MCP_REGISTRATION_POLL_INTERVAL_MS);
62432
+ await delay(
62433
+ CLAUDE_MCP_REGISTRATION_POLL_INTERVAL_MS,
62434
+ this.abortController.signal
62435
+ );
62424
62436
  }
62425
62437
  }
62426
62438
  messageProbeContext() {
@@ -62575,10 +62587,19 @@ function mcpStatusDetailList(statuses) {
62575
62587
  (server) => server.error ? `${server.name}:${server.status}(${server.error})` : `${server.name}:${server.status}`
62576
62588
  ).join(",");
62577
62589
  }
62578
- function delay(ms) {
62590
+ function delay(ms, signal) {
62591
+ if (signal?.aborted) {
62592
+ return Promise.resolve();
62593
+ }
62579
62594
  return new Promise((resolve2) => {
62580
- const timer = setTimeout(resolve2, ms);
62595
+ const finish = () => {
62596
+ clearTimeout(timer);
62597
+ signal?.removeEventListener("abort", finish);
62598
+ resolve2();
62599
+ };
62600
+ const timer = setTimeout(finish, ms);
62581
62601
  timer.unref?.();
62602
+ signal?.addEventListener("abort", finish, { once: true });
62582
62603
  });
62583
62604
  }
62584
62605
  function claudeAgentUserMessage(message) {
@@ -62675,11 +62696,13 @@ function createClaudeCodeCommandHandler(input) {
62675
62696
  var ClaudeCodeCommandHandler = class {
62676
62697
  constructor(input) {
62677
62698
  this.input = input;
62699
+ this.claudeConfig = input.claude;
62678
62700
  this.outputBuffer = new AgentBridgeOutputBuffer(input);
62679
62701
  }
62680
62702
  input;
62681
62703
  context = null;
62682
62704
  agentSession = null;
62705
+ claudeConfig;
62683
62706
  persistedAgentId = null;
62684
62707
  injectedCommands = /* @__PURE__ */ new Set();
62685
62708
  // Message commands whose injection has started but not settled. A fresh SDK
@@ -62879,6 +62902,7 @@ var ClaudeCodeCommandHandler = class {
62879
62902
  );
62880
62903
  const sendStartedAt = Date.now();
62881
62904
  const mode = deliveryMode(delivery);
62905
+ this.applySelectionForMessage(delivery);
62882
62906
  this.input.runtimeLogger?.info(
62883
62907
  "agent_bridge_claude_command_send_message_started",
62884
62908
  commandLogContext(delivery, {
@@ -63112,7 +63136,7 @@ var ClaudeCodeCommandHandler = class {
63112
63136
  return this.agentSession;
63113
63137
  }
63114
63138
  const session = claudeAgentBridgeRuntime.start({
63115
- claude: this.input.claude,
63139
+ claude: this.claudeConfig,
63116
63140
  resumeAgentId: this.storedResumeAgentId(),
63117
63141
  canUseTool: this.canUseTool,
63118
63142
  onMessage: (message, meta3) => this.handleAgentMessage(message, meta3),
@@ -63129,6 +63153,27 @@ var ClaudeCodeCommandHandler = class {
63129
63153
  this.agentSession = session;
63130
63154
  return session;
63131
63155
  }
63156
+ applySelectionForMessage(delivery) {
63157
+ const selection = deliverySelection(delivery);
63158
+ if (!selection.model && selection.reasoningEffort === void 0) {
63159
+ return;
63160
+ }
63161
+ const next = {
63162
+ ...this.claudeConfig,
63163
+ ...selection.model ? { model: selection.model } : {},
63164
+ ...selection.reasoningEffort ? { reasoningEffort: selection.reasoningEffort } : {}
63165
+ };
63166
+ if (sameClaudeConfigSelection(this.claudeConfig, next)) {
63167
+ return;
63168
+ }
63169
+ this.claudeConfig = next;
63170
+ this.agentSession?.close();
63171
+ this.agentSession = null;
63172
+ this.settlePendingQuestions("The runtime restarted to change model");
63173
+ this.input.writeOutput?.(
63174
+ `agent_bridge_claude_model_selection_changed provider=${next.model?.provider ?? ""} model=${next.model?.id ?? ""} reasoning_effort=${next.reasoningEffort ?? ""}`
63175
+ );
63176
+ }
63132
63177
  };
63133
63178
  function withConsumedCommandIds(projection, meta3) {
63134
63179
  const consumedCommandIds = meta3?.consumedCommandIds;
@@ -63153,6 +63198,23 @@ function deliveryMessage(delivery) {
63153
63198
  }
63154
63199
  return null;
63155
63200
  }
63201
+ function deliverySelection(delivery) {
63202
+ const payload = delivery.payload;
63203
+ if (!payload || typeof payload !== "object") {
63204
+ return {};
63205
+ }
63206
+ const model = "model" in payload ? AgentBridgeModelSelectionSchema.safeParse(payload.model) : null;
63207
+ const reasoningEffort = "reasoningEffort" in payload ? AgentBridgeClaudeReasoningEffortSchema.safeParse(
63208
+ payload.reasoningEffort
63209
+ ) : null;
63210
+ return {
63211
+ ...model?.success ? { model: model.data } : {},
63212
+ ...reasoningEffort?.success ? { reasoningEffort: reasoningEffort.data } : {}
63213
+ };
63214
+ }
63215
+ function sameClaudeConfigSelection(current, next) {
63216
+ return current.model?.provider === next.model?.provider && current.model?.id === next.model?.id && current.reasoningEffort === next.reasoningEffort;
63217
+ }
63156
63218
  function deliveryMode(delivery) {
63157
63219
  const payload = delivery.payload;
63158
63220
  if (payload && typeof payload === "object" && "deliveryMode" in payload) {
@@ -63536,9 +63598,14 @@ import { join } from "path";
63536
63598
  var CODEX_EXECUTABLE_PATH = "codex";
63537
63599
  var CODEX_DEFAULT_MODEL = "gpt-5.3-codex";
63538
63600
  var CODEX_HTTP_PROVIDER_ID = "openai-responses-http";
63601
+ var CODEX_OPENROUTER_PROVIDER_ID = "openrouter-responses-http";
63602
+ var CODEX_APPROVAL_POLICY = "never";
63603
+ var CODEX_SANDBOX_MODE = "danger-full-access";
63539
63604
  var CODEX_OPENAI_BASE_URL = "https://api.openai.com/v1";
63605
+ var CODEX_OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1";
63540
63606
  var CODEX_API_KEY_ENV = "OPENAI_API_KEY";
63541
63607
  var MODEL_GATEWAY_OPENAI_BASE_URL_ENV = "AUTO_MODEL_GATEWAY_OPENAI_BASE_URL";
63608
+ var MODEL_GATEWAY_OPENROUTER_BASE_URL_ENV = "AUTO_MODEL_GATEWAY_OPENROUTER_BASE_URL";
63542
63609
  var CODEX_RUNTIME_PROCESS_ENV_KEYS = ["PATH", "HOME"];
63543
63610
  function codexLaunchOptions(config2) {
63544
63611
  return {
@@ -63561,8 +63628,16 @@ function codexThreadParams(config2) {
63561
63628
  }
63562
63629
  function renderCodexConfigToml(config2) {
63563
63630
  const lines = [];
63564
- lines.push(`model = ${tomlString(CODEX_DEFAULT_MODEL)}`);
63565
- lines.push(`model_provider = ${tomlString(CODEX_HTTP_PROVIDER_ID)}`);
63631
+ const selectedProvider = codexProviderIdForModel(config2);
63632
+ lines.push(`model = ${tomlString(config2.model?.id ?? CODEX_DEFAULT_MODEL)}`);
63633
+ lines.push(`model_provider = ${tomlString(selectedProvider)}`);
63634
+ if (config2.reasoningEffort) {
63635
+ lines.push(
63636
+ `model_reasoning_effort = ${tomlString(config2.reasoningEffort)}`
63637
+ );
63638
+ }
63639
+ lines.push(`approval_policy = ${tomlString(CODEX_APPROVAL_POLICY)}`);
63640
+ lines.push(`sandbox_mode = ${tomlString(CODEX_SANDBOX_MODE)}`);
63566
63641
  lines.push("");
63567
63642
  lines.push(`[model_providers.${CODEX_HTTP_PROVIDER_ID}]`);
63568
63643
  lines.push('name = "OpenAI"');
@@ -63572,6 +63647,15 @@ function renderCodexConfigToml(config2) {
63572
63647
  lines.push('wire_api = "responses"');
63573
63648
  lines.push(`env_key = ${tomlString(CODEX_API_KEY_ENV)}`);
63574
63649
  lines.push("supports_websockets = false");
63650
+ lines.push("");
63651
+ lines.push(`[model_providers.${CODEX_OPENROUTER_PROVIDER_ID}]`);
63652
+ lines.push('name = "OpenRouter"');
63653
+ lines.push(
63654
+ `base_url = ${tomlString(openRouterBaseUrlForCodexConfig(config2.env))}`
63655
+ );
63656
+ lines.push('wire_api = "responses"');
63657
+ lines.push(`env_key = ${tomlString(CODEX_API_KEY_ENV)}`);
63658
+ lines.push("supports_websockets = false");
63575
63659
  for (const [name23, server] of Object.entries(config2.mcpServers ?? {})) {
63576
63660
  lines.push("");
63577
63661
  lines.push(`[mcp_servers.${tomlKey(name23)}]`);
@@ -63599,6 +63683,12 @@ function codexProcessEnv(env) {
63599
63683
  function openaiBaseUrlForCodexConfig(env) {
63600
63684
  return env[MODEL_GATEWAY_OPENAI_BASE_URL_ENV] ?? CODEX_OPENAI_BASE_URL;
63601
63685
  }
63686
+ function openRouterBaseUrlForCodexConfig(env) {
63687
+ return env[MODEL_GATEWAY_OPENROUTER_BASE_URL_ENV] ?? CODEX_OPENROUTER_BASE_URL;
63688
+ }
63689
+ function codexProviderIdForModel(config2) {
63690
+ return config2.model?.provider === "openrouter" ? CODEX_OPENROUTER_PROVIDER_ID : CODEX_HTTP_PROVIDER_ID;
63691
+ }
63602
63692
  function codexHomeDir() {
63603
63693
  const home = process.env.HOME;
63604
63694
  if (!home) {
@@ -63653,6 +63743,7 @@ var CodexAgentBridgeSessionImpl = class {
63653
63743
  // set means an interrupt/steer would race an unsettled item (FRA-3049 analog).
63654
63744
  pendingToolItemIds = /* @__PURE__ */ new Set();
63655
63745
  settlementWaiters = /* @__PURE__ */ new Set();
63746
+ callbackQueue = Promise.resolve();
63656
63747
  // Messages held in "deferred" mode while a turn is in flight; flushed as a
63657
63748
  // fresh turn once the active turn completes.
63658
63749
  deferredMessages = [];
@@ -63924,10 +64015,12 @@ var CodexAgentBridgeSessionImpl = class {
63924
64015
  return;
63925
64016
  case "notification":
63926
64017
  this.trackNotification(message.notification);
63927
- void this.input.onNotification(message.notification);
64018
+ this.enqueueCallback(
64019
+ () => this.input.onNotification(message.notification)
64020
+ );
63928
64021
  return;
63929
64022
  case "serverRequest":
63930
- void this.input.onServerRequest(message.request);
64023
+ this.enqueueCallback(() => this.input.onServerRequest(message.request));
63931
64024
  return;
63932
64025
  case "elicitation":
63933
64026
  this.writeFrame({
@@ -63953,6 +64046,18 @@ var CodexAgentBridgeSessionImpl = class {
63953
64046
  return;
63954
64047
  }
63955
64048
  }
64049
+ enqueueCallback(callback) {
64050
+ this.callbackQueue = this.callbackQueue.then(async () => {
64051
+ try {
64052
+ await callback();
64053
+ } catch (error51) {
64054
+ try {
64055
+ await this.input.onError(error51);
64056
+ } catch {
64057
+ }
64058
+ }
64059
+ });
64060
+ }
63956
64061
  // Track turn/item lifecycle so steer/interrupt target the live turn and gate on
63957
64062
  // tool-item settlement.
63958
64063
  trackNotification(notification) {
@@ -64090,17 +64195,20 @@ function createCodexCommandHandler(input) {
64090
64195
  var CodexCommandHandler = class {
64091
64196
  constructor(input) {
64092
64197
  this.input = input;
64198
+ this.codexConfig = input.codex;
64093
64199
  this.outputBuffer = new AgentBridgeOutputBuffer(input);
64094
64200
  }
64095
64201
  input;
64096
64202
  context = null;
64097
64203
  session = null;
64204
+ codexConfig;
64098
64205
  injectedCommands = /* @__PURE__ */ new Set();
64099
64206
  // itemId -> JSON-RPC request id of the parked approval request, so an `answer`
64100
64207
  // command keyed by toolCallId (= itemId) can resolve the right server request.
64101
64208
  pendingApprovals = /* @__PURE__ */ new Map();
64102
64209
  outputBuffer;
64103
64210
  projector = new CodexProjector();
64211
+ skipResumeForNextSession = false;
64104
64212
  // ---------------------------------------------------------------------------
64105
64213
  // Lifecycle (public API)
64106
64214
  // ---------------------------------------------------------------------------
@@ -64155,6 +64263,7 @@ var CodexCommandHandler = class {
64155
64263
  }
64156
64264
  this.injectedCommands.add(delivery.commandId);
64157
64265
  try {
64266
+ this.applySelectionForMessage(delivery);
64158
64267
  await this.emitUserMessageEntry(
64159
64268
  activeContext,
64160
64269
  delivery.commandId,
@@ -64288,9 +64397,10 @@ var CodexCommandHandler = class {
64288
64397
  if (this.session) {
64289
64398
  return this.session;
64290
64399
  }
64291
- const resumeThreadId = this.storedResumeThreadId();
64400
+ const resumeThreadId = this.skipResumeForNextSession ? void 0 : this.storedResumeThreadId();
64401
+ this.skipResumeForNextSession = false;
64292
64402
  const session = codexAgentBridgeRuntime.start({
64293
- codex: this.input.codex,
64403
+ codex: this.codexConfig,
64294
64404
  ...resumeThreadId ? { resumeThreadId } : {},
64295
64405
  onNotification: (notification) => this.handleNotification(notification),
64296
64406
  onServerRequest: (request) => this.handleServerRequest(request),
@@ -64307,6 +64417,28 @@ var CodexCommandHandler = class {
64307
64417
  this.session = session;
64308
64418
  return session;
64309
64419
  }
64420
+ applySelectionForMessage(delivery) {
64421
+ const selection = deliverySelection2(delivery);
64422
+ if (!selection.model && selection.reasoningEffort === void 0) {
64423
+ return;
64424
+ }
64425
+ const next = {
64426
+ ...this.codexConfig,
64427
+ ...selection.model ? { model: selection.model } : {},
64428
+ ...selection.reasoningEffort ? { reasoningEffort: selection.reasoningEffort } : {}
64429
+ };
64430
+ if (sameCodexConfigSelection(this.codexConfig, next)) {
64431
+ return;
64432
+ }
64433
+ this.codexConfig = next;
64434
+ this.skipResumeForNextSession = true;
64435
+ this.session?.close();
64436
+ this.session = null;
64437
+ this.pendingApprovals.clear();
64438
+ this.input.writeOutput?.(
64439
+ `agent_bridge_codex_model_selection_changed provider=${next.model?.provider ?? ""} model=${next.model?.id ?? ""} reasoning_effort=${next.reasoningEffort ?? ""}`
64440
+ );
64441
+ }
64310
64442
  storedResumeThreadId() {
64311
64443
  const store = this.input.sessionResume;
64312
64444
  const activeContext = this.context;
@@ -64353,6 +64485,21 @@ function deliveryMessage2(delivery) {
64353
64485
  }
64354
64486
  return null;
64355
64487
  }
64488
+ function deliverySelection2(delivery) {
64489
+ const payload = delivery.payload;
64490
+ if (!payload || typeof payload !== "object") {
64491
+ return {};
64492
+ }
64493
+ const model = "model" in payload ? AgentBridgeModelSelectionSchema.safeParse(payload.model) : null;
64494
+ const reasoningEffort = "reasoningEffort" in payload ? AgentBridgeCodexReasoningEffortSchema.safeParse(payload.reasoningEffort) : null;
64495
+ return {
64496
+ ...model?.success ? { model: model.data } : {},
64497
+ ...reasoningEffort?.success ? { reasoningEffort: reasoningEffort.data } : {}
64498
+ };
64499
+ }
64500
+ function sameCodexConfigSelection(current, next) {
64501
+ return current.model?.provider === next.model?.provider && current.model?.id === next.model?.id && current.reasoningEffort === next.reasoningEffort;
64502
+ }
64356
64503
  function deliveryMode2(delivery) {
64357
64504
  const payload = delivery.payload;
64358
64505
  if (payload && typeof payload === "object" && "deliveryMode" in payload) {
package/dist/index.js CHANGED
@@ -16694,7 +16694,7 @@ function validateReasoningEffortForHarness(input) {
16694
16694
  }
16695
16695
  const rules = modelRulesForHarness(input.harness);
16696
16696
  if (!rules.reasoningEfforts.includes(input.reasoningEffort)) {
16697
- throw new Error(
16697
+ throw new InvalidModelSelectionError(
16698
16698
  `${input.harness} does not support reasoning effort "${input.reasoningEffort}"`
16699
16699
  );
16700
16700
  }
@@ -16731,7 +16731,9 @@ function validateAgentModelFieldsForHarness(spec, context) {
16731
16731
  function validateModelProviderForHarness(harness, provider) {
16732
16732
  const rules = modelRulesForHarness(harness);
16733
16733
  if (!rules.providers.includes(provider)) {
16734
- throw new Error(`${harness} does not support ${provider} models`);
16734
+ throw new InvalidModelSelectionError(
16735
+ `${harness} does not support ${provider} models`
16736
+ );
16735
16737
  }
16736
16738
  }
16737
16739
  function validateModelIdForProvider(input) {
@@ -16745,15 +16747,15 @@ function validateModelIdForProvider(input) {
16745
16747
  return;
16746
16748
  }
16747
16749
  if (curated) {
16748
- throw new Error(
16750
+ throw new InvalidModelSelectionError(
16749
16751
  `${input.provider} model "${input.id}" is not available for ${input.harness}`
16750
16752
  );
16751
16753
  }
16752
- throw new Error(
16754
+ throw new InvalidModelSelectionError(
16753
16755
  `${input.provider} model ids are not open for ${input.harness}`
16754
16756
  );
16755
16757
  }
16756
- var MODEL_API_TOKEN_PROVIDERS, ModelApiTokenProviderSchema, CLAUDE_CODE_REASONING_EFFORTS, CODEX_REASONING_EFFORTS, ClaudeCodeReasoningEffortSchema, CodexReasoningEffortSchema, AgentReasoningEffortSchema, OPENROUTER_MODEL_SLUG_PATTERN, AgentModelSelectionSchema, ResolvedAgentModelSelectionSchema, HARNESS_MODEL_RULES;
16758
+ var MODEL_API_TOKEN_PROVIDERS, ModelApiTokenProviderSchema, CLAUDE_CODE_REASONING_EFFORTS, CODEX_REASONING_EFFORTS, ClaudeCodeReasoningEffortSchema, CodexReasoningEffortSchema, AgentReasoningEffortSchema, OPENROUTER_MODEL_SLUG_PATTERN, AgentModelSelectionSchema, ResolvedAgentModelSelectionSchema, InvalidModelSelectionError, HARNESS_MODEL_RULES;
16757
16759
  var init_model_selection = __esm({
16758
16760
  "../../packages/schemas/src/model-selection.ts"() {
16759
16761
  "use strict";
@@ -16797,6 +16799,12 @@ var init_model_selection = __esm({
16797
16799
  ResolvedAgentModelSelectionSchema = AgentModelSelectionSchema.extend({
16798
16800
  provider: ModelApiTokenProviderSchema
16799
16801
  });
16802
+ InvalidModelSelectionError = class extends Error {
16803
+ constructor(message) {
16804
+ super(message);
16805
+ this.name = "InvalidModelSelectionError";
16806
+ }
16807
+ };
16800
16808
  HARNESS_MODEL_RULES = {
16801
16809
  "claude-code": {
16802
16810
  defaultProvider: "anthropic",
@@ -27058,7 +27066,7 @@ var init_package = __esm({
27058
27066
  "package.json"() {
27059
27067
  package_default = {
27060
27068
  name: "@autohq/cli",
27061
- version: "0.1.316",
27069
+ version: "0.1.318",
27062
27070
  license: "SEE LICENSE IN README.md",
27063
27071
  publishConfig: {
27064
27072
  access: "public"
@@ -39219,7 +39227,8 @@ function claudeAgentOptions(config2, input = {}) {
39219
39227
  includePartialMessages: true,
39220
39228
  thinking: { type: "adaptive", display: "summarized" },
39221
39229
  settings: { showThinkingSummaries: true },
39222
- model: CLAUDE_CODE_DEFAULT_MODEL,
39230
+ model: config2.model?.id ?? CLAUDE_CODE_DEFAULT_MODEL,
39231
+ ...config2.reasoningEffort ? { effort: config2.reasoningEffort } : {},
39223
39232
  permissionMode: "bypassPermissions",
39224
39233
  allowDangerouslySkipPermissions: true,
39225
39234
  pathToClaudeCodeExecutable: claudeCodeExecutablePath(),
@@ -39961,7 +39970,10 @@ var ClaudeAgentBridgeSessionImpl = class {
39961
39970
  );
39962
39971
  return { outcome: "timeout" };
39963
39972
  }
39964
- await delay(CLAUDE_MCP_REGISTRATION_POLL_INTERVAL_MS);
39973
+ await delay(
39974
+ CLAUDE_MCP_REGISTRATION_POLL_INTERVAL_MS,
39975
+ this.abortController.signal
39976
+ );
39965
39977
  }
39966
39978
  }
39967
39979
  messageProbeContext() {
@@ -40116,10 +40128,19 @@ function mcpStatusDetailList(statuses) {
40116
40128
  (server) => server.error ? `${server.name}:${server.status}(${server.error})` : `${server.name}:${server.status}`
40117
40129
  ).join(",");
40118
40130
  }
40119
- function delay(ms) {
40131
+ function delay(ms, signal) {
40132
+ if (signal?.aborted) {
40133
+ return Promise.resolve();
40134
+ }
40120
40135
  return new Promise((resolve4) => {
40121
- const timer = setTimeout(resolve4, ms);
40136
+ const finish = () => {
40137
+ clearTimeout(timer);
40138
+ signal?.removeEventListener("abort", finish);
40139
+ resolve4();
40140
+ };
40141
+ const timer = setTimeout(finish, ms);
40122
40142
  timer.unref?.();
40143
+ signal?.addEventListener("abort", finish, { once: true });
40123
40144
  });
40124
40145
  }
40125
40146
  function claudeAgentUserMessage(message) {
@@ -40216,11 +40237,13 @@ function createClaudeCodeCommandHandler(input) {
40216
40237
  var ClaudeCodeCommandHandler = class {
40217
40238
  constructor(input) {
40218
40239
  this.input = input;
40240
+ this.claudeConfig = input.claude;
40219
40241
  this.outputBuffer = new AgentBridgeOutputBuffer(input);
40220
40242
  }
40221
40243
  input;
40222
40244
  context = null;
40223
40245
  agentSession = null;
40246
+ claudeConfig;
40224
40247
  persistedAgentId = null;
40225
40248
  injectedCommands = /* @__PURE__ */ new Set();
40226
40249
  // Message commands whose injection has started but not settled. A fresh SDK
@@ -40420,6 +40443,7 @@ var ClaudeCodeCommandHandler = class {
40420
40443
  );
40421
40444
  const sendStartedAt = Date.now();
40422
40445
  const mode = deliveryMode(delivery);
40446
+ this.applySelectionForMessage(delivery);
40423
40447
  this.input.runtimeLogger?.info(
40424
40448
  "agent_bridge_claude_command_send_message_started",
40425
40449
  commandLogContext(delivery, {
@@ -40653,7 +40677,7 @@ var ClaudeCodeCommandHandler = class {
40653
40677
  return this.agentSession;
40654
40678
  }
40655
40679
  const session = claudeAgentBridgeRuntime.start({
40656
- claude: this.input.claude,
40680
+ claude: this.claudeConfig,
40657
40681
  resumeAgentId: this.storedResumeAgentId(),
40658
40682
  canUseTool: this.canUseTool,
40659
40683
  onMessage: (message, meta3) => this.handleAgentMessage(message, meta3),
@@ -40670,6 +40694,27 @@ var ClaudeCodeCommandHandler = class {
40670
40694
  this.agentSession = session;
40671
40695
  return session;
40672
40696
  }
40697
+ applySelectionForMessage(delivery) {
40698
+ const selection = deliverySelection(delivery);
40699
+ if (!selection.model && selection.reasoningEffort === void 0) {
40700
+ return;
40701
+ }
40702
+ const next = {
40703
+ ...this.claudeConfig,
40704
+ ...selection.model ? { model: selection.model } : {},
40705
+ ...selection.reasoningEffort ? { reasoningEffort: selection.reasoningEffort } : {}
40706
+ };
40707
+ if (sameClaudeConfigSelection(this.claudeConfig, next)) {
40708
+ return;
40709
+ }
40710
+ this.claudeConfig = next;
40711
+ this.agentSession?.close();
40712
+ this.agentSession = null;
40713
+ this.settlePendingQuestions("The runtime restarted to change model");
40714
+ this.input.writeOutput?.(
40715
+ `agent_bridge_claude_model_selection_changed provider=${next.model?.provider ?? ""} model=${next.model?.id ?? ""} reasoning_effort=${next.reasoningEffort ?? ""}`
40716
+ );
40717
+ }
40673
40718
  };
40674
40719
  function withConsumedCommandIds(projection, meta3) {
40675
40720
  const consumedCommandIds = meta3?.consumedCommandIds;
@@ -40694,6 +40739,23 @@ function deliveryMessage(delivery) {
40694
40739
  }
40695
40740
  return null;
40696
40741
  }
40742
+ function deliverySelection(delivery) {
40743
+ const payload = delivery.payload;
40744
+ if (!payload || typeof payload !== "object") {
40745
+ return {};
40746
+ }
40747
+ const model = "model" in payload ? AgentBridgeModelSelectionSchema.safeParse(payload.model) : null;
40748
+ const reasoningEffort = "reasoningEffort" in payload ? AgentBridgeClaudeReasoningEffortSchema.safeParse(
40749
+ payload.reasoningEffort
40750
+ ) : null;
40751
+ return {
40752
+ ...model?.success ? { model: model.data } : {},
40753
+ ...reasoningEffort?.success ? { reasoningEffort: reasoningEffort.data } : {}
40754
+ };
40755
+ }
40756
+ function sameClaudeConfigSelection(current, next) {
40757
+ return current.model?.provider === next.model?.provider && current.model?.id === next.model?.id && current.reasoningEffort === next.reasoningEffort;
40758
+ }
40697
40759
  function deliveryMode(delivery) {
40698
40760
  const payload = delivery.payload;
40699
40761
  if (payload && typeof payload === "object" && "deliveryMode" in payload) {
@@ -41082,9 +41144,14 @@ import { join as join3 } from "path";
41082
41144
  var CODEX_EXECUTABLE_PATH = "codex";
41083
41145
  var CODEX_DEFAULT_MODEL = "gpt-5.3-codex";
41084
41146
  var CODEX_HTTP_PROVIDER_ID = "openai-responses-http";
41147
+ var CODEX_OPENROUTER_PROVIDER_ID = "openrouter-responses-http";
41148
+ var CODEX_APPROVAL_POLICY = "never";
41149
+ var CODEX_SANDBOX_MODE = "danger-full-access";
41085
41150
  var CODEX_OPENAI_BASE_URL = "https://api.openai.com/v1";
41151
+ var CODEX_OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1";
41086
41152
  var CODEX_API_KEY_ENV = "OPENAI_API_KEY";
41087
41153
  var MODEL_GATEWAY_OPENAI_BASE_URL_ENV = "AUTO_MODEL_GATEWAY_OPENAI_BASE_URL";
41154
+ var MODEL_GATEWAY_OPENROUTER_BASE_URL_ENV = "AUTO_MODEL_GATEWAY_OPENROUTER_BASE_URL";
41088
41155
  var CODEX_RUNTIME_PROCESS_ENV_KEYS = ["PATH", "HOME"];
41089
41156
  function codexLaunchOptions(config2) {
41090
41157
  return {
@@ -41107,8 +41174,16 @@ function codexThreadParams(config2) {
41107
41174
  }
41108
41175
  function renderCodexConfigToml(config2) {
41109
41176
  const lines = [];
41110
- lines.push(`model = ${tomlString(CODEX_DEFAULT_MODEL)}`);
41111
- lines.push(`model_provider = ${tomlString(CODEX_HTTP_PROVIDER_ID)}`);
41177
+ const selectedProvider = codexProviderIdForModel(config2);
41178
+ lines.push(`model = ${tomlString(config2.model?.id ?? CODEX_DEFAULT_MODEL)}`);
41179
+ lines.push(`model_provider = ${tomlString(selectedProvider)}`);
41180
+ if (config2.reasoningEffort) {
41181
+ lines.push(
41182
+ `model_reasoning_effort = ${tomlString(config2.reasoningEffort)}`
41183
+ );
41184
+ }
41185
+ lines.push(`approval_policy = ${tomlString(CODEX_APPROVAL_POLICY)}`);
41186
+ lines.push(`sandbox_mode = ${tomlString(CODEX_SANDBOX_MODE)}`);
41112
41187
  lines.push("");
41113
41188
  lines.push(`[model_providers.${CODEX_HTTP_PROVIDER_ID}]`);
41114
41189
  lines.push('name = "OpenAI"');
@@ -41118,6 +41193,15 @@ function renderCodexConfigToml(config2) {
41118
41193
  lines.push('wire_api = "responses"');
41119
41194
  lines.push(`env_key = ${tomlString(CODEX_API_KEY_ENV)}`);
41120
41195
  lines.push("supports_websockets = false");
41196
+ lines.push("");
41197
+ lines.push(`[model_providers.${CODEX_OPENROUTER_PROVIDER_ID}]`);
41198
+ lines.push('name = "OpenRouter"');
41199
+ lines.push(
41200
+ `base_url = ${tomlString(openRouterBaseUrlForCodexConfig(config2.env))}`
41201
+ );
41202
+ lines.push('wire_api = "responses"');
41203
+ lines.push(`env_key = ${tomlString(CODEX_API_KEY_ENV)}`);
41204
+ lines.push("supports_websockets = false");
41121
41205
  for (const [name, server] of Object.entries(config2.mcpServers ?? {})) {
41122
41206
  lines.push("");
41123
41207
  lines.push(`[mcp_servers.${tomlKey(name)}]`);
@@ -41145,6 +41229,12 @@ function codexProcessEnv(env) {
41145
41229
  function openaiBaseUrlForCodexConfig(env) {
41146
41230
  return env[MODEL_GATEWAY_OPENAI_BASE_URL_ENV] ?? CODEX_OPENAI_BASE_URL;
41147
41231
  }
41232
+ function openRouterBaseUrlForCodexConfig(env) {
41233
+ return env[MODEL_GATEWAY_OPENROUTER_BASE_URL_ENV] ?? CODEX_OPENROUTER_BASE_URL;
41234
+ }
41235
+ function codexProviderIdForModel(config2) {
41236
+ return config2.model?.provider === "openrouter" ? CODEX_OPENROUTER_PROVIDER_ID : CODEX_HTTP_PROVIDER_ID;
41237
+ }
41148
41238
  function codexHomeDir() {
41149
41239
  const home = process.env.HOME;
41150
41240
  if (!home) {
@@ -41199,6 +41289,7 @@ var CodexAgentBridgeSessionImpl = class {
41199
41289
  // set means an interrupt/steer would race an unsettled item (FRA-3049 analog).
41200
41290
  pendingToolItemIds = /* @__PURE__ */ new Set();
41201
41291
  settlementWaiters = /* @__PURE__ */ new Set();
41292
+ callbackQueue = Promise.resolve();
41202
41293
  // Messages held in "deferred" mode while a turn is in flight; flushed as a
41203
41294
  // fresh turn once the active turn completes.
41204
41295
  deferredMessages = [];
@@ -41470,10 +41561,12 @@ var CodexAgentBridgeSessionImpl = class {
41470
41561
  return;
41471
41562
  case "notification":
41472
41563
  this.trackNotification(message.notification);
41473
- void this.input.onNotification(message.notification);
41564
+ this.enqueueCallback(
41565
+ () => this.input.onNotification(message.notification)
41566
+ );
41474
41567
  return;
41475
41568
  case "serverRequest":
41476
- void this.input.onServerRequest(message.request);
41569
+ this.enqueueCallback(() => this.input.onServerRequest(message.request));
41477
41570
  return;
41478
41571
  case "elicitation":
41479
41572
  this.writeFrame({
@@ -41499,6 +41592,18 @@ var CodexAgentBridgeSessionImpl = class {
41499
41592
  return;
41500
41593
  }
41501
41594
  }
41595
+ enqueueCallback(callback) {
41596
+ this.callbackQueue = this.callbackQueue.then(async () => {
41597
+ try {
41598
+ await callback();
41599
+ } catch (error51) {
41600
+ try {
41601
+ await this.input.onError(error51);
41602
+ } catch {
41603
+ }
41604
+ }
41605
+ });
41606
+ }
41502
41607
  // Track turn/item lifecycle so steer/interrupt target the live turn and gate on
41503
41608
  // tool-item settlement.
41504
41609
  trackNotification(notification) {
@@ -41636,17 +41741,20 @@ function createCodexCommandHandler(input) {
41636
41741
  var CodexCommandHandler = class {
41637
41742
  constructor(input) {
41638
41743
  this.input = input;
41744
+ this.codexConfig = input.codex;
41639
41745
  this.outputBuffer = new AgentBridgeOutputBuffer(input);
41640
41746
  }
41641
41747
  input;
41642
41748
  context = null;
41643
41749
  session = null;
41750
+ codexConfig;
41644
41751
  injectedCommands = /* @__PURE__ */ new Set();
41645
41752
  // itemId -> JSON-RPC request id of the parked approval request, so an `answer`
41646
41753
  // command keyed by toolCallId (= itemId) can resolve the right server request.
41647
41754
  pendingApprovals = /* @__PURE__ */ new Map();
41648
41755
  outputBuffer;
41649
41756
  projector = new CodexProjector();
41757
+ skipResumeForNextSession = false;
41650
41758
  // ---------------------------------------------------------------------------
41651
41759
  // Lifecycle (public API)
41652
41760
  // ---------------------------------------------------------------------------
@@ -41701,6 +41809,7 @@ var CodexCommandHandler = class {
41701
41809
  }
41702
41810
  this.injectedCommands.add(delivery.commandId);
41703
41811
  try {
41812
+ this.applySelectionForMessage(delivery);
41704
41813
  await this.emitUserMessageEntry(
41705
41814
  activeContext,
41706
41815
  delivery.commandId,
@@ -41834,9 +41943,10 @@ var CodexCommandHandler = class {
41834
41943
  if (this.session) {
41835
41944
  return this.session;
41836
41945
  }
41837
- const resumeThreadId = this.storedResumeThreadId();
41946
+ const resumeThreadId = this.skipResumeForNextSession ? void 0 : this.storedResumeThreadId();
41947
+ this.skipResumeForNextSession = false;
41838
41948
  const session = codexAgentBridgeRuntime.start({
41839
- codex: this.input.codex,
41949
+ codex: this.codexConfig,
41840
41950
  ...resumeThreadId ? { resumeThreadId } : {},
41841
41951
  onNotification: (notification) => this.handleNotification(notification),
41842
41952
  onServerRequest: (request) => this.handleServerRequest(request),
@@ -41853,6 +41963,28 @@ var CodexCommandHandler = class {
41853
41963
  this.session = session;
41854
41964
  return session;
41855
41965
  }
41966
+ applySelectionForMessage(delivery) {
41967
+ const selection = deliverySelection2(delivery);
41968
+ if (!selection.model && selection.reasoningEffort === void 0) {
41969
+ return;
41970
+ }
41971
+ const next = {
41972
+ ...this.codexConfig,
41973
+ ...selection.model ? { model: selection.model } : {},
41974
+ ...selection.reasoningEffort ? { reasoningEffort: selection.reasoningEffort } : {}
41975
+ };
41976
+ if (sameCodexConfigSelection(this.codexConfig, next)) {
41977
+ return;
41978
+ }
41979
+ this.codexConfig = next;
41980
+ this.skipResumeForNextSession = true;
41981
+ this.session?.close();
41982
+ this.session = null;
41983
+ this.pendingApprovals.clear();
41984
+ this.input.writeOutput?.(
41985
+ `agent_bridge_codex_model_selection_changed provider=${next.model?.provider ?? ""} model=${next.model?.id ?? ""} reasoning_effort=${next.reasoningEffort ?? ""}`
41986
+ );
41987
+ }
41856
41988
  storedResumeThreadId() {
41857
41989
  const store = this.input.sessionResume;
41858
41990
  const activeContext = this.context;
@@ -41899,6 +42031,21 @@ function deliveryMessage2(delivery) {
41899
42031
  }
41900
42032
  return null;
41901
42033
  }
42034
+ function deliverySelection2(delivery) {
42035
+ const payload = delivery.payload;
42036
+ if (!payload || typeof payload !== "object") {
42037
+ return {};
42038
+ }
42039
+ const model = "model" in payload ? AgentBridgeModelSelectionSchema.safeParse(payload.model) : null;
42040
+ const reasoningEffort = "reasoningEffort" in payload ? AgentBridgeCodexReasoningEffortSchema.safeParse(payload.reasoningEffort) : null;
42041
+ return {
42042
+ ...model?.success ? { model: model.data } : {},
42043
+ ...reasoningEffort?.success ? { reasoningEffort: reasoningEffort.data } : {}
42044
+ };
42045
+ }
42046
+ function sameCodexConfigSelection(current, next) {
42047
+ return current.model?.provider === next.model?.provider && current.model?.id === next.model?.id && current.reasoningEffort === next.reasoningEffort;
42048
+ }
41902
42049
  function deliveryMode2(delivery) {
41903
42050
  const payload = delivery.payload;
41904
42051
  if (payload && typeof payload === "object" && "deliveryMode" in payload) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autohq/cli",
3
- "version": "0.1.316",
3
+ "version": "0.1.318",
4
4
  "license": "SEE LICENSE IN README.md",
5
5
  "publishConfig": {
6
6
  "access": "public"