remote-codex 0.11.42 → 0.11.43

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.
@@ -10,13 +10,13 @@
10
10
  <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
11
11
  <link rel="manifest" href="/site.webmanifest" />
12
12
  <title>Remote Codex</title>
13
- <script type="module" crossorigin src="/assets/index-BvxWpPKW.js"></script>
13
+ <script type="module" crossorigin src="/assets/index-BT0SM9C-.js"></script>
14
14
  <link rel="modulepreload" crossorigin href="/assets/react-vendor-Dfg_6BLf.js">
15
15
  <link rel="modulepreload" crossorigin href="/assets/ui-vendor-CuR8GHb0.js">
16
16
  <link rel="modulepreload" crossorigin href="/assets/graph-vendor-DVQUpZ8C.js">
17
17
  <link rel="modulepreload" crossorigin href="/assets/terminal-vendor-C5bTa-Ka.js">
18
18
  <link rel="modulepreload" crossorigin href="/assets/markdown-vendor-RZk8L7-L.js">
19
- <link rel="modulepreload" crossorigin href="/assets/thread-ui-BLThton-.js">
19
+ <link rel="modulepreload" crossorigin href="/assets/thread-ui-Dmrigdek.js">
20
20
  <link rel="stylesheet" crossorigin href="/assets/graph-vendor-C5ap-Sga.css">
21
21
  <link rel="stylesheet" crossorigin href="/assets/terminal-vendor-Beg8tuEN.css">
22
22
  <link rel="stylesheet" crossorigin href="/assets/index-BcCLYWAf.css">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remote-codex",
3
- "version": "0.11.42",
3
+ "version": "0.11.43",
4
4
  "description": "Local web supervisor for Codex workspaces and threads.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -88,6 +88,7 @@ class FakeQuery implements Query {
88
88
  return [
89
89
  {
90
90
  value: 'claude-sonnet-4-5',
91
+ resolvedModel: 'claude-sonnet-4-5-20250929',
91
92
  displayName: 'Claude Sonnet 4.5',
92
93
  description: 'Test model',
93
94
  supportsEffort: true,
@@ -801,14 +802,17 @@ describe('ClaudeRuntimeAdapter', () => {
801
802
  await expect(adapter.listLoadedSessions()).resolves.toEqual(['claude-session-1']);
802
803
  });
803
804
 
804
- it('exposes Claude Code model aliases and enables the 1M context beta', async () => {
805
+ it('discovers versioned Claude Code model labels while idle and enables the 1M context beta', async () => {
805
806
  const sdkOptions: Record<string, unknown>[] = [];
807
+ const queries: FakeQuery[] = [];
806
808
  const adapter = new ClaudeRuntimeAdapter({
807
809
  home: '/tmp/claude-home',
808
810
  command: 'claude',
809
811
  query: ((params: { prompt: string; options: Record<string, unknown> }) => {
810
812
  sdkOptions.push(params.options);
811
- return new FakeQuery([systemInit(), result()]);
813
+ const query = new FakeQuery([systemInit(), result()]);
814
+ queries.push(query);
815
+ return query;
812
816
  }) as any,
813
817
  listSessions: (async () => [] satisfies SDKSessionInfo[]) as any,
814
818
  getSessionInfo: (async () => null) as any,
@@ -819,12 +823,12 @@ describe('ClaudeRuntimeAdapter', () => {
819
823
  expect.arrayContaining([
820
824
  expect.objectContaining({
821
825
  model: 'sonnet',
822
- displayName: 'Claude Sonnet',
826
+ displayName: 'Sonnet · 4.5',
823
827
  isDefault: true,
824
828
  }),
825
829
  expect.objectContaining({
826
830
  model: 'sonnet[1m]',
827
- displayName: 'Claude Sonnet 1M',
831
+ displayName: 'Sonnet · 4.5 (1M context)',
828
832
  }),
829
833
  expect.objectContaining({
830
834
  model: 'fable',
@@ -836,6 +840,9 @@ describe('ClaudeRuntimeAdapter', () => {
836
840
  }),
837
841
  ]),
838
842
  );
843
+ expect(queries[0]?.closed).toBe(true);
844
+ await adapter.listModels();
845
+ expect(queries).toHaveLength(1);
839
846
 
840
847
  await adapter.startSession({
841
848
  cwd: '/tmp/workspace',
@@ -844,7 +851,7 @@ describe('ClaudeRuntimeAdapter', () => {
844
851
  sandboxMode: 'workspace-write',
845
852
  });
846
853
 
847
- expect(sdkOptions[0]).toMatchObject({
854
+ expect(sdkOptions.at(-1)).toMatchObject({
848
855
  model: 'sonnet',
849
856
  betas: ['context-1m-2025-08-07'],
850
857
  });
@@ -177,6 +177,7 @@ interface SDKSessionInfo {
177
177
  type SessionMessage = SDKMessage;
178
178
  interface ModelInfo {
179
179
  value: string;
180
+ resolvedModel?: string;
180
181
  displayName: string;
181
182
  description: string;
182
183
  supportedEffortLevels?: string[];
@@ -711,7 +712,7 @@ function mapModelInfo(model: ModelInfo, index: number): AgentModel {
711
712
  return {
712
713
  id: model.value,
713
714
  model: model.value,
714
- displayName: model.displayName,
715
+ displayName: versionedClaudeModelDisplayName(model),
715
716
  description: model.description,
716
717
  isDefault: index === 0,
717
718
  hidden: false,
@@ -723,11 +724,52 @@ function mapModelInfo(model: ModelInfo, index: number): AgentModel {
723
724
  };
724
725
  }
725
726
 
727
+ function versionedClaudeModelDisplayName(model: ModelInfo) {
728
+ const resolved = model.resolvedModel?.match(
729
+ /^claude-(sonnet|opus|haiku|fable)-(\d+)(?:-(\d+))?(?:-|\[|$)/i,
730
+ );
731
+ if (!resolved) {
732
+ return model.displayName;
733
+ }
734
+
735
+ const family = `${resolved[1]![0]!.toUpperCase()}${resolved[1]!.slice(1).toLowerCase()}`;
736
+ const version = resolved[3] ? `${resolved[2]}.${resolved[3]}` : resolved[2]!;
737
+ if (model.value === 'default') {
738
+ return `Default · ${family} ${version}`;
739
+ }
740
+
741
+ const qualifier = model.displayName.match(/\s*(\([^)]+\))\s*$/)?.[1];
742
+ return `${family} · ${version}${qualifier ? ` ${qualifier}` : ''}`;
743
+ }
744
+
745
+ function versionedAlias(
746
+ alias: AgentModel,
747
+ discovered: AgentModel | undefined,
748
+ qualifier?: string,
749
+ ) {
750
+ if (!discovered) {
751
+ return alias;
752
+ }
753
+ return {
754
+ ...alias,
755
+ displayName: `${discovered.displayName.replace(/\s+\([^)]+\)\s*$/, '')}${qualifier ?? ''}`,
756
+ description: discovered.description,
757
+ supportedReasoningEfforts: discovered.supportedReasoningEfforts,
758
+ defaultReasoningEffort: discovered.defaultReasoningEffort,
759
+ };
760
+ }
761
+
726
762
  function withClaudeCodeModelAliases(models: AgentModel[]) {
727
763
  const output = [...models];
728
- const defaultSonnet = DEFAULT_CLAUDE_MODELS[0]!;
729
- const oneMillionSonnet = DEFAULT_CLAUDE_MODELS[1]!;
730
- const fable = DEFAULT_CLAUDE_MODELS[2]!;
764
+ const discoveredSonnet = output.find((model) => /^Sonnet · /.test(model.displayName));
765
+ const discoveredFable = output.find((model) => /^Fable · /.test(model.displayName));
766
+ const defaultSonnet = versionedAlias(DEFAULT_CLAUDE_MODELS[0]!, discoveredSonnet);
767
+ const oneMillionSonnet = versionedAlias(
768
+ DEFAULT_CLAUDE_MODELS[1]!,
769
+ discoveredSonnet,
770
+ ' (1M context)',
771
+ );
772
+ const fable = versionedAlias(DEFAULT_CLAUDE_MODELS[2]!, discoveredFable);
731
773
  const hasSonnetAlias = output.some((model) => model.model === 'sonnet');
732
774
  if (!hasSonnetAlias) {
733
775
  output.unshift(defaultSonnet);
@@ -1344,6 +1386,7 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
1344
1386
  >();
1345
1387
  private subscriptionAuthKind: 'subscription' | 'apiKey' | 'unknown' = 'unknown';
1346
1388
  private subscriptionUsageObservedAt: string | null = null;
1389
+ private modelOptionsCache: AgentModel[] | null = null;
1347
1390
  private readonly historicalTurnIdAliases = new Map<string, Map<string, string>>();
1348
1391
  private readonly clientApp: string;
1349
1392
  private sdkLoadError: string | null = null;
@@ -1509,15 +1552,35 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
1509
1552
 
1510
1553
  async listModels(): Promise<AgentModel[]> {
1511
1554
  const active = [...this.activeTurns.values()][0];
1512
- if (!active) {
1513
- return DEFAULT_CLAUDE_MODELS;
1555
+ if (!active && this.modelOptionsCache) {
1556
+ return this.modelOptionsCache;
1514
1557
  }
1515
1558
 
1559
+ let query = active?.query ?? null;
1560
+
1516
1561
  try {
1517
- const models = await active.query.supportedModels();
1518
- return withClaudeCodeModelAliases(models.map(mapModelInfo));
1562
+ query ??= this.queryFactory({
1563
+ prompt: '',
1564
+ options: queryOptionsForRuntime({
1565
+ home: this.options.home,
1566
+ command: this.options.command,
1567
+ clientApp: this.clientApp,
1568
+ approvalMode: 'guarded',
1569
+ includePartialMessages: false,
1570
+ tools: [],
1571
+ maxTurns: 1,
1572
+ }),
1573
+ });
1574
+ const models = await query.supportedModels();
1575
+ const mapped = withClaudeCodeModelAliases(models.map(mapModelInfo));
1576
+ this.modelOptionsCache = mapped;
1577
+ return mapped;
1519
1578
  } catch {
1520
- return DEFAULT_CLAUDE_MODELS;
1579
+ return this.modelOptionsCache ?? DEFAULT_CLAUDE_MODELS;
1580
+ } finally {
1581
+ if (!active && query) {
1582
+ query.close();
1583
+ }
1521
1584
  }
1522
1585
  }
1523
1586