@oh-my-pi/pi-ai 17.1.8 → 17.2.1
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 +66 -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 +38 -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 +17 -11
- package/dist/types/providers/claude-code-fingerprint.d.ts +12 -8
- package/dist/types/providers/cowork-fetch.d.ts +3 -0
- 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/proxy.d.ts +2 -0
- package/dist/types/utils/schema/normalize.d.ts +1 -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 +466 -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 +80 -75
- package/src/providers/claude-code-fingerprint.ts +12 -11
- package/src/providers/cowork-fetch.ts +201 -0
- 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/openai-codex-responses.ts +106 -26
- 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 +75 -12
- 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 +13 -6
- 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/proxy.ts +6 -2
- package/src/utils/schema/normalize.ts +140 -38
|
@@ -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.
|
|
@@ -397,7 +397,7 @@ export declare function repairOrphanResponsesToolOutputs(input: ResponseInput):
|
|
|
397
397
|
* {@link repairOrphanResponsesToolOutputs}.
|
|
398
398
|
*/
|
|
399
399
|
export declare function repairOrphanResponsesToolCalls(input: ResponseInput): ResponseInput;
|
|
400
|
-
export declare function convertResponsesInputContent(content: string | Array<TextContent | ImageContent>, supportsImages: boolean, supportsImageDetailOriginal: boolean): ResponseInputContent[] | undefined;
|
|
400
|
+
export declare function convertResponsesInputContent(content: string | Array<TextContent | ImageContent>, supportsImages: boolean, supportsImageDetailOriginal: boolean, escapeControlTokens?: boolean): ResponseInputContent[] | undefined;
|
|
401
401
|
export interface BuildResponsesInputOptions<TApi extends Api> {
|
|
402
402
|
model: Model<TApi>;
|
|
403
403
|
context: Context;
|
|
@@ -414,6 +414,18 @@ export interface BuildResponsesInputOptions<TApi extends Api> {
|
|
|
414
414
|
/** Preserve assistant message item IDs from text signatures during fallback replay. */
|
|
415
415
|
preserveAssistantMessageIds?: boolean;
|
|
416
416
|
}
|
|
417
|
+
/**
|
|
418
|
+
* Escape reserved Harmony control tokens in the client-boundary text of
|
|
419
|
+
* replayed Responses input items — user/developer/system message text and
|
|
420
|
+
* tool-result output. Model-owned items (assistant output, reasoning, tool-call
|
|
421
|
+
* arguments) carry no client data and are returned untouched.
|
|
422
|
+
*
|
|
423
|
+
* Native history replay pushes stored `providerPayload` items straight onto the
|
|
424
|
+
* wire, bypassing {@link convertResponsesInputContent}; without this a stored
|
|
425
|
+
* `input_text` carrying `<|channel|>analysis` still reaches gpt-5.x raw (#6913).
|
|
426
|
+
* Callers gate on {@link isHarmonyDialectModel}. Items are copied, not mutated.
|
|
427
|
+
*/
|
|
428
|
+
export declare function escapeReplayedClientText(items: ResponseInput): ResponseInput;
|
|
417
429
|
export declare function buildResponsesInput<TApi extends Api>(options: BuildResponsesInputOptions<TApi>): ResponseInput;
|
|
418
430
|
export declare function convertResponsesAssistantMessage<TApi extends Api>(assistantMsg: AssistantMessage, model: Model<TApi>, msgIndex: number, knownCallIds: Set<string>, includeThinkingSignatures?: boolean, customCallIds?: Set<string>, preserveMessageIds?: boolean, supportsCustomToolCalls?: boolean, customToolWireNameMap?: ReadonlyMap<string, string>, computerCallIds?: Set<string>): ResponseInput;
|
|
419
431
|
/** Appends one tool result while keeping consecutive outputs ahead of its synthetic image messages. */
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { OAuthLoginCallbacks } from "./oauth/types.js";
|
|
2
|
+
export declare const loginExa: (options: import("./oauth/index.js").OAuthController) => Promise<string>;
|
|
3
|
+
export declare const exaProvider: {
|
|
4
|
+
readonly id: "exa";
|
|
5
|
+
readonly name: "Exa";
|
|
6
|
+
readonly envKeys: "EXA_API_KEY";
|
|
7
|
+
readonly login: (cb: OAuthLoginCallbacks) => Promise<string>;
|
|
8
|
+
};
|
|
@@ -64,6 +64,11 @@ declare const ALL: ({
|
|
|
64
64
|
readonly login: (cb: import("./oauth/index.js").OAuthLoginCallbacks) => Promise<string>;
|
|
65
65
|
readonly callbackPort: 59653;
|
|
66
66
|
readonly pasteCodeFlow: true;
|
|
67
|
+
} | {
|
|
68
|
+
readonly id: "exa";
|
|
69
|
+
readonly name: "Exa";
|
|
70
|
+
readonly envKeys: "EXA_API_KEY";
|
|
71
|
+
readonly login: (cb: import("./oauth/index.js").OAuthLoginCallbacks) => Promise<string>;
|
|
67
72
|
} | {
|
|
68
73
|
readonly id: "firepass";
|
|
69
74
|
readonly name: "Fire Pass (Fireworks Kimi K2.6 Turbo subscription)";
|
|
@@ -282,7 +287,8 @@ declare const ALL: ({
|
|
|
282
287
|
readonly login: (cb: import("./oauth/index.js").OAuthLoginCallbacks) => Promise<string>;
|
|
283
288
|
} | {
|
|
284
289
|
readonly id: "xai";
|
|
285
|
-
readonly name: "xAI";
|
|
290
|
+
readonly name: "xAI API";
|
|
291
|
+
readonly login: (cb: import("./oauth/index.js").OAuthLoginCallbacks) => Promise<string>;
|
|
286
292
|
} | {
|
|
287
293
|
readonly id: "xai-oauth";
|
|
288
294
|
readonly name: "xAI Grok OAuth (SuperGrok or X Premium+)";
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import type { OAuthLoginCallbacks } from "./oauth/types.js";
|
|
2
|
+
export declare const loginXAI: (options: import("./oauth/index.js").OAuthController) => Promise<string>;
|
|
1
3
|
export declare const xaiProvider: {
|
|
2
4
|
readonly id: "xai";
|
|
3
|
-
readonly name: "xAI";
|
|
5
|
+
readonly name: "xAI API";
|
|
6
|
+
readonly login: (cb: OAuthLoginCallbacks) => Promise<string>;
|
|
4
7
|
};
|
package/dist/types/stream.d.ts
CHANGED
|
@@ -5,6 +5,8 @@ import type { GoogleGeminiCliOptions } from "./providers/google-gemini-cli.js";
|
|
|
5
5
|
import type { GoogleVertexOptions } from "./providers/google-vertex.js";
|
|
6
6
|
import type { Api, AssistantMessage, Context, Model, OptionsForApi, SimpleStreamOptions, ToolChoice } from "./types.js";
|
|
7
7
|
import { AssistantMessageEventStream } from "./utils/event-stream.js";
|
|
8
|
+
/** Strict official-Codex endpoint check; exact origin or a path boundary after {@link CODEX_BASE_URL}. */
|
|
9
|
+
export declare function isOfficialCodexApiUrl(baseUrl: string | undefined): boolean;
|
|
8
10
|
export declare function configureProviderMaxInFlightRequests(limits: Record<string, number> | undefined): void;
|
|
9
11
|
export declare const __providerInFlightForTesting: {
|
|
10
12
|
setRoot(root: string | undefined): void;
|
package/dist/types/types.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export * from "@oh-my-pi/pi-catalog/effort";
|
|
2
2
|
export * from "@oh-my-pi/pi-catalog/types";
|
|
3
|
-
import type { DeleteArgs, DeleteResult, DiagnosticsArgs, DiagnosticsResult, GrepArgs, GrepResult, LsArgs, LsResult, McpResult, ReadArgs, ReadResult, ShellArgs, ShellResult, WriteArgs, WriteResult } from "@oh-my-pi/pi-catalog/discovery/cursor-gen/agent_pb";
|
|
3
|
+
import type { DeleteArgs, DeleteResult, DiagnosticsArgs, DiagnosticsResult, GrepArgs, GrepResult, LsArgs, LsResult, McpResult, PiBashExecArgs, PiBashExecResult, PiEditExecArgs, PiEditExecResult, PiFindExecArgs, PiFindExecResult, PiGrepExecArgs, PiGrepExecResult, PiLsExecArgs, PiLsExecResult, PiReadExecArgs, PiReadExecResult, PiWriteExecArgs, PiWriteExecResult, ReadArgs, ReadResult, ShellArgs, ShellResult, WriteArgs, WriteResult } from "@oh-my-pi/pi-catalog/discovery/cursor-gen/agent_pb";
|
|
4
4
|
import type { Effort } from "@oh-my-pi/pi-catalog/effort";
|
|
5
5
|
import type { Api, FetchImpl, Model, Provider, ThinkingBudgets, Usage } from "@oh-my-pi/pi-catalog/types";
|
|
6
6
|
import type { Type } from "arktype";
|
|
@@ -754,6 +754,14 @@ export interface CursorMcpCall {
|
|
|
754
754
|
toolCallId: string;
|
|
755
755
|
args: Record<string, unknown>;
|
|
756
756
|
rawArgs: Record<string, Uint8Array>;
|
|
757
|
+
/**
|
|
758
|
+
* The frame asks only whether this call would be permitted — it must not
|
|
759
|
+
* run. The server sends it to resolve a smart-mode approval decision ahead
|
|
760
|
+
* of the real invocation, and answers with the dedicated `approved`
|
|
761
|
+
* variant, so executing here would fire a side-effecting tool the user has
|
|
762
|
+
* not yet been asked about (and fire it twice once the real call arrives).
|
|
763
|
+
*/
|
|
764
|
+
approvalOnly?: boolean;
|
|
757
765
|
}
|
|
758
766
|
export interface CursorTodoSnapshotItem {
|
|
759
767
|
content: string;
|
|
@@ -796,6 +804,51 @@ export interface CursorShellStreamCallbacks {
|
|
|
796
804
|
onStdout(data: string): void;
|
|
797
805
|
onStderr(data: string): void;
|
|
798
806
|
}
|
|
807
|
+
/**
|
|
808
|
+
* A modern Pi exec frame plus the call id the dispatcher minted for it.
|
|
809
|
+
*
|
|
810
|
+
* Unlike the legacy exec args (`ReadArgs`, `ShellArgs`, ...), the Pi frames
|
|
811
|
+
* carry no `tool_call_id` field: on modern builds the id rides the streamed
|
|
812
|
+
* `ToolCall` envelope (`ToolCall.tool_call_id = 57`) instead of each variant's
|
|
813
|
+
* args. The exec channel has no access to that envelope, so the dispatcher
|
|
814
|
+
* mints an id and hands it to the handler, keeping the synthesized transcript
|
|
815
|
+
* block and its paired `toolResult` on the same key.
|
|
816
|
+
*/
|
|
817
|
+
export interface CursorPiCall<TArgs> {
|
|
818
|
+
args: TArgs;
|
|
819
|
+
toolCallId: string;
|
|
820
|
+
}
|
|
821
|
+
/** One resource a host's MCP servers advertise. */
|
|
822
|
+
export interface CursorMcpResource {
|
|
823
|
+
uri: string;
|
|
824
|
+
name?: string;
|
|
825
|
+
description?: string;
|
|
826
|
+
mimeType?: string;
|
|
827
|
+
/** The server advertising it; Cursor addresses reads by this name. */
|
|
828
|
+
server: string;
|
|
829
|
+
}
|
|
830
|
+
/**
|
|
831
|
+
* The content of one resource read.
|
|
832
|
+
*
|
|
833
|
+
* `text` and `blob` are the wire's content oneof: exactly one is sent, with
|
|
834
|
+
* `text` winning when a host supplies both. A download instead sets
|
|
835
|
+
* `downloadPath` and no content at all — the model is told where the file
|
|
836
|
+
* landed rather than being handed its bytes.
|
|
837
|
+
*/
|
|
838
|
+
export interface CursorMcpResourceContent {
|
|
839
|
+
uri: string;
|
|
840
|
+
name?: string;
|
|
841
|
+
description?: string;
|
|
842
|
+
mimeType?: string;
|
|
843
|
+
text?: string;
|
|
844
|
+
blob?: Uint8Array;
|
|
845
|
+
/**
|
|
846
|
+
* Where the host wrote the resource, workspace-relative, when the frame
|
|
847
|
+
* asked for a download. Set this INSTEAD of `text`/`blob`: the wire
|
|
848
|
+
* contract is that a download returns no content to the model.
|
|
849
|
+
*/
|
|
850
|
+
downloadPath?: string;
|
|
851
|
+
}
|
|
799
852
|
export interface CursorExecHandlers {
|
|
800
853
|
read?: (args: ReadArgs) => Promise<CursorExecHandlerResult<ReadResult>>;
|
|
801
854
|
ls?: (args: LsArgs) => Promise<CursorExecHandlerResult<LsResult>>;
|
|
@@ -806,6 +859,53 @@ export interface CursorExecHandlers {
|
|
|
806
859
|
shellStream?: (args: ShellArgs, callbacks: CursorShellStreamCallbacks) => Promise<CursorExecHandlerResult<ShellResult>>;
|
|
807
860
|
diagnostics?: (args: DiagnosticsArgs) => Promise<CursorExecHandlerResult<DiagnosticsResult>>;
|
|
808
861
|
mcp?: (call: CursorMcpCall) => Promise<CursorExecHandlerResult<McpResult>>;
|
|
862
|
+
/**
|
|
863
|
+
* Answers "would this MCP call be permitted", without running it.
|
|
864
|
+
*
|
|
865
|
+
* A modern `mcpArgs` frame carrying `smart_mode_approval_only` asks for the
|
|
866
|
+
* permission decision alone, ahead of the real invocation. Executing the
|
|
867
|
+
* tool to answer it would fire a side effect the user never approved — and
|
|
868
|
+
* fire it twice once the real call arrives.
|
|
869
|
+
*
|
|
870
|
+
* `true` only when the host's policy resolves to a definite allow. A pending
|
|
871
|
+
* prompt is `false`: it can only be answered interactively at execution
|
|
872
|
+
* time, and there is no "ask me later" reply in this frame's result. When no
|
|
873
|
+
* handler is registered the provider refuses, since it cannot decide.
|
|
874
|
+
*/
|
|
875
|
+
mcpApprovalPreflight?: (call: CursorMcpCall) => Promise<boolean>;
|
|
876
|
+
/**
|
|
877
|
+
* Modern Cursor CLI Pi tool frames (`ExecServerMessage` 45-51). They are a
|
|
878
|
+
* distinct frame family from the legacy `readArgs`/`shellArgs`/... set, not
|
|
879
|
+
* an alias: different args, different result oneofs, and no `tool_call_id`.
|
|
880
|
+
*/
|
|
881
|
+
piRead?: (call: CursorPiCall<PiReadExecArgs>) => Promise<CursorExecHandlerResult<PiReadExecResult>>;
|
|
882
|
+
piBash?: (call: CursorPiCall<PiBashExecArgs>) => Promise<CursorExecHandlerResult<PiBashExecResult>>;
|
|
883
|
+
piEdit?: (call: CursorPiCall<PiEditExecArgs>) => Promise<CursorExecHandlerResult<PiEditExecResult>>;
|
|
884
|
+
piWrite?: (call: CursorPiCall<PiWriteExecArgs>) => Promise<CursorExecHandlerResult<PiWriteExecResult>>;
|
|
885
|
+
piGrep?: (call: CursorPiCall<PiGrepExecArgs>) => Promise<CursorExecHandlerResult<PiGrepExecResult>>;
|
|
886
|
+
piFind?: (call: CursorPiCall<PiFindExecArgs>) => Promise<CursorExecHandlerResult<PiFindExecResult>>;
|
|
887
|
+
piLs?: (call: CursorPiCall<PiLsExecArgs>) => Promise<CursorExecHandlerResult<PiLsExecResult>>;
|
|
888
|
+
/**
|
|
889
|
+
* The resources the host's MCP servers advertise, optionally filtered to one
|
|
890
|
+
* server. Without a handler the provider answers an empty catalog, which
|
|
891
|
+
* hides resources a host is in fact holding live connections to.
|
|
892
|
+
*/
|
|
893
|
+
listMcpResources?: (args: {
|
|
894
|
+
server?: string;
|
|
895
|
+
}) => Promise<CursorMcpResource[]>;
|
|
896
|
+
/**
|
|
897
|
+
* Read one resource. `null` means the server or uri is genuinely unknown,
|
|
898
|
+
* which the provider answers as `not_found`; throwing surfaces as `error`.
|
|
899
|
+
*/
|
|
900
|
+
readMcpResource?: (args: {
|
|
901
|
+
server: string;
|
|
902
|
+
uri: string;
|
|
903
|
+
/**
|
|
904
|
+
* When set, write the resource here (workspace-relative) and return
|
|
905
|
+
* `downloadPath` instead of content.
|
|
906
|
+
*/
|
|
907
|
+
downloadPath?: string;
|
|
908
|
+
}) => Promise<CursorMcpResourceContent | null>;
|
|
809
909
|
/** Mirror Cursor's server-owned todo list into local session state. */
|
|
810
910
|
todoSync?: CursorTodoSyncHandler;
|
|
811
911
|
onToolResult?: CursorToolResultHandler;
|
|
@@ -14,6 +14,17 @@ export declare function clearStreamingPartialJson(block: StreamingPartialJsonCar
|
|
|
14
14
|
export declare const kStreamingBlockIndex: unique symbol;
|
|
15
15
|
/** Stores the last parsed argument prefix length for throttled streaming JSON parsing. */
|
|
16
16
|
export declare const kStreamingLastParseLen: unique symbol;
|
|
17
|
+
/**
|
|
18
|
+
* The Cursor interaction envelope's `call_id` for a streamed tool-call block.
|
|
19
|
+
*
|
|
20
|
+
* Tracked separately from the block's own `id` because they are NOT the same
|
|
21
|
+
* key: MCP and Pi blocks are filed under the id inside the call's `args`, which
|
|
22
|
+
* is what the exec channel pairs its result under, while every streamed
|
|
23
|
+
* `ToolCall*Update` correlates on the envelope's `call_id`. Matching
|
|
24
|
+
* completions against the block id would mis-route every call whose args carry
|
|
25
|
+
* their own id.
|
|
26
|
+
*/
|
|
27
|
+
export declare const kStreamingEnvelopeId: unique symbol;
|
|
17
28
|
/** Marks streamed tool-call arguments that already received an authoritative done payload. */
|
|
18
29
|
export declare const kStreamingArgumentsDone: unique symbol;
|
|
19
30
|
/** Classifies Cursor's in-flight tool-call kind without leaking provider-private state. */
|
|
@@ -1,13 +1,21 @@
|
|
|
1
|
+
import type { AssistantMessage, Model, ToolCall } from "../types.js";
|
|
1
2
|
/**
|
|
2
|
-
*
|
|
3
|
+
* Escape reserved Harmony control tokens in arbitrary text so it can be
|
|
4
|
+
* transported as data to a harmony-dialect model. Returns the input unchanged
|
|
5
|
+
* when it carries no reserved spelling.
|
|
3
6
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* truncate-and-resume primitive for the `edit` tool when its input is in
|
|
7
|
-
* hashline DSL form. Other tools and surfaces fall through to
|
|
8
|
-
* abort-and-retry handled by the agent loop.
|
|
7
|
+
* Callers MUST gate on a harmony target and escape only the transport copy —
|
|
8
|
+
* the persisted transcript keeps the byte-for-byte original.
|
|
9
9
|
*/
|
|
10
|
-
|
|
10
|
+
export declare function escapeHarmonyControlTokens(text: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* Whether requests to `model` are served by a Harmony-dialect backend
|
|
13
|
+
* (gpt-5.x / gpt-oss), which rejects reserved control-token spellings appearing
|
|
14
|
+
* as data in the request. Resolves the wire model id (`requestModelId ?? id`)
|
|
15
|
+
* so deployment/catalog aliases — e.g. an Azure alias whose `requestModelId` is
|
|
16
|
+
* `gpt-5.4` — are detected even when the local id is opaque.
|
|
17
|
+
*/
|
|
18
|
+
export declare function isHarmonyDialectModel(model: Model): boolean;
|
|
11
19
|
declare const SIGNAL_ORDER: readonly ["M", "C", "G", "S", "B", "R", "T"];
|
|
12
20
|
export type HarmonySignalClass = "H" | (typeof SIGNAL_ORDER)[number];
|
|
13
21
|
export type HarmonySurface = "assistant_text" | "assistant_thinking" | "tool_arg";
|
|
@@ -29,6 +29,8 @@ export interface ConnectProxiedSocketOptions {
|
|
|
29
29
|
signal?: AbortSignal;
|
|
30
30
|
/** Maximum wall-clock time to establish the final TLS tunnel. Disabled when absent or non-positive. */
|
|
31
31
|
timeoutMs?: number;
|
|
32
|
+
/** Target TLS profile. Cursor defaults to HTTP/2 when this is absent. */
|
|
33
|
+
tls?: tls.ConnectionOptions;
|
|
32
34
|
}
|
|
33
35
|
/**
|
|
34
36
|
* Tunnel a socket connection through an HTTP CONNECT proxy.
|
|
@@ -26,6 +26,7 @@ export interface NormalizeSchemaOptions {
|
|
|
26
26
|
inferTypeForBareEnum: boolean;
|
|
27
27
|
foldOneOfIntoAnyOf: boolean;
|
|
28
28
|
dropNonScalarEnum: boolean;
|
|
29
|
+
stringEnumsOnly?: boolean;
|
|
29
30
|
rejectResidualIncompatibilities?: ReadonlyArray<ResidualSchemaIncompatibility>;
|
|
30
31
|
validateAndFallback?: {
|
|
31
32
|
fallback: unknown;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-ai",
|
|
4
|
-
"version": "17.1
|
|
4
|
+
"version": "17.2.1",
|
|
5
5
|
"description": "Unified LLM API with automatic model discovery and provider configuration",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -38,9 +38,9 @@
|
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@bufbuild/protobuf": "^2.12.1",
|
|
41
|
-
"@oh-my-pi/pi-catalog": "17.1
|
|
42
|
-
"@oh-my-pi/pi-utils": "17.1
|
|
43
|
-
"@oh-my-pi/pi-wire": "17.1
|
|
41
|
+
"@oh-my-pi/pi-catalog": "17.2.1",
|
|
42
|
+
"@oh-my-pi/pi-utils": "17.2.1",
|
|
43
|
+
"@oh-my-pi/pi-wire": "17.2.1",
|
|
44
44
|
"arktype": "2.2.3",
|
|
45
45
|
"zod": "^4"
|
|
46
46
|
},
|
|
@@ -28,6 +28,7 @@ import type {
|
|
|
28
28
|
UsageResponse,
|
|
29
29
|
UsageStaleResponse,
|
|
30
30
|
} from "./types";
|
|
31
|
+
import { AUTH_BROKER_CAPABILITIES_HEADER, AUTH_BROKER_CAPABILITY_CODEX_METER_BLOCK_SCOPES } from "./types";
|
|
31
32
|
import { getAuthBrokerWireSchemas } from "./wire-schema-resource";
|
|
32
33
|
|
|
33
34
|
type AuthBrokerResponseSchemaName =
|
|
@@ -135,7 +136,9 @@ export class AuthBrokerClient {
|
|
|
135
136
|
const query = new URLSearchParams();
|
|
136
137
|
if (opts.waitMs !== undefined) query.set("wait", String(opts.waitMs));
|
|
137
138
|
const path = `/v1/snapshot${query.size > 0 ? `?${query.toString()}` : ""}`;
|
|
138
|
-
const headers: Record<string, string> = {
|
|
139
|
+
const headers: Record<string, string> = {
|
|
140
|
+
[AUTH_BROKER_CAPABILITIES_HEADER]: AUTH_BROKER_CAPABILITY_CODEX_METER_BLOCK_SCOPES,
|
|
141
|
+
};
|
|
139
142
|
if (opts.ifGenerationGt !== undefined) headers["If-None-Match"] = `"${opts.ifGenerationGt}"`;
|
|
140
143
|
const timeoutMs =
|
|
141
144
|
opts.waitMs !== undefined && opts.waitMs > 0 ? Math.max(this.#timeoutMs, opts.waitMs + 1000) : undefined;
|
|
@@ -176,6 +179,7 @@ export class AuthBrokerClient {
|
|
|
176
179
|
const headers: Record<string, string> = {
|
|
177
180
|
Accept: "text/event-stream",
|
|
178
181
|
Authorization: `Bearer ${this.#token}`,
|
|
182
|
+
[AUTH_BROKER_CAPABILITIES_HEADER]: AUTH_BROKER_CAPABILITY_CODEX_METER_BLOCK_SCOPES,
|
|
179
183
|
};
|
|
180
184
|
if (opts.signal?.aborted) {
|
|
181
185
|
throw new AuthBrokerError("Auth broker request aborted", { cause: opts.signal.reason });
|