@bitkyc08/opencodex 2.69.0 → 2.70.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/gui/dist/assets/App-_MrbTrBe.js +51 -0
- package/gui/dist/assets/{Tray-uqKRqfvw.js → Tray-5PuUalET.js} +1 -1
- package/gui/dist/assets/index-DKrO2eF3.js +86 -0
- package/gui/dist/assets/quota-summary-BCLivc0Q.js +1 -0
- package/gui/dist/index.html +1 -1
- package/package.json +1 -1
- package/src/adapters/anthropic-model-contract.ts +119 -0
- package/src/adapters/anthropic.ts +14 -83
- package/src/adapters/base.ts +2 -0
- package/src/adapters/command-code-project-context.ts +542 -0
- package/src/adapters/command-code-tool-text.ts +99 -67
- package/src/adapters/command-code.ts +5 -1
- package/src/adapters/cursor/catalog.ts +11 -0
- package/src/adapters/cursor/effort-map.ts +3 -0
- package/src/adapters/devin/cloud-direct/catalog.ts +91 -0
- package/src/adapters/devin/cloud-direct/chat.ts +78 -48
- package/src/adapters/devin/cloud-direct/tool-schema.ts +121 -0
- package/src/adapters/devin/context-overflow.ts +75 -0
- package/src/adapters/devin/live-models.ts +174 -13
- package/src/adapters/devin/reasoning-signature.ts +100 -0
- package/src/adapters/devin.ts +310 -117
- package/src/adapters/kiro/payload.ts +10 -10
- package/src/adapters/kiro-images.ts +58 -7
- package/src/adapters/openai-chat/passthrough.ts +3 -1
- package/src/adapters/openai-chat.ts +2 -1
- package/src/adapters/openai-responses/passthrough.ts +2 -1
- package/src/bridge/response-json.ts +15 -1
- package/src/bridge/sse.ts +3 -1
- package/src/claude/intercept/model-bindings.ts +1 -0
- package/src/cli/account-extended.ts +31 -1
- package/src/cli/account.ts +3 -0
- package/src/cli/capabilities.ts +13 -0
- package/src/cli/client-start-fence.ts +36 -0
- package/src/cli/dispatch.ts +3 -2
- package/src/cli/index.ts +98 -117
- package/src/cli/provider-runtime.ts +23 -2
- package/src/cli/provider.ts +3 -0
- package/src/cli/resolve.ts +18 -0
- package/src/cli/start-owner-fence.ts +30 -0
- package/src/cli/stop-approval.ts +13 -1
- package/src/cli/stop-restore.ts +73 -0
- package/src/cli/tray-proxy.ts +221 -18
- package/src/cli/version-skew.ts +25 -23
- package/src/client/runtime.ts +8 -4
- package/src/codex/auth-api/account-list.ts +11 -5
- package/src/codex/auth-api/login-flow.ts +5 -3
- package/src/codex/auth-api/main-account-probe.ts +186 -110
- package/src/codex/auth-api/pool-mode-gate.ts +61 -7
- package/src/codex/auth-api/pool-quota-probe.ts +142 -90
- package/src/codex/auth-api/reset-credit-service.ts +1 -1
- package/src/codex/catalog/gather-capture.ts +1 -0
- package/src/codex/catalog/model-hints.ts +3 -3
- package/src/codex/catalog/provider-models.ts +2 -0
- package/src/codex/low-quota-events.ts +28 -0
- package/src/codex/low-quota-observer.ts +23 -0
- package/src/codex/low-quota-protection.ts +272 -0
- package/src/codex/quota-query-backoff.ts +148 -0
- package/src/codex/quota.ts +7 -2
- package/src/config/diagnostics.ts +10 -1
- package/src/config/load-degrade.ts +17 -0
- package/src/config/mutation-lock.ts +3 -4
- package/src/config/process-state.ts +1 -1
- package/src/config/provider-validation.ts +22 -0
- package/src/config/schema/blocked-model-redirects.ts +17 -0
- package/src/config/schema/config-schema.ts +4 -1
- package/src/config/schema/leaf-validators.ts +33 -2
- package/src/config/serving-runtimes.ts +412 -0
- package/src/generated/compatibility-version.json +211 -115
- package/src/generated/model-metadata.ts +3 -3
- package/src/images/loop.ts +3 -0
- package/src/lib/errors.ts +2 -1
- package/src/lib/handled-signal-exit.ts +23 -0
- package/src/lib/request-failure-model.ts +1 -0
- package/src/lib/self-launch-argv.ts +9 -0
- package/src/lib/shadow-call.ts +5 -2
- package/src/lib/strict-semver.ts +26 -0
- package/src/lib/transient-service-path.ts +16 -0
- package/src/lib/windows-service-wrappers.ts +10 -6
- package/src/lib/winsw.ts +3 -1
- package/src/oauth/anthropic-model-routes.ts +105 -0
- package/src/oauth/anthropic-routing.ts +85 -48
- package/src/oauth/devin.ts +135 -5
- package/src/oauth/index.ts +20 -3
- package/src/oauth/kiro-terminal-failover.ts +23 -9
- package/src/oauth/pool-settings-capability.ts +10 -2
- package/src/oauth/store.ts +1 -1
- package/src/protocols/encoders/adapter-events.ts +3 -1
- package/src/providers/github-copilot-context.ts +27 -0
- package/src/providers/kiro-models.ts +4 -0
- package/src/providers/model-rename-fields.ts +3 -0
- package/src/providers/quota/account-cache.ts +8 -3
- package/src/providers/quota/devin.ts +286 -0
- package/src/providers/quota/vendor-probes-oauth.ts +6 -2
- package/src/providers/quota.ts +1 -1
- package/src/providers/registry/entries-core.ts +1 -1
- package/src/providers/registry/model-seeds.ts +5 -2
- package/src/responses/compaction-images.ts +27 -0
- package/src/router.ts +104 -16
- package/src/routing/analytics.ts +1 -0
- package/src/server/auth-cors.ts +9 -1
- package/src/server/background-lifecycle.ts +21 -10
- package/src/server/chat-completions.ts +2 -1
- package/src/server/chat-native.ts +1 -0
- package/src/server/index.ts +4 -8
- package/src/server/inference/client-encoder-delivery.ts +3 -0
- package/src/server/management/context.ts +3 -0
- package/src/server/management/low-quota-routes.ts +14 -0
- package/src/server/management/oauth-account-routes.ts +21 -1
- package/src/server/management/provider-overwrite-carry.ts +79 -6
- package/src/server/management/provider-routes.ts +41 -28
- package/src/server/management/route-registry.ts +1 -0
- package/src/server/management-api.ts +7 -0
- package/src/server/responses/adapter-continuation.ts +3 -0
- package/src/server/responses/adapter-delivery.ts +3 -0
- package/src/server/responses/adapter-dispatch.ts +20 -4
- package/src/server/responses/antigravity-validation-refusal.ts +20 -0
- package/src/server/responses/core-auth.ts +1 -0
- package/src/server/responses/core-codex-account.ts +1 -0
- package/src/server/responses/core-normalize.ts +4 -0
- package/src/server/responses/passthrough-dispatch.ts +8 -1
- package/src/server/responses/request-sidecar-auth.ts +2 -0
- package/src/server/responses/request-transport.ts +27 -10
- package/src/server/responses/response-effects.ts +4 -1
- package/src/server/responses/run-turn-execution.ts +126 -42
- package/src/server/responses/sidecar-execution.ts +4 -1
- package/src/service/diagnostics.ts +3 -1
- package/src/service/guarded-manager-target.ts +39 -12
- package/src/service/launchd.ts +14 -6
- package/src/service/repair.ts +6 -1
- package/src/service/service-child-ownership.ts +168 -0
- package/src/service/state.ts +22 -4
- package/src/service/systemd.ts +2 -2
- package/src/service/windows-guarded-manager.ts +530 -0
- package/src/service/windows-taskxml.ts +2 -2
- package/src/service.ts +2 -0
- package/src/types/config.ts +26 -0
- package/src/types/provider.ts +12 -0
- package/src/types/request.ts +2 -0
- package/src/types.ts +1 -0
- package/src/usage/expected-prices.ts +13 -0
- package/src/usage/telemetry-contract.ts +1 -0
- package/src/vision/anthropic-describe.ts +2 -1
- package/src/web-search/anthropic-executor.ts +2 -1
- package/src/web-search/loop.ts +1 -0
- package/gui/dist/assets/App-DDbgOTh6.js +0 -51
- package/gui/dist/assets/index-CuaBJkG4.js +0 -86
- package/gui/dist/assets/quota-summary-COppQSVq.js +0 -1
|
@@ -22,9 +22,10 @@ import { validatesRestoredValue } from "./command-code-restored-schema";
|
|
|
22
22
|
* A text block that opens with `<tool_call>` is therefore held instead of streamed. It is dropped
|
|
23
23
|
* when a native call proves it is a duplicate, or restored on an eligible clean MiMo finish when
|
|
24
24
|
* it names a declared tool with arguments that fit its schema. Other markup is released unchanged.
|
|
25
|
-
* MiMo can also append the markup after ordinary prose inside one text block
|
|
26
|
-
*
|
|
27
|
-
*
|
|
25
|
+
* MiMo can also append the markup after ordinary prose inside one text block. A marker that
|
|
26
|
+
* follows prose can never become a call: its envelope is still held — a matching native call
|
|
27
|
+
* strips it as an echo — and otherwise it is released as the presentation text it is.
|
|
28
|
+
* A leading bare envelope remains eligible under the declared-tool rules.
|
|
28
29
|
* A malformed envelope that still opens and closes around a declared function name, but that the
|
|
29
30
|
* strict parser rejects, is dropped instead of released when the native call for that same function
|
|
30
31
|
* arrives, and on the clean-finish path, so the echo never reaches the client.
|
|
@@ -236,8 +237,14 @@ interface TextBlock {
|
|
|
236
237
|
state: "probing" | "held" | "queued" | "dropped" | "streaming";
|
|
237
238
|
ended: boolean;
|
|
238
239
|
interrupted: boolean;
|
|
239
|
-
/**
|
|
240
|
+
/**
|
|
241
|
+
* Tool inputs the block could echo: those open when it started, plus, for a post-prose tail,
|
|
242
|
+
* at most one later input of the envelope's own tool. The block waits only while one of them
|
|
243
|
+
* is still open.
|
|
244
|
+
*/
|
|
240
245
|
candidates: Set<string>;
|
|
246
|
+
/** The one later input a post-prose tail admitted as a candidate, if any. */
|
|
247
|
+
lateCandidate?: string;
|
|
241
248
|
}
|
|
242
249
|
|
|
243
250
|
interface TextChunk {
|
|
@@ -296,7 +303,19 @@ export class CommandCodeToolTextFilter {
|
|
|
296
303
|
|
|
297
304
|
toolInputStart(id: unknown, name: unknown): AdapterEvent[] {
|
|
298
305
|
const events = this.breakOpenBlocks();
|
|
299
|
-
if (typeof id === "string" && typeof name === "string")
|
|
306
|
+
if (typeof id === "string" && typeof name === "string") {
|
|
307
|
+
this.openInputs.set(id, name);
|
|
308
|
+
// A post-prose echo can precede the start of the native input it duplicates. An echo
|
|
309
|
+
// duplicates one call, so a complete tail admits one later input of its own tool and no
|
|
310
|
+
// other: unrelated or repeated starts cannot keep extending the wait. Once every candidate
|
|
311
|
+
// closes without a match, matchNative releases the tail as text.
|
|
312
|
+
for (const block of this.held) {
|
|
313
|
+
if (!block.interrupted || block.candidates.size === 0 || block.lateCandidate !== undefined) continue;
|
|
314
|
+
if (looseEnvelopeName(block.markupParts.join(""), this.declared) !== name) continue;
|
|
315
|
+
block.lateCandidate = id;
|
|
316
|
+
block.candidates.add(id);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
300
319
|
return events;
|
|
301
320
|
}
|
|
302
321
|
|
|
@@ -341,54 +360,60 @@ export class CommandCodeToolTextFilter {
|
|
|
341
360
|
block = { id: key, markupParts: [], probe: "", bytes: 0, state: "probing", ended: false, interrupted: false, candidates: new Set(this.openInputs.keys()) };
|
|
342
361
|
this.blocks.set(key, block);
|
|
343
362
|
}
|
|
344
|
-
//
|
|
345
|
-
//
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
if (block.state === "streaming" && this.head === this.pending.length) {
|
|
363
|
-
proseEvents = [{ type: "text_delta", text: prose }];
|
|
364
|
-
} else {
|
|
365
|
-
if (block.state === "dropped" || block.state === "streaming") {
|
|
366
|
-
block = { id: key, markupParts: [], probe: "", bytes: 0, state: "queued", ended: false, interrupted: true, candidates: new Set() };
|
|
367
|
-
this.blocks.set(key, block);
|
|
368
|
-
}
|
|
369
|
-
proseEvents = this.queueProseDelta(block, prose);
|
|
370
|
-
this.probeBlockText(block, prose);
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
if (block.state === "queued") block.state = "streaming";
|
|
374
|
-
this.activeProbes.delete(key);
|
|
375
|
-
const probeBlock: TextBlock = { id: key, markupParts: [], probe: "", bytes: 0, state: "probing", ended: false, interrupted: false, candidates: new Set(this.openInputs.keys()) };
|
|
376
|
-
this.blocks.set(key, probeBlock);
|
|
377
|
-
return [...boundaryEvents, ...proseEvents, ...this.textDelta(id, marked)];
|
|
378
|
-
}
|
|
379
|
-
if (markerIndex === -1 && block.state === "streaming" && this.head === this.pending.length) {
|
|
380
|
-
return [...boundaryEvents, { type: "text_delta", text }];
|
|
363
|
+
// Probe before retaining so the state transition precedes the marker scan: a delta that
|
|
364
|
+
// carries prose AND a marker must split this visit, not a later one.
|
|
365
|
+
if (block.state === "probing") {
|
|
366
|
+
this.probeBlockText(block, text);
|
|
367
|
+
if (block.state === "probing") this.activeProbes.set(key, block);
|
|
368
|
+
else this.activeProbes.delete(key);
|
|
369
|
+
}
|
|
370
|
+
// Only a bare text block can open protocol markup. Once prose has committed the block, a
|
|
371
|
+
// marker inside the delta starts a held tail instead: it never restores a call, but a
|
|
372
|
+
// matching native call still strips the echo and an unmatched one releases as text.
|
|
373
|
+
if (block.state === "streaming" || block.state === "queued") {
|
|
374
|
+
const markerStart = this.findFreshMarker(text);
|
|
375
|
+
if (markerStart !== undefined) {
|
|
376
|
+
return [
|
|
377
|
+
...boundaryEvents,
|
|
378
|
+
...this.enqueueTailProse(block, text.slice(0, markerStart)),
|
|
379
|
+
...this.openHeldTail(key, text.slice(markerStart)),
|
|
380
|
+
];
|
|
381
381
|
}
|
|
382
382
|
}
|
|
383
|
+
if (block.state === "streaming" && this.head === this.pending.length) {
|
|
384
|
+
return [...boundaryEvents, { type: "text_delta", text }];
|
|
385
|
+
}
|
|
383
386
|
// Once a duplicate is dropped, later text is a new chunk at its own wire position.
|
|
384
387
|
if (block.state === "dropped" || block.state === "streaming") {
|
|
385
388
|
block = { id: key, markupParts: [], probe: "", bytes: 0, state: "queued", ended: false, interrupted: true, candidates: new Set() };
|
|
386
389
|
this.blocks.set(key, block);
|
|
387
390
|
}
|
|
388
|
-
const
|
|
389
|
-
this.
|
|
390
|
-
|
|
391
|
+
const events = this.retainChunk(block, text);
|
|
392
|
+
return [...boundaryEvents, ...events, ...this.limitPending()];
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/** Find a complete marker or its trailing prefix before either can reach presentation text. */
|
|
396
|
+
private findFreshMarker(text: string): number | undefined {
|
|
397
|
+
const index = text.indexOf(TOOL_CALL_MARKER);
|
|
398
|
+
if (index >= 0) return index;
|
|
399
|
+
for (let length = Math.min(text.length, TOOL_CALL_MARKER.length - 1); length > 0; length--) {
|
|
400
|
+
if (text.endsWith(TOOL_CALL_MARKER.slice(0, length))) return text.length - length;
|
|
401
|
+
}
|
|
402
|
+
return undefined;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/** Retain a text fragment on a block and append its pending chunk. Never drains. */
|
|
406
|
+
private retainChunk(block: TextBlock, text: string): AdapterEvent[] {
|
|
391
407
|
const bytes = encoder.encode(text).byteLength;
|
|
408
|
+
const flushing = this.queuedBytes + bytes > MAX_HELD_TOOL_TEXT_BYTES;
|
|
409
|
+
const preceding = this.makeRoom(bytes);
|
|
410
|
+
// The new block has no pending chunk during the flush, so demote it here too.
|
|
411
|
+
if (flushing && (block.state === "held" || block.state === "probing")) {
|
|
412
|
+
block.state = "queued";
|
|
413
|
+
block.markupParts = [];
|
|
414
|
+
this.activeProbes.delete(block.id);
|
|
415
|
+
}
|
|
416
|
+
this.retain(block, text);
|
|
392
417
|
const tail = this.pending.at(-1);
|
|
393
418
|
if (tail?.kind === "chunk" && tail.block === block && this.head < this.pending.length) {
|
|
394
419
|
tail.parts.push(text);
|
|
@@ -399,9 +424,32 @@ export class CommandCodeToolTextFilter {
|
|
|
399
424
|
this.queueOperations++;
|
|
400
425
|
}
|
|
401
426
|
this.queuedBytes += bytes;
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
427
|
+
return preceding;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Emit or retain the prose that precedes a mid-prose marker. Streamed text takes the same
|
|
432
|
+
* immediate path it would have without a marker; anything queued stays on the wire order.
|
|
433
|
+
*/
|
|
434
|
+
private enqueueTailProse(block: TextBlock, text: string): AdapterEvent[] {
|
|
435
|
+
if (text === "") return [];
|
|
436
|
+
if (block.state === "streaming" && this.head === this.pending.length) {
|
|
437
|
+
return [{ type: "text_delta", text }];
|
|
438
|
+
}
|
|
439
|
+
return this.retainChunk(block, text);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Open a budgeted probing/held tail for markup or a marker prefix that followed prose. The tail shares the native-call matching of
|
|
444
|
+
* an ordinary held block — a same-content call drops it as an echo — but `interrupted` bars
|
|
445
|
+
* restoration forever: prose-prefixed markup can never mint a call, only disappear or be text.
|
|
446
|
+
*/
|
|
447
|
+
private openHeldTail(key: string, text: string): AdapterEvent[] {
|
|
448
|
+
const tail: TextBlock = { id: key, markupParts: [], probe: "", bytes: 0, state: "probing", ended: false, interrupted: true, candidates: new Set(this.openInputs.keys()) };
|
|
449
|
+
this.blocks.set(key, tail);
|
|
450
|
+
this.probeBlockText(tail, text);
|
|
451
|
+
if (tail.state === "probing") this.activeProbes.set(key, tail);
|
|
452
|
+
return [...this.retainChunk(tail, text), ...this.limitPending()];
|
|
405
453
|
}
|
|
406
454
|
|
|
407
455
|
textEnd(id: unknown): AdapterEvent[] {
|
|
@@ -476,7 +524,9 @@ export class CommandCodeToolTextFilter {
|
|
|
476
524
|
// native call is for the function it declares, that call carries the execution, so drop the
|
|
477
525
|
// echo rather than releasing it as text. A native call for any other tool proves nothing
|
|
478
526
|
// about this envelope, so it keeps the release-as-text path below.
|
|
479
|
-
|
|
527
|
+
// A held tail (markup after prose) never drops on name alone — its context is ordinary
|
|
528
|
+
// prose the model wrote, so only an exact input match can prove it is an echo.
|
|
529
|
+
if (!block.interrupted && markup === undefined && looseEnvelopeName(text, this.declared) === name) {
|
|
480
530
|
this.drop(block);
|
|
481
531
|
block.state = "dropped";
|
|
482
532
|
this.activeProbes.delete(block.id);
|
|
@@ -593,24 +643,6 @@ export class CommandCodeToolTextFilter {
|
|
|
593
643
|
}
|
|
594
644
|
}
|
|
595
645
|
|
|
596
|
-
/** Route ordinary prose through the queued wire path (shared by the mid-stream marker split). */
|
|
597
|
-
private queueProseDelta(block: TextBlock, prose: string): AdapterEvent[] {
|
|
598
|
-
const preceding = this.makeRoom(encoder.encode(prose).byteLength);
|
|
599
|
-
this.retain(block, prose);
|
|
600
|
-
const bytes = encoder.encode(prose).byteLength;
|
|
601
|
-
const tail = this.pending.at(-1);
|
|
602
|
-
if (tail?.kind === "chunk" && tail.block === block && this.head < this.pending.length) {
|
|
603
|
-
tail.parts.push(prose);
|
|
604
|
-
tail.bytes += bytes;
|
|
605
|
-
this.queueOperations++;
|
|
606
|
-
} else {
|
|
607
|
-
this.pending.push({ kind: "chunk", block, parts: [prose], bytes });
|
|
608
|
-
this.queueOperations++;
|
|
609
|
-
}
|
|
610
|
-
this.queuedBytes += bytes;
|
|
611
|
-
return preceding;
|
|
612
|
-
}
|
|
613
|
-
|
|
614
646
|
private drop(block: TextBlock): void {
|
|
615
647
|
this.budget.releaseRetained(block.bytes, { kind: "live_transient" });
|
|
616
648
|
this.queuedBytes = Math.max(0, this.queuedBytes - block.bytes);
|
|
@@ -16,6 +16,7 @@ import { parseDataUrl } from "./image";
|
|
|
16
16
|
import { createAdapterPhysicalSend } from "./physical-send";
|
|
17
17
|
import { SendBudgetExhaustedError } from "../lib/upstream-retry";
|
|
18
18
|
import { CommandCodeToolTextFilter, type CommandCodeDeclaredTools } from "./command-code-tool-text";
|
|
19
|
+
import { EMPTY_COMMAND_CODE_PROJECT_CONTEXT, loadCommandCodeProjectContext } from "./command-code-project-context";
|
|
19
20
|
|
|
20
21
|
function declaredTools(tools: OcxTool[]): CommandCodeDeclaredTools {
|
|
21
22
|
return new Map(tools.map(tool => [
|
|
@@ -610,8 +611,11 @@ export function createCommandCodeAdapter(provider: OcxProviderConfig): ProviderA
|
|
|
610
611
|
...(choiceInstruction ? [choiceInstruction] : []),
|
|
611
612
|
].join("\n\n"), parsed.modelId);
|
|
612
613
|
const reasoningEffort = supportedCommandCodeEffort(provider, parsed.modelId, parsed.options.reasoning);
|
|
614
|
+
const projectContext = provider.projectContext === "on"
|
|
615
|
+
? await loadCommandCodeProjectContext(cwd)
|
|
616
|
+
: EMPTY_COMMAND_CODE_PROJECT_CONTEXT;
|
|
613
617
|
const body = {
|
|
614
|
-
config: await commandCodeConfig(cwd),
|
|
618
|
+
config: await commandCodeConfig(cwd), ...projectContext,
|
|
615
619
|
permissionMode: "standard", mode: "agent",
|
|
616
620
|
params: {
|
|
617
621
|
model: canonicalCommandCodeModelId(parsed.modelId),
|
|
@@ -140,6 +140,17 @@ export const CURSOR_CAPABILITIES: Record<string, CursorCapability> = {
|
|
|
140
140
|
thinking: { levels: FULL, order: T },
|
|
141
141
|
},
|
|
142
142
|
},
|
|
143
|
+
// 260929 Claude Sonnet 5.5: cursor.com/docs/models/claude-sonnet-5-5 lists it (1M max context),
|
|
144
|
+
// but the live GetUsableModels roster does not yet. Shaped like Opus 5.5 (flat effort ids, no
|
|
145
|
+
// thinking variant); re-shape from the roster once it appears.
|
|
146
|
+
"claude-sonnet-5-5": {
|
|
147
|
+
displayName: "Claude Sonnet 5.5",
|
|
148
|
+
window: CONTEXT_1M,
|
|
149
|
+
defaultVariant: "regular",
|
|
150
|
+
variants: {
|
|
151
|
+
regular: { levels: FULL },
|
|
152
|
+
},
|
|
153
|
+
},
|
|
143
154
|
"claude-sonnet-5": {
|
|
144
155
|
displayName: "Claude Sonnet 5",
|
|
145
156
|
window: CONTEXT_1M,
|
|
@@ -39,6 +39,9 @@ const CURSOR_MODEL_EFFORT_TIERS: Record<string, readonly string[]> = {
|
|
|
39
39
|
// 260923 Opus 5.5: live GetUsableModels roster advertises low..max in both regular and fast forms.
|
|
40
40
|
"claude-opus-5-5": ["low", "medium", "high", "xhigh", "max"],
|
|
41
41
|
"claude-opus-5-5-fast": ["low", "medium", "high", "xhigh", "max"],
|
|
42
|
+
// 260929 preemptive Sonnet 5.5: Anthropic documents low..max; flat ids like Opus 5.5 until the
|
|
43
|
+
// live GetUsableModels roster lists the model.
|
|
44
|
+
"claude-sonnet-5-5": ["low", "medium", "high", "xhigh", "max"],
|
|
42
45
|
"claude-sonnet-5": ["low", "medium", "high", "xhigh", "max"],
|
|
43
46
|
"glm-5.2": ["high", "max"],
|
|
44
47
|
// 260825 live GetUsableModels. gemini-3.6-flash was the first Cursor model exposing
|
|
@@ -35,8 +35,18 @@
|
|
|
35
35
|
* #5 supports_images bool ← tri-state: absent stays unknown
|
|
36
36
|
* #18 max_input_tokens varint ← per-account context window
|
|
37
37
|
* #22 model_uid string ← what `GetChatMessage` accepts
|
|
38
|
+
* #23 model_info ModelInfo { #6 features { #15 supports_thinking },
|
|
39
|
+
* #13 max_output_tokens, #23 model_family_uid }
|
|
40
|
+
* #30 family_metadata ModelFamilyMetadata { #1 family_label,
|
|
41
|
+
* #2 repeated Entry { #1 axis key, #2 { #1 order, #2 name } },
|
|
42
|
+
* #3 is_default_model_in_family }
|
|
43
|
+
* #31 is_default_model_in_family bool
|
|
38
44
|
* }
|
|
39
45
|
*
|
|
46
|
+
* #23/#30/#31 were read back from a live 267-row catalog (2026-09-27): every
|
|
47
|
+
* current row names its family, and each family marks one default member.
|
|
48
|
+
* Legacy `MODEL_*` rows carry no #30.
|
|
49
|
+
*
|
|
40
50
|
* Disabled semantics: TRUE means "this UID exists in the catalog but the
|
|
41
51
|
* caller's account/tier cannot run inference against it." BYOK models
|
|
42
52
|
* surface as `disabled: false` so users with their own provider keys still
|
|
@@ -91,6 +101,73 @@ export interface ModelCatalogEntry {
|
|
|
91
101
|
* (see src/providers/antigravity-models.ts).
|
|
92
102
|
*/
|
|
93
103
|
supportsImages?: boolean;
|
|
104
|
+
/** ModelInfo #13: the model's own output-token ceiling. */
|
|
105
|
+
maxOutputTokens?: number;
|
|
106
|
+
/** ModelInfo #6.15. */
|
|
107
|
+
supportsThinking?: boolean;
|
|
108
|
+
/** ModelInfo #23, e.g. `swe-1.7` for both `swe-1-7` and `swe-1-7-medium`. */
|
|
109
|
+
familyUid?: string;
|
|
110
|
+
/** ModelFamilyMetadata #1, e.g. `SWE-1.7`. */
|
|
111
|
+
familyLabel?: string;
|
|
112
|
+
/**
|
|
113
|
+
* ModelFamilyMetadata #2: this row's position on each of its family's axes,
|
|
114
|
+
* keyed by axis name (`Effort`, `Reasoning Effort`, `Fast Mode`, `1M Context`,
|
|
115
|
+
* `Thinking`, ...). Toggle axes such as `Fast Mode` carry only an order.
|
|
116
|
+
*/
|
|
117
|
+
familyAxes?: Record<string, DevinFamilyAxisValue>;
|
|
118
|
+
/** #31 (or #30.3): the member the family selects when nothing is asked for. */
|
|
119
|
+
isFamilyDefault?: boolean;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export interface DevinFamilyAxisValue {
|
|
123
|
+
order: number;
|
|
124
|
+
name?: string;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Rows whose catalog entry claims image support that the model does not have.
|
|
129
|
+
* Live 2026-09-27: `swe-1-6` answered "NOIMAGE" to a solid red PNG while
|
|
130
|
+
* `swe-1-6-fast` and `swe-2-medium` named the colour, so the image is dropped
|
|
131
|
+
* server-side without an error. Marking it text-only lets the vision fallback
|
|
132
|
+
* describe the image instead of the model silently never seeing it.
|
|
133
|
+
*/
|
|
134
|
+
const IMAGE_BLIND_UIDS = new Set(['swe-1-6']);
|
|
135
|
+
|
|
136
|
+
function parseFamilyMetadata(buf: Buffer): { label?: string; axes: Record<string, DevinFamilyAxisValue>; isDefault: boolean } {
|
|
137
|
+
let label: string | undefined;
|
|
138
|
+
let isDefault = false;
|
|
139
|
+
const axes: Record<string, DevinFamilyAxisValue> = {};
|
|
140
|
+
for (const f of iterFields(buf)) {
|
|
141
|
+
if (f.num === 1 && f.wire === 2 && Buffer.isBuffer(f.value)) label = f.value.toString('utf8');
|
|
142
|
+
else if (f.num === 3 && f.wire === 0) isDefault = f.value === 1n;
|
|
143
|
+
else if (f.num === 2 && f.wire === 2 && Buffer.isBuffer(f.value)) {
|
|
144
|
+
let key = '';
|
|
145
|
+
const value: DevinFamilyAxisValue = { order: 0 };
|
|
146
|
+
for (const e of iterFields(f.value)) {
|
|
147
|
+
if (e.num === 1 && e.wire === 2 && Buffer.isBuffer(e.value)) key = e.value.toString('utf8');
|
|
148
|
+
else if (e.num === 2 && e.wire === 2 && Buffer.isBuffer(e.value)) {
|
|
149
|
+
for (const v of iterFields(e.value)) {
|
|
150
|
+
if (v.num === 1 && v.wire === 0) value.order = Number(v.value);
|
|
151
|
+
else if (v.num === 2 && v.wire === 2 && Buffer.isBuffer(v.value)) value.name = v.value.toString('utf8');
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (key) axes[key] = value;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return { ...(label ? { label } : {}), axes, isDefault };
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function parseModelInfo(buf: Buffer): { maxOutputTokens?: number; familyUid?: string; supportsThinking?: boolean } {
|
|
162
|
+
const out: { maxOutputTokens?: number; familyUid?: string; supportsThinking?: boolean } = {};
|
|
163
|
+
for (const f of iterFields(buf)) {
|
|
164
|
+
if (f.num === 13 && typeof f.value === 'bigint' && f.value > 0n) out.maxOutputTokens = Number(f.value);
|
|
165
|
+
else if (f.num === 23 && f.wire === 2 && Buffer.isBuffer(f.value) && f.value.length > 0) out.familyUid = f.value.toString('utf8');
|
|
166
|
+
else if (f.num === 6 && f.wire === 2 && Buffer.isBuffer(f.value)) {
|
|
167
|
+
for (const g of iterFields(f.value)) if (g.num === 15 && g.wire === 0) out.supportsThinking = g.value === 1n;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return out;
|
|
94
171
|
}
|
|
95
172
|
|
|
96
173
|
export interface CacheEntry {
|
|
@@ -127,6 +204,9 @@ export function parseCatalogBuffer(buf: Buffer, apiKey: string, host: string): C
|
|
|
127
204
|
let disabled = false;
|
|
128
205
|
let contextWindow = 0;
|
|
129
206
|
let supportsImages: boolean | undefined;
|
|
207
|
+
let info: ReturnType<typeof parseModelInfo> = {};
|
|
208
|
+
let family: ReturnType<typeof parseFamilyMetadata> | undefined;
|
|
209
|
+
let isFamilyDefault = false;
|
|
130
210
|
for (const sf of iterFields(f.value as Buffer)) {
|
|
131
211
|
if (sf.num === 1 && sf.wire === 2 && Buffer.isBuffer(sf.value)) {
|
|
132
212
|
label = (sf.value as Buffer).toString('utf8');
|
|
@@ -145,8 +225,15 @@ export function parseCatalogBuffer(buf: Buffer, apiKey: string, host: string): C
|
|
|
145
225
|
contextWindow = Number(sf.value);
|
|
146
226
|
} else if (sf.num === 22 && sf.wire === 2 && Buffer.isBuffer(sf.value)) {
|
|
147
227
|
modelUid = (sf.value as Buffer).toString('utf8');
|
|
228
|
+
} else if (sf.num === 23 && sf.wire === 2 && Buffer.isBuffer(sf.value)) {
|
|
229
|
+
info = parseModelInfo(sf.value);
|
|
230
|
+
} else if (sf.num === 30 && sf.wire === 2 && Buffer.isBuffer(sf.value)) {
|
|
231
|
+
family = parseFamilyMetadata(sf.value);
|
|
232
|
+
} else if (sf.num === 31 && sf.wire === 0) {
|
|
233
|
+
isFamilyDefault = sf.value === 1n;
|
|
148
234
|
}
|
|
149
235
|
}
|
|
236
|
+
if (IMAGE_BLIND_UIDS.has(modelUid)) supportsImages = false;
|
|
150
237
|
if (modelUid.length > 0) {
|
|
151
238
|
byUid.set(modelUid, {
|
|
152
239
|
modelUid,
|
|
@@ -154,6 +241,10 @@ export function parseCatalogBuffer(buf: Buffer, apiKey: string, host: string): C
|
|
|
154
241
|
disabled,
|
|
155
242
|
...(contextWindow > 0 ? { contextWindow } : {}),
|
|
156
243
|
...(supportsImages !== undefined ? { supportsImages } : {}),
|
|
244
|
+
...info,
|
|
245
|
+
...(family?.label ? { familyLabel: family.label } : {}),
|
|
246
|
+
...(family ? { familyAxes: family.axes } : {}),
|
|
247
|
+
...(isFamilyDefault || family?.isDefault ? { isFamilyDefault: true } : {}),
|
|
157
248
|
});
|
|
158
249
|
}
|
|
159
250
|
}
|