@oh-my-pi/pi-ai 17.1.7 → 17.2.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/CHANGELOG.md +64 -0
- package/dist/types/auth-broker/server.d.ts +5 -0
- package/dist/types/auth-broker/types.d.ts +4 -0
- package/dist/types/auth-storage.d.ts +26 -1
- package/dist/types/error/classes.d.ts +5 -1
- package/dist/types/error/rate-limit.d.ts +5 -4
- package/dist/types/providers/anthropic-client.d.ts +13 -1
- package/dist/types/providers/anthropic.d.ts +9 -1
- package/dist/types/providers/cursor/exec-modern.d.ts +98 -0
- package/dist/types/providers/cursor-pi-args.d.ts +99 -0
- package/dist/types/providers/cursor.d.ts +53 -3
- package/dist/types/providers/error-message.d.ts +2 -4
- package/dist/types/providers/openai-codex-responses.d.ts +10 -0
- package/dist/types/providers/openai-responses-wire.d.ts +8 -0
- package/dist/types/providers/openai-shared.d.ts +13 -1
- package/dist/types/registry/exa.d.ts +8 -0
- package/dist/types/registry/registry.d.ts +7 -1
- package/dist/types/registry/xai.d.ts +4 -1
- package/dist/types/stream.d.ts +2 -0
- package/dist/types/types.d.ts +101 -1
- package/dist/types/usage/umans.d.ts +2 -0
- package/dist/types/utils/block-symbols.d.ts +11 -0
- package/dist/types/utils/harmony-leak.d.ts +15 -7
- package/dist/types/utils/schema/normalize.d.ts +1 -0
- package/dist/types/utils.d.ts +8 -0
- package/package.json +4 -4
- package/src/auth-broker/client.ts +5 -1
- package/src/auth-broker/server.ts +103 -9
- package/src/auth-broker/snapshot-cache.ts +12 -3
- package/src/auth-broker/types.ts +6 -0
- package/src/auth-storage.ts +447 -28
- package/src/error/classes.ts +98 -3
- package/src/error/flags.ts +6 -1
- package/src/error/rate-limit.ts +18 -12
- package/src/providers/amazon-bedrock.ts +3 -3
- package/src/providers/anthropic-client.ts +24 -2
- package/src/providers/anthropic.ts +31 -6
- package/src/providers/cursor/exec-modern.ts +495 -0
- package/src/providers/cursor/proto/agent.proto +1007 -0
- package/src/providers/cursor-pi-args.ts +135 -0
- package/src/providers/cursor.ts +1138 -66
- package/src/providers/devin.ts +2 -1
- package/src/providers/error-message.ts +3 -1
- package/src/providers/google-vertex.ts +3 -5
- package/src/providers/openai-codex-responses.ts +109 -27
- package/src/providers/openai-completions.ts +19 -4
- package/src/providers/openai-responses-wire.ts +8 -0
- package/src/providers/openai-responses.ts +12 -1
- package/src/providers/openai-shared.ts +83 -14
- package/src/registry/api-key-validation.ts +18 -34
- package/src/registry/exa.ts +19 -0
- package/src/registry/novita.ts +6 -3
- package/src/registry/registry.ts +3 -1
- package/src/registry/xai.ts +17 -1
- package/src/stream.ts +3 -4
- package/src/types.ts +115 -0
- package/src/usage/umans.ts +192 -0
- package/src/utils/block-symbols.ts +12 -0
- package/src/utils/harmony-leak.ts +32 -0
- package/src/utils/idle-iterator.ts +2 -2
- package/src/utils/schema/normalize.ts +140 -38
- package/src/utils.ts +173 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,70 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [17.2.0] - 2026-07-30
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added first-class parentTurnId support for nested Codex requests, allowing stream options and metadata helpers to accept and safely propagate the initiating turn's ID.
|
|
10
|
+
- Added preservation of the Codex `encrypted_function_args` plaintext-collaboration marker on replayed function calls, keeping server-marked plaintext tool arguments from being reinterpreted as encrypted on subsequent turns.
|
|
11
|
+
- Added interactive Exa API-key login through `/login exa`, opening the official API-key dashboard and saving pasted keys to the credential store ([#1798](https://github.com/can1357/oh-my-pi/issues/1798)).
|
|
12
|
+
- Cursor's modern exec wire protocol is now handled end to end. `agent.proto` models the frames current Cursor CLI builds emit — the seven Pi tools (`ExecServerMessage` 45-51), hooks, subagents, allowlist prechecks, MCP state, smart-mode classification, canvas diagnostics, conversation search, agent-store conflicts and git diff — and every one of them gets a typed answer. The Pi frames run their local equivalents (`read`/`bash`/`edit`/`write`/`grep`/`glob`); the rest answer with the error, not-found or empty-but-valid variant that is actually true of this client. Frames this build cannot name at all now raise `ExecClientControlMessage.throw` with `unknown_exec_variant`, and recognised frames with no truthful answer (`git_diff_request`, whose `GetDiffResponse` has no error variant) raise `exec_variant_unsupported`, instead of a silent ack that leaves the server waiting.
|
|
13
|
+
- `lsp` is advertised in the MCP tool catalog again. It was filtered out as a Cursor-native tool, but the native `diagnostics` frame covers one of roughly ten LSP actions, so the other nine were unreachable.
|
|
14
|
+
- Added `pinSessionOAuthAccount` support for backdating the sticky's last-use timestamp (`options.lastUsedAtMs`), so pins restored from persisted sessions keep the provider's warm-window semantics: resumes inside the prompt-cache TTL reuse the account, stale resumes still re-rank.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- Codex turn metadata now reserves the codex-rs `code_mode_tool_names` key, preventing caller-supplied client metadata extras from colliding with the core-owned field.
|
|
19
|
+
- Codex SSE requests to the official endpoint now use zstd-compressed bodies by default to match the official client, which can be disabled with PI_CODEX_ZSTD=0.
|
|
20
|
+
- API-key validation now preserves provider HTTP status and retry headers, allowing authentication, rate-limit, and server failures to retain their original error classifications.
|
|
21
|
+
- The Cursor Pi arg translation (`piReadPath`, `piJoinPath`, `piLsPath`, `piEscapeRegexLiteral`, `piLimit`) moved to `providers/cursor-pi-args`, re-exported from `providers/cursor/exec-modern` so existing imports are unaffected. The legacy pi shim shares these helpers and is compiled into the bundled virtual module registry, where a nested `providers/<dir>/<mod>` specifier is unresolvable under bunfs — and importing them from the exec module would drag the whole protobuf graph in for two string functions.
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- Fixed Novita login rejecting valid API keys belonging to Developer and Basic team members by validating against the chat completions endpoint instead of the billing balance endpoint.
|
|
26
|
+
- Fixed Cursor resource_exhausted errors being incorrectly classified as QUOTA_EXHAUSTED (which caused 30-minute credential blocks), mapping them to MODEL_CAPACITY_EXHAUSTED with a shorter backoff instead.
|
|
27
|
+
- Fixed a crash in Amazon Bedrock and Devin providers when Context.systemPrompt is passed as a bare string.
|
|
28
|
+
- Fixed aborted usage-limit recovery incorrectly blocking credentials or waiting on local usage fetches after the session had already changed.
|
|
29
|
+
- Fixed Codex WebSocket sessions echoing stale or missing turn states by capturing x-codex-turn-state refreshes from response metadata event headers.
|
|
30
|
+
- Fixed Harmony-dialect models (e.g., gpt-5.x, openai-codex) failing with invalid_prompt or "Request blocked" errors by escaping reserved control tokens in untrusted user and tool-result text.
|
|
31
|
+
- Fixed named forced tool_choice not being enforced on string-only OpenAI-compatible hosts (such as llama.cpp and LM Studio) by narrowing the advertised tools to the forced tool.
|
|
32
|
+
- Fixed direct Anthropic Claude Opus requests failing with HTTP 400 when the endpoint rejects strict tool fields.
|
|
33
|
+
- Fixed usage-based credential ranking for Anthropic accounts where a missing long-window (7-day) metric was incorrectly treated as a short-window metric.
|
|
34
|
+
- Fixed legacy Codex usage blocks continuing to gate all models after per-meter backoff was introduced, splitting the old shared scope into independent chat and spark blocks while maintaining backward compatibility with older clients and database schemas.
|
|
35
|
+
- Fixed Anthropic retry loops ignoring `maxRetryDelayMs` for long server `retry-after` hints, so over-budget delays surface immediately without losing response details or abort cleanup ([#7003](https://github.com/can1357/oh-my-pi/issues/7003)).
|
|
36
|
+
- Added interactive xAI API-key login with key validation through the xAI models endpoint.
|
|
37
|
+
- Fixed Google Gemini and Vertex tool declarations carrying numeric, boolean, object-valued, or mixed `enum` arrays that the Google Schema wire type cannot represent. Unsupported enums are omitted while valid string enums remain constrained.
|
|
38
|
+
- Umans usage provider: fetches `GET /v1/usage` and surfaces the rolling 5h request window + concurrency limits in `/usage`, `omp usage`, and the TUI status bar.
|
|
39
|
+
- Fixed ranged legacy Cursor reads reporting the returned window byte length as the full file size.
|
|
40
|
+
- Updated the Cursor client build advertisement to activate the modern exec-frame protocol handled by this provider.
|
|
41
|
+
- Fixed a windowed Cursor `read` reporting the window's line count as the file's. `total_lines` and `file_size` were derived from the payload, which is the whole file only for an unranged read — a 20-line page of a 100-line file answered `total_lines: 20`, which a paginating server reads as the end of the file. The count now comes from the read's own record of the file (`details.meta.truncation.totalLines`), falling back to counting the payload when the read returned the file whole.
|
|
42
|
+
- Fixed a `pi_grep` that hit the native backend's internal match ceiling answering as an unqualified success. `GrepTool` folds that cap into the flat `details.truncated` alone, setting neither `details.truncation` nor `perFileLimitReached` — the two fields the Pi result was built from — so the one truncation a caller can neither detect nor page around was the one it was never told about. The flat flag is now translated into a `PiTruncation`, and only when no specific cap already reported itself.
|
|
43
|
+
- Fixed a `pi_grep` frame's `context` and `limit` vanishing from the transcript. The bridge honors both by building a scoped `grep`, but neither is expressible in the model-facing schema, so the synthesized block recorded a plain pattern/path search — replaying a context-widened or capped search as an ordinary grep sitting beside output no ordinary grep produces. Both are now recorded on the block.
|
|
44
|
+
- Fixed a Cursor MCP resource listing shrinking to a count in the transcript. The full URI/name/mime catalog goes out on the wire, but the paired local result recorded `Listed N MCP resource(s)` — and rebuilt history is serialized from that result, so one reload later the model knew it had seen N resources and could name none of them. The paired result now lists what the answer carried.
|
|
45
|
+
- Fixed the `pi_read` range translation padding the slice it asks for. `piReadPath` composed a plain `:N+K` selector, which the local `read` tool expands by one leading and three trailing context line — so a frame naming offset 5/limit 20 received lines 4-27. Ranged Pi reads now compose `:raw:N+K`; the wire result is an opaque output string, so the line-number gutter `raw` also drops carries nothing the contract needs.
|
|
46
|
+
- Fixed four Cursor exec frames answering with a result whose oneof was never set. In proto3 that is not an empty result — the server reads it as "the tool ran and produced nothing", indistinguishable from real success. `listMcpResourcesExecResult`, `readMcpResourceExecResult`, `recordScreenResult` and `computerUseResult` now send `ListMcpResourcesSuccess{resources: []}`, `ReadMcpResourceNotFound{uri}`, `RecordScreenFailure` and `ComputerUseError` respectively.
|
|
47
|
+
- The MCP resource frames now answer from the host instead of a fixed verdict. `CursorExecHandlers` gained `listMcpResources`/`readMcpResource`, so a host holding live MCP connections advertises them; the empty catalog and `not_found` above remain the answer when no handler is supplied. A handler that throws surfaces as `ListMcpResourcesError`/`ReadMcpResourceError` rather than collapsing into "none exist", which the model cannot retry. A read carrying `download_path` forwards it and answers with `ReadMcpResourceSuccess.download_path` and no content, which is what that mode means.
|
|
48
|
+
- Fixed Cursor `connect_scm` calls losing their repository and settling on a fabricated verdict. The target rides in the `ConnectScmArgs.target` oneof, so reading a flat `github` property always saw `undefined`; and the authoritative `success`/`error`/`rejected` result only arrives on the completion frame, so answering at the announcement persisted a fixed failure for every call — including the ones the server went on to accept. The block now opens on the start frame and settles from the completion's decoded result.
|
|
49
|
+
- Fixed interleaved Cursor tool calls corrupting each other. The stream decoder tracked a single "current" block and settled it on any `toolCallCompleted`, ignoring the envelope's `call_id`: a completion for one call closed whichever block happened to be open and paired it with the wrong result, and `start A, start B` orphaned A entirely so its own completion settled B while A was never paired — which strips the whole interaction from every rebuilt transcript. Open blocks are now retained per envelope `call_id`, and end-of-stream closes all of them rather than only the last.
|
|
50
|
+
- Fixed a Cursor `search_conversations` call leaving no transcript block. The frame is answered from a fixed verdict, so nothing downstream pairs a result for it, and an unpaired call takes its whole interaction out of every rebuilt transcript.
|
|
51
|
+
- Fixed a Cursor `read_mcp_resource` call leaving no transcript block. The frame runs locally — and in download mode writes a workspace file — but synthesized no tool call and paired no result, so the read was invisible in the UI and absent from every rebuilt history; a resource download could mutate the workspace with nothing on record. The frame now synthesizes a `read_mcp_resource` block (not `read`: it is a remote MCP operation, and the name drives rendering and prune semantics) and pairs a result on success, not-found and error alike. Frames answered without a handler still synthesize nothing, since nothing ran.
|
|
52
|
+
- Fixed a Cursor `list_mcp_resources` call leaving no transcript block. The model consumed the catalog, but the frame synthesized no tool call and paired no result — its streamed `ListMcpResourcesToolCall` announcement was equally unrecognized — so the listing was invisible in the UI and absent from every rebuilt history. Frames a handler answered now synthesize a `list_mcp_resources` block and pair a result derived from the same answer that went on the wire; frames answered from the fixed no-handler catalog still synthesize nothing, since nothing ran.
|
|
53
|
+
- Fixed an unavailable `pi_edit`/`pi_write` answering with the error variant. Both results model refusal and failure as separate oneof cases, and a denial reported as `error` reads as "the tool ran and broke" — inviting a retry of an operation that was never permitted. A frame whose tool is not granted, or whose handler produced nothing, now answers with `PiEditExecRejected`/`PiWriteExecRejected`; execution failures keep the error variant.
|
|
54
|
+
- Fixed a Cursor MCP approval probe actually running the tool. A modern `mcpArgs` frame carrying `smart_mode_approval_only` asks only whether a call would be permitted, not for the call itself. The decoder dropped the flag, so the frame ran a side-effecting MCP tool the user had not been asked about, then ran it again when the real call followed. The flag is now carried through and the probe is answered from the host's policy without executing: approved only for a definite allow, refused for a deny, for a mode that demands a prompt the frame cannot raise, and for a tool the session does not have. No transcript block is synthesized either, since nothing ran.
|
|
55
|
+
- Fixed the Cursor stream's end-of-transport cleanup erasing the arguments of every block still open. Blocks whose args arrive whole (todo, connect-SCM, MCP) never feed the streamed partial-JSON buffer, and reparsing an absent buffer yields `{}`, so a truncated or disconnected turn rebuilt those calls with no arguments at all. Only blocks that actually streamed their args are reparsed now.
|
|
56
|
+
- Fixed a Cursor stream dying mid-turn stranding the call it left open. `connect_scm` and native todo blocks are stamped resolved the moment they open, so the agent loop synthesizes no placeholder and only their completion frame pairs a result — a transport that closed first left the card animating and the call unpaired, which takes the whole interaction out of every rebuilt transcript. The terminal-error path now closes open blocks and pairs those server-owned calls with an interrupted result; the flush ran only on clean completion before, which is not the path a dying stream takes. Exec-settled MCP blocks are left alone, since the dispatch that ran them owns their result.
|
|
57
|
+
- Fixed the Pi exec frames displaying a different operation than the one they run. The provider synthesized its transcript block from a second, hand-rolled translation of the frame args, so `pi_read`'s `offset`/`limit` were shown as a whole-file read, `pi_grep`'s `literal` pattern as an unescaped regex, and `pi_find`'s path/glob join differed from the executed one. Both sides now share a single translation.
|
|
58
|
+
- Fixed the streamed `pi_*_tool_call` announcements that modern builds send alongside each exec frame being unrecognized. The exec channel already synthesizes those blocks when it runs the tool; the duplicate was avoided only because the decoder recognized none of the variants, which would have started double-rendering as soon as any one was added.
|
|
59
|
+
- Fixed `pi_bash` results reaching Cursor clipped with no truncation notice. Two truncation records exist locally: `read`/`grep` set `details.truncation`, which carries an explicit `truncated` flag, while `bash` sets `details.meta.truncation`, whose record has no such flag — its presence is the signal. `piTruncation` read only the first shape and required the flag, so every real Bash truncation was dropped and the server was told the clipped output was complete. Both shapes now translate, and an explicit `truncated: false` still suppresses the field.
|
|
60
|
+
|
|
61
|
+
## [17.1.8] - 2026-07-28
|
|
62
|
+
|
|
63
|
+
### Fixed
|
|
64
|
+
|
|
65
|
+
- Fixed an HTTP 400 error when resuming or replaying OpenAI history after an interrupted native Computer Use turn.
|
|
66
|
+
- Fixed connection 404 errors when using Google Vertex AI in multi-region locations (eu and us) by correctly resolving regional endpoint (REP) hosts.
|
|
67
|
+
- Fixed a resource leak in SqliteAuthCredentialStore.close() where unclosed prepared statements kept the SQLite connection alive, preventing database file cleanup (especially on Windows where files remained locked).
|
|
68
|
+
|
|
5
69
|
## [17.1.7] - 2026-07-27
|
|
6
70
|
|
|
7
71
|
### Changed
|
|
@@ -20,6 +20,11 @@ export interface AuthBrokerServerOptions {
|
|
|
20
20
|
* without long sleeps. Default {@link DEFAULT_STREAM_KEEPALIVE_MS}.
|
|
21
21
|
*/
|
|
22
22
|
streamKeepaliveMs?: number;
|
|
23
|
+
/**
|
|
24
|
+
* Override cross-process SQLite change polling in milliseconds.
|
|
25
|
+
* Internal-only — tests use a short interval. Default 250ms.
|
|
26
|
+
*/
|
|
27
|
+
externalChangePollMs?: number;
|
|
23
28
|
}
|
|
24
29
|
export interface AuthBrokerServerHandle {
|
|
25
30
|
/** Bound URL (`http://host:port`). */
|
|
@@ -131,6 +131,10 @@ export type SnapshotStreamEvent = SnapshotStreamSnapshotEvent | SnapshotStreamEn
|
|
|
131
131
|
* unauthenticated for liveness probes; everything else requires a bearer.
|
|
132
132
|
*/
|
|
133
133
|
export declare const AUTH_BROKER_API_PREFIX = "/v1";
|
|
134
|
+
/** Request header used by clients to advertise optional auth-broker protocol features. */
|
|
135
|
+
export declare const AUTH_BROKER_CAPABILITIES_HEADER = "OMP-Auth-Broker-Capabilities";
|
|
136
|
+
/** Client understands independent Codex `chat` and `spark` credential-block scopes. */
|
|
137
|
+
export declare const AUTH_BROKER_CAPABILITY_CODEX_METER_BLOCK_SCOPES = "codex-meter-block-scopes";
|
|
134
138
|
/** Default port when none is configured. Loopback-only, no external exposure. */
|
|
135
139
|
export declare const DEFAULT_AUTH_BROKER_BIND = "127.0.0.1:8765";
|
|
136
140
|
/** Default broker→provider refresh skew. Refresh credentials this close to expiry. */
|
|
@@ -257,6 +257,13 @@ export interface CredentialRefreshLeaseFence {
|
|
|
257
257
|
}
|
|
258
258
|
export interface AuthCredentialStore {
|
|
259
259
|
close(): void;
|
|
260
|
+
/**
|
|
261
|
+
* Stateful probe for commits made by another process to the backing store.
|
|
262
|
+
* Returns true once per observed change.
|
|
263
|
+
*/
|
|
264
|
+
pollExternalChanges?(): boolean;
|
|
265
|
+
/** Record the current auth revision after a local mutation already notified consumers. */
|
|
266
|
+
acknowledgeLocalChanges?(): void;
|
|
260
267
|
/** Optional hook to notify the underlying store that usage report cache is stale. */
|
|
261
268
|
invalidateUsageCache?(signal?: AbortSignal): Promise<void>;
|
|
262
269
|
listAuthCredentials(provider?: string): StoredAuthCredential[];
|
|
@@ -711,6 +718,11 @@ export declare class AuthStorage {
|
|
|
711
718
|
*/
|
|
712
719
|
close(): void;
|
|
713
720
|
getGeneration(): number;
|
|
721
|
+
/**
|
|
722
|
+
* Reload state after another process commits to the backing store, then
|
|
723
|
+
* notify snapshot consumers even when only credential blocks changed.
|
|
724
|
+
*/
|
|
725
|
+
pollExternalChanges(): Promise<boolean>;
|
|
714
726
|
onGenerationChanged(listener: (generation: number) => void): () => void;
|
|
715
727
|
offGenerationChanged(listener: (generation: number) => void): void;
|
|
716
728
|
/**
|
|
@@ -1041,8 +1053,15 @@ export declare class AuthStorage {
|
|
|
1041
1053
|
* The durable credential id keeps the pin stable across credential refreshes,
|
|
1042
1054
|
* storage reordering, and process restarts. Normal auth retry and usage-limit
|
|
1043
1055
|
* handling may still route around an unavailable account.
|
|
1056
|
+
*
|
|
1057
|
+
* `options.lastUsedAtMs` backdates the sticky's last-use timestamp so a pin
|
|
1058
|
+
* restored from a persisted session keeps the provider's warm-window
|
|
1059
|
+
* semantics: a resume inside the prompt-cache TTL reuses the account, a
|
|
1060
|
+
* stale resume still re-ranks.
|
|
1044
1061
|
*/
|
|
1045
|
-
pinSessionOAuthAccount(provider: string, sessionId: string, credentialId: number
|
|
1062
|
+
pinSessionOAuthAccount(provider: string, sessionId: string, credentialId: number, options?: {
|
|
1063
|
+
lastUsedAtMs?: number;
|
|
1064
|
+
}): boolean;
|
|
1046
1065
|
/**
|
|
1047
1066
|
* Resolve every stored OAuth credential for `provider` independently.
|
|
1048
1067
|
*
|
|
@@ -1314,5 +1333,11 @@ export declare class SqliteAuthCredentialStore implements AuthCredentialStore {
|
|
|
1314
1333
|
* Delete all credentials for a provider.
|
|
1315
1334
|
*/
|
|
1316
1335
|
deleteProvider(provider: string): void;
|
|
1336
|
+
/**
|
|
1337
|
+
* SQLite increments `data_version` when another connection commits. Own
|
|
1338
|
+
* writes leave it unchanged and already notify AuthStorage directly.
|
|
1339
|
+
*/
|
|
1340
|
+
pollExternalChanges(): boolean;
|
|
1341
|
+
acknowledgeLocalChanges(): void;
|
|
1317
1342
|
close(): void;
|
|
1318
1343
|
}
|
|
@@ -31,12 +31,16 @@ export declare class OpenAIHttpError extends ProviderHttpError {
|
|
|
31
31
|
code: string | undefined;
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
|
+
/** Test-only control for the otherwise bounded Anthropic error-body drain. */
|
|
35
|
+
export declare const __anthropicApiErrorForTesting: {
|
|
36
|
+
setBodyReadTimeoutMs(timeoutMs: number | undefined): void;
|
|
37
|
+
};
|
|
34
38
|
/** Non-2xx response from the Anthropic API. */
|
|
35
39
|
export declare class AnthropicApiError extends ProviderHttpError {
|
|
36
40
|
readonly headers: Headers;
|
|
37
41
|
readonly requestId: string | null;
|
|
38
42
|
constructor(status: number, message: string, headers: Headers);
|
|
39
|
-
static fromResponse(response: Response): Promise<AnthropicApiError>;
|
|
43
|
+
static fromResponse(response: Response, signal?: AbortSignal): Promise<AnthropicApiError>;
|
|
40
44
|
}
|
|
41
45
|
/** Network-level failure (DNS, TLS, socket reset) after retries were exhausted. */
|
|
42
46
|
export declare class AnthropicConnectionError extends Error {
|
|
@@ -5,11 +5,12 @@
|
|
|
5
5
|
export type RateLimitReason = "QUOTA_EXHAUSTED" | "RATE_LIMIT_EXCEEDED" | "MODEL_CAPACITY_EXHAUSTED" | "SERVER_ERROR" | "UNKNOWN";
|
|
6
6
|
/**
|
|
7
7
|
* Classify a rate-limit error message into a reason category.
|
|
8
|
-
* Priority order:
|
|
9
|
-
*
|
|
8
|
+
* Priority order: explicit details in a resource-exhausted error > QUOTA
|
|
9
|
+
* (Antigravity "quota will reset") > MODEL_CAPACITY > QUOTA (account) >
|
|
10
|
+
* RATE_LIMIT > QUOTA (generic) > SERVER_ERROR > bare resource-exhausted > UNKNOWN.
|
|
10
11
|
*
|
|
11
|
-
* "resource exhausted" maps to MODEL_CAPACITY (transient, short wait)
|
|
12
|
-
*
|
|
12
|
+
* Bare "resource exhausted" / "resource_exhausted" maps to MODEL_CAPACITY (transient, short wait).
|
|
13
|
+
* Explicit details such as "quota exceeded" retain their normal classification.
|
|
13
14
|
*/
|
|
14
15
|
export declare function parseRateLimitReason(errorMessage: string): RateLimitReason;
|
|
15
16
|
/**
|
|
@@ -9,6 +9,12 @@ export interface AnthropicRequestOptions {
|
|
|
9
9
|
timeout?: number;
|
|
10
10
|
/** Per-request retry budget override. */
|
|
11
11
|
maxRetries?: number;
|
|
12
|
+
/**
|
|
13
|
+
* Maximum delay in milliseconds to wait for a server-directed retry. If the
|
|
14
|
+
* server's `retry-after` hint exceeds this value, the retry is declined and
|
|
15
|
+
* the original error is surfaced. Non-positive values disable the cap. Defaults to 60000.
|
|
16
|
+
*/
|
|
17
|
+
maxRetryDelayMs?: number;
|
|
12
18
|
/** Per-request headers merged after client defaults. */
|
|
13
19
|
headers?: Record<string, string>;
|
|
14
20
|
}
|
|
@@ -38,6 +44,12 @@ export interface AnthropicClientOptions {
|
|
|
38
44
|
authToken?: string | null;
|
|
39
45
|
baseURL?: string | null;
|
|
40
46
|
maxRetries?: number;
|
|
47
|
+
/**
|
|
48
|
+
* Maximum delay in milliseconds to wait for a server-directed retry. If the
|
|
49
|
+
* server's `retry-after` hint exceeds this value, the retry is declined and
|
|
50
|
+
* the original error is surfaced. Non-positive values disable the cap. Defaults to 60000.
|
|
51
|
+
*/
|
|
52
|
+
maxRetryDelayMs?: number;
|
|
41
53
|
/** Pre-response timeout in milliseconds. Defaults to 10 minutes. */
|
|
42
54
|
timeout?: number;
|
|
43
55
|
defaultHeaders?: Record<string, string>;
|
|
@@ -45,7 +57,7 @@ export interface AnthropicClientOptions {
|
|
|
45
57
|
fetchOptions?: AnthropicFetchOptions;
|
|
46
58
|
}
|
|
47
59
|
/** Server-suggested delay (`retry-after-ms`, then `retry-after` seconds or HTTP date). */
|
|
48
|
-
export declare function retryDelayFromHeaders(headers: Headers | undefined): number | undefined;
|
|
60
|
+
export declare function retryDelayFromHeaders(headers: Pick<Headers, "get"> | undefined): number | undefined;
|
|
49
61
|
export declare function calculateAnthropicRetryDelayMs(attempt: number): number;
|
|
50
62
|
/**
|
|
51
63
|
* Lazy in-flight request handle. The HTTP request starts on the first
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FetchImpl, Message, Model, ProviderSessionState, ServiceTier, SimpleStreamOptions, StreamFunction, StreamOptions, Usage } from "../types.js";
|
|
1
|
+
import type { Api, FetchImpl, Message, Model, ProviderSessionState, ServiceTier, SimpleStreamOptions, StreamFunction, StreamOptions, Usage } from "../types.js";
|
|
2
2
|
import { type AnthropicFetchOptions, type AnthropicMessagesClientLike } from "./anthropic-client.js";
|
|
3
3
|
import { type FallbackParam, type MessageParam, type TextBlockParam } from "./anthropic-wire.js";
|
|
4
4
|
export type AnthropicHeaderOptions = {
|
|
@@ -26,6 +26,12 @@ type AnthropicCacheControl = NonNullable<TextBlockParam["cache_control"]>;
|
|
|
26
26
|
* hasn't been materialized yet.
|
|
27
27
|
*/
|
|
28
28
|
export declare function clearAnthropicFastModeFallback(providerSessionState: Map<string, ProviderSessionState> | undefined): void;
|
|
29
|
+
/**
|
|
30
|
+
* Whether the direct Anthropic model's endpoint-scoped fast-mode fallback is
|
|
31
|
+
* currently active. Reading the map directly is intentional: inspection must
|
|
32
|
+
* not materialize a state entry for a model that has never streamed.
|
|
33
|
+
*/
|
|
34
|
+
export declare function isAnthropicFastModeFallbackDisabled(providerSessionState: Map<string, ProviderSessionState> | undefined, model: Model<Api>): boolean;
|
|
29
35
|
export * from "./claude-code-fingerprint.js";
|
|
30
36
|
export declare function mapStainlessOs(platform: string): "MacOS" | "Windows" | "Linux" | "FreeBSD" | `Other::${string}`;
|
|
31
37
|
export declare function mapStainlessArch(arch: string): "x64" | "arm64" | "x86" | `other::${string}`;
|
|
@@ -156,6 +162,7 @@ export type AnthropicClientOptionsArgs = {
|
|
|
156
162
|
thinkingDisplay?: AnthropicThinkingDisplay;
|
|
157
163
|
disableStrictTools?: boolean;
|
|
158
164
|
fetch?: FetchImpl;
|
|
165
|
+
maxRetryDelayMs?: number;
|
|
159
166
|
claudeCodeSessionId?: string;
|
|
160
167
|
};
|
|
161
168
|
export type AnthropicClientOptionsResult = {
|
|
@@ -164,6 +171,7 @@ export type AnthropicClientOptionsResult = {
|
|
|
164
171
|
authToken?: string | null;
|
|
165
172
|
baseURL?: string;
|
|
166
173
|
maxRetries: number;
|
|
174
|
+
maxRetryDelayMs?: number;
|
|
167
175
|
defaultHeaders: Record<string, string>;
|
|
168
176
|
fetch?: FetchImpl;
|
|
169
177
|
fetchOptions?: AnthropicFetchOptions;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Proto builders for the modern Cursor CLI exec frames (`ExecServerMessage`
|
|
3
|
+
* 27-31, 36-38, 40-55).
|
|
4
|
+
*
|
|
5
|
+
* Split out of `cursor.ts` because these are pure `create(...)` shapes with no
|
|
6
|
+
* transport, stream, or block-state coupling: the dispatcher decides *which*
|
|
7
|
+
* answer a frame gets, this module knows *what* that answer looks like on the
|
|
8
|
+
* wire. Every builder returns a result whose oneof case is set — an
|
|
9
|
+
* `ExecClientMessage` carrying a result with an unset oneof is a fake success
|
|
10
|
+
* the server reads as "the tool ran and produced nothing".
|
|
11
|
+
*/
|
|
12
|
+
import { type ExecuteHookRequest, type ExecuteHookResult, type McpStateExecResult, type McpToolDefinition, type PiBashExecResult, type PiEditExecResult, type PiFindExecResult, type PiGrepExecResult, type PiLsExecResult, type PiReadExecResult, type PiTruncation, type PiWriteExecResult } from "@oh-my-pi/pi-catalog/discovery/cursor-gen/agent_pb";
|
|
13
|
+
import type { ToolResultMessage } from "../../types.js";
|
|
14
|
+
/**
|
|
15
|
+
* The pure arg translation lives in `../cursor-pi-args` so the legacy pi shim
|
|
16
|
+
* can share it without pulling this module's protobuf graph into the bundled
|
|
17
|
+
* virtual registry. Re-exported here because this is where the frame builders
|
|
18
|
+
* and their translation are consumed together.
|
|
19
|
+
*/
|
|
20
|
+
export { piEscapeRegexLiteral, piGrepSkip, piJoinPath, piLimit, piLsPath, piReadDisplayPath, piReadPath, piTimeout, } from "../cursor-pi-args.js";
|
|
21
|
+
/** Flatten a tool result's content into the single `output` string the Pi frames carry. */
|
|
22
|
+
export declare function piOutputText(toolResult: ToolResultMessage): string;
|
|
23
|
+
/**
|
|
24
|
+
* Translate a local tool's truncation summary into `PiTruncation`.
|
|
25
|
+
*
|
|
26
|
+
* Two shapes reach here. `read`/`grep` set `details.truncation`
|
|
27
|
+
* (`TruncationResult`), which carries an explicit `truncated` boolean. `bash`
|
|
28
|
+
* sets `details.meta.truncation` (`TruncationMeta`), which has **no** such
|
|
29
|
+
* flag — its presence *is* the signal, and requiring the boolean silently
|
|
30
|
+
* dropped every Bash truncation, handing Cursor clipped output with no notice
|
|
31
|
+
* that it was clipped.
|
|
32
|
+
*
|
|
33
|
+
* Returns `undefined` when nothing was truncated: the field is `optional` on
|
|
34
|
+
* every Pi success message, and emitting a zeroed `PiTruncation` would tell the
|
|
35
|
+
* server the output was trimmed to nothing.
|
|
36
|
+
*/
|
|
37
|
+
export declare function piTruncation(toolResult: ToolResultMessage): PiTruncation | undefined;
|
|
38
|
+
export declare function buildPiReadResult(toolResult: ToolResultMessage): PiReadExecResult;
|
|
39
|
+
export declare function buildPiReadError(error: string): PiReadExecResult;
|
|
40
|
+
export declare function buildPiBashResult(toolResult: ToolResultMessage): PiBashExecResult;
|
|
41
|
+
export declare function buildPiBashError(error: string): PiBashExecResult;
|
|
42
|
+
/**
|
|
43
|
+
* `PiEditExecSuccess` requires `diff` and `patch` alongside `output`. The local
|
|
44
|
+
* `edit` tool reports them under `details`; when it does not, the strings stay
|
|
45
|
+
* empty rather than being faked from the output text.
|
|
46
|
+
*/
|
|
47
|
+
export declare function buildPiEditResult(toolResult: ToolResultMessage): PiEditExecResult;
|
|
48
|
+
export declare function buildPiEditError(error: string): PiEditExecResult;
|
|
49
|
+
/**
|
|
50
|
+
* A refusal is not an execution failure: `PiEditExecResult` models them as
|
|
51
|
+
* separate variants, and answering a denied call with `error` reads as "the
|
|
52
|
+
* edit ran and broke", which invites a retry of an operation that was never
|
|
53
|
+
* permitted.
|
|
54
|
+
*/
|
|
55
|
+
export declare function buildPiEditRejected(reason: string): PiEditExecResult;
|
|
56
|
+
export declare function buildPiWriteResult(toolResult: ToolResultMessage): PiWriteExecResult;
|
|
57
|
+
export declare function buildPiWriteError(error: string): PiWriteExecResult;
|
|
58
|
+
/** Same variant split as {@link buildPiEditRejected}. */
|
|
59
|
+
export declare function buildPiWriteRejected(reason: string): PiWriteExecResult;
|
|
60
|
+
export declare function buildPiGrepResult(toolResult: ToolResultMessage): PiGrepExecResult;
|
|
61
|
+
export declare function buildPiGrepError(error: string): PiGrepExecResult;
|
|
62
|
+
export declare function buildPiFindResult(toolResult: ToolResultMessage): PiFindExecResult;
|
|
63
|
+
export declare function buildPiFindError(error: string): PiFindExecResult;
|
|
64
|
+
export declare function buildPiLsResult(toolResult: ToolResultMessage): PiLsExecResult;
|
|
65
|
+
export declare function buildPiLsError(error: string): PiLsExecResult;
|
|
66
|
+
/**
|
|
67
|
+
* Answer `mcpStateExecArgs` (frame 36) from the catalog already advertised in
|
|
68
|
+
* `RequestContext.tools`.
|
|
69
|
+
*
|
|
70
|
+
* This client hosts no MCP servers of its own: every forwarded tool is a local
|
|
71
|
+
* pi-agent tool published under a synthetic `providerIdentifier`. Regrouping
|
|
72
|
+
* the same list keeps the server's view of "which servers exist and what do
|
|
73
|
+
* they expose" consistent with what it was told at context time, instead of
|
|
74
|
+
* claiming zero servers while tool calls for them keep arriving.
|
|
75
|
+
*
|
|
76
|
+
* `serverIdentifiers` filters the answer when the server asks about specific
|
|
77
|
+
* servers. `kickOnly` is a restart request — there is nothing to restart, so it
|
|
78
|
+
* is answered with the same state rather than an error.
|
|
79
|
+
*/
|
|
80
|
+
export declare function buildMcpStateResult(tools: McpToolDefinition[], serverIdentifiers: readonly string[]): McpStateExecResult;
|
|
81
|
+
/**
|
|
82
|
+
* Build the neutral response for a hook query: the matching response case with
|
|
83
|
+
* every field unset.
|
|
84
|
+
*
|
|
85
|
+
* This client runs no Cursor hooks, and every field of every response variant
|
|
86
|
+
* is `optional` — so an empty response of the right case means "no hook had
|
|
87
|
+
* anything to say", which is exactly true. It is NOT the unset-oneof fake
|
|
88
|
+
* success: the case itself is set, only the payload is empty.
|
|
89
|
+
*
|
|
90
|
+
* `ExecuteHookRequest` and `ExecuteHookResponse` are parallel oneofs whose case
|
|
91
|
+
* names line up, but the two unions are unrelated to the compiler: a `switch`
|
|
92
|
+
* is what makes each pairing individually type-checked, and it forces a
|
|
93
|
+
* deliberate branch when a future regen adds a request case.
|
|
94
|
+
*
|
|
95
|
+
* Returns `null` for a request case this build does not model, which the
|
|
96
|
+
* dispatcher answers with `ExecClientThrow` rather than guessing a case.
|
|
97
|
+
*/
|
|
98
|
+
export declare function buildNeutralHookResult(request: ExecuteHookRequest | undefined): ExecuteHookResult | null;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Translate a Pi frame's args into the local tool kwargs that run it.
|
|
3
|
+
*
|
|
4
|
+
* Shared deliberately by three consumers: the provider synthesizes a display
|
|
5
|
+
* block from these, the coding-agent bridge executes with them, and the legacy
|
|
6
|
+
* pi shim performs the identical translation for the old wire. Separate
|
|
7
|
+
* hand-rolled copies drift, and the drift is invisible — the transcript shows
|
|
8
|
+
* one operation while a different one runs.
|
|
9
|
+
*
|
|
10
|
+
* Kept apart from `cursor/exec-modern.ts` on purpose: these are pure
|
|
11
|
+
* string/path functions with no protobuf coupling, while that module pulls in
|
|
12
|
+
* `@bufbuild/protobuf` and the generated `agent_pb` graph. The legacy shim is
|
|
13
|
+
* compiled into the bundled virtual module registry, so importing it from a
|
|
14
|
+
* nested path would drag the whole exec implementation in with it — and
|
|
15
|
+
* `./providers/*` is a single-segment wildcard export that cannot serve a
|
|
16
|
+
* nested specifier under bunfs (issue #3442).
|
|
17
|
+
*
|
|
18
|
+
* Every `optional int32` here is presence-sensitive: `0` is a supplied value,
|
|
19
|
+
* not "unset", so it must never be folded into a default.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* A `pi_read` range composed onto the path as `read`'s inline `:raw:N+K`
|
|
23
|
+
* selector.
|
|
24
|
+
*
|
|
25
|
+
* `read` exposes no range kwargs, so an uncomposed range reads the whole file.
|
|
26
|
+
* `offset` is a 1-indexed start clamped like the reference's
|
|
27
|
+
* `Math.max(0, offset - 1)` over 0-indexed lines; `limit` is a line count.
|
|
28
|
+
* `null` marks a present `limit: 0` — zero lines, which no selector expresses
|
|
29
|
+
* and which must not degrade into a whole-file read.
|
|
30
|
+
*
|
|
31
|
+
* The range is `raw` because a plain `:N+K` deliberately pads with one leading
|
|
32
|
+
* and three trailing context lines: helpful for a human reading a snippet,
|
|
33
|
+
* wrong for a caller that asked for exactly `limit` lines from `offset`. The
|
|
34
|
+
* wire result is an opaque `output` string, so the hashline and line-number
|
|
35
|
+
* gutter that `raw` also drops carry nothing the frame's contract needs.
|
|
36
|
+
* A range-free read keeps the ordinary form — whole-file reads want them.
|
|
37
|
+
*/
|
|
38
|
+
export declare function piReadPath(readPath: string, offset?: number, limit?: number): string | null;
|
|
39
|
+
/**
|
|
40
|
+
* The same range as {@link piReadPath}, rendered for a transcript block rather
|
|
41
|
+
* than for execution.
|
|
42
|
+
*
|
|
43
|
+
* Differs only at `limit: 0`, where `piReadPath` returns `null` because no
|
|
44
|
+
* selector reads zero lines and the frame is answered with empty output
|
|
45
|
+
* directly. The block still has to say so: falling back to the bare path there
|
|
46
|
+
* would record a whole-file read whose result is empty, which is the widest
|
|
47
|
+
* possible gap between what a rebuilt transcript shows and what happened.
|
|
48
|
+
* `+0` is never executed — it exists to be read.
|
|
49
|
+
*/
|
|
50
|
+
export declare function piReadDisplayPath(readPath: string, offset?: number, limit?: number): string;
|
|
51
|
+
/**
|
|
52
|
+
* A legacy `grep` frame's pagination `offset` as the local tool's file `skip`.
|
|
53
|
+
*
|
|
54
|
+
* `grep` paginates by file and reports "use skip=N for the next page" in that
|
|
55
|
+
* same unit, so the offset maps across directly. A present `0` means "start at
|
|
56
|
+
* the beginning", which is the unskipped search rather than a skip of zero.
|
|
57
|
+
*
|
|
58
|
+
* Shared because both the executing bridge and the provider's transcript
|
|
59
|
+
* synthesis need it: a block showing an unskipped search beside a result from
|
|
60
|
+
* a later file window misreports what was searched.
|
|
61
|
+
*/
|
|
62
|
+
export declare function piGrepSkip(offset?: number): number | undefined;
|
|
63
|
+
/**
|
|
64
|
+
* Join a Pi frame's optional `path` with the `glob`/`pattern` it scopes.
|
|
65
|
+
*
|
|
66
|
+
* The local `grep`/`glob` tools take one combined path spec. An absolute
|
|
67
|
+
* pattern ignores the path, and an absent or `.` path leaves the pattern
|
|
68
|
+
* standing alone rather than building a `./`- or `//`-prefixed spec.
|
|
69
|
+
*
|
|
70
|
+
* Uses `node:path` rather than string surgery so Windows absolutes (`C:\…`,
|
|
71
|
+
* UNC) are recognised and separators stay normalized.
|
|
72
|
+
*/
|
|
73
|
+
export declare function piJoinPath(basePath: string | undefined, pattern: string): string;
|
|
74
|
+
/**
|
|
75
|
+
* The path a `pi_ls` frame lists.
|
|
76
|
+
*
|
|
77
|
+
* The frame's `limit` is deliberately NOT mapped. It caps directory *entries*
|
|
78
|
+
* (the reference does a flat `readdir` and slices the entry array), while the
|
|
79
|
+
* local `read` tool renders a depth-2 tree with per-directory caps and elision
|
|
80
|
+
* summaries and applies a selector as a *rendered line* slice. Nested rows,
|
|
81
|
+
* headers and "N more" lines all count toward that slice, so `:1+K` would cap
|
|
82
|
+
* a different unit while looking honored — worse than leaving it unset, which
|
|
83
|
+
* at least reports the local listing's own truncation faithfully.
|
|
84
|
+
*/
|
|
85
|
+
export declare function piLsPath(basePath: string | undefined): string;
|
|
86
|
+
/** Escape a literal string so the regex-only local `grep` tool matches it verbatim. */
|
|
87
|
+
export declare function piEscapeRegexLiteral(value: string): string;
|
|
88
|
+
/** Clamp a present `optional int32` result cap the way the reference does; `undefined` stays unset. */
|
|
89
|
+
export declare function piLimit(limit: number | undefined): number | undefined;
|
|
90
|
+
/**
|
|
91
|
+
* A `pi_bash` frame's timeout as the local `bash` tool's kwarg.
|
|
92
|
+
*
|
|
93
|
+
* Presence-sensitive like every other `optional int32` here, and unusually
|
|
94
|
+
* load-bearing: `bash` documents `timeout: 0` as "disables the command
|
|
95
|
+
* deadline", so folding a supplied `0` into `undefined` applies the 300s
|
|
96
|
+
* default and kills exactly the long-running command that asked not to be.
|
|
97
|
+
* Negative values have no local meaning and fall back to the default.
|
|
98
|
+
*/
|
|
99
|
+
export declare function piTimeout(timeout: number | undefined): number | undefined;
|
|
@@ -3,10 +3,10 @@ import { type JsonValue } from "@bufbuild/protobuf";
|
|
|
3
3
|
import type { McpToolDefinition } from "@oh-my-pi/pi-catalog/discovery/cursor-gen/agent_pb";
|
|
4
4
|
import { type AgentServerMessage, type ConversationStateStructure } from "@oh-my-pi/pi-catalog/discovery/cursor-gen/agent_pb";
|
|
5
5
|
import type { AssistantMessage, CursorExecHandlerResult, CursorExecHandlers, CursorExecPairing, CursorTodoSyncHandler, CursorToolResultHandler, Message, StreamFunction, StreamOptions, TextContent, ThinkingContent, Tool, ToolCall, ToolResultMessage } from "../types.js";
|
|
6
|
-
import { kCursorExecResolved, kStreamingBlockIndex, kStreamingBlockKind, kStreamingLastParseLen, kStreamingPartialJson } from "../utils/block-symbols.js";
|
|
6
|
+
import { kCursorExecResolved, kStreamingBlockIndex, kStreamingBlockKind, kStreamingEnvelopeId, kStreamingLastParseLen, kStreamingPartialJson } from "../utils/block-symbols.js";
|
|
7
7
|
import { AssistantMessageEventStream } from "../utils/event-stream.js";
|
|
8
8
|
export declare const CURSOR_API_URL = "https://api2.cursor.sh";
|
|
9
|
-
export declare const CURSOR_CLIENT_VERSION = "cli-2026.
|
|
9
|
+
export declare const CURSOR_CLIENT_VERSION = "cli-2026.07.23-e383d2b";
|
|
10
10
|
export interface CursorOptions extends StreamOptions {
|
|
11
11
|
customSystemPrompt?: string;
|
|
12
12
|
conversationId?: string;
|
|
@@ -32,7 +32,8 @@ export type ToolCallState = ToolCall & {
|
|
|
32
32
|
[kStreamingBlockIndex]: number;
|
|
33
33
|
[kStreamingPartialJson]?: string;
|
|
34
34
|
[kStreamingLastParseLen]?: number;
|
|
35
|
-
[kStreamingBlockKind]: "mcp" | "todo" | "cursor-exec";
|
|
35
|
+
[kStreamingBlockKind]: "mcp" | "todo" | "cursor-exec" | "connect-scm";
|
|
36
|
+
[kStreamingEnvelopeId]?: string;
|
|
36
37
|
[kCursorExecResolved]?: true;
|
|
37
38
|
};
|
|
38
39
|
export interface BlockState {
|
|
@@ -43,6 +44,17 @@ export interface BlockState {
|
|
|
43
44
|
[kStreamingBlockIndex]: number;
|
|
44
45
|
}) | null;
|
|
45
46
|
currentToolCall: ToolCallState | null;
|
|
47
|
+
/**
|
|
48
|
+
* Open streamed tool-call blocks, keyed by the interaction envelope's
|
|
49
|
+
* `call_id`.
|
|
50
|
+
*
|
|
51
|
+
* Cursor interleaves calls: two `toolCallStarted` frames can arrive before
|
|
52
|
+
* either completes. A single "current" slot would let the second overwrite
|
|
53
|
+
* the first, orphaning a block that nothing then settles. Every keyed block
|
|
54
|
+
* stays reachable until its own completion, and `currentToolCall` remains
|
|
55
|
+
* only as the fallback for frames that carry no `call_id`.
|
|
56
|
+
*/
|
|
57
|
+
openToolCalls: Map<string, ToolCallState>;
|
|
46
58
|
/** MCP call IDs synthesized from exec frames before their redundant streamed block arrives. */
|
|
47
59
|
resolvedMcpToolCallIds: Set<string>;
|
|
48
60
|
firstTokenTime: number | undefined;
|
|
@@ -102,6 +114,44 @@ export declare function resolveExecHandler<TArgs, TResult>(args: TArgs, handler:
|
|
|
102
114
|
* specific recovery hint.
|
|
103
115
|
*/
|
|
104
116
|
export declare function emptyGrepPatternRejection(pattern: string | undefined, glob: string | undefined): string | null;
|
|
117
|
+
/**
|
|
118
|
+
* Retain a freshly opened streamed tool-call block.
|
|
119
|
+
*
|
|
120
|
+
* Keyed by the interaction envelope's `call_id`, which is the only key every
|
|
121
|
+
* `ToolCall*Update` for that call shares. The block's own `id` is deliberately
|
|
122
|
+
* not the key: MCP, Pi and connect-SCM blocks are filed under the id carried
|
|
123
|
+
* inside the call's `args`, because that is what the exec channel pairs its
|
|
124
|
+
* result under and what the transcript files the visible block under.
|
|
125
|
+
*
|
|
126
|
+
* `currentToolCall` is still set, as the fallback for frames that carry no
|
|
127
|
+
* `call_id` (proto3-optional, and unset on what older builds send).
|
|
128
|
+
*/
|
|
129
|
+
/**
|
|
130
|
+
* Close every tool-call block still open when the stream ends.
|
|
131
|
+
*
|
|
132
|
+
* Not just the last one started: with interleaved calls several can be open at
|
|
133
|
+
* once, and an unclosed block leaves its live card animating and its call
|
|
134
|
+
* unpaired.
|
|
135
|
+
*
|
|
136
|
+
* Only blocks fed by a streamed argument buffer get reparsed. Todo,
|
|
137
|
+
* connect-SCM and MCP-settled frames arrive with complete `arguments` and
|
|
138
|
+
* never set the partial buffer; `parseStreamingJson(undefined)` returns `{}`,
|
|
139
|
+
* so reparsing unconditionally would erase the arguments of every such block
|
|
140
|
+
* caught open by a truncated stream.
|
|
141
|
+
*
|
|
142
|
+
* Server-owned blocks are also paired here. `connect-scm` and `todo` are
|
|
143
|
+
* stamped {@link kCursorExecResolved} the moment they open, so `agent-loop.ts`
|
|
144
|
+
* synthesizes no placeholder for them and only their `toolCallCompleted` frame
|
|
145
|
+
* pairs a result. A transport that closes before that frame would leave the
|
|
146
|
+
* call unpaired, and `buildSessionContext` strips a dangling call from every
|
|
147
|
+
* rebuilt transcript — the interaction disappears. An interrupted result is
|
|
148
|
+
* emitted instead.
|
|
149
|
+
*
|
|
150
|
+
* MCP blocks are excluded even when resolved: the exec dispatch that marked
|
|
151
|
+
* them owns their result, and `drainInFlightDispatches` awaits it before this
|
|
152
|
+
* runs, so pairing here would duplicate one against the same `toolCallId`.
|
|
153
|
+
*/
|
|
154
|
+
export declare function flushOpenToolCalls(output: AssistantMessage, stream: AssistantMessageEventStream, state: BlockState): void;
|
|
105
155
|
/**
|
|
106
156
|
* Merge the decoded completion-frame `McpArgs` map into the args assembled
|
|
107
157
|
* from streamed `args_text_delta` snapshots.
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import type { Api, Model } from "../types.js";
|
|
2
2
|
export declare function createProviderErrorMessage(model: Model<Api>, err: unknown): {
|
|
3
3
|
role: "assistant";
|
|
4
|
-
content:
|
|
5
|
-
|
|
6
|
-
text: string;
|
|
7
|
-
}[];
|
|
4
|
+
content: never[];
|
|
5
|
+
errorMessage: string;
|
|
8
6
|
api: Api;
|
|
9
7
|
provider: string;
|
|
10
8
|
model: string;
|
|
@@ -27,6 +27,14 @@ export interface OpenAICodexResponsesOptions extends StreamOptions {
|
|
|
27
27
|
* keys are ignored; extras are never emitted as top-level metadata fields.
|
|
28
28
|
*/
|
|
29
29
|
clientMetadata?: Record<string, string>;
|
|
30
|
+
/**
|
|
31
|
+
* Turn id of the initiating (parent) Codex turn for nested requests such as
|
|
32
|
+
* subagent spawns (codex-rs `parent_turn_id`, #35835). Emitted both as the
|
|
33
|
+
* flat `client_metadata.parent_turn_id` key and inside the
|
|
34
|
+
* `x-codex-turn-metadata` JSON blob; blank values are ignored. The key is
|
|
35
|
+
* reserved: `clientMetadata` extras cannot supply it.
|
|
36
|
+
*/
|
|
37
|
+
parentTurnId?: string;
|
|
30
38
|
/**
|
|
31
39
|
* Invoked when the server streams a `response.metadata` event carrying
|
|
32
40
|
* ChatGPT moderation metadata (`metadata.openai_chatgpt_moderation_metadata`)
|
|
@@ -44,6 +52,8 @@ export interface OpenAICodexCompatibilityMetadataOptions {
|
|
|
44
52
|
startNewTurn?: boolean;
|
|
45
53
|
turnStartedAtUnixMs?: number;
|
|
46
54
|
clientMetadata?: Readonly<Record<string, string>>;
|
|
55
|
+
/** Parent Codex turn id for nested requests; see {@link OpenAICodexResponsesOptions.parentTurnId}. */
|
|
56
|
+
parentTurnId?: string;
|
|
47
57
|
/** Add the direct installation header required by `/responses/compact`. */
|
|
48
58
|
includeInstallationHeader?: boolean;
|
|
49
59
|
}
|
|
@@ -2453,6 +2453,14 @@ export interface ResponseFunctionToolCall {
|
|
|
2453
2453
|
* The namespace of the function to run.
|
|
2454
2454
|
*/
|
|
2455
2455
|
namespace?: string;
|
|
2456
|
+
/**
|
|
2457
|
+
* Plaintext-argument marker for collaboration tool calls (codex-rs
|
|
2458
|
+
* `encrypted_function_args`, #35845): an empty array marks the arguments as
|
|
2459
|
+
* plaintext agent-message payloads rather than encrypted blobs. Preserved
|
|
2460
|
+
* verbatim across history replay so the backend keeps treating them as
|
|
2461
|
+
* plaintext; omitted entirely for ordinary function calls.
|
|
2462
|
+
*/
|
|
2463
|
+
encrypted_function_args?: string[];
|
|
2456
2464
|
/**
|
|
2457
2465
|
* The status of the item. One of `in_progress`, `completed`, or `incomplete`.
|
|
2458
2466
|
* Populated when items are returned via API.
|