remote-codex 0.11.32 → 0.11.34
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/apps/supervisor-api/dist/index.js +65 -2
- package/apps/supervisor-web/dist/assets/index-BTG-ELMo.css +1 -0
- package/apps/supervisor-web/dist/assets/index-PHqiYl42.js +21 -0
- package/apps/supervisor-web/dist/assets/{thread-ui-B9eC2H4u.js → thread-ui-DoKAPILv.js} +1 -1
- package/apps/supervisor-web/dist/index.html +3 -3
- package/package.json +1 -1
- package/packages/claude/src/runtimeAdapter.test.ts +64 -1
- package/packages/claude/src/runtimeAdapter.ts +101 -2
- package/apps/supervisor-web/dist/assets/index-CGHHTNkM.js +0 -21
- package/apps/supervisor-web/dist/assets/index-CdjTdnJt.css +0 -1
|
@@ -10,16 +10,16 @@
|
|
|
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-
|
|
13
|
+
<script type="module" crossorigin src="/assets/index-PHqiYl42.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-
|
|
19
|
+
<link rel="modulepreload" crossorigin href="/assets/thread-ui-DoKAPILv.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
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
22
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BTG-ELMo.css">
|
|
23
23
|
</head>
|
|
24
24
|
<body class="bg-stone-950">
|
|
25
25
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -15,6 +15,7 @@ interface Query extends AsyncIterable<SDKMessage> {
|
|
|
15
15
|
interrupt(): Promise<void>;
|
|
16
16
|
supportedModels(): Promise<any[]>;
|
|
17
17
|
mcpServerStatus(): Promise<any[]>;
|
|
18
|
+
usage_EXPERIMENTAL_MAY_CHANGE_DO_NOT_RELY_ON_THIS_API_YET(): Promise<any>;
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
function wait(ms = 0) {
|
|
@@ -29,7 +30,7 @@ class FakeQuery implements Query {
|
|
|
29
30
|
|
|
30
31
|
constructor(
|
|
31
32
|
private readonly messages: SDKMessage[],
|
|
32
|
-
private readonly options: { holdOpen?: boolean } = {},
|
|
33
|
+
private readonly options: { holdOpen?: boolean; usage?: Record<string, any> } = {},
|
|
33
34
|
) {}
|
|
34
35
|
|
|
35
36
|
[Symbol.asyncIterator]() {
|
|
@@ -104,6 +105,12 @@ class FakeQuery implements Query {
|
|
|
104
105
|
async getContextUsage(): Promise<any> {
|
|
105
106
|
return {};
|
|
106
107
|
}
|
|
108
|
+
async usage_EXPERIMENTAL_MAY_CHANGE_DO_NOT_RELY_ON_THIS_API_YET(): Promise<any> {
|
|
109
|
+
if (!this.options.usage) {
|
|
110
|
+
throw new Error('Structured usage unavailable in this fixture.');
|
|
111
|
+
}
|
|
112
|
+
return this.options.usage;
|
|
113
|
+
}
|
|
107
114
|
async readFile(): Promise<any> {
|
|
108
115
|
return {};
|
|
109
116
|
}
|
|
@@ -208,6 +215,55 @@ function makeAdapter(
|
|
|
208
215
|
}
|
|
209
216
|
|
|
210
217
|
describe('ClaudeRuntimeAdapter', () => {
|
|
218
|
+
it('actively reads Claude subscription windows from the structured usage API', async () => {
|
|
219
|
+
const adapter = makeAdapter(() => new FakeQuery(
|
|
220
|
+
[systemInit(), result()],
|
|
221
|
+
{
|
|
222
|
+
usage: {
|
|
223
|
+
subscription_type: 'max',
|
|
224
|
+
rate_limits_available: true,
|
|
225
|
+
rate_limits: {
|
|
226
|
+
five_hour: {
|
|
227
|
+
utilization: 23,
|
|
228
|
+
resets_at: '2027-01-15T08:00:00.000Z',
|
|
229
|
+
},
|
|
230
|
+
seven_day: {
|
|
231
|
+
utilization: 84,
|
|
232
|
+
resets_at: '2027-01-20T08:00:00.000Z',
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
));
|
|
238
|
+
|
|
239
|
+
await adapter.start();
|
|
240
|
+
await adapter.startSession({
|
|
241
|
+
cwd: '/tmp/workspace',
|
|
242
|
+
model: 'sonnet',
|
|
243
|
+
approvalMode: 'guarded',
|
|
244
|
+
sandboxMode: 'workspace-write',
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
await expect(adapter.getSubscriptionUsage()).resolves.toMatchObject({
|
|
248
|
+
provider: 'claude',
|
|
249
|
+
authKind: 'subscription',
|
|
250
|
+
windows: [
|
|
251
|
+
{
|
|
252
|
+
id: 'five_hour',
|
|
253
|
+
label: '5h',
|
|
254
|
+
usedPercent: 23,
|
|
255
|
+
resetsAt: '2027-01-15T08:00:00.000Z',
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
id: 'seven_day',
|
|
259
|
+
label: '7d',
|
|
260
|
+
usedPercent: 84,
|
|
261
|
+
resetsAt: '2027-01-20T08:00:00.000Z',
|
|
262
|
+
},
|
|
263
|
+
],
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
|
|
211
267
|
it('captures Claude subscription rate-limit windows from SDK events', async () => {
|
|
212
268
|
const adapter = makeAdapter(() => [
|
|
213
269
|
systemInit(),
|
|
@@ -544,6 +600,13 @@ describe('ClaudeRuntimeAdapter', () => {
|
|
|
544
600
|
}),
|
|
545
601
|
],
|
|
546
602
|
});
|
|
603
|
+
|
|
604
|
+
await adapter.interruptTurn({
|
|
605
|
+
providerSessionId: 'claude-session-1',
|
|
606
|
+
providerTurnId: started.providerTurnId,
|
|
607
|
+
});
|
|
608
|
+
const reloadedSession = await adapter.readSession('claude-session-1');
|
|
609
|
+
expect(reloadedSession.turns[0]?.providerTurnId).toBe(started.providerTurnId);
|
|
547
610
|
});
|
|
548
611
|
|
|
549
612
|
it('keeps image blocks visible when reading Claude session history', async () => {
|
|
@@ -99,6 +99,19 @@ interface Query extends AsyncIterable<SDKMessage> {
|
|
|
99
99
|
interrupt(): Promise<void>;
|
|
100
100
|
supportedModels(): Promise<ModelInfo[]>;
|
|
101
101
|
mcpServerStatus(): Promise<McpServerStatus[]>;
|
|
102
|
+
usage_EXPERIMENTAL_MAY_CHANGE_DO_NOT_RELY_ON_THIS_API_YET?(): Promise<SDKUsageResponse>;
|
|
103
|
+
}
|
|
104
|
+
interface SDKUsageWindow {
|
|
105
|
+
utilization: number | null;
|
|
106
|
+
resets_at: string | null;
|
|
107
|
+
}
|
|
108
|
+
interface SDKUsageResponse {
|
|
109
|
+
subscription_type: string | null;
|
|
110
|
+
rate_limits_available: boolean;
|
|
111
|
+
rate_limits: {
|
|
112
|
+
five_hour?: SDKUsageWindow | null;
|
|
113
|
+
seven_day?: SDKUsageWindow | null;
|
|
114
|
+
} | null;
|
|
102
115
|
}
|
|
103
116
|
interface SDKMessage {
|
|
104
117
|
type: string;
|
|
@@ -1239,7 +1252,9 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1239
1252
|
'five_hour' | 'seven_day',
|
|
1240
1253
|
{ usedPercent: number; resetsAt: string | null }
|
|
1241
1254
|
>();
|
|
1255
|
+
private subscriptionAuthKind: 'subscription' | 'apiKey' | 'unknown' = 'unknown';
|
|
1242
1256
|
private subscriptionUsageObservedAt: string | null = null;
|
|
1257
|
+
private readonly historicalTurnIdAliases = new Map<string, Map<string, string>>();
|
|
1243
1258
|
private readonly clientApp: string;
|
|
1244
1259
|
private sdkLoadError: string | null = null;
|
|
1245
1260
|
|
|
@@ -1271,7 +1286,7 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1271
1286
|
}));
|
|
1272
1287
|
return {
|
|
1273
1288
|
provider: 'claude' as const,
|
|
1274
|
-
authKind:
|
|
1289
|
+
authKind: this.subscriptionAuthKind,
|
|
1275
1290
|
observedAt,
|
|
1276
1291
|
stale: false,
|
|
1277
1292
|
windows,
|
|
@@ -1297,9 +1312,56 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1297
1312
|
? new Date(info.resetsAt * 1000).toISOString()
|
|
1298
1313
|
: null,
|
|
1299
1314
|
});
|
|
1315
|
+
this.subscriptionAuthKind = 'subscription';
|
|
1300
1316
|
this.subscriptionUsageObservedAt = new Date().toISOString();
|
|
1301
1317
|
}
|
|
1302
1318
|
|
|
1319
|
+
private async captureStructuredSubscriptionUsage(query: Query) {
|
|
1320
|
+
const getUsage = query.usage_EXPERIMENTAL_MAY_CHANGE_DO_NOT_RELY_ON_THIS_API_YET;
|
|
1321
|
+
if (!getUsage) {
|
|
1322
|
+
return;
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
try {
|
|
1326
|
+
const usage = await getUsage.call(query);
|
|
1327
|
+
const nextWindows = new Map<
|
|
1328
|
+
'five_hour' | 'seven_day',
|
|
1329
|
+
{ usedPercent: number; resetsAt: string | null }
|
|
1330
|
+
>();
|
|
1331
|
+
const addWindow = (
|
|
1332
|
+
id: 'five_hour' | 'seven_day',
|
|
1333
|
+
window: SDKUsageWindow | null | undefined,
|
|
1334
|
+
) => {
|
|
1335
|
+
if (
|
|
1336
|
+
typeof window?.utilization !== 'number'
|
|
1337
|
+
|| !Number.isFinite(window.utilization)
|
|
1338
|
+
) {
|
|
1339
|
+
return;
|
|
1340
|
+
}
|
|
1341
|
+
nextWindows.set(id, {
|
|
1342
|
+
usedPercent: Math.max(0, Math.min(100, window.utilization)),
|
|
1343
|
+
resetsAt: typeof window.resets_at === 'string' ? window.resets_at : null,
|
|
1344
|
+
});
|
|
1345
|
+
};
|
|
1346
|
+
addWindow('five_hour', usage.rate_limits?.five_hour);
|
|
1347
|
+
addWindow('seven_day', usage.rate_limits?.seven_day);
|
|
1348
|
+
|
|
1349
|
+
this.subscriptionUsageWindows.clear();
|
|
1350
|
+
for (const [id, window] of nextWindows) {
|
|
1351
|
+
this.subscriptionUsageWindows.set(id, window);
|
|
1352
|
+
}
|
|
1353
|
+
this.subscriptionAuthKind = usage.subscription_type
|
|
1354
|
+
? 'subscription'
|
|
1355
|
+
: usage.rate_limits_available
|
|
1356
|
+
? 'subscription'
|
|
1357
|
+
: 'apiKey';
|
|
1358
|
+
this.subscriptionUsageObservedAt = new Date().toISOString();
|
|
1359
|
+
} catch {
|
|
1360
|
+
// This SDK method is experimental. Rate-limit events remain the
|
|
1361
|
+
// compatibility fallback for Claude versions that do not expose it.
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1303
1365
|
private updateToolboxItemsFromSystemInit(message: SDKMessage) {
|
|
1304
1366
|
this.managementSchema.toolboxItems = buildClaudeToolboxItems(
|
|
1305
1367
|
normalizeClaudeSlashCommands(message.slash_commands),
|
|
@@ -1430,7 +1492,10 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1430
1492
|
workspacePath: options.workspacePath || cwd,
|
|
1431
1493
|
...(options.localThreadId ? { localThreadId: options.localThreadId } : {}),
|
|
1432
1494
|
};
|
|
1433
|
-
const turns =
|
|
1495
|
+
const turns = this.applyHistoricalTurnIdAliases(
|
|
1496
|
+
providerSessionId,
|
|
1497
|
+
await this.sessionMessagesToTurns(messages, historyAssetContext),
|
|
1498
|
+
);
|
|
1434
1499
|
const activeTurn = [...this.activeTurns.values()].find(
|
|
1435
1500
|
(turn) => turn.providerSessionId === providerSessionId,
|
|
1436
1501
|
);
|
|
@@ -1463,9 +1528,14 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1463
1528
|
let providerSessionId: string | null = null;
|
|
1464
1529
|
let model: string | null = input.model;
|
|
1465
1530
|
const rawMessages: SDKMessage[] = [];
|
|
1531
|
+
let capturedStructuredUsage = false;
|
|
1466
1532
|
try {
|
|
1467
1533
|
for await (const message of query) {
|
|
1468
1534
|
rawMessages.push(message);
|
|
1535
|
+
if (!capturedStructuredUsage) {
|
|
1536
|
+
capturedStructuredUsage = true;
|
|
1537
|
+
await this.captureStructuredSubscriptionUsage(query);
|
|
1538
|
+
}
|
|
1469
1539
|
this.captureRateLimit(message);
|
|
1470
1540
|
if (message.type === 'system' && message.subtype === 'init') {
|
|
1471
1541
|
this.updateToolboxItemsFromSystemInit(message);
|
|
@@ -1701,6 +1771,16 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1701
1771
|
return turns;
|
|
1702
1772
|
}
|
|
1703
1773
|
|
|
1774
|
+
const transcriptTurn = turns[transcriptTurnIndex];
|
|
1775
|
+
if (transcriptTurn && transcriptTurn.providerTurnId !== activeTurn.providerTurnId) {
|
|
1776
|
+
let aliases = this.historicalTurnIdAliases.get(providerSessionId);
|
|
1777
|
+
if (!aliases) {
|
|
1778
|
+
aliases = new Map();
|
|
1779
|
+
this.historicalTurnIdAliases.set(providerSessionId, aliases);
|
|
1780
|
+
}
|
|
1781
|
+
aliases.set(transcriptTurn.providerTurnId, activeTurn.providerTurnId);
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1704
1784
|
return turns.map((turn, index) => {
|
|
1705
1785
|
if (index !== transcriptTurnIndex) {
|
|
1706
1786
|
return turn;
|
|
@@ -1718,6 +1798,20 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1718
1798
|
});
|
|
1719
1799
|
}
|
|
1720
1800
|
|
|
1801
|
+
private applyHistoricalTurnIdAliases(
|
|
1802
|
+
providerSessionId: string,
|
|
1803
|
+
turns: AgentTurn[],
|
|
1804
|
+
) {
|
|
1805
|
+
const aliases = this.historicalTurnIdAliases.get(providerSessionId);
|
|
1806
|
+
if (!aliases || aliases.size === 0) {
|
|
1807
|
+
return turns;
|
|
1808
|
+
}
|
|
1809
|
+
return turns.map((turn) => {
|
|
1810
|
+
const providerTurnId = aliases.get(turn.providerTurnId);
|
|
1811
|
+
return providerTurnId ? { ...turn, providerTurnId } : turn;
|
|
1812
|
+
});
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1721
1815
|
async listMcpServers(): Promise<AgentMcpServer[]> {
|
|
1722
1816
|
const active = [...this.activeTurns.values()][0];
|
|
1723
1817
|
if (!active) {
|
|
@@ -1755,9 +1849,14 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1755
1849
|
const rawMessages: SDKMessage[] = [];
|
|
1756
1850
|
let terminalStatus: AgentTurn['status'] | null = null;
|
|
1757
1851
|
let terminalError: string | null = null;
|
|
1852
|
+
let capturedStructuredUsage = false;
|
|
1758
1853
|
try {
|
|
1759
1854
|
for await (const message of state.query) {
|
|
1760
1855
|
rawMessages.push(message);
|
|
1856
|
+
if (!capturedStructuredUsage) {
|
|
1857
|
+
capturedStructuredUsage = true;
|
|
1858
|
+
await this.captureStructuredSubscriptionUsage(state.query);
|
|
1859
|
+
}
|
|
1761
1860
|
this.captureRateLimit(message);
|
|
1762
1861
|
this.consumeMessage(state, message);
|
|
1763
1862
|
const status = queryResultStatus(message);
|