remote-codex 0.1.9 → 0.11.0
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 +11942 -6101
- package/apps/supervisor-web/dist/assets/{highlighted-body-OFNGDK62-BFD4Ytvg.js → highlighted-body-OFNGDK62-ChrwAL9u.js} +1 -1
- package/apps/supervisor-web/dist/assets/index-DHf2HOXx.js +381 -0
- package/apps/supervisor-web/dist/assets/index-DpWxXCgt.css +32 -0
- package/apps/supervisor-web/dist/assets/{xterm-CukFWbxr.js → xterm-D4sevve4.js} +1 -1
- package/apps/supervisor-web/dist/index.html +2 -2
- package/config/codex-model-pricing.json +63 -0
- package/package.json +5 -2
- package/packages/agent-runtime/src/index.ts +4 -0
- package/packages/agent-runtime/src/management-errors.ts +11 -0
- package/packages/agent-runtime/src/model-pricing.ts +312 -0
- package/packages/agent-runtime/src/registry.ts +19 -4
- package/packages/agent-runtime/src/runtime-errors.ts +97 -0
- package/packages/agent-runtime/src/types.ts +50 -4
- package/packages/agent-runtime/src/unavailable-runtime.ts +169 -0
- package/packages/claude/src/historyItems.ts +693 -0
- package/packages/claude/src/index.ts +2 -0
- package/packages/claude/src/runtimeAdapter.test.ts +2138 -0
- package/packages/claude/src/runtimeAdapter.ts +2145 -0
- package/packages/codex/src/appServerManager.ts +12 -3
- package/packages/codex/src/historyItems.test.ts +110 -0
- package/packages/codex/src/historyItems.ts +97 -16
- package/packages/codex/src/hookHistory.test.ts +59 -0
- package/packages/codex/src/index.ts +7 -0
- package/packages/codex/src/local-session-store.ts +390 -0
- package/packages/codex/src/management/codex-management-service.ts +454 -0
- package/packages/codex/src/management/codexHostConfig.test.ts +88 -0
- package/packages/codex/src/management/codexHostConfig.ts +188 -0
- package/packages/codex/src/management/errors.ts +20 -0
- package/packages/codex/src/modelPricing.test.ts +184 -0
- package/packages/codex/src/modelPricing.ts +9 -0
- package/packages/codex/src/runtime-errors.test.ts +72 -0
- package/packages/codex/src/runtime-errors.ts +37 -0
- package/packages/codex/src/runtimeAdapter.ts +25 -2
- package/packages/codex/src/thread-title.ts +1 -0
- package/packages/db/src/repositories.ts +30 -0
- package/packages/opencode/src/historyItems.test.ts +504 -0
- package/packages/opencode/src/historyItems.ts +896 -0
- package/packages/opencode/src/index.ts +2 -0
- package/packages/opencode/src/runtimeAdapter.test.ts +1355 -0
- package/packages/opencode/src/runtimeAdapter.ts +1469 -0
- package/packages/shared/src/agent-providers.ts +56 -0
- package/packages/shared/src/index.ts +174 -35
- package/apps/supervisor-web/dist/assets/index-CbIt0KnL.css +0 -32
- package/apps/supervisor-web/dist/assets/index-Rd2EBQac.js +0 -377
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
import type {
|
|
5
|
+
ThreadTurnPriceEstimateDto,
|
|
6
|
+
ThreadTurnTokenUsageDto,
|
|
7
|
+
} from '../../shared/src/index';
|
|
8
|
+
|
|
9
|
+
export type PricingTierKey = 'standard' | 'fast';
|
|
10
|
+
|
|
11
|
+
interface ModelPricingEntry {
|
|
12
|
+
inputUsdPerMillion: number;
|
|
13
|
+
cachedInputUsdPerMillion: number;
|
|
14
|
+
outputUsdPerMillion: number;
|
|
15
|
+
supportsFastMode: boolean;
|
|
16
|
+
fastMultiplier?: number;
|
|
17
|
+
contextWindowTokens?: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface PricingTierConfig {
|
|
21
|
+
multiplier: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface TurnPricingSnapshot {
|
|
25
|
+
pricingModelKey: string;
|
|
26
|
+
pricingTierKey: PricingTierKey;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface PricingConfig {
|
|
30
|
+
currency: 'USD';
|
|
31
|
+
tiers: Record<PricingTierKey, PricingTierConfig>;
|
|
32
|
+
models: Record<string, ModelPricingEntry>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const TOKEN_PRICE_DENOMINATOR = 1_000_000;
|
|
36
|
+
let cachedPricingConfig: PricingConfig | null = null;
|
|
37
|
+
|
|
38
|
+
function resolvePackageRoot(start = process.cwd()) {
|
|
39
|
+
if (process.env.REMOTE_CODEX_PACKAGE_ROOT) {
|
|
40
|
+
return path.resolve(process.env.REMOTE_CODEX_PACKAGE_ROOT);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let current = path.resolve(start);
|
|
44
|
+
|
|
45
|
+
while (current !== path.dirname(current)) {
|
|
46
|
+
if (fs.existsSync(path.join(current, 'pnpm-workspace.yaml'))) {
|
|
47
|
+
return current;
|
|
48
|
+
}
|
|
49
|
+
current = path.dirname(current);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
throw new Error('Unable to locate package root for model pricing config.');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function getPricingConfigPath() {
|
|
56
|
+
return path.join(resolvePackageRoot(), 'config', 'codex-model-pricing.json');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function isPositiveNumber(value: unknown) {
|
|
60
|
+
return typeof value === 'number' && Number.isFinite(value) && value >= 0;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function parsePricingConfig(raw: unknown): PricingConfig {
|
|
64
|
+
if (!raw || typeof raw !== 'object') {
|
|
65
|
+
throw new Error('Pricing config must be a JSON object.');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const config = raw as {
|
|
69
|
+
currency?: unknown;
|
|
70
|
+
tiers?: unknown;
|
|
71
|
+
models?: unknown;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
if (config.currency !== 'USD') {
|
|
75
|
+
throw new Error('Pricing config currency must be "USD".');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (!config.tiers || typeof config.tiers !== 'object') {
|
|
79
|
+
throw new Error('Pricing config must include a "tiers" object.');
|
|
80
|
+
}
|
|
81
|
+
if (!config.models || typeof config.models !== 'object') {
|
|
82
|
+
throw new Error('Pricing config must include a "models" object.');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const tiersSource = config.tiers as Record<string, unknown>;
|
|
86
|
+
const modelsSource = config.models as Record<string, unknown>;
|
|
87
|
+
|
|
88
|
+
const tiers: Record<PricingTierKey, PricingTierConfig> = {
|
|
89
|
+
standard: {
|
|
90
|
+
multiplier: 1,
|
|
91
|
+
},
|
|
92
|
+
fast: {
|
|
93
|
+
multiplier: 1,
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
for (const tierKey of ['standard', 'fast'] as const) {
|
|
98
|
+
const value = tiersSource[tierKey];
|
|
99
|
+
if (!value || typeof value !== 'object') {
|
|
100
|
+
throw new Error(`Pricing config tier "${tierKey}" is missing or invalid.`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const multiplier = (value as { multiplier?: unknown }).multiplier;
|
|
104
|
+
if (!isPositiveNumber(multiplier)) {
|
|
105
|
+
throw new Error(`Pricing config tier "${tierKey}" multiplier must be a non-negative number.`);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
tiers[tierKey] = {
|
|
109
|
+
multiplier: multiplier as number,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const models: Record<string, ModelPricingEntry> = {};
|
|
114
|
+
for (const [modelKey, value] of Object.entries(modelsSource)) {
|
|
115
|
+
if (!value || typeof value !== 'object') {
|
|
116
|
+
throw new Error(`Pricing config model "${modelKey}" is invalid.`);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const entry = value as {
|
|
120
|
+
inputUsdPerMillion?: unknown;
|
|
121
|
+
cachedInputUsdPerMillion?: unknown;
|
|
122
|
+
outputUsdPerMillion?: unknown;
|
|
123
|
+
supportsFastMode?: unknown;
|
|
124
|
+
fastMultiplier?: unknown;
|
|
125
|
+
contextWindowTokens?: unknown;
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
if (
|
|
129
|
+
!isPositiveNumber(entry.inputUsdPerMillion) ||
|
|
130
|
+
!isPositiveNumber(entry.cachedInputUsdPerMillion) ||
|
|
131
|
+
!isPositiveNumber(entry.outputUsdPerMillion) ||
|
|
132
|
+
typeof entry.supportsFastMode !== 'boolean'
|
|
133
|
+
) {
|
|
134
|
+
throw new Error(`Pricing config model "${modelKey}" has invalid fields.`);
|
|
135
|
+
}
|
|
136
|
+
if (
|
|
137
|
+
entry.fastMultiplier !== undefined &&
|
|
138
|
+
!isPositiveNumber(entry.fastMultiplier)
|
|
139
|
+
) {
|
|
140
|
+
throw new Error(`Pricing config model "${modelKey}" fastMultiplier must be a non-negative number.`);
|
|
141
|
+
}
|
|
142
|
+
if (
|
|
143
|
+
entry.contextWindowTokens !== undefined &&
|
|
144
|
+
!isPositiveNumber(entry.contextWindowTokens)
|
|
145
|
+
) {
|
|
146
|
+
throw new Error(`Pricing config model "${modelKey}" contextWindowTokens must be a non-negative number.`);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
models[modelKey] = {
|
|
150
|
+
inputUsdPerMillion: entry.inputUsdPerMillion as number,
|
|
151
|
+
cachedInputUsdPerMillion: entry.cachedInputUsdPerMillion as number,
|
|
152
|
+
outputUsdPerMillion: entry.outputUsdPerMillion as number,
|
|
153
|
+
supportsFastMode: entry.supportsFastMode,
|
|
154
|
+
...(entry.fastMultiplier !== undefined
|
|
155
|
+
? { fastMultiplier: entry.fastMultiplier as number }
|
|
156
|
+
: {}),
|
|
157
|
+
...(entry.contextWindowTokens !== undefined
|
|
158
|
+
? { contextWindowTokens: entry.contextWindowTokens as number }
|
|
159
|
+
: {}),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
currency: 'USD',
|
|
165
|
+
tiers,
|
|
166
|
+
models,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function getPricingConfig() {
|
|
171
|
+
if (cachedPricingConfig) {
|
|
172
|
+
return cachedPricingConfig;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const configPath = getPricingConfigPath();
|
|
176
|
+
const content = fs.readFileSync(configPath, 'utf8');
|
|
177
|
+
cachedPricingConfig = parsePricingConfig(JSON.parse(content) as unknown);
|
|
178
|
+
return cachedPricingConfig;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export function resetPricingConfigCacheForTest() {
|
|
182
|
+
cachedPricingConfig = null;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export function pricingTierForFastMode(fastMode: boolean): PricingTierKey {
|
|
186
|
+
return fastMode ? 'fast' : 'standard';
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function pricingModelKeyForModel(model: string | null | undefined) {
|
|
190
|
+
const modelKey = model?.trim();
|
|
191
|
+
if (!modelKey) {
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const models = getPricingConfig().models;
|
|
196
|
+
if (models[modelKey]) {
|
|
197
|
+
return modelKey;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const claudeDateSuffixMatch = modelKey.match(/^(claude-[a-z]+-\d+(?:-\d+)?)-20\d{6}$/);
|
|
201
|
+
if (claudeDateSuffixMatch?.[1] && models[claudeDateSuffixMatch[1]]) {
|
|
202
|
+
return claudeDateSuffixMatch[1];
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return modelKey;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export function supportsFastMode(model: string | null | undefined) {
|
|
209
|
+
const pricingModelKey = pricingModelKeyForModel(model);
|
|
210
|
+
if (!pricingModelKey) {
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return getPricingConfig().models[pricingModelKey]?.supportsFastMode === true;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export function contextWindowForModel(model: string | null | undefined) {
|
|
218
|
+
const pricingModelKey = pricingModelKeyForModel(model);
|
|
219
|
+
if (!pricingModelKey) {
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const contextWindow = getPricingConfig().models[pricingModelKey]?.contextWindowTokens;
|
|
224
|
+
return typeof contextWindow === 'number' && contextWindow > 0
|
|
225
|
+
? contextWindow
|
|
226
|
+
: null;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export function buildTurnPricingSnapshot(
|
|
230
|
+
model: string | null | undefined,
|
|
231
|
+
fastMode: boolean,
|
|
232
|
+
): TurnPricingSnapshot | null {
|
|
233
|
+
const pricingModelKey = pricingModelKeyForModel(model);
|
|
234
|
+
if (!pricingModelKey) {
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return {
|
|
239
|
+
pricingModelKey,
|
|
240
|
+
pricingTierKey: pricingTierForFastMode(fastMode),
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export function estimateTurnPrice(
|
|
245
|
+
usage: ThreadTurnTokenUsageDto | null | undefined,
|
|
246
|
+
snapshot:
|
|
247
|
+
| {
|
|
248
|
+
pricingModelKey: string | null | undefined;
|
|
249
|
+
pricingTierKey: PricingTierKey | string | null | undefined;
|
|
250
|
+
}
|
|
251
|
+
| null
|
|
252
|
+
| undefined,
|
|
253
|
+
): ThreadTurnPriceEstimateDto | null {
|
|
254
|
+
if (!usage?.total) {
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const pricingModelKey = pricingModelKeyForModel(snapshot?.pricingModelKey);
|
|
259
|
+
if (!pricingModelKey) {
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const pricingConfig = getPricingConfig();
|
|
264
|
+
const modelPricing = pricingConfig.models[pricingModelKey];
|
|
265
|
+
if (!modelPricing) {
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const tierKey =
|
|
270
|
+
snapshot?.pricingTierKey === 'fast' ? 'fast' : snapshot?.pricingTierKey === 'standard'
|
|
271
|
+
? 'standard'
|
|
272
|
+
: null;
|
|
273
|
+
if (!tierKey) {
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const tier = pricingConfig.tiers[tierKey];
|
|
278
|
+
if (!tier) {
|
|
279
|
+
return null;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const nonCachedInputTokens = Math.max(
|
|
283
|
+
usage.total.inputTokens - usage.total.cachedInputTokens,
|
|
284
|
+
0,
|
|
285
|
+
);
|
|
286
|
+
const cachedInputTokens = Math.max(usage.total.cachedInputTokens, 0);
|
|
287
|
+
const outputTokens = Math.max(usage.total.outputTokens, 0);
|
|
288
|
+
const multiplier =
|
|
289
|
+
tierKey === 'fast' && modelPricing.fastMultiplier !== undefined
|
|
290
|
+
? modelPricing.fastMultiplier
|
|
291
|
+
: tier.multiplier;
|
|
292
|
+
|
|
293
|
+
const inputUsd =
|
|
294
|
+
(nonCachedInputTokens * modelPricing.inputUsdPerMillion * multiplier) /
|
|
295
|
+
TOKEN_PRICE_DENOMINATOR;
|
|
296
|
+
const cachedInputUsd =
|
|
297
|
+
(cachedInputTokens * modelPricing.cachedInputUsdPerMillion * multiplier) /
|
|
298
|
+
TOKEN_PRICE_DENOMINATOR;
|
|
299
|
+
const outputUsd =
|
|
300
|
+
(outputTokens * modelPricing.outputUsdPerMillion * multiplier) /
|
|
301
|
+
TOKEN_PRICE_DENOMINATOR;
|
|
302
|
+
|
|
303
|
+
return {
|
|
304
|
+
pricingModelKey,
|
|
305
|
+
pricingTierKey: tierKey,
|
|
306
|
+
currency: pricingConfig.currency,
|
|
307
|
+
inputUsd,
|
|
308
|
+
cachedInputUsd,
|
|
309
|
+
outputUsd,
|
|
310
|
+
totalUsd: inputUsd + cachedInputUsd + outputUsd,
|
|
311
|
+
};
|
|
312
|
+
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defaultAgentBackendId,
|
|
3
|
+
} from '../../shared/src/index';
|
|
1
4
|
import {
|
|
2
5
|
AgentProviderId,
|
|
3
6
|
AgentRuntime,
|
|
@@ -7,7 +10,10 @@ import {
|
|
|
7
10
|
export class AgentRuntimeRegistry {
|
|
8
11
|
private readonly runtimes = new Map<AgentProviderId, AgentRuntime>();
|
|
9
12
|
|
|
10
|
-
constructor(
|
|
13
|
+
constructor(
|
|
14
|
+
runtimes: AgentRuntime[],
|
|
15
|
+
private readonly defaultProvider: AgentProviderId = defaultAgentBackendId,
|
|
16
|
+
) {
|
|
11
17
|
for (const runtime of runtimes) {
|
|
12
18
|
this.runtimes.set(runtime.provider, runtime);
|
|
13
19
|
}
|
|
@@ -30,15 +36,24 @@ export class AgentRuntimeRegistry {
|
|
|
30
36
|
}
|
|
31
37
|
|
|
32
38
|
list(): AgentRuntimeDescriptor[] {
|
|
33
|
-
return this.all().map((runtime
|
|
39
|
+
return this.all().map((runtime) => ({
|
|
34
40
|
provider: runtime.provider,
|
|
35
41
|
displayName: runtime.displayName,
|
|
36
42
|
description: runtime.description,
|
|
37
|
-
enabled:
|
|
38
|
-
isDefault:
|
|
43
|
+
enabled: isAgentRuntimeEnabled(runtime),
|
|
44
|
+
isDefault: runtime.provider === this.defaultProvider,
|
|
39
45
|
status: runtime.getStatus(),
|
|
40
46
|
capabilities: runtime.capabilities,
|
|
41
47
|
managementSchema: runtime.managementSchema,
|
|
48
|
+
installation: runtime.installation,
|
|
42
49
|
}));
|
|
43
50
|
}
|
|
44
51
|
}
|
|
52
|
+
|
|
53
|
+
export function isAgentRuntimeEnabled(runtime: Pick<AgentRuntime, 'capabilities' | 'installation'>) {
|
|
54
|
+
return (
|
|
55
|
+
runtime.installation.installed &&
|
|
56
|
+
runtime.capabilities.sessions.resume &&
|
|
57
|
+
runtime.capabilities.turns.start
|
|
58
|
+
);
|
|
59
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { AgentRuntimeError } from './types';
|
|
2
|
+
|
|
3
|
+
export type TurnSteerRace =
|
|
4
|
+
| { type: 'missing' }
|
|
5
|
+
| { type: 'turnIdMismatch'; actualTurnId: string };
|
|
6
|
+
|
|
7
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
8
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function stringField(value: unknown, key: string) {
|
|
12
|
+
return isRecord(value) && typeof value[key] === 'string' ? value[key] : null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function remoteErrorMessage(error: unknown) {
|
|
16
|
+
if (error instanceof AgentRuntimeError) {
|
|
17
|
+
return error.message;
|
|
18
|
+
}
|
|
19
|
+
return error instanceof Error ? error.message : null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function parseTurnSteerRace(error: unknown): TurnSteerRace | null {
|
|
23
|
+
if (error instanceof AgentRuntimeError) {
|
|
24
|
+
const raceType = stringField(error.details, 'turnSteerRace');
|
|
25
|
+
if (raceType === 'missing') {
|
|
26
|
+
return { type: 'missing' };
|
|
27
|
+
}
|
|
28
|
+
if (raceType === 'turnIdMismatch') {
|
|
29
|
+
const actualTurnId = stringField(error.details, 'actualTurnId');
|
|
30
|
+
if (actualTurnId) {
|
|
31
|
+
return { type: 'turnIdMismatch', actualTurnId };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const message = remoteErrorMessage(error);
|
|
37
|
+
if (!message) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (message === 'no active turn to steer') {
|
|
42
|
+
return { type: 'missing' };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const mismatchPrefix = 'expected active turn id `';
|
|
46
|
+
const mismatchSeparator = '` but found `';
|
|
47
|
+
if (!message.startsWith(mismatchPrefix)) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const actualTurnId = message
|
|
52
|
+
.slice(mismatchPrefix.length)
|
|
53
|
+
.split(mismatchSeparator)[1]
|
|
54
|
+
?.replace(/`$/, '');
|
|
55
|
+
|
|
56
|
+
if (!actualTurnId) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
type: 'turnIdMismatch',
|
|
62
|
+
actualTurnId,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function isRuntimeRequestError(error: unknown) {
|
|
67
|
+
return error instanceof AgentRuntimeError;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function isRemoteThreadBootstrapError(error: unknown) {
|
|
71
|
+
if (!(error instanceof AgentRuntimeError)) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
error.message.includes('includeTurns is unavailable before first user message') ||
|
|
77
|
+
error.message.includes('is not materialized yet') ||
|
|
78
|
+
error.message.includes('no rollout found for thread id') ||
|
|
79
|
+
error.message.includes('failed to load rollout') ||
|
|
80
|
+
(error.message.includes('rollout at') && error.message.includes('is empty'))
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function isUnsupportedHooksListError(error: unknown) {
|
|
85
|
+
if (!(error instanceof AgentRuntimeError)) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const remoteCode = isRecord(error.details) ? error.details.code : null;
|
|
90
|
+
const message = error.message.toLowerCase();
|
|
91
|
+
return (
|
|
92
|
+
remoteCode === -32601 ||
|
|
93
|
+
message.includes('endpoint not found') ||
|
|
94
|
+
message.includes('method not found') ||
|
|
95
|
+
(message.includes('hooks/list') && message.includes('not found'))
|
|
96
|
+
);
|
|
97
|
+
}
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import { EventEmitter } from 'node:events';
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
AgentBackendIdDto,
|
|
4
|
+
AgentBackendInstallationDto,
|
|
5
|
+
ThreadHistoryItemDto,
|
|
6
|
+
} from '../../shared/src/index';
|
|
3
7
|
|
|
4
|
-
export
|
|
8
|
+
export const transientAgentHistoryItemSymbol: unique symbol = Symbol(
|
|
9
|
+
'remoteCodex.transientAgentHistoryItem',
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
export type AgentProviderId = AgentBackendIdDto;
|
|
5
13
|
|
|
6
14
|
export type AgentRuntimeErrorCode =
|
|
7
15
|
| 'provider_unavailable'
|
|
@@ -84,6 +92,7 @@ export interface AgentRuntimeDescriptor {
|
|
|
84
92
|
status: AgentRuntimeStatus;
|
|
85
93
|
capabilities: AgentProviderCapabilities;
|
|
86
94
|
managementSchema: AgentRuntimeManagementSchema;
|
|
95
|
+
installation: AgentBackendInstallationDto;
|
|
87
96
|
}
|
|
88
97
|
|
|
89
98
|
export interface AgentRuntimeConfigFileSchema {
|
|
@@ -142,6 +151,7 @@ export interface AgentModel {
|
|
|
142
151
|
description: string;
|
|
143
152
|
isDefault: boolean;
|
|
144
153
|
hidden: boolean;
|
|
154
|
+
supportsPerformanceMode?: boolean;
|
|
145
155
|
supportedReasoningEfforts: Array<{
|
|
146
156
|
reasoningEffort: string;
|
|
147
157
|
description: string;
|
|
@@ -169,13 +179,33 @@ export interface AgentSessionSummary {
|
|
|
169
179
|
rawSession?: unknown;
|
|
170
180
|
}
|
|
171
181
|
|
|
172
|
-
export type AgentHistoryItem = ThreadHistoryItemDto
|
|
182
|
+
export type AgentHistoryItem = ThreadHistoryItemDto & {
|
|
183
|
+
[transientAgentHistoryItemSymbol]?: true;
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
export function markTransientAgentHistoryItem<T extends ThreadHistoryItemDto>(
|
|
187
|
+
item: T,
|
|
188
|
+
): T & AgentHistoryItem {
|
|
189
|
+
Object.defineProperty(item, transientAgentHistoryItemSymbol, {
|
|
190
|
+
value: true,
|
|
191
|
+
enumerable: false,
|
|
192
|
+
configurable: true,
|
|
193
|
+
});
|
|
194
|
+
return item as T & AgentHistoryItem;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export function isTransientAgentHistoryItem(
|
|
198
|
+
item: ThreadHistoryItemDto,
|
|
199
|
+
): item is AgentHistoryItem & { [transientAgentHistoryItemSymbol]: true } {
|
|
200
|
+
return Boolean((item as AgentHistoryItem)[transientAgentHistoryItemSymbol]);
|
|
201
|
+
}
|
|
173
202
|
|
|
174
203
|
export type AgentTurnItem = AgentHistoryItem;
|
|
175
204
|
|
|
176
205
|
export interface AgentTurn {
|
|
177
206
|
providerTurnId: string;
|
|
178
207
|
rawTurnId?: string;
|
|
208
|
+
startedAt?: string | null;
|
|
179
209
|
status: 'completed' | 'interrupted' | 'failed' | 'inProgress';
|
|
180
210
|
error: { message?: string } | null;
|
|
181
211
|
items: AgentHistoryItem[];
|
|
@@ -184,6 +214,14 @@ export interface AgentTurn {
|
|
|
184
214
|
|
|
185
215
|
export interface AgentSessionDetail extends AgentSessionSummary {
|
|
186
216
|
turns: AgentTurn[];
|
|
217
|
+
totalTurnCount?: number | null;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export interface ReadAgentSessionOptions {
|
|
221
|
+
limit?: number;
|
|
222
|
+
beforeTurnId?: string | null;
|
|
223
|
+
localThreadId?: string;
|
|
224
|
+
workspacePath?: string;
|
|
187
225
|
}
|
|
188
226
|
|
|
189
227
|
export interface StartAgentSessionInput {
|
|
@@ -214,12 +252,15 @@ export interface ResumeAgentSessionInput {
|
|
|
214
252
|
export interface StartAgentTurnInput {
|
|
215
253
|
providerSessionId: string;
|
|
216
254
|
prompt: string;
|
|
255
|
+
displayPrompt?: string | null;
|
|
217
256
|
model?: string | null;
|
|
218
257
|
reasoningEffort?: string | null;
|
|
219
258
|
collaborationMode?: 'default' | 'plan' | null;
|
|
220
259
|
sandboxMode?: 'read-only' | 'workspace-write' | 'danger-full-access' | null;
|
|
221
260
|
workspacePath?: string | null;
|
|
222
261
|
performanceMode?: 'standard' | 'fast' | null;
|
|
262
|
+
hidden?: boolean;
|
|
263
|
+
displayTurnId?: string | null;
|
|
223
264
|
}
|
|
224
265
|
|
|
225
266
|
export interface SendAgentInputInput {
|
|
@@ -455,6 +496,7 @@ export interface AgentActionQuestion {
|
|
|
455
496
|
id: string;
|
|
456
497
|
header: string;
|
|
457
498
|
question: string;
|
|
499
|
+
multiSelect?: boolean;
|
|
458
500
|
isOther: boolean;
|
|
459
501
|
isSecret: boolean;
|
|
460
502
|
options: AgentActionQuestionOption[] | null;
|
|
@@ -495,6 +537,7 @@ export interface AgentRuntime extends EventEmitter {
|
|
|
495
537
|
readonly description: string;
|
|
496
538
|
readonly capabilities: AgentProviderCapabilities;
|
|
497
539
|
readonly managementSchema: AgentRuntimeManagementSchema;
|
|
540
|
+
readonly installation: AgentBackendInstallationDto;
|
|
498
541
|
|
|
499
542
|
getStatus(): AgentRuntimeStatus;
|
|
500
543
|
start(): Promise<void>;
|
|
@@ -503,7 +546,10 @@ export interface AgentRuntime extends EventEmitter {
|
|
|
503
546
|
listModels(): Promise<AgentModel[]>;
|
|
504
547
|
listSessions(): Promise<AgentSessionSummary[]>;
|
|
505
548
|
listLoadedSessions(): Promise<string[]>;
|
|
506
|
-
readSession(
|
|
549
|
+
readSession(
|
|
550
|
+
providerSessionId: string,
|
|
551
|
+
options?: ReadAgentSessionOptions,
|
|
552
|
+
): Promise<AgentSessionDetail>;
|
|
507
553
|
startSession(input: StartAgentSessionInput): Promise<StartAgentSessionResult>;
|
|
508
554
|
resumeSession(input: ResumeAgentSessionInput): Promise<StartAgentSessionResult>;
|
|
509
555
|
|