@oh-my-pi/pi-ai 17.1.3 → 17.1.4
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 +47 -0
- package/README.md +1 -1
- package/dist/types/auth-broker/client.d.ts +7 -1
- package/dist/types/auth-broker/remote-store.d.ts +4 -1
- package/dist/types/auth-broker/types.d.ts +6 -1
- package/dist/types/auth-broker/wire-schemas.d.ts +41 -0
- package/dist/types/auth-storage.d.ts +55 -0
- package/dist/types/providers/anthropic.d.ts +1 -7
- package/dist/types/providers/claude-code-fingerprint.d.ts +15 -0
- package/dist/types/providers/cursor.d.ts +29 -7
- package/dist/types/providers/openai-codex/request-transformer.d.ts +5 -4
- package/dist/types/providers/openai-codex-responses.d.ts +3 -0
- package/dist/types/registry/alibaba-token-plan.d.ts +11 -0
- package/dist/types/registry/oauth/anthropic-constants.d.ts +12 -0
- package/dist/types/registry/oauth/anthropic.d.ts +1 -0
- package/dist/types/registry/oauth/index.d.ts +1 -0
- package/dist/types/registry/oauth/types.d.ts +8 -0
- package/dist/types/types.d.ts +71 -1
- package/dist/types/usage/minimax-code.d.ts +1 -0
- package/dist/types/usage.d.ts +10 -0
- package/package.json +4 -4
- package/src/auth-broker/client.ts +24 -1
- package/src/auth-broker/remote-store.ts +12 -0
- package/src/auth-broker/server.ts +7 -0
- package/src/auth-broker/types.ts +7 -0
- package/src/auth-broker/wire-schemas.ts +23 -0
- package/src/auth-storage.ts +279 -29
- package/src/error/flags.ts +1 -1
- package/src/providers/__tests__/kimi-code-thinking.test.ts +40 -5
- package/src/providers/amazon-bedrock.ts +3 -4
- package/src/providers/anthropic.ts +98 -32
- package/src/providers/azure-openai-responses.ts +36 -5
- package/src/providers/claude-code-fingerprint.ts +19 -0
- package/src/providers/cursor.ts +514 -38
- package/src/providers/openai-codex/request-transformer.ts +27 -7
- package/src/providers/openai-codex-responses.ts +37 -14
- package/src/providers/openai-responses.ts +14 -8
- package/src/providers/openai-shared.ts +12 -1
- package/src/registry/alibaba-token-plan.ts +103 -21
- package/src/registry/oauth/anthropic-constants.ts +12 -0
- package/src/registry/oauth/anthropic.ts +3 -1
- package/src/registry/oauth/index.ts +1 -0
- package/src/registry/oauth/types.ts +8 -0
- package/src/stream.ts +7 -2
- package/src/types.ts +79 -1
- package/src/usage/alibaba-token-plan.ts +34 -6
- package/src/usage/claude.ts +7 -2
- package/src/usage/minimax-code.ts +280 -19
- package/src/usage/openai-codex.ts +61 -14
- package/src/usage.ts +10 -0
- package/src/utils.ts +5 -5
package/dist/types/types.d.ts
CHANGED
|
@@ -350,6 +350,13 @@ export interface StreamOptions {
|
|
|
350
350
|
* and then to a 120s default.
|
|
351
351
|
*/
|
|
352
352
|
streamIdleTimeoutMs?: number;
|
|
353
|
+
/**
|
|
354
|
+
* Optional cap on Codex SSE pre-response attempts, including the initial
|
|
355
|
+
* request. WebSocket retries and outer agent retries have separate budgets.
|
|
356
|
+
* Finite values below `1` and non-finite values are clamped to one request;
|
|
357
|
+
* omission preserves the provider default.
|
|
358
|
+
*/
|
|
359
|
+
codexSseMaxAttempts?: number;
|
|
353
360
|
/**
|
|
354
361
|
* Optional retry delay hook for tests and transports that need custom scheduling.
|
|
355
362
|
*/
|
|
@@ -400,7 +407,14 @@ export interface SimpleStreamOptions extends Omit<StreamOptions, "apiKey"> {
|
|
|
400
407
|
thinkingBudgets?: ThinkingBudgets;
|
|
401
408
|
/** Cursor exec handlers for local tool execution */
|
|
402
409
|
cursorExecHandlers?: CursorExecHandlers;
|
|
403
|
-
/**
|
|
410
|
+
/**
|
|
411
|
+
* Optional rewrite of Cursor exec-channel tool results. May return a Promise.
|
|
412
|
+
*
|
|
413
|
+
* The Agent reserves the original result in its buffer before awaiting this
|
|
414
|
+
* hook, and the `message_end` drain waits for a still-pending rewrite, so an
|
|
415
|
+
* async transformer is honored even when the turn closes in the same chunk.
|
|
416
|
+
* A rejecting transformer is swallowed and the reserved payload stands in.
|
|
417
|
+
*/
|
|
404
418
|
cursorOnToolResult?: CursorToolResultHandler;
|
|
405
419
|
/** Optional tool choice override for compatible providers */
|
|
406
420
|
toolChoice?: ToolChoice;
|
|
@@ -715,7 +729,24 @@ export type CursorExecHandlerResult<T> = {
|
|
|
715
729
|
result: T;
|
|
716
730
|
toolResult?: ToolResultMessage;
|
|
717
731
|
} | T | ToolResultMessage;
|
|
732
|
+
/**
|
|
733
|
+
* Optional rewrite of a Cursor exec-channel tool result.
|
|
734
|
+
* May return a Promise. Returning `undefined` keeps the original result.
|
|
735
|
+
*
|
|
736
|
+
* The Agent reserves the original result in its buffer before awaiting this
|
|
737
|
+
* hook, and the `message_end` drain waits for a still-pending rewrite, so an
|
|
738
|
+
* async transformer is honored even when the turn closes in the same chunk.
|
|
739
|
+
* A rejecting transformer is swallowed and the reserved payload stands in.
|
|
740
|
+
*/
|
|
718
741
|
export type CursorToolResultHandler = (result: ToolResultMessage) => ToolResultMessage | undefined | Promise<ToolResultMessage | undefined>;
|
|
742
|
+
/**
|
|
743
|
+
* Identifies the synthesized assistant block a Cursor exec call was filed
|
|
744
|
+
* under, so paths that produce no handler `toolResult` can still pair one.
|
|
745
|
+
*/
|
|
746
|
+
export interface CursorExecPairing {
|
|
747
|
+
toolCallId: string;
|
|
748
|
+
toolName: string;
|
|
749
|
+
}
|
|
719
750
|
export interface CursorMcpCall {
|
|
720
751
|
name: string;
|
|
721
752
|
providerIdentifier: string;
|
|
@@ -724,6 +755,43 @@ export interface CursorMcpCall {
|
|
|
724
755
|
args: Record<string, unknown>;
|
|
725
756
|
rawArgs: Record<string, Uint8Array>;
|
|
726
757
|
}
|
|
758
|
+
export interface CursorTodoSnapshotItem {
|
|
759
|
+
content: string;
|
|
760
|
+
status: "pending" | "in_progress" | "completed" | "abandoned";
|
|
761
|
+
}
|
|
762
|
+
/**
|
|
763
|
+
* Authoritative todo list state settled by Cursor's server-side
|
|
764
|
+
* `update_todos` / `read_todos` tools.
|
|
765
|
+
*/
|
|
766
|
+
export interface CursorTodoSnapshot {
|
|
767
|
+
todos: CursorTodoSnapshotItem[];
|
|
768
|
+
/** True when the server reported the update as a merge. Presentation only. */
|
|
769
|
+
merged: boolean;
|
|
770
|
+
}
|
|
771
|
+
/**
|
|
772
|
+
* Settles a native todo call in the host.
|
|
773
|
+
*
|
|
774
|
+
* Called for every completed native todo call, not just successful ones: the
|
|
775
|
+
* interactive todo card only resolves on a matching `tool_execution_end`, so a
|
|
776
|
+
* refused or failed call that stayed silent would animate forever.
|
|
777
|
+
*
|
|
778
|
+
* `snapshot` is the server-confirmed list, or `null` when there is nothing to
|
|
779
|
+
* mirror — a server error (`error` set), or a benign refusal with `error` null:
|
|
780
|
+
* a filtered, truncated, or empty read, or a snapshot the local model cannot
|
|
781
|
+
* represent (two rows sharing content). Local state MUST be left untouched
|
|
782
|
+
* unless a snapshot is supplied.
|
|
783
|
+
*
|
|
784
|
+
* `toolCallId` is the id of the streamed native call, which is also the key the
|
|
785
|
+
* interactive transcript filed the visible block under. The host MUST reuse it
|
|
786
|
+
* when emitting the synthetic completion, or that block never resolves.
|
|
787
|
+
*
|
|
788
|
+
* Returns the result to persist for that block — always, since every settle
|
|
789
|
+
* needs a paired result or `buildSessionContext` strips the block as dangling.
|
|
790
|
+
* Only the host knows the phase grouping the todo renderer replays from, so the
|
|
791
|
+
* provider persists this value verbatim. When no handler is registered at all,
|
|
792
|
+
* the provider falls back to its own summary-only result.
|
|
793
|
+
*/
|
|
794
|
+
export type CursorTodoSyncHandler = (snapshot: CursorTodoSnapshot | null, toolCallId: string, error: string | null) => ToolResultMessage;
|
|
727
795
|
export interface CursorShellStreamCallbacks {
|
|
728
796
|
onStdout(data: string): void;
|
|
729
797
|
onStderr(data: string): void;
|
|
@@ -738,6 +806,8 @@ export interface CursorExecHandlers {
|
|
|
738
806
|
shellStream?: (args: ShellArgs, callbacks: CursorShellStreamCallbacks) => Promise<CursorExecHandlerResult<ShellResult>>;
|
|
739
807
|
diagnostics?: (args: DiagnosticsArgs) => Promise<CursorExecHandlerResult<DiagnosticsResult>>;
|
|
740
808
|
mcp?: (call: CursorMcpCall) => Promise<CursorExecHandlerResult<McpResult>>;
|
|
809
|
+
/** Mirror Cursor's server-owned todo list into local session state. */
|
|
810
|
+
todoSync?: CursorTodoSyncHandler;
|
|
741
811
|
onToolResult?: CursorToolResultHandler;
|
|
742
812
|
}
|
|
743
813
|
/**
|
package/dist/types/usage.d.ts
CHANGED
|
@@ -401,6 +401,16 @@ export interface CredentialRankingStrategy {
|
|
|
401
401
|
* not block unrelated families on the same OAuth credential.
|
|
402
402
|
*/
|
|
403
403
|
blockScope?(context?: CredentialRankingContext): string | undefined;
|
|
404
|
+
/**
|
|
405
|
+
* Scopes that apply to a request, most specific first. With a context, the
|
|
406
|
+
* request's own scope plus any legacy catch-all scope whose blocks still
|
|
407
|
+
* apply to everything. Without one — reconciliation runs with no request —
|
|
408
|
+
* every scope whose blocks must be healed.
|
|
409
|
+
*
|
|
410
|
+
* A provider that scopes backoff by model family must implement this, or a
|
|
411
|
+
* block written under one scope is invisible to requests and to healing.
|
|
412
|
+
*/
|
|
413
|
+
blockScopes?(context?: CredentialRankingContext): string[];
|
|
404
414
|
/** Fallback window durations (ms) when limits don't specify durationMs. */
|
|
405
415
|
windowDefaults: {
|
|
406
416
|
primaryMs: number;
|
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.1.4",
|
|
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.1.4",
|
|
42
|
+
"@oh-my-pi/pi-utils": "17.1.4",
|
|
43
|
+
"@oh-my-pi/pi-wire": "17.1.4",
|
|
44
44
|
"arktype": "2.2.3",
|
|
45
45
|
"zod": "^4"
|
|
46
46
|
},
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { readSseEvents } from "@oh-my-pi/pi-utils";
|
|
9
9
|
import { type } from "arktype";
|
|
10
|
-
import type { AuthCredential } from "../auth-storage";
|
|
10
|
+
import type { AuthCredential, DisabledCredentialSummary } from "../auth-storage";
|
|
11
11
|
import type {
|
|
12
12
|
ClientUsageReportRequest,
|
|
13
13
|
ClientUsageReportResponse,
|
|
@@ -20,6 +20,7 @@ import type {
|
|
|
20
20
|
CredentialRefreshResponse,
|
|
21
21
|
CredentialUploadRequest,
|
|
22
22
|
CredentialUploadResponse,
|
|
23
|
+
DisabledCredentialsResponse,
|
|
23
24
|
HealthzResponse,
|
|
24
25
|
SnapshotResponse,
|
|
25
26
|
SnapshotStreamEvent,
|
|
@@ -35,6 +36,7 @@ import {
|
|
|
35
36
|
credentialDisableResponseSchema,
|
|
36
37
|
credentialRefreshResponseSchema,
|
|
37
38
|
credentialUploadResponseSchema,
|
|
39
|
+
disabledCredentialsResponseSchema,
|
|
38
40
|
healthzResponseSchema,
|
|
39
41
|
snapshotResponseSchema,
|
|
40
42
|
snapshotStreamEventSchema,
|
|
@@ -306,6 +308,27 @@ export class AuthBrokerClient {
|
|
|
306
308
|
});
|
|
307
309
|
}
|
|
308
310
|
|
|
311
|
+
/**
|
|
312
|
+
* Disabled-credential tombstones (identity + cause, no token material).
|
|
313
|
+
* Returns an empty list against brokers predating `GET
|
|
314
|
+
* /v1/credentials/disabled` (404).
|
|
315
|
+
*/
|
|
316
|
+
async listDisabledCredentials(provider?: string, signal?: AbortSignal): Promise<DisabledCredentialSummary[]> {
|
|
317
|
+
const params = new URLSearchParams();
|
|
318
|
+
if (provider) params.set("provider", provider);
|
|
319
|
+
const path = `/v1/credentials/disabled${params.size > 0 ? `?${params.toString()}` : ""}`;
|
|
320
|
+
try {
|
|
321
|
+
const response = await this.#request<DisabledCredentialsResponse>("GET", path, {
|
|
322
|
+
schema: disabledCredentialsResponseSchema,
|
|
323
|
+
signal,
|
|
324
|
+
});
|
|
325
|
+
return response.disabled;
|
|
326
|
+
} catch (error) {
|
|
327
|
+
if (error instanceof AuthBrokerError && error.status === 404) return [];
|
|
328
|
+
throw error;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
309
332
|
async uploadCredential(
|
|
310
333
|
provider: string,
|
|
311
334
|
credential: AuthCredential,
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
type AuthCredential,
|
|
15
15
|
type AuthCredentialSnapshotEntry,
|
|
16
16
|
type AuthCredentialStore,
|
|
17
|
+
type DisabledCredentialSummary,
|
|
17
18
|
type OAuthCredential,
|
|
18
19
|
REMOTE_REFRESH_SENTINEL,
|
|
19
20
|
type StoredAuthCredential,
|
|
@@ -471,6 +472,11 @@ export class RemoteAuthCredentialStore implements AuthCredentialStore {
|
|
|
471
472
|
return out;
|
|
472
473
|
}
|
|
473
474
|
|
|
475
|
+
/** Broker-backed disabled tombstones; empty against brokers predating the endpoint. */
|
|
476
|
+
listDisabledCredentials(provider?: string, signal?: AbortSignal): Promise<DisabledCredentialSummary[]> {
|
|
477
|
+
return this.#client.listDisabledCredentials(provider, signal);
|
|
478
|
+
}
|
|
479
|
+
|
|
474
480
|
getCredentialBlock(credentialId: number, providerKey: string, blockScope: string): number | undefined {
|
|
475
481
|
const nowMs = Date.now();
|
|
476
482
|
this.cleanExpiredCredentialBlocks(nowMs);
|
|
@@ -533,6 +539,12 @@ export class RemoteAuthCredentialStore implements AuthCredentialStore {
|
|
|
533
539
|
});
|
|
534
540
|
}
|
|
535
541
|
|
|
542
|
+
deleteCredentialBlock(_credentialId: number, _providerKey: string, _blockScope: string): void {
|
|
543
|
+
// The broker protocol only supports deleting every block for a credential.
|
|
544
|
+
// Keep scoped blocks until expiry rather than risk deleting unrelated or
|
|
545
|
+
// newer broker state through that broader operation.
|
|
546
|
+
}
|
|
547
|
+
|
|
536
548
|
deleteCredentialBlocks(credentialId: number): void {
|
|
537
549
|
this.#deleteSnapshotBlocks(credentialId);
|
|
538
550
|
for (const key of this.#credentialBlockReconcileAfter.keys()) {
|
|
@@ -22,6 +22,7 @@ import type {
|
|
|
22
22
|
CredentialDisableResponse,
|
|
23
23
|
CredentialRefreshResponse,
|
|
24
24
|
CredentialUploadResponse,
|
|
25
|
+
DisabledCredentialsResponse,
|
|
25
26
|
HealthzResponse,
|
|
26
27
|
RefresherSchedule,
|
|
27
28
|
SnapshotEntry,
|
|
@@ -659,6 +660,12 @@ export function startAuthBroker(opts: AuthBrokerServerOptions): AuthBrokerServer
|
|
|
659
660
|
return json(500, { error: message });
|
|
660
661
|
}
|
|
661
662
|
}
|
|
663
|
+
if (req.method === "GET" && pathname === "/v1/credentials/disabled") {
|
|
664
|
+
const provider = url.searchParams.get("provider") ?? undefined;
|
|
665
|
+
const disabled = await opts.storage.listDisabledCredentials(provider, req.signal);
|
|
666
|
+
const body: DisabledCredentialsResponse = { generatedAt: Date.now(), disabled };
|
|
667
|
+
return json(200, body);
|
|
668
|
+
}
|
|
662
669
|
const refreshMatch = req.method === "POST" ? pathname.match(REFRESH_ROUTE) : null;
|
|
663
670
|
if (refreshMatch) {
|
|
664
671
|
const id = Number.parseInt(refreshMatch[1], 10);
|
package/src/auth-broker/types.ts
CHANGED
|
@@ -10,6 +10,7 @@ import type {
|
|
|
10
10
|
AuthCredential,
|
|
11
11
|
AuthCredentialSnapshot,
|
|
12
12
|
AuthCredentialSnapshotEntry,
|
|
13
|
+
DisabledCredentialSummary,
|
|
13
14
|
StoredCredentialBlock,
|
|
14
15
|
} from "../auth-storage";
|
|
15
16
|
import type { ClientUsageClientSummary, ClientUsageReport, UsageHistoryEntry, UsageReport } from "../usage";
|
|
@@ -86,6 +87,12 @@ export interface CredentialDisableResponse {
|
|
|
86
87
|
ok: boolean;
|
|
87
88
|
}
|
|
88
89
|
|
|
90
|
+
/** GET /v1/credentials/disabled response body — tombstones of auto-disabled rows. */
|
|
91
|
+
export interface DisabledCredentialsResponse {
|
|
92
|
+
generatedAt: number;
|
|
93
|
+
disabled: DisabledCredentialSummary[];
|
|
94
|
+
}
|
|
95
|
+
|
|
89
96
|
/** POST /v1/credential/:id/block request body. */
|
|
90
97
|
export type CredentialBlockRequest = CredentialBlockSnapshot;
|
|
91
98
|
|
|
@@ -34,6 +34,7 @@ export const oauthCredentialSchema = type({
|
|
|
34
34
|
"accountId?": "string",
|
|
35
35
|
"orgId?": "string",
|
|
36
36
|
"orgName?": "string",
|
|
37
|
+
"authorizedAt?": "number",
|
|
37
38
|
});
|
|
38
39
|
|
|
39
40
|
/** OAuth credential as it appears in broker snapshots — refresh replaced with sentinel. */
|
|
@@ -49,6 +50,7 @@ export const remoteOauthCredentialSchema = type({
|
|
|
49
50
|
"accountId?": "string",
|
|
50
51
|
"orgId?": "string",
|
|
51
52
|
"orgName?": "string",
|
|
53
|
+
"authorizedAt?": "number",
|
|
52
54
|
});
|
|
53
55
|
|
|
54
56
|
export const apiKeyCredentialSchema = type({
|
|
@@ -320,6 +322,27 @@ export const credentialDisableResponseSchema = type({
|
|
|
320
322
|
ok: "boolean",
|
|
321
323
|
});
|
|
322
324
|
|
|
325
|
+
/** One disabled-credential tombstone — identity + cause, never token material. */
|
|
326
|
+
export const disabledCredentialSummarySchema = type({
|
|
327
|
+
"+": "reject",
|
|
328
|
+
id: "number.integer",
|
|
329
|
+
provider: type("string").atLeastLength(1),
|
|
330
|
+
type: "'oauth' | 'api_key'",
|
|
331
|
+
"email?": "string",
|
|
332
|
+
"accountId?": "string",
|
|
333
|
+
"orgId?": "string",
|
|
334
|
+
"orgName?": "string",
|
|
335
|
+
cause: "string",
|
|
336
|
+
"disabledAtMs?": "number",
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
/** Broker `GET /v1/credentials/disabled` response. */
|
|
340
|
+
export const disabledCredentialsResponseSchema = type({
|
|
341
|
+
"+": "reject",
|
|
342
|
+
generatedAt: "number",
|
|
343
|
+
disabled: disabledCredentialSummarySchema.array(),
|
|
344
|
+
});
|
|
345
|
+
|
|
323
346
|
// ─── Credential blocks ──────────────────────────────────────────────────────
|
|
324
347
|
|
|
325
348
|
export const credentialBlockRequestSchema = credentialBlockSnapshotSchema;
|