@gajae-code/ai 0.15.5 → 0.16.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.
Files changed (88) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/dist/types/adapter-internals/aws-region.d.ts +7 -0
  3. package/dist/types/auth-broker/client.d.ts +6 -2
  4. package/dist/types/auth-broker/remote-store.d.ts +14 -2
  5. package/dist/types/auth-broker/types.d.ts +6 -0
  6. package/dist/types/auth-broker/wire-schemas.d.ts +19 -0
  7. package/dist/types/auth-gateway/server.d.ts +39 -5
  8. package/dist/types/auth-gateway/types.d.ts +16 -2
  9. package/dist/types/auth-storage.d.ts +92 -24
  10. package/dist/types/core.d.ts +1 -0
  11. package/dist/types/index.d.ts +1 -0
  12. package/dist/types/provider-models/openai-compat.d.ts +1 -0
  13. package/dist/types/providers/anthropic.d.ts +1 -1
  14. package/dist/types/providers/google-gemini-headers.d.ts +1 -1
  15. package/dist/types/providers/openai-codex-responses.d.ts +6 -0
  16. package/dist/types/providers/register-builtins.d.ts +12 -12
  17. package/dist/types/stream.d.ts +2 -1
  18. package/dist/types/types.d.ts +22 -2
  19. package/dist/types/utils/oauth/api-key-login.d.ts +4 -1
  20. package/dist/types/utils/oauth/api-key-validation.d.ts +12 -6
  21. package/dist/types/utils/oauth/commandcode.d.ts +1 -0
  22. package/dist/types/utils/oauth/types.d.ts +1 -1
  23. package/dist/types/utils/retry.d.ts +2 -0
  24. package/dist/types/utils/schema/normalize.d.ts +0 -5
  25. package/dist/types/utils/sqlite-errors.d.ts +4 -0
  26. package/package.json +3 -3
  27. package/src/adapter-internals/aws-region.d.ts +7 -0
  28. package/src/adapter-internals/aws-region.ts +14 -0
  29. package/src/auth-broker/client.ts +41 -13
  30. package/src/auth-broker/redact.ts +25 -1
  31. package/src/auth-broker/remote-store.ts +374 -115
  32. package/src/auth-broker/server.ts +131 -91
  33. package/src/auth-broker/types.ts +6 -0
  34. package/src/auth-broker/wire-schemas.ts +6 -0
  35. package/src/auth-gateway/server.ts +447 -79
  36. package/src/auth-gateway/types.ts +28 -2
  37. package/src/auth-storage.ts +672 -168
  38. package/src/cli.ts +1 -0
  39. package/src/core.ts +1 -0
  40. package/src/index.ts +1 -0
  41. package/src/model-thinking.ts +8 -0
  42. package/src/models.json +1224 -3
  43. package/src/provider-models/descriptors.ts +3 -1
  44. package/src/provider-models/openai-compat.ts +102 -1
  45. package/src/providers/amazon-bedrock.ts +5 -1
  46. package/src/providers/anthropic.d.ts +1 -1
  47. package/src/providers/anthropic.ts +8 -2
  48. package/src/providers/aws-credentials.ts +6 -0
  49. package/src/providers/azure-openai-responses.ts +4 -1
  50. package/src/providers/cursor.ts +256 -101
  51. package/src/providers/gitlab-duo.ts +18 -1
  52. package/src/providers/google-gemini-cli.ts +3 -0
  53. package/src/providers/google-gemini-headers.d.ts +1 -1
  54. package/src/providers/google-gemini-headers.ts +1 -1
  55. package/src/providers/google-shared.ts +3 -0
  56. package/src/providers/kiro-api-key.ts +33 -8
  57. package/src/providers/kiro-codewhisperer.ts +28 -9
  58. package/src/providers/ollama.ts +3 -0
  59. package/src/providers/openai-codex-responses.d.ts +6 -0
  60. package/src/providers/openai-codex-responses.ts +37 -8
  61. package/src/providers/openai-completions.ts +11 -1
  62. package/src/providers/openai-responses.ts +10 -1
  63. package/src/providers/pi-native-client.ts +25 -1
  64. package/src/providers/pi-native-server.ts +24 -0
  65. package/src/providers/register-builtins.d.ts +12 -12
  66. package/src/providers/register-builtins.ts +16 -3
  67. package/src/stream.d.ts +2 -1
  68. package/src/stream.ts +175 -67
  69. package/src/types.d.ts +22 -2
  70. package/src/types.ts +27 -1
  71. package/src/utils/oauth/api-key-login.ts +13 -2
  72. package/src/utils/oauth/api-key-validation.ts +242 -41
  73. package/src/utils/oauth/commandcode.ts +17 -0
  74. package/src/utils/oauth/index.ts +20 -5
  75. package/src/utils/oauth/kiro.ts +91 -22
  76. package/src/utils/oauth/types.d.ts +1 -1
  77. package/src/utils/oauth/types.ts +1 -0
  78. package/src/utils/retry.d.ts +2 -0
  79. package/src/utils/retry.ts +15 -2
  80. package/src/utils/schema/dereference.ts +169 -49
  81. package/src/utils/schema/draft.ts +46 -23
  82. package/src/utils/schema/normalize.d.ts +0 -5
  83. package/src/utils/schema/normalize.ts +396 -119
  84. package/src/utils/schema/types.ts +3 -1
  85. package/src/utils/schema/zod-decontaminate.ts +83 -29
  86. package/src/utils/sqlite-errors.d.ts +4 -0
  87. package/src/utils/sqlite-errors.ts +13 -0
  88. package/src/utils/tool-choice-capability.ts +2 -3
@@ -15,6 +15,11 @@ export type ApiKeyCredential = {
15
15
  type: "api_key";
16
16
  key: string;
17
17
  };
18
+ /**
19
+ * Extracts the bearer token from the structured API-key form used by OAuth
20
+ * providers that need to carry token metadata alongside the access token.
21
+ */
22
+ export declare function extractStructuredApiKeyToken(apiKey: string): string | undefined;
18
23
  export interface MCPOAuthBinding {
19
24
  /** Exact HTTP(S) origin of the MCP resource endpoint. */
20
25
  resourceOrigin: string;
@@ -203,6 +208,7 @@ export interface AuthCredentialSnapshotEntry {
203
208
  provider: string;
204
209
  credential: SnapshotCredential;
205
210
  identityKey: string | null;
211
+ revision?: number;
206
212
  }
207
213
  export type AuthCredentialIfAbsentReason = "inserted" | "updated-existing" | "skipped-existing" | "skipped-existing-runtime" | "skipped-existing-config" | "skipped-existing-env" | "skipped-existing-fallback" | "skipped-invalid";
208
214
  export interface AuthCredentialIfAbsentResult {
@@ -253,8 +259,20 @@ export type OAuthRefreshLeaseClaim = {
253
259
  } | {
254
260
  kind: "missing";
255
261
  };
262
+ /**
263
+ * Store-owned ticket that orders a provider admission against remote
264
+ * credential snapshot application. The ticket is intentionally released at
265
+ * provider admission, not response completion.
266
+ */
267
+ export interface CredentialDispatchTicket {
268
+ release(): void;
269
+ }
256
270
  export interface AuthCredentialStore {
257
271
  close(): void;
272
+ refreshSnapshot?(signal?: AbortSignal): Promise<unknown>;
273
+ onSnapshotChanged?(listener: () => void): () => void;
274
+ /** Order provider admission with remote snapshot authority application. */
275
+ acquireCredentialDispatchTicket?(provider: Provider, signal?: AbortSignal): Promise<CredentialDispatchTicket>;
258
276
  listAuthCredentials(provider?: string): StoredAuthCredential[];
259
277
  /** Payload-free account inventory; active and soft-disabled rows are included. */
260
278
  listCredentialInventory?(provider?: string): CredentialInventoryRecord[];
@@ -265,6 +283,7 @@ export interface AuthCredentialStore {
265
283
  updateAuthCredential(id: number, credential: AuthCredential): void;
266
284
  deleteAuthCredential(id: number, disabledCause: string): void;
267
285
  tryDisableAuthCredentialIfMatches(id: number, expectedData: string, disabledCause: string): boolean;
286
+ tryDisableAuthCredentialIfRevision?(id: number, expectedRevision: number, disabledCause: string): boolean;
268
287
  replaceAuthCredentialsForProvider(provider: string, credentials: AuthCredential[]): StoredAuthCredential[];
269
288
  upsertAuthCredentialForProvider(provider: string, credential: AuthCredential): StoredAuthCredential[];
270
289
  upsertAuthCredentialForProviderIfAbsent(provider: string, credential: AuthCredential): AuthCredentialIfAbsentResult;
@@ -273,6 +292,8 @@ export interface AuthCredentialStore {
273
292
  includeExpired?: boolean;
274
293
  }): string | null;
275
294
  setCache(key: string, value: string, expiresAtSec: number): void;
295
+ /** Atomically allocate a durable sequence for broker restart epochs. */
296
+ allocateMonotonicSequence(key: string, expiresAtSec: number): number;
276
297
  deleteCachePrefix?(prefix: string): void;
277
298
  cleanExpiredCache(): void;
278
299
  /**
@@ -320,6 +341,7 @@ export interface AuthCredentialStore {
320
341
  * `signal` propagates the agent's cancel down to the broker fetch.
321
342
  */
322
343
  fetchUsageReports?(signal?: AbortSignal): Promise<UsageReport[] | null>;
344
+ fetchUsageReportsForProvider?(provider: Provider, signal?: AbortSignal): Promise<UsageReport[] | null>;
323
345
  /** Synchronous, zero-network usage presentation peek. */
324
346
  peekCachedUsagePresentation?(provider: Provider, credentialId: number): CachedUsagePresentation | undefined;
325
347
  /** Record a safe usage observation after an explicit fetch/check. */
@@ -360,6 +382,16 @@ export interface AuthCredentialStore {
360
382
  markCredentialSuspect?(credentialId: number, opts?: {
361
383
  signal?: AbortSignal;
362
384
  }): Promise<void>;
385
+ /**
386
+ * Optional async write hook to disable one credential through an authoritative
387
+ * remote store. Remote clients MUST use this hook instead of the synchronous
388
+ * local delete methods when an OAuth refresh fails definitively.
389
+ *
390
+ * Returns `false` when the row is already absent (for example, a peer
391
+ * disabled it first). Implementations MUST NOT treat a failed remote write as
392
+ * a successful local deletion.
393
+ */
394
+ disableAuthCredentialRemote?(credentialId: number, disabledCause: string, signal?: AbortSignal, expectedRevision?: number): Promise<boolean>;
363
395
  /**
364
396
  * Optional async write hook for upserting a single credential. When present,
365
397
  * `AuthStorage.#upsertOAuthCredential` routes through this instead of the
@@ -468,10 +500,13 @@ export type AuthStorageOptions = {
468
500
  * AuthStorage caller surfaces that to its own consumer unchanged.
469
501
  */
470
502
  fetchUsageReports?: (signal?: AbortSignal) => Promise<UsageReport[] | null>;
503
+ fetchUsageReportsForProvider?: (provider: Provider, signal?: AbortSignal) => Promise<UsageReport[] | null>;
471
504
  };
472
- type AuthApiKeyOptions = {
505
+ export type AuthApiKeyOptions = {
473
506
  baseUrl?: string;
474
507
  modelId?: string;
508
+ /** Select config registrations owned by one caller (for example a ModelRegistry). */
509
+ owner?: object;
475
510
  /**
476
511
  * Caller's cancel signal. Threaded into any broker-bound OAuth refresh so
477
512
  * `ESC` / request abort actually kills a hung broker fetch instead of
@@ -506,7 +541,11 @@ export interface OAuthAccess {
506
541
  export interface InvalidateCredentialMatchingOptions {
507
542
  signal?: AbortSignal;
508
543
  sessionId?: string;
544
+ owner?: object;
509
545
  }
546
+ /** Read optional broker error detail without allowing hostile objects to escape classification. */
547
+ /** @internal Tested directly because hostile accessors must preserve the original error identity. */
548
+ export declare function readBrokerErrorBody(error: unknown): string | undefined;
510
549
  /**
511
550
  * Credential storage backed by an AuthCredentialStore.
512
551
  * Reads from storage on reload(), manages round-robin credential selection,
@@ -528,9 +567,14 @@ export declare class AuthStorage {
528
567
  */
529
568
  close(): void;
530
569
  getGeneration(): number;
570
+ getCache(key: string, options?: {
571
+ includeExpired?: boolean;
572
+ }): string | null;
573
+ setCache(key: string, value: string, expiresAtSec: number): void;
574
+ allocateMonotonicSequence(key: string, expiresAtSec: number): number;
531
575
  getProviderConfigurationGeneration(provider: string): number;
532
576
  getProviderOAuthRefreshGeneration(provider: string): number;
533
- getProviderEvidenceGeneration(provider: string, resolvedApiKey?: string): string;
577
+ getProviderEvidenceGeneration(provider: string, resolvedApiKey?: string, owner?: object): string;
534
578
  onGenerationChanged(listener: (generation: number) => void): () => void;
535
579
  offGenerationChanged(listener: (generation: number) => void): void;
536
580
  /**
@@ -568,8 +612,12 @@ export declare class AuthStorage {
568
612
  hasCredentialScopeLease(scopeId: string): boolean;
569
613
  /** Release one credential-scope lease; final release clears only that scope's derived state. */
570
614
  releaseCredentialScope(scopeId: string): void;
571
- /** Set the selector derived from a durable session pin or a session seed. */
572
- setSessionCredentialSelector(scopeId: string, provider: string, selector: AuthCredentialSelector): void;
615
+ /**
616
+ * Set the selector derived from a durable session pin or a session seed.
617
+ * `owner` scopes config-override validation to one ModelRegistry; omitted
618
+ * owners retain process-wide caller semantics.
619
+ */
620
+ setSessionCredentialSelector(scopeId: string, provider: string, selector: AuthCredentialSelector, owner?: object): void;
573
621
  /** Explicitly mask persistent/process-global selection and return the provider to AUTO for one scope. */
574
622
  setSessionCredentialAuto(provider: string, scopeId: string): void;
575
623
  /** Clear a scope's explicit selector and AUTO mask, restoring normal precedence. */
@@ -581,9 +629,13 @@ export declare class AuthStorage {
581
629
  /** Resolve the effective selector precedence for a provider/scope. */
582
630
  resolveEffectiveCredentialSelector(provider: string, scopeId?: string, explicitSelector?: AuthCredentialSelector): AuthCredentialSelector | undefined;
583
631
  /** @internal Return cache provenance for an exact stored literal API-key row without resolving its value. */
584
- getStoredLiteralApiKeyEvidenceGeneration(provider: string, selector: AuthCredentialSelector): string | undefined;
585
- /** Validate and canonicalize an OAuth-only selector for account pinning. */
586
- resolveOAuthPinTarget(provider: string, selector: AuthCredentialSelector): OAuthPinTarget;
632
+ getStoredLiteralApiKeyEvidenceGeneration(provider: string, selector: AuthCredentialSelector, owner?: object): string | undefined;
633
+ /**
634
+ * Validate and canonicalize an OAuth-only selector for account pinning.
635
+ * `owner` scopes config-override checks to one ModelRegistry; omitted owners
636
+ * retain process-wide caller semantics.
637
+ */
638
+ resolveOAuthPinTarget(provider: string, selector: AuthCredentialSelector, owner?: object): OAuthPinTarget;
587
639
  /** Return all local inventory rows, including soft-disabled metadata, without payloads. */
588
640
  listCredentialInventory(provider?: string): CredentialInventoryRecord[];
589
641
  /** Return local credential hard-removal action targets, including disabled rows. */
@@ -617,7 +669,7 @@ export declare class AuthStorage {
617
669
  /** Whether a provider is currently authenticated by a runtime API-key override. */
618
670
  hasRuntimeApiKey(provider: string): boolean;
619
671
  /** Whether a provider is currently authenticated by a config API-key override. */
620
- hasConfigApiKey(provider: string): boolean;
672
+ hasConfigApiKey(provider: string, owner?: object): boolean;
621
673
  /**
622
674
  * Whether credential selection for a provider is pinned to one stored row by
623
675
  * a runtime selector (`--credential`).
@@ -664,7 +716,8 @@ export declare class AuthStorage {
664
716
  * runtime API-key override (`--api-key`), or a config-sourced API key
665
717
  * (`models.yml` `apiKey`) would each re-decide the credential on the very
666
718
  * next {@link AuthStorage.getApiKey} call and make this switch appear to
667
- * silently do nothing.
719
+ * silently do nothing. `owner` scopes the config-override check to one
720
+ * ModelRegistry; omitted owners retain process-wide caller semantics.
668
721
  *
669
722
  * Deliberately does not touch credential-blocked state: if the target row
670
723
  * is still backoff-blocked from a prior quota failure, the existing
@@ -672,7 +725,7 @@ export declare class AuthStorage {
672
725
  * falls back to a usable account instead of re-issuing a request that would
673
726
  * just draw another 429/quota error.
674
727
  */
675
- switchSessionCredential(provider: string, sessionId: string, selector: AuthCredentialSelector): void;
728
+ switchSessionCredential(provider: string, sessionId: string, selector: AuthCredentialSelector, owner?: object): void;
676
729
  /**
677
730
  * Register a per-provider API key sourced from user configuration
678
731
  * (e.g. `models.yml` `providers.<name>.apiKey`). Higher priority than
@@ -683,6 +736,9 @@ export declare class AuthStorage {
683
736
  * Lower priority than {@link setRuntimeApiKey} so a CLI `--api-key`
684
737
  * still wins for the duration of a single invocation.
685
738
  *
739
+ * `options.owner` scopes the override to one registry or other caller. The
740
+ * unscoped form is process-wide and is retained for standalone callers.
741
+ *
686
742
  * `options.envSourced` marks the value as resolved from a models.yml
687
743
  * `apiKeyEnv` indirection. Unlike a literal pin, an env pointer only says
688
744
  * where to look for a key; when the user has since run `auth login`, the
@@ -692,25 +748,33 @@ export declare class AuthStorage {
692
748
  */
693
749
  setConfigApiKey(provider: string, apiKey: string, options?: {
694
750
  envSourced?: boolean;
751
+ owner?: object;
695
752
  }): void;
696
753
  /**
697
754
  * Remove a single config-sourced API key override.
698
755
  */
699
- removeConfigApiKey(provider: string): void;
756
+ removeConfigApiKey(provider: string, owner?: object): void;
700
757
  /**
701
- * Drop every config-sourced API key. Called by `ModelRegistry` before
702
- * re-parsing `models.yml` so removed entries actually disappear.
758
+ * Drop config-sourced API keys. An owner removes only its own registrations;
759
+ * the unscoped form remains an explicit global reset for callers that own the
760
+ * entire AuthStorage instance.
703
761
  */
704
- clearConfigApiKeys(): void;
762
+ clearConfigApiKeys(owner?: object): void;
705
763
  /**
706
764
  * Set a fallback resolver for API keys not found in storage or env vars.
707
765
  * Used for custom provider keys from models.json.
708
766
  */
709
- setFallbackResolver(resolver: (provider: string) => string | undefined): void;
767
+ setFallbackResolver(resolver: (provider: string) => string | undefined, owner?: object): () => void;
710
768
  /**
711
769
  * Reload credentials from storage.
712
770
  */
713
771
  reload(): Promise<void>;
772
+ /**
773
+ * Acquire a store-owned provider-admission ticket when the backing store
774
+ * provides one (for example, a remote broker snapshot store). Local stores
775
+ * need no additional ordering and return `undefined`.
776
+ */
777
+ acquireCredentialDispatchTicket(provider: Provider, signal?: AbortSignal): Promise<CredentialDispatchTicket | undefined>;
714
778
  /** Returns the credential type selected for a provider/session, if one has been recorded. */
715
779
  getSessionCredentialType(provider: string, sessionId?: string): AuthCredential["type"] | undefined;
716
780
  /**
@@ -721,7 +785,7 @@ export declare class AuthStorage {
721
785
  * Set credential for a provider.
722
786
  */
723
787
  set(provider: string, credential: AuthCredentialEntry): Promise<void>;
724
- importCredentialIfAbsent(provider: string, credential: AuthCredential): Promise<AuthCredentialIfAbsentSnapshotResult>;
788
+ importCredentialIfAbsent(provider: string, credential: AuthCredential, owner?: object): Promise<AuthCredentialIfAbsentSnapshotResult>;
725
789
  /**
726
790
  * Remove credential for a provider.
727
791
  */
@@ -734,17 +798,18 @@ export declare class AuthStorage {
734
798
  * Check if credentials exist for a provider in storage.
735
799
  */
736
800
  has(provider: string): boolean;
737
- hasAuth(provider: string, sessionId?: string): boolean;
801
+ disableCredentialByIdIfRevision(id: number, expectedRevision: number, disabledCause: string): boolean;
802
+ hasAuth(provider: string, sessionId?: string, options?: Pick<AuthApiKeyOptions, "owner">): boolean;
738
803
  /**
739
804
  * Credential type that a provider/session will dispatch first without performing I/O.
740
805
  * Mirrors getApiKey selector validation, overrides, session OAuth stickiness,
741
806
  * cached command-key usability, OAuth retry, and environment fallback order.
742
807
  */
743
- getEffectiveCredentialType(provider: string, sessionId?: string): AuthCredential["type"] | undefined;
808
+ getEffectiveCredentialType(provider: string, sessionId?: string, options?: Pick<AuthApiKeyOptions, "owner">): AuthCredential["type"] | undefined;
744
809
  /**
745
810
  * Check whether configured auth is currently usable without resolving credentials.
746
811
  */
747
- hasUsableAuth(provider: string): boolean;
812
+ hasUsableAuth(provider: string, options?: Pick<AuthApiKeyOptions, "owner">): boolean;
748
813
  /**
749
814
  * Check if OAuth credentials are configured for a provider.
750
815
  */
@@ -752,7 +817,7 @@ export declare class AuthStorage {
752
817
  /**
753
818
  * Get OAuth credentials for a provider.
754
819
  */
755
- getOAuthCredential(provider: string, sessionId?: string): OAuthCredential | undefined;
820
+ getOAuthCredential(provider: string, sessionId?: string, options?: Pick<AuthApiKeyOptions, "owner">): OAuthCredential | undefined;
756
821
  /**
757
822
  * Get the OAuth `accountId` for a provider, preferring the credential that is
758
823
  * session-sticky for `sessionId` when multiple OAuth credentials are configured.
@@ -760,7 +825,7 @@ export declare class AuthStorage {
760
825
  * first call before any `getApiKey` has been issued, or single-credential setups).
761
826
  * Returns `undefined` when no OAuth credential carries an `accountId`.
762
827
  */
763
- getOAuthAccountId(provider: string, sessionId?: string): string | undefined;
828
+ getOAuthAccountId(provider: string, sessionId?: string, options?: Pick<AuthApiKeyOptions, "owner">): string | undefined;
764
829
  /**
765
830
  * Get all credentials.
766
831
  */
@@ -785,6 +850,7 @@ export declare class AuthStorage {
785
850
  */
786
851
  logout(provider: string): Promise<void>;
787
852
  fetchUsageReports(options?: {
853
+ provider?: Provider;
788
854
  baseUrlResolver?: (provider: Provider) => string | undefined;
789
855
  /** Caller's cancel signal; only rejects this caller, never the shared upstream fetch. */
790
856
  signal?: AbortSignal;
@@ -829,6 +895,7 @@ export declare class AuthStorage {
829
895
  retryAfterMs?: number;
830
896
  baseUrl?: string;
831
897
  signal?: AbortSignal;
898
+ owner?: object;
832
899
  }): Promise<boolean>;
833
900
  /**
834
901
  * Earliest instant at which any currently blocked stored credential for this
@@ -844,7 +911,7 @@ export declare class AuthStorage {
844
911
  * and get a best-effort token. For GitHub Copilot we preserve enterprise
845
912
  * routing metadata so discovery can hit the correct host.
846
913
  */
847
- peekApiKey(provider: string): Promise<string | undefined>;
914
+ peekApiKey(provider: string, options?: Pick<AuthApiKeyOptions, "owner">): Promise<string | undefined>;
848
915
  /**
849
916
  * Get API key for a provider.
850
917
  * Priority:
@@ -936,7 +1003,7 @@ export declare class AuthStorage {
936
1003
  *
937
1004
  * The string is purely informational; consumers must not parse it.
938
1005
  */
939
- describeCredentialSource(provider: string, sessionId?: string): string | undefined;
1006
+ describeCredentialSource(provider: string, sessionId?: string, options?: Pick<AuthApiKeyOptions, "owner">): string | undefined;
940
1007
  }
941
1008
  /**
942
1009
  * Default SQLite-backed implementation of {@link AuthCredentialStore}.
@@ -969,11 +1036,13 @@ export declare class SqliteAuthCredentialStore implements AuthCredentialStore {
969
1036
  * row between our pre-check and the disable.
970
1037
  */
971
1038
  tryDisableAuthCredentialIfMatches(id: number, expectedData: string, disabledCause: string): boolean;
1039
+ tryDisableAuthCredentialIfRevision(id: number, expectedRevision: number, disabledCause: string): boolean;
972
1040
  deleteAuthCredentialsForProvider(provider: string, disabledCause: string): void;
973
1041
  getCache(key: string, options?: {
974
1042
  includeExpired?: boolean;
975
1043
  }): string | null;
976
1044
  setCache(key: string, value: string, expiresAtSec: number): void;
1045
+ allocateMonotonicSequence(key: string, expiresAtSec: number): number;
977
1046
  deleteCachePrefix(prefix: string): void;
978
1047
  cleanExpiredCache(): void;
979
1048
  /**
@@ -1003,4 +1072,3 @@ export declare class SqliteAuthCredentialStore implements AuthCredentialStore {
1003
1072
  deleteProvider(provider: string): void;
1004
1073
  close(): void;
1005
1074
  }
1006
- export {};
@@ -31,5 +31,6 @@ export type { OAuthCredentials, OAuthProvider, OAuthProviderId, OAuthProviderInf
31
31
  export * from "./utils/overflow";
32
32
  export * from "./utils/retry";
33
33
  export * from "./utils/schema";
34
+ export * from "./utils/sqlite-errors";
34
35
  export * from "./utils/tool-choice-capability";
35
36
  export * from "./utils/validation";
@@ -51,5 +51,6 @@ export * from "./utils/overflow";
51
51
  export * from "./utils/provider-safety-stop";
52
52
  export * from "./utils/retry";
53
53
  export * from "./utils/schema";
54
+ export * from "./utils/sqlite-errors";
54
55
  export * from "./utils/tool-choice-capability";
55
56
  export * from "./utils/validation";
@@ -98,6 +98,7 @@ export interface OpenCodeModelManagerConfig {
98
98
  }
99
99
  export declare function opencodeZenModelManagerOptions(config?: OpenCodeModelManagerConfig): ModelManagerOptions<"openai-completions">;
100
100
  export declare function opencodeGoModelManagerOptions(config?: OpenCodeModelManagerConfig): ModelManagerOptions<"openai-completions">;
101
+ export declare function commandCodeModelManagerOptions(config?: OpenCodeModelManagerConfig): ModelManagerOptions<Api>;
101
102
  export interface OllamaModelManagerConfig {
102
103
  apiKey?: string;
103
104
  baseUrl?: string;
@@ -107,7 +107,7 @@ export interface CpaToolAliasRestoreFailure {
107
107
  */
108
108
  export declare function parseCpaToolAliasRestoreFailure(error: unknown): CpaToolAliasRestoreFailure | undefined;
109
109
  export declare function isCpaToolAliasRestoreFailure(error: unknown): boolean;
110
- export declare const claudeCodeVersion = "2.1.219";
110
+ export declare const claudeCodeVersion = "2.1.257";
111
111
  export declare const claudeCodeEntrypoint = "sdk-cli";
112
112
  export declare const claudeToolPrefix: string;
113
113
  export declare const claudeCodeSystemInstruction = "You are a Claude agent, built on Anthropic's Claude Agent SDK.";
@@ -5,7 +5,7 @@
5
5
  */
6
6
  export declare const GEMINI_CLI_VERSION_ENV = "GJC_AI_GEMINI_CLI_VERSION";
7
7
  export declare const LEGACY_GEMINI_CLI_VERSION_ENV = "PI_AI_GEMINI_CLI_VERSION";
8
- export declare const DEFAULT_GEMINI_CLI_VERSION = "0.52.0";
8
+ export declare const DEFAULT_GEMINI_CLI_VERSION = "0.58.0";
9
9
  export declare function getGeminiCliUserAgent(modelId?: string): string;
10
10
  export declare const getGeminiCliHeaders: (modelId?: string) => {
11
11
  "User-Agent": string;
@@ -25,6 +25,12 @@ export declare function normalizeCodexToolChoice(choice: ToolChoice | undefined,
25
25
  export declare function formatCodexUserAgent(platform: string, release: string, arch: string): string;
26
26
  export declare const streamOpenAICodexResponses: StreamFunction<"openai-codex-responses">;
27
27
  export declare function prewarmOpenAICodexResponses(model: Model<"openai-codex-responses">, options?: Pick<OpenAICodexResponsesOptions, "apiKey" | "headers" | "sessionId" | "signal" | "preferWebsockets" | "providerSessionState">): Promise<void>;
28
+ /**
29
+ * Bun 1.4.0's Windows WebSocket client can segfault during TLS handshakes.
30
+ * Keep the model's websocket preference available on other platforms, while
31
+ * requiring an explicit opt-in on Windows until the bundled runtime is fixed.
32
+ */
33
+ export declare function isCodexWebSocketSafeByDefault(platform?: NodeJS.Platform): boolean;
28
34
  export interface OpenAICodexTransportDetails {
29
35
  websocketPreferred: boolean;
30
36
  lastTransport?: CodexTransport;
@@ -44,16 +44,16 @@ export declare function resolveLazyStreamFirstEventFallbackMs(provider: string,
44
44
  export declare const PROVIDER_RUNTIME_DESCRIPTORS: readonly ProviderRuntimeDescriptor<Api, unknown>[];
45
45
  /** Return the lazy descriptor for a built-in API, if one is registered. */
46
46
  export declare function getProviderRuntimeDescriptor<TApi extends Api>(api: TApi): ProviderRuntimeDescriptor<TApi, unknown> | undefined;
47
- export declare const streamAnthropic: (model: Model<"anthropic-messages">, context: Context, options: OptionsForApi<"anthropic-messages">) => EventStreamImpl;
48
- export declare const streamAzureOpenAIResponses: (model: Model<"azure-openai-responses">, context: Context, options: OptionsForApi<"azure-openai-responses">) => EventStreamImpl;
49
- export declare const streamGoogle: (model: Model<"google-generative-ai">, context: Context, options: OptionsForApi<"google-generative-ai">) => EventStreamImpl;
50
- export declare const streamGoogleGeminiCli: (model: Model<"google-gemini-cli">, context: Context, options: OptionsForApi<"google-gemini-cli">) => EventStreamImpl;
51
- export declare const streamGoogleVertex: (model: Model<"google-vertex">, context: Context, options: OptionsForApi<"google-vertex">) => EventStreamImpl;
52
- export declare const streamOpenAICodexResponses: (model: Model<"openai-codex-responses">, context: Context, options: OptionsForApi<"openai-codex-responses">) => EventStreamImpl;
53
- export declare const streamOpenAICompletions: (model: Model<"openai-completions">, context: Context, options: OptionsForApi<"openai-completions">) => EventStreamImpl;
54
- export declare const streamOpenAIResponses: (model: Model<"openai-responses">, context: Context, options: OptionsForApi<"openai-responses">) => EventStreamImpl;
55
- export declare const streamCursor: (model: Model<"cursor-agent">, context: Context, options: OptionsForApi<"cursor-agent">) => EventStreamImpl;
56
- export declare const streamOllama: (model: Model<"ollama-chat">, context: Context, options: OptionsForApi<"ollama-chat">) => EventStreamImpl;
57
- export declare const streamBedrock: (model: Model<"bedrock-converse-stream">, context: Context, options: OptionsForApi<"bedrock-converse-stream">) => EventStreamImpl;
58
- export declare const streamKiroCodeWhisperer: (model: Model<"kiro-codewhisperer-stream">, context: Context, options: OptionsForApi<"kiro-codewhisperer-stream">) => EventStreamImpl;
47
+ export declare const streamAnthropic: (model: Model<"anthropic-messages">, context: Context, options: OptionsForApi<"anthropic-messages">, onStreamCreated?: () => void) => EventStreamImpl;
48
+ export declare const streamAzureOpenAIResponses: (model: Model<"azure-openai-responses">, context: Context, options: OptionsForApi<"azure-openai-responses">, onStreamCreated?: () => void) => EventStreamImpl;
49
+ export declare const streamGoogle: (model: Model<"google-generative-ai">, context: Context, options: OptionsForApi<"google-generative-ai">, onStreamCreated?: () => void) => EventStreamImpl;
50
+ export declare const streamGoogleGeminiCli: (model: Model<"google-gemini-cli">, context: Context, options: OptionsForApi<"google-gemini-cli">, onStreamCreated?: () => void) => EventStreamImpl;
51
+ export declare const streamGoogleVertex: (model: Model<"google-vertex">, context: Context, options: OptionsForApi<"google-vertex">, onStreamCreated?: () => void) => EventStreamImpl;
52
+ export declare const streamOpenAICodexResponses: (model: Model<"openai-codex-responses">, context: Context, options: OptionsForApi<"openai-codex-responses">, onStreamCreated?: () => void) => EventStreamImpl;
53
+ export declare const streamOpenAICompletions: (model: Model<"openai-completions">, context: Context, options: OptionsForApi<"openai-completions">, onStreamCreated?: () => void) => EventStreamImpl;
54
+ export declare const streamOpenAIResponses: (model: Model<"openai-responses">, context: Context, options: OptionsForApi<"openai-responses">, onStreamCreated?: () => void) => EventStreamImpl;
55
+ export declare const streamCursor: (model: Model<"cursor-agent">, context: Context, options: OptionsForApi<"cursor-agent">, onStreamCreated?: () => void) => EventStreamImpl;
56
+ export declare const streamOllama: (model: Model<"ollama-chat">, context: Context, options: OptionsForApi<"ollama-chat">, onStreamCreated?: () => void) => EventStreamImpl;
57
+ export declare const streamBedrock: (model: Model<"bedrock-converse-stream">, context: Context, options: OptionsForApi<"bedrock-converse-stream">, onStreamCreated?: () => void) => EventStreamImpl;
58
+ export declare const streamKiroCodeWhisperer: (model: Model<"kiro-codewhisperer-stream">, context: Context, options: OptionsForApi<"kiro-codewhisperer-stream">, onStreamCreated?: () => void) => EventStreamImpl;
59
59
  export {};
@@ -29,12 +29,13 @@ export declare function listProvidersWithEnvKey(): string[];
29
29
  * handling, so callers can append it unconditionally.
30
30
  */
31
31
  export declare function formatProviderCredentialHint(provider: string): string;
32
+ export declare function streamFromLazyImport(createInner: () => Promise<AssistantMessageEventStream>, signal?: AbortSignal, onStreamCreated?: () => void): AssistantMessageEventStream;
32
33
  /**
33
34
  * Build an actionable "missing API key" error for a provider, used by the
34
35
  * low-level `stream`/`complete` entry points (#755).
35
36
  */
36
37
  export declare function formatMissingApiKeyError(provider: string): string;
37
- export declare function stream<TApi extends Api>(model: Model<TApi>, context: Context, options?: OptionsForApi<TApi>): AssistantMessageEventStream;
38
+ export declare function stream<TApi extends Api>(model: Model<TApi>, context: Context, options?: OptionsForApi<TApi>, onStreamCreated?: () => void): AssistantMessageEventStream;
38
39
  export declare function complete<TApi extends Api>(model: Model<TApi>, context: Context, options?: OptionsForApi<TApi>): Promise<AssistantMessage>;
39
40
  export declare function streamSimple<TApi extends Api>(model: Model<TApi>, context: Context, options?: SimpleStreamOptions): AssistantMessageEventStream;
40
41
  export declare function completeSimple<TApi extends Api>(model: Model<TApi>, context: Context, options?: SimpleStreamOptions): Promise<AssistantMessage>;
@@ -54,7 +54,7 @@ export interface ThinkingConfig {
54
54
  /** Provider-specific transport used to encode the selected effort. */
55
55
  mode: ThinkingControlMode;
56
56
  }
57
- export declare const KNOWN_PROVIDERS: readonly ["alibaba-token-plan", "amazon-bedrock", "kiro", "azure-openai", "anthropic", "google", "google-gemini-cli", "google-antigravity", "google-vertex", "openai", "openai-codex", "opencodex", "kimi-code", "minimax-code", "minimax-code-cn", "github-copilot", "fireworks", "firepass", "fugu", "gitlab-duo", "cursor", "jetbrains-junie", "deepseek", "deepinfra", "xai", "groq", "cerebras", "openrouter", "kilo", "vercel-ai-gateway", "zai", "glm-zcode", "mistral", "minimax", "opencode-go", "opencode-zen", "opengateway", "bizrouter", "mara", "synthetic", "cloudflare-ai-gateway", "huggingface", "litellm", "moonshot", "nvidia", "nanogpt", "ollama", "ollama-cloud", "qianfan", "qwen-portal", "sglang", "together", "venice", "vllm", "xiaomi", "xiaomi-token-plan-sgp", "xiaomi-token-plan-ams", "xiaomi-token-plan-cn", "zenmux", "lm-studio", "omlx"];
57
+ export declare const KNOWN_PROVIDERS: readonly ["alibaba-token-plan", "amazon-bedrock", "kiro", "azure-openai", "anthropic", "google", "google-gemini-cli", "google-antigravity", "google-vertex", "openai", "openai-codex", "opencodex", "kimi-code", "minimax-code", "minimax-code-cn", "github-copilot", "fireworks", "firepass", "fugu", "gitlab-duo", "cursor", "jetbrains-junie", "deepseek", "deepinfra", "xai", "groq", "cerebras", "openrouter", "kilo", "vercel-ai-gateway", "zai", "glm-zcode", "mistral", "minimax", "opencode-go", "commandcode-goat", "opencode-zen", "opengateway", "bizrouter", "mara", "synthetic", "cloudflare-ai-gateway", "huggingface", "litellm", "moonshot", "nvidia", "nanogpt", "ollama", "ollama-cloud", "qianfan", "qwen-portal", "sglang", "together", "venice", "vllm", "xiaomi", "xiaomi-token-plan-sgp", "xiaomi-token-plan-ams", "xiaomi-token-plan-cn", "zenmux", "lm-studio", "omlx"];
58
58
  export type KnownProvider = (typeof KNOWN_PROVIDERS)[number];
59
59
  export declare function isKnownProvider(provider: string): provider is KnownProvider;
60
60
  export type Provider = KnownProvider | string;
@@ -155,6 +155,18 @@ export interface RawSseEvent {
155
155
  export type FetchImpl = ((input: string | URL | Request, init?: RequestInit) => Promise<Response>) & {
156
156
  preconnect?: typeof globalThis.fetch.preconnect;
157
157
  };
158
+ /**
159
+ * Credential returned by an auth retry resolver.
160
+ *
161
+ * The optional admission callback lets an authority-bearing caller retain a
162
+ * credential lease until the replacement provider request is actually
163
+ * admitted. Ordinary callers can continue returning a string from
164
+ * {@link StreamOptions.onAuthError}.
165
+ */
166
+ export interface AuthRetryCredential {
167
+ apiKey: string;
168
+ onStreamCreated?: () => void;
169
+ }
158
170
  export interface StreamOptions {
159
171
  temperature?: number;
160
172
  topP?: number;
@@ -186,7 +198,7 @@ export interface StreamOptions {
186
198
  * event has been emitted. Returning a different key retries the provider
187
199
  * request once.
188
200
  */
189
- onAuthError?: (provider: string, apiKey: string, error: unknown) => Promise<string | undefined>;
201
+ onAuthError?: (provider: string, apiKey: string, error: unknown) => Promise<string | AuthRetryCredential | undefined>;
190
202
  cacheRetention?: CacheRetention;
191
203
  /**
192
204
  * Additional headers to include in provider requests.
@@ -243,6 +255,14 @@ export interface StreamOptions {
243
255
  * The `scope` parameter carries the per-attempt identity for execution attribution.
244
256
  */
245
257
  onResponse?: (response: ProviderResponseMetadata, model?: Model<Api>, scope?: AttemptScopeRef) => void | Promise<void>;
258
+ /**
259
+ * Internal dispatch-admission hook. Providers invoke this immediately before
260
+ * submitting an outbound request; stream forwarding retains a first-response
261
+ * fallback for custom providers that do not expose a transport seam.
262
+ */
263
+ onStreamCreated?: () => void;
264
+ /** Internal authority policy: disable provider-owned retries and corrective replays. */
265
+ disableProviderRetries?: boolean;
246
266
  /**
247
267
  * Optional callback for raw Server-Sent Events as they arrive from HTTP streaming providers.
248
268
  *
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Shared factory for API-key-paste "login" flows.
3
3
  *
4
- * Several providers (Cerebras, Synthetic, Moonshot, Together, NanoGPT, ZenMux)
4
+ * Several providers (Cerebras, Synthetic, Moonshot, Together, NanoGPT, ZenMux,
5
+ * Command Code GOAT)
5
6
  * don't actually implement OAuth — they just ask the user to paste an API key,
6
7
  * optionally validate it, and return the trimmed key.
7
8
  */
@@ -11,6 +12,7 @@ type ChatCompletionsValidation = {
11
12
  provider: string;
12
13
  baseUrl: string;
13
14
  model: string;
15
+ requireInferenceResponse?: boolean;
14
16
  };
15
17
  type ModelsEndpointValidation = {
16
18
  kind: "models-endpoint";
@@ -30,6 +32,7 @@ export type ApiKeyLoginConfig = {
30
32
  placeholder: string;
31
33
  /** Validation strategy, or `null` to skip validation. */
32
34
  validation: ChatCompletionsValidation | ModelsEndpointValidation | null;
35
+ validationProgressMessage?: string;
33
36
  };
34
37
  export declare function createApiKeyLogin(config: ApiKeyLoginConfig): (options: OAuthController) => Promise<string>;
35
38
  export {};
@@ -4,12 +4,17 @@ type OpenAICompatibleValidationOptions = {
4
4
  baseUrl: string;
5
5
  model: string;
6
6
  signal?: AbortSignal;
7
+ fetch?: typeof globalThis.fetch;
8
+ requireInferenceResponse?: boolean;
9
+ timeoutMs?: number;
7
10
  };
8
11
  type ModelListValidationOptions = {
9
12
  provider: string;
10
13
  apiKey: string;
11
14
  modelsUrl: string;
12
15
  signal?: AbortSignal;
16
+ fetch?: typeof globalThis.fetch;
17
+ timeoutMs?: number;
13
18
  };
14
19
  /**
15
20
  * Validate an API key against an OpenAI-compatible chat completions endpoint.
@@ -18,16 +23,17 @@ type ModelListValidationOptions = {
18
23
  */
19
24
  export declare function validateOpenAICompatibleApiKey(options: OpenAICompatibleValidationOptions): Promise<void>;
20
25
  /**
21
- * Validate an API key against a provider models endpoint.
26
+ * Validate a provider models endpoint's reachability and response shape.
22
27
  *
23
28
  * Useful for providers where access to specific models may vary by plan and
24
- * should not block key validation.
29
+ * should not block login; an available model list is not proof that an
30
+ * authenticated inference request will succeed for the supplied key.
25
31
  *
26
32
  * A 200 status alone is NOT accepted: a captive portal, misrouting proxy, or
27
- * broken gateway can answer 200 with an HTML page or an empty JSON object, and
28
- * accepting the key on status alone would store a credential that was never
29
- * actually checked. The body must parse as JSON and carry a recognizable model
30
- * list before the key is considered validated.
33
+ * broken gateway can answer 200 with an HTML page or an empty JSON object.
34
+ * The body must parse as JSON and carry a recognizable model list before the
35
+ * endpoint is considered reachable. This catalog check is not proof that
36
+ * authenticated inference is entitled to use the supplied key.
31
37
  */
32
38
  export declare function validateApiKeyAgainstModelsEndpoint(options: ModelListValidationOptions): Promise<void>;
33
39
  export {};
@@ -0,0 +1 @@
1
+ export declare const loginCommandCode: (options: import("./types").OAuthController) => Promise<string>;
@@ -7,7 +7,7 @@ export type OAuthCredentials = {
7
7
  email?: string;
8
8
  accountId?: string;
9
9
  };
10
- export type OAuthProvider = "kiro" | "alibaba-token-plan" | "anthropic" | "bizrouter" | "mara" | "cerebras" | "cloudflare-ai-gateway" | "cursor" | "deepseek" | "deepinfra" | "fireworks" | "firepass" | "fugu" | "github-copilot" | "google-gemini-cli" | "google-antigravity" | "gitlab-duo" | "huggingface" | "kimi-code" | "kilo" | "kagi" | "litellm" | "lm-studio" | "minimax-code" | "minimax-code-cn" | "moonshot" | "nvidia" | "nanogpt" | "ollama" | "ollama-cloud" | "openai-codex" | "openai-codex-device" | "opencode-go" | "opencode-zen" | "opengateway" | "openrouter" | "parallel" | "perplexity" | "qianfan" | "qwen-portal" | "sglang" | "synthetic" | "tavily" | "together" | "venice" | "vercel-ai-gateway" | "vllm" | "xai" | "glm-zcode" | "xiaomi" | "xiaomi-token-plan-sgp" | "xiaomi-token-plan-ams" | "xiaomi-token-plan-cn" | "zenmux" | "opencodex" | "zai";
10
+ export type OAuthProvider = "kiro" | "alibaba-token-plan" | "anthropic" | "bizrouter" | "mara" | "cerebras" | "cloudflare-ai-gateway" | "cursor" | "deepseek" | "deepinfra" | "fireworks" | "firepass" | "fugu" | "github-copilot" | "google-gemini-cli" | "google-antigravity" | "gitlab-duo" | "huggingface" | "kimi-code" | "kilo" | "kagi" | "litellm" | "lm-studio" | "minimax-code" | "minimax-code-cn" | "moonshot" | "nvidia" | "nanogpt" | "ollama" | "ollama-cloud" | "openai-codex" | "openai-codex-device" | "opencode-go" | "opencode-zen" | "commandcode-goat" | "opengateway" | "openrouter" | "parallel" | "perplexity" | "qianfan" | "qwen-portal" | "sglang" | "synthetic" | "tavily" | "together" | "venice" | "vercel-ai-gateway" | "vllm" | "xai" | "glm-zcode" | "xiaomi" | "xiaomi-token-plan-sgp" | "xiaomi-token-plan-ams" | "xiaomi-token-plan-cn" | "zenmux" | "opencodex" | "zai";
11
11
  export type OAuthProviderId = OAuthProvider | (string & {});
12
12
  export type OAuthPrompt = {
13
13
  message: string;
@@ -24,4 +24,6 @@ export declare function callWithCopilotModelRetry<T>(fn: () => Promise<T>, optio
24
24
  signal?: AbortSignal;
25
25
  retryBaseDelayMs?: number;
26
26
  fallbackManaged?: boolean;
27
+ requestMaxRetries?: number;
28
+ disableProviderRetries?: boolean;
27
29
  }): Promise<T>;
@@ -25,11 +25,6 @@ export interface NormalizeSchemaOptions {
25
25
  }
26
26
  /** Copy all keys from a schema except the specified combiner key. */
27
27
  export declare function copySchemaWithout(schema: JsonObject, combiner: string): JsonObject;
28
- /**
29
- * Recursively strip any remaining anyOf/oneOf that same-type or mixed-type
30
- * collapse can handle. This is needed because object-combiner merging can
31
- * create new anyOf in merged subtrees after child normalization already ran.
32
- */
33
28
  export declare function stripResidualCombiners(value: unknown, epoch?: number): unknown;
34
29
  export declare function normalizeSchema(value: unknown, options: NormalizeSchemaOptions): unknown;
35
30
  export declare function normalizeSchemaForGoogle(value: unknown): unknown;
@@ -0,0 +1,4 @@
1
+ /** Return whether an error carries a SQLite result code. */
2
+ export declare function isSqliteError(error: unknown): boolean;
3
+ /** Return whether an error is one of SQLite's explicit database-corruption classes. */
4
+ export declare function isSqliteCorruptionError(error: unknown): boolean;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@gajae-code/ai",
4
- "version": "0.15.5",
4
+ "version": "0.16.0",
5
5
  "description": "Unified LLM API with automatic model discovery and provider configuration",
6
6
  "homepage": "https://gajae-code.com",
7
7
  "author": "Yeachan-Heo and Gajae Code Contributors",
@@ -40,8 +40,8 @@
40
40
  "dependencies": {
41
41
  "@anthropic-ai/sdk": "^0.94.0",
42
42
  "@bufbuild/protobuf": "^2.12.0",
43
- "@gajae-code/natives": "0.15.5",
44
- "@gajae-code/utils": "0.15.5",
43
+ "@gajae-code/natives": "0.16.0",
44
+ "@gajae-code/utils": "0.16.0",
45
45
  "openai": "^6.36.0",
46
46
  "partial-json": "^0.1.7",
47
47
  "zod": "4.4.3"