@jini-ai/agent-runtime 0.3.9 → 0.4.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 (200) hide show
  1. package/CHANGELOG.md +103 -0
  2. package/README.md +34 -17
  3. package/dist/acp-model-probe.d.ts +6 -4
  4. package/dist/acp-model-probe.js +3 -3
  5. package/dist/agent-protocol/acp/account-failure.d.ts +4 -2
  6. package/dist/agent-protocol/acp/account-failure.js +1 -1
  7. package/dist/agent-protocol/acp/json.d.ts +6 -6
  8. package/dist/agent-protocol/acp/json.js +3 -3
  9. package/dist/agent-protocol/acp/models.d.ts +10 -5
  10. package/dist/agent-protocol/acp/models.js +32 -31
  11. package/dist/agent-protocol/acp/session-params.d.ts +3 -1
  12. package/dist/agent-protocol/acp/session-params.js +2 -1
  13. package/dist/agent-protocol/acp/session.d.ts +28 -22
  14. package/dist/agent-protocol/acp/session.js +181 -147
  15. package/dist/agent-protocol/acp/text-suppression.d.ts +1 -1
  16. package/dist/agent-protocol/acp/text-suppression.js +1 -1
  17. package/dist/agent-protocol/acp/types.d.ts +3 -2
  18. package/dist/agent-protocol/acp/updates.d.ts +11 -11
  19. package/dist/agent-protocol/acp/updates.js +2 -2
  20. package/dist/agent-protocol/core/json-line-stream.d.ts +24 -8
  21. package/dist/agent-protocol/core/json-line-stream.js +8 -8
  22. package/dist/agent-protocol/pi-rpc/events.d.ts +5 -1
  23. package/dist/agent-protocol/pi-rpc/events.js +36 -36
  24. package/dist/agent-protocol/pi-rpc/internal.d.ts +4 -1
  25. package/dist/agent-protocol/pi-rpc/models.d.ts +3 -1
  26. package/dist/agent-protocol/pi-rpc/models.js +1 -1
  27. package/dist/agent-protocol/pi-rpc/session.d.ts +1 -1
  28. package/dist/agent-protocol/pi-rpc/session.js +33 -32
  29. package/dist/amr-model-cache.d.ts +12 -4
  30. package/dist/amr-model-cache.js +17 -21
  31. package/dist/amr-profile-resolver.d.ts +3 -1
  32. package/dist/anthropic-live-models.js +0 -0
  33. package/dist/artifact-taxonomy.d.ts +6 -2
  34. package/dist/auth.d.ts +52 -15
  35. package/dist/auth.js +36 -36
  36. package/dist/claude-code-models.js +2 -2
  37. package/dist/claude-stream.d.ts +22 -3
  38. package/dist/claude-stream.js +24 -8
  39. package/dist/copilot-stream.d.ts +7 -3
  40. package/dist/copilot-stream.js +3 -3
  41. package/dist/defs/aider.d.ts +8 -1
  42. package/dist/defs/aider.js +2 -2
  43. package/dist/defs/amp.d.ts +8 -1
  44. package/dist/defs/amp.js +2 -2
  45. package/dist/defs/amr.d.ts +22 -6
  46. package/dist/defs/amr.js +23 -23
  47. package/dist/defs/antigravity.d.ts +15 -4
  48. package/dist/defs/antigravity.js +9 -8
  49. package/dist/defs/auggie.d.ts +4 -1
  50. package/dist/defs/auggie.js +1 -1
  51. package/dist/defs/claude.d.ts +16 -2
  52. package/dist/defs/claude.js +22 -4
  53. package/dist/defs/cline.d.ts +4 -1
  54. package/dist/defs/cline.js +1 -1
  55. package/dist/defs/codebuddy.d.ts +8 -1
  56. package/dist/defs/codebuddy.js +2 -2
  57. package/dist/defs/codex.d.ts +18 -4
  58. package/dist/defs/codex.js +7 -7
  59. package/dist/defs/copilot.d.ts +8 -1
  60. package/dist/defs/copilot.js +2 -2
  61. package/dist/defs/crush.d.ts +8 -1
  62. package/dist/defs/crush.js +1 -1
  63. package/dist/defs/cursor-agent.d.ts +14 -3
  64. package/dist/defs/cursor-agent.js +5 -5
  65. package/dist/defs/deepseek.d.ts +8 -1
  66. package/dist/defs/deepseek.js +2 -2
  67. package/dist/defs/devin.d.ts +12 -2
  68. package/dist/defs/devin.js +3 -3
  69. package/dist/defs/droid.d.ts +8 -1
  70. package/dist/defs/droid.js +1 -1
  71. package/dist/defs/gemini.d.ts +8 -1
  72. package/dist/defs/gemini.js +1 -1
  73. package/dist/defs/goose.d.ts +4 -1
  74. package/dist/defs/goose.js +1 -1
  75. package/dist/defs/grok-build.d.ts +11 -2
  76. package/dist/defs/grok-build.js +3 -3
  77. package/dist/defs/hermes.d.ts +4 -1
  78. package/dist/defs/hermes.js +2 -2
  79. package/dist/defs/kilo.d.ts +4 -1
  80. package/dist/defs/kilo.js +2 -2
  81. package/dist/defs/kimi.d.ts +4 -1
  82. package/dist/defs/kimi.js +2 -2
  83. package/dist/defs/kiro.d.ts +4 -1
  84. package/dist/defs/kiro.js +2 -2
  85. package/dist/defs/mimo.d.ts +8 -1
  86. package/dist/defs/mimo.js +2 -2
  87. package/dist/defs/opencode.d.ts +9 -2
  88. package/dist/defs/opencode.js +2 -2
  89. package/dist/defs/pi.d.ts +12 -2
  90. package/dist/defs/pi.js +9 -9
  91. package/dist/defs/qoder.d.ts +8 -1
  92. package/dist/defs/qoder.js +2 -2
  93. package/dist/defs/qwen.d.ts +8 -1
  94. package/dist/defs/qwen.js +2 -2
  95. package/dist/defs/reasonix.d.ts +4 -1
  96. package/dist/defs/reasonix.js +3 -3
  97. package/dist/defs/shared.d.ts +4 -2
  98. package/dist/defs/shared.js +2 -2
  99. package/dist/defs/trae-cli.d.ts +12 -2
  100. package/dist/defs/trae-cli.js +3 -3
  101. package/dist/defs/vibe.d.ts +4 -1
  102. package/dist/defs/vibe.js +2 -2
  103. package/dist/detection.d.ts +38 -3
  104. package/dist/detection.js +77 -37
  105. package/dist/diagnostics.d.ts +14 -3
  106. package/dist/diagnostics.js +5 -5
  107. package/dist/env.d.ts +16 -4
  108. package/dist/env.js +7 -7
  109. package/dist/executables.d.ts +24 -8
  110. package/dist/executables.js +13 -13
  111. package/dist/index.d.ts +228 -4
  112. package/dist/index.js +230 -6
  113. package/dist/invocation.d.ts +6 -1
  114. package/dist/invocation.js +2 -2
  115. package/dist/json-event-stream.d.ts +7 -2
  116. package/dist/json-event-stream.js +3 -3
  117. package/dist/launch.d.ts +12 -2
  118. package/dist/launch.js +3 -3
  119. package/dist/log-file.d.ts +4 -1
  120. package/dist/log-file.js +2 -2
  121. package/dist/mcp.d.ts +6 -3
  122. package/dist/mcp.js +1 -1
  123. package/dist/metadata.d.ts +7 -3
  124. package/dist/metadata.js +1 -1
  125. package/dist/mmd-routes.d.ts +22 -6
  126. package/dist/mmd-routes.js +14 -14
  127. package/dist/model-catalog-cache.d.ts +50 -0
  128. package/dist/model-catalog-cache.js +61 -0
  129. package/dist/model-loading-state.d.ts +10 -0
  130. package/dist/model-loading-state.js +23 -0
  131. package/dist/model-registry.d.ts +28 -7
  132. package/dist/model-registry.js +11 -8
  133. package/dist/models.d.ts +31 -6
  134. package/dist/models.js +6 -6
  135. package/dist/opencode-log.d.ts +12 -4
  136. package/dist/opencode-log.js +8 -8
  137. package/dist/paths.d.ts +6 -2
  138. package/dist/paths.js +3 -3
  139. package/dist/pi-models.d.ts +3 -1
  140. package/dist/pi-models.js +2 -2
  141. package/dist/prompt-budget.d.ts +17 -4
  142. package/dist/prompt-budget.js +3 -3
  143. package/dist/prompt-file.d.ts +5 -1
  144. package/dist/prompt-file.js +1 -1
  145. package/dist/providers/aihubmix.d.ts +34 -9
  146. package/dist/providers/aihubmix.js +26 -26
  147. package/dist/providers/anthropic-messages.d.ts +77 -20
  148. package/dist/providers/anthropic-messages.js +53 -50
  149. package/dist/providers/azure-chat.d.ts +21 -7
  150. package/dist/providers/azure-chat.js +18 -16
  151. package/dist/providers/connection-guard.d.ts +45 -31
  152. package/dist/providers/connection-guard.js +40 -143
  153. package/dist/providers/connection-test.d.ts +1 -1
  154. package/dist/providers/connection-test.js +13 -30
  155. package/dist/providers/elevenlabs.d.ts +7 -2
  156. package/dist/providers/elevenlabs.js +4 -4
  157. package/dist/providers/google-messages.d.ts +44 -10
  158. package/dist/providers/google-messages.js +36 -34
  159. package/dist/providers/google-schema.d.ts +26 -0
  160. package/dist/providers/google-schema.js +253 -0
  161. package/dist/providers/google.d.ts +21 -6
  162. package/dist/providers/google.js +10 -10
  163. package/dist/providers/index.d.ts +3 -2
  164. package/dist/providers/index.js +3 -2
  165. package/dist/providers/model-catalog.d.ts +1 -1
  166. package/dist/providers/model-catalog.js +14 -27
  167. package/dist/providers/oauth-callback-server.d.ts +1 -1
  168. package/dist/providers/oauth-callback-server.js +3 -2
  169. package/dist/providers/oauth-credentials.d.ts +7 -1
  170. package/dist/providers/oauth-credentials.js +5 -5
  171. package/dist/providers/oauth-provider.d.ts +2 -2
  172. package/dist/providers/oauth-provider.js +20 -25
  173. package/dist/providers/oauth-tokens.d.ts +26 -6
  174. package/dist/providers/oauth-tokens.js +9 -9
  175. package/dist/providers/ollama-chat.d.ts +66 -31
  176. package/dist/providers/ollama-chat.js +64 -61
  177. package/dist/providers/openai-chat.d.ts +77 -22
  178. package/dist/providers/openai-chat.js +71 -67
  179. package/dist/providers/pkce.d.ts +33 -20
  180. package/dist/providers/pkce.js +75 -146
  181. package/dist/providers/sse-decode.d.ts +3 -1
  182. package/dist/providers/sse-decode.js +1 -1
  183. package/dist/providers/token-params.d.ts +16 -5
  184. package/dist/providers/token-params.js +6 -6
  185. package/dist/providers/tool-turn-types.d.ts +89 -0
  186. package/dist/providers/tool-turn-types.js +2 -0
  187. package/dist/providers/tool-turn.d.ts +10 -0
  188. package/dist/providers/tool-turn.js +252 -0
  189. package/dist/qoder-stream.d.ts +7 -3
  190. package/dist/qoder-stream.js +3 -3
  191. package/dist/registry.d.ts +6 -2
  192. package/dist/registry.js +4 -4
  193. package/dist/resolution.d.ts +5 -1
  194. package/dist/resolution.js +3 -3
  195. package/dist/role-marker-guard.d.ts +9 -5
  196. package/dist/role-marker-guard.js +5 -5
  197. package/dist/terminal-launch.d.ts +6 -1
  198. package/dist/terminal-launch.js +2 -2
  199. package/dist/types.d.ts +37 -6
  200. package/package.json +43 -4
@@ -25,8 +25,11 @@ export interface PendingAuthState {
25
25
  resource?: string;
26
26
  createdAt: number;
27
27
  }
28
+ /** RFC 7636 §4.1 permits 43–128 verifier characters; 64 random bytes encode to 86. */
28
29
  export declare function generateCodeVerifier(): string;
29
- export declare function deriveCodeChallenge(verifier: string): string;
30
+ export declare function deriveCodeChallenge({ verifier }: {
31
+ verifier: string;
32
+ }): string;
30
33
  export declare function generateState(): string;
31
34
  export interface AuthorizeUrlInput {
32
35
  authServer: AuthorizationServerMetadata;
@@ -37,7 +40,7 @@ export interface AuthorizeUrlInput {
37
40
  scope?: string;
38
41
  resource?: string;
39
42
  }
40
- export declare function buildAuthorizeUrl(input: AuthorizeUrlInput): string;
43
+ export declare function buildAuthorizeUrl(requiredArgs: Pick<AuthorizeUrlInput, "authServer" | "clientId" | "redirectUri" | "state" | "codeChallenge">, optionalArgs?: Omit<AuthorizeUrlInput, "authServer" | "clientId" | "redirectUri" | "state" | "codeChallenge">): string;
41
44
  export interface ExchangeCodeInput {
42
45
  tokenEndpoint: string;
43
46
  clientId: string;
@@ -47,7 +50,11 @@ export interface ExchangeCodeInput {
47
50
  codeVerifier: string;
48
51
  resource?: string;
49
52
  }
50
- export declare function exchangeCodeForToken(input: ExchangeCodeInput, fetchImpl?: typeof fetch): Promise<OAuthTokenResponse>;
53
+ export declare function exchangeCodeForToken({ input }: {
54
+ input: ExchangeCodeInput;
55
+ }, { fetchImpl }?: {
56
+ fetchImpl?: typeof fetch;
57
+ }): Promise<OAuthTokenResponse>;
51
58
  export interface RefreshTokenInput {
52
59
  tokenEndpoint: string;
53
60
  clientId: string;
@@ -56,26 +63,32 @@ export interface RefreshTokenInput {
56
63
  scope?: string;
57
64
  resource?: string;
58
65
  }
59
- export declare function refreshAccessToken(input: RefreshTokenInput, fetchImpl?: typeof fetch): Promise<OAuthTokenResponse>;
60
- /**
61
- * In-memory pending-authorization cache keyed by the OAuth `state`
62
- * parameter. Bridges the "begin" (mint state + verifier) and "complete"
63
- * (browser returns code + state) halves of the dance; persistence isn't
64
- * needed because the caller completes auth in the same process, and state
65
- * is single-use.
66
+ export declare function refreshAccessToken({ input }: {
67
+ input: RefreshTokenInput;
68
+ }, { fetchImpl }?: {
69
+ fetchImpl?: typeof fetch;
70
+ }): Promise<OAuthTokenResponse>;
71
+ /** In-memory pending authorization keyed by the OAuth state parameter. Bridges the
72
+ * begin (mint state + verifier) and complete (browser returns code + state) halves.
73
+ * Persistence is not needed because the caller completes auth in the same process,
74
+ * and state is single-use. The host timer adapter retains unref and the synchronous
75
+ * cache contract while delegating storage and expiry to the main OAuth factory.
66
76
  */
67
77
  export declare class PendingAuthCache {
68
- private readonly ttlMs;
69
- private store;
70
- private timer;
71
- constructor(ttlMs?: number);
72
- put(state: string, value: PendingAuthState): void;
73
- /** One-shot consume — any successful callback removes the state so a replay can't reuse it. */
74
- consume(state: string): PendingAuthState | null;
78
+ private readonly cache;
79
+ constructor(_requiredArgs?: Record<string, never>, { ttlMs }?: {
80
+ ttlMs?: number;
81
+ });
82
+ put({ state, value }: {
83
+ state: string;
84
+ value: PendingAuthState;
85
+ }): void;
86
+ /** One-shot consume removes state before returning so a callback replay cannot reuse it. */
87
+ consume({ state }: {
88
+ state: string;
89
+ }): PendingAuthState | null;
75
90
  size(): number;
76
- /** Stops the background sweeper. Production lets the timer ride on the host process lifetime. */
91
+ /** Stops the background sweeper; its timer ownership belongs to the host scheduler. */
77
92
  stop(): void;
78
- private startSweeper;
79
- private sweep;
80
93
  }
81
94
  //# sourceMappingURL=pkce.d.ts.map
@@ -1,11 +1,11 @@
1
1
  /**
2
2
  * @module providers/pkce
3
3
  *
4
- * Generic OAuth 2.0 Authorization Code + PKCE (RFC 7636) client primitives —
4
+ * Fixed-issuer OAuth 2.0 Authorization Code + PKCE (RFC 7636) provider adapters —
5
5
  * verifier/challenge/state generation, authorize-URL building, and the
6
6
  * code-exchange/refresh token-endpoint calls.
7
7
  *
8
- * Vendored from the minimal subset of OD's `apps/daemon/src/mcp-oauth.ts`
8
+ * Originally vendored from the minimal subset of OD's `apps/daemon/src/mcp-oauth.ts`
9
9
  * (a 601-line "daemon-side OAuth 2.1 client for HTTP/SSE MCP servers") that
10
10
  * `integrations/xai-oauth.ts` actually depends on: PKCE generation,
11
11
  * `buildAuthorizeUrl`, `exchangeCodeForToken`, `refreshAccessToken`, and the
@@ -19,158 +19,87 @@
19
19
  * ported, mirroring the same reasoning `@jini-ai/agent-runtime`'s
20
20
  * `acp-model-probe.ts` used to exclude the ACP transport (a distinct
21
21
  * subsystem named as its own future extraction target). No product-identity
22
- * strings in the vendored subset — ported verbatim apart from doc-comment
23
- * wording.
22
+ * strings in the vendored subset. Protocol implementation now lives in
23
+ * `@jini-ai/oauth`; this module retains the provider DTO and synchronous callback adapter.
24
+ * The historical split still explains why discovery and dynamic registration do not
25
+ * belong in this fixed-issuer bridge.
24
26
  */
25
- import { createHash, randomBytes } from 'node:crypto';
26
- const VERIFIER_LEN = 64; // RFC 7636 §4.1: 43-128 chars
27
- function base64url(buf) {
28
- return buf
29
- .toString('base64')
30
- .replace(/\+/g, '-')
31
- .replace(/\//g, '_')
32
- .replace(/=+$/g, '');
27
+ import { randomBytes } from 'node:crypto';
28
+ import { createPkcePair, deriveCodeChallenge as deriveOAuthCodeChallenge, generateOAuthState, buildOAuthAuthorizationUrl, exchangeOAuthAuthorizationCode, refreshAccessToken as refreshOAuthAccessToken, createPendingAuthorizationStore, createOAuthUrlGuard, } from '@jini-ai/oauth';
29
+ const entropy = ({ byteLength }) => randomBytes(byteLength);
30
+ /** RFC 7636 §4.1 permits 43–128 verifier characters; 64 random bytes encode to 86. */
31
+ export function generateCodeVerifier() { return createPkcePair({ randomBytesFn: entropy }, { verifierBytes: 64 }).codeVerifier; }
32
+ export function deriveCodeChallenge({ verifier }) { return deriveOAuthCodeChallenge({ codeVerifier: verifier }); }
33
+ export function generateState() { return generateOAuthState({ randomBytesFn: entropy }); }
34
+ export function buildAuthorizeUrl(requiredArgs, optionalArgs = {}) {
35
+ return buildOAuthAuthorizationUrl({
36
+ authorizationEndpoint: requiredArgs.authServer.authorization_endpoint,
37
+ clientId: requiredArgs.clientId, redirectUri: requiredArgs.redirectUri,
38
+ state: requiredArgs.state, codeChallenge: requiredArgs.codeChallenge,
39
+ }, optionalArgs);
33
40
  }
34
- export function generateCodeVerifier() {
35
- return base64url(randomBytes(VERIFIER_LEN));
41
+ export async function exchangeCodeForToken({ input }, { fetchImpl = fetch } = {}) {
42
+ let issuedAtMs = 0;
43
+ const tokenClock = { nowMs: () => (issuedAtMs = Date.now()) };
44
+ const tokens = await exchangeOAuthAuthorizationCode({
45
+ fetchFn: ({ url }, init) => fetchImpl(url, init), guard, clock: tokenClock,
46
+ tokenEndpoint: input.tokenEndpoint, client: clientFor(input),
47
+ redirectUri: input.redirectUri, code: input.code, codeVerifier: input.codeVerifier,
48
+ }, input.resource === undefined ? {} : { resource: input.resource });
49
+ return persistedWireTokens({ tokens, issuedAtMs });
36
50
  }
37
- export function deriveCodeChallenge(verifier) {
38
- return base64url(createHash('sha256').update(verifier).digest());
51
+ export async function refreshAccessToken({ input }, { fetchImpl = fetch } = {}) {
52
+ let issuedAtMs = 0;
53
+ const tokenClock = { nowMs: () => (issuedAtMs = Date.now()) };
54
+ const tokens = await refreshOAuthAccessToken({
55
+ fetchFn: ({ url }, init) => fetchImpl(url, init), guard, clock: tokenClock,
56
+ tokenEndpoint: input.tokenEndpoint, client: clientFor(input), refreshToken: input.refreshToken,
57
+ }, { ...(input.scope === undefined ? {} : { scopes: input.scope.split(/\s+/).filter(Boolean) }),
58
+ ...(input.resource === undefined ? {} : { resource: input.resource }) });
59
+ return persistedWireTokens({ tokens, issuedAtMs });
39
60
  }
40
- export function generateState() {
41
- return base64url(randomBytes(32));
61
+ const clock = { nowMs: () => Date.now() };
62
+ // Fixed-issuer provider definitions supply endpoints; the shared scheme gate
63
+ // still refuses plaintext except for explicitly allowed local authorization servers.
64
+ const guard = createOAuthUrlGuard({ assertAllowed: () => undefined }, { allowLoopbackHttp: true });
65
+ function clientFor(input) {
66
+ return input.clientSecret
67
+ ? { clientId: input.clientId, clientSecret: input.clientSecret, authMethod: 'client_secret_basic' }
68
+ : { clientId: input.clientId, authMethod: 'none' };
42
69
  }
43
- export function buildAuthorizeUrl(input) {
44
- const u = new URL(input.authServer.authorization_endpoint);
45
- u.searchParams.set('response_type', 'code');
46
- u.searchParams.set('client_id', input.clientId);
47
- u.searchParams.set('redirect_uri', input.redirectUri);
48
- u.searchParams.set('state', input.state);
49
- u.searchParams.set('code_challenge', input.codeChallenge);
50
- u.searchParams.set('code_challenge_method', 'S256');
51
- if (input.scope)
52
- u.searchParams.set('scope', input.scope);
53
- // RFC 8707 resource indicator — narrows the issued token to the resource
54
- // actually being requested. Most authoritative servers require it;
55
- // harmless when ignored.
56
- if (input.resource)
57
- u.searchParams.set('resource', input.resource);
58
- return u.toString();
70
+ /** Persistence keeps the provider adapter's existing snake_case format; parsing is OAuth-owned. */
71
+ function persistedWireTokens({ tokens, issuedAtMs }) {
72
+ return { access_token: tokens.accessToken, token_type: tokens.tokenType,
73
+ ...(tokens.refreshToken === null ? {} : { refresh_token: tokens.refreshToken }),
74
+ ...(tokens.expiresAt === null ? {} : { expires_in: Math.max(0, (Date.parse(tokens.expiresAt) - issuedAtMs) / 1000) }),
75
+ ...(tokens.scopes.length === 0 ? {} : { scope: tokens.scopes.join(' ') }) };
59
76
  }
60
- export async function exchangeCodeForToken(input, fetchImpl = fetch) {
61
- const form = new URLSearchParams();
62
- form.set('grant_type', 'authorization_code');
63
- form.set('code', input.code);
64
- form.set('redirect_uri', input.redirectUri);
65
- form.set('client_id', input.clientId);
66
- form.set('code_verifier', input.codeVerifier);
67
- if (input.resource)
68
- form.set('resource', input.resource);
69
- return tokenRequest(input.tokenEndpoint, form, input.clientSecret, fetchImpl);
70
- }
71
- export async function refreshAccessToken(input, fetchImpl = fetch) {
72
- const form = new URLSearchParams();
73
- form.set('grant_type', 'refresh_token');
74
- form.set('refresh_token', input.refreshToken);
75
- form.set('client_id', input.clientId);
76
- if (input.scope)
77
- form.set('scope', input.scope);
78
- if (input.resource)
79
- form.set('resource', input.resource);
80
- return tokenRequest(input.tokenEndpoint, form, input.clientSecret, fetchImpl);
81
- }
82
- async function tokenRequest(tokenEndpoint, form, clientSecret, fetchImpl) {
83
- const headers = {
84
- 'content-type': 'application/x-www-form-urlencoded',
85
- accept: 'application/json',
86
- };
87
- if (clientSecret) {
88
- // RFC 6749 §2.3.1 — confidential clients use HTTP Basic with the
89
- // client_id already in the form. Public clients (PKCE-only) skip this.
90
- const basic = Buffer.from(`${form.get('client_id')}:${clientSecret}`).toString('base64');
91
- headers['authorization'] = `Basic ${basic}`;
92
- }
93
- const res = await fetchImpl(tokenEndpoint, {
94
- method: 'POST',
95
- headers,
96
- body: form.toString(),
97
- });
98
- if (!res.ok) {
99
- const txt = await safeText(res);
100
- throw new Error(`token endpoint rejected request: HTTP ${res.status} ${res.statusText} ${txt}`);
101
- }
102
- const json = (await res.json());
103
- if (!json.access_token) {
104
- throw new Error('token endpoint response missing access_token');
105
- }
106
- return json;
107
- }
108
- async function safeText(res) {
109
- try {
110
- const t = await res.text();
111
- return t.slice(0, 500);
112
- }
113
- catch {
114
- return '';
115
- }
116
- }
117
- /**
118
- * In-memory pending-authorization cache keyed by the OAuth `state`
119
- * parameter. Bridges the "begin" (mint state + verifier) and "complete"
120
- * (browser returns code + state) halves of the dance; persistence isn't
121
- * needed because the caller completes auth in the same process, and state
122
- * is single-use.
77
+ /** In-memory pending authorization keyed by the OAuth state parameter. Bridges the
78
+ * begin (mint state + verifier) and complete (browser returns code + state) halves.
79
+ * Persistence is not needed because the caller completes auth in the same process,
80
+ * and state is single-use. The host timer adapter retains unref and the synchronous
81
+ * cache contract while delegating storage and expiry to the main OAuth factory.
123
82
  */
124
83
  export class PendingAuthCache {
125
- ttlMs;
126
- store = new Map();
127
- timer = null;
128
- constructor(ttlMs = 10 * 60 * 1000) {
129
- this.ttlMs = ttlMs;
130
- }
131
- put(state, value) {
132
- this.store.set(state, value);
133
- this.startSweeper();
134
- }
135
- /** One-shot consume — any successful callback removes the state so a replay can't reuse it. */
136
- consume(state) {
137
- const v = this.store.get(state);
138
- if (!v)
139
- return null;
140
- this.store.delete(state);
141
- if (Date.now() - v.createdAt > this.ttlMs)
142
- return null;
143
- return v;
144
- }
145
- size() {
146
- return this.store.size;
147
- }
148
- /** Stops the background sweeper. Production lets the timer ride on the host process lifetime. */
149
- stop() {
150
- if (this.timer) {
151
- clearInterval(this.timer);
152
- this.timer = null;
153
- }
154
- }
155
- startSweeper() {
156
- if (this.timer)
157
- return;
158
- this.timer = setInterval(() => this.sweep(), Math.min(this.ttlMs, 60_000));
159
- // unref so the cache doesn't keep the event loop alive in tests.
160
- if (typeof this.timer === 'object' && this.timer && typeof this.timer.unref === 'function') {
161
- this.timer.unref();
162
- }
163
- }
164
- sweep() {
165
- const now = Date.now();
166
- for (const [k, v] of this.store) {
167
- if (now - v.createdAt > this.ttlMs)
168
- this.store.delete(k);
169
- }
170
- if (this.store.size === 0 && this.timer) {
171
- clearInterval(this.timer);
172
- this.timer = null;
173
- }
84
+ cache;
85
+ constructor(_requiredArgs = {}, { ttlMs = 10 * 60 * 1000 } = {}) {
86
+ this.cache = createPendingAuthorizationStore({ clock }, {
87
+ ttlMs, expiry: ({ value, ttlMs }) => value.createdAt + ttlMs, exclusiveExpiry: true,
88
+ scheduler: {
89
+ every: ({ intervalMs, run }) => {
90
+ const timer = setInterval(run, intervalMs);
91
+ // Pending browser authorization must not keep an otherwise idle host process alive.
92
+ timer.unref();
93
+ return () => clearInterval(timer);
94
+ },
95
+ },
96
+ });
174
97
  }
98
+ put({ state, value }) { this.cache.put({ state, value }); }
99
+ /** One-shot consume removes state before returning so a callback replay cannot reuse it. */
100
+ consume({ state }) { return this.cache.consume({ state }); }
101
+ size() { return this.cache.size({}); }
102
+ /** Stops the background sweeper; its timer ownership belongs to the host scheduler. */
103
+ stop() { this.cache.stop({}); }
175
104
  }
176
105
  //# sourceMappingURL=pkce.js.map
@@ -43,5 +43,7 @@ export interface DecodedSseEvent {
43
43
  * source iterable ends, so a provider closing the connection immediately
44
44
  * after its last byte never silently loses that last record.
45
45
  */
46
- export declare function decodeSseStream(source: AsyncIterable<Uint8Array | string>): AsyncGenerator<DecodedSseEvent>;
46
+ export declare function decodeSseStream({ source }: {
47
+ source: AsyncIterable<Uint8Array | string>;
48
+ }): AsyncGenerator<DecodedSseEvent>;
47
49
  //# sourceMappingURL=sse-decode.d.ts.map
@@ -38,7 +38,7 @@
38
38
  * source iterable ends, so a provider closing the connection immediately
39
39
  * after its last byte never silently loses that last record.
40
40
  */
41
- export async function* decodeSseStream(source) {
41
+ export async function* decodeSseStream({ source }) {
42
42
  const decoder = new TextDecoder();
43
43
  let buffer = '';
44
44
  let eventType = null;
@@ -9,21 +9,32 @@
9
9
  * origin — ported verbatim.
10
10
  */
11
11
  /** True when `model` belongs to a family that rejects the legacy `max_tokens` field. */
12
- export declare function usesMaxCompletionTokens(model: string): boolean;
12
+ export declare function usesMaxCompletionTokens({ model }: {
13
+ model: string;
14
+ }): boolean;
13
15
  /** Selects `max_tokens` or `max_completion_tokens` per {@link usesMaxCompletionTokens}. */
14
- export declare function buildOpenAIChatTokenParam(model: string, maxTokens: number): {
16
+ export declare function buildOpenAIChatTokenParam({ model, maxTokens }: {
17
+ model: string;
18
+ maxTokens: number;
19
+ }): {
15
20
  max_tokens: number;
16
21
  } | {
17
22
  max_completion_tokens: number;
18
23
  };
19
24
  /** Always the legacy `max_tokens` shape — for callers that already know the model family. */
20
- export declare function buildLegacyMaxTokensParam(maxTokens: number): {
25
+ export declare function buildLegacyMaxTokensParam({ maxTokens }: {
26
+ maxTokens: number;
27
+ }): {
21
28
  max_tokens: number;
22
29
  };
23
30
  /** Always the newer `max_completion_tokens` shape — for callers that already know the model family. */
24
- export declare function buildMaxCompletionTokensParam(maxTokens: number): {
31
+ export declare function buildMaxCompletionTokensParam({ maxTokens }: {
32
+ maxTokens: number;
33
+ }): {
25
34
  max_completion_tokens: number;
26
35
  };
27
36
  /** Detects the provider error text a gateway returns when `max_tokens` was rejected in favor of `max_completion_tokens`. */
28
- export declare function isUnsupportedMaxTokensError(detail: string): boolean;
37
+ export declare function isUnsupportedMaxTokensError({ detail }: {
38
+ detail: string;
39
+ }): boolean;
29
40
  //# sourceMappingURL=token-params.d.ts.map
@@ -9,7 +9,7 @@
9
9
  * origin — ported verbatim.
10
10
  */
11
11
  /** True when `model` belongs to a family that rejects the legacy `max_tokens` field. */
12
- export function usesMaxCompletionTokens(model) {
12
+ export function usesMaxCompletionTokens({ model }) {
13
13
  const normalized = model.trim().toLowerCase();
14
14
  return (/^gpt-5(?:[.-]|$)/.test(normalized) ||
15
15
  /^o1(?:[.-]|$)/.test(normalized) ||
@@ -17,22 +17,22 @@ export function usesMaxCompletionTokens(model) {
17
17
  /^o4(?:[.-]|$)/.test(normalized));
18
18
  }
19
19
  /** Selects `max_tokens` or `max_completion_tokens` per {@link usesMaxCompletionTokens}. */
20
- export function buildOpenAIChatTokenParam(model, maxTokens) {
21
- if (usesMaxCompletionTokens(model)) {
20
+ export function buildOpenAIChatTokenParam({ model, maxTokens }) {
21
+ if (usesMaxCompletionTokens({ model: model })) {
22
22
  return { max_completion_tokens: maxTokens };
23
23
  }
24
24
  return { max_tokens: maxTokens };
25
25
  }
26
26
  /** Always the legacy `max_tokens` shape — for callers that already know the model family. */
27
- export function buildLegacyMaxTokensParam(maxTokens) {
27
+ export function buildLegacyMaxTokensParam({ maxTokens }) {
28
28
  return { max_tokens: maxTokens };
29
29
  }
30
30
  /** Always the newer `max_completion_tokens` shape — for callers that already know the model family. */
31
- export function buildMaxCompletionTokensParam(maxTokens) {
31
+ export function buildMaxCompletionTokensParam({ maxTokens }) {
32
32
  return { max_completion_tokens: maxTokens };
33
33
  }
34
34
  /** Detects the provider error text a gateway returns when `max_tokens` was rejected in favor of `max_completion_tokens`. */
35
- export function isUnsupportedMaxTokensError(detail) {
35
+ export function isUnsupportedMaxTokensError({ detail }) {
36
36
  const normalized = detail.toLowerCase();
37
37
  return (normalized.includes('unsupported parameter') &&
38
38
  normalized.includes('max_tokens') &&
@@ -0,0 +1,89 @@
1
+ import type { runAnthropicToolTurn } from './anthropic-messages.js';
2
+ import type { runOpenAiToolTurn } from './openai-chat.js';
3
+ import type { runAzureToolTurn } from './azure-chat.js';
4
+ import type { runGoogleToolTurn } from './google-messages.js';
5
+ /** Adapter ports retain each existing provider's request and tool-loop contract. */
6
+ export interface ProviderTurnAdapters {
7
+ readonly anthropic: typeof runAnthropicToolTurn;
8
+ readonly openai: typeof runOpenAiToolTurn;
9
+ readonly azure: typeof runAzureToolTurn;
10
+ readonly google: typeof runGoogleToolTurn;
11
+ }
12
+ /** Structural descriptors keep host registries out of the runtime dependency graph. */
13
+ export interface ProviderToolDescriptor {
14
+ readonly id: string;
15
+ readonly description?: string;
16
+ readonly inputSchema?: unknown;
17
+ }
18
+ export type ProviderProtocol = "anthropic" | "openai" | "azure" | "google";
19
+ export interface ProviderChatMessage {
20
+ readonly role: "user" | "assistant";
21
+ readonly content: string;
22
+ }
23
+ export type ProviderTurnEvent = {
24
+ readonly type: "status";
25
+ readonly label: string;
26
+ } | {
27
+ readonly type: "text_delta";
28
+ readonly delta: string;
29
+ } | {
30
+ readonly type: "tool_use";
31
+ readonly id: string;
32
+ readonly name: string;
33
+ readonly input: unknown;
34
+ } | {
35
+ readonly type: "tool_result";
36
+ readonly toolUseId: string;
37
+ readonly content: string;
38
+ readonly isError: boolean;
39
+ } | {
40
+ readonly type: "usage";
41
+ readonly usage: Record<string, unknown> | null;
42
+ } | {
43
+ readonly type: "error";
44
+ readonly message: string;
45
+ } | {
46
+ readonly type: "end";
47
+ readonly reason: string;
48
+ };
49
+ export interface ProviderToolCall {
50
+ readonly id: string;
51
+ readonly name: string;
52
+ readonly input: unknown;
53
+ }
54
+ export type ProviderToolResultBlock = {
55
+ readonly type: "text";
56
+ readonly text: string;
57
+ } | {
58
+ readonly type: "image";
59
+ readonly mimeType: string;
60
+ readonly data: string;
61
+ };
62
+ export interface ProviderToolResult {
63
+ readonly content: string | readonly ProviderToolResultBlock[];
64
+ readonly isError?: boolean;
65
+ }
66
+ export type ProviderToolExecutor = (call: ProviderToolCall) => Promise<ProviderToolResult>;
67
+ export interface ProviderToolTurnInput {
68
+ readonly protocol: ProviderProtocol;
69
+ readonly adapters: ProviderTurnAdapters;
70
+ readonly apiKey: string;
71
+ readonly model: string;
72
+ readonly system: string;
73
+ readonly messages: readonly ProviderChatMessage[];
74
+ readonly tools: readonly ProviderToolDescriptor[];
75
+ readonly executeTool: ProviderToolExecutor;
76
+ readonly onEvent: (event: ProviderTurnEvent) => void;
77
+ }
78
+ export interface ProviderToolTurnResult {
79
+ readonly stopReason: string | null;
80
+ readonly toolTurns: number;
81
+ }
82
+ /** Optional turn controls; dependencies belong in the required input object. */
83
+ export interface ProviderToolTurnOptions {
84
+ readonly baseUrl?: string;
85
+ readonly maxTokens?: number;
86
+ readonly maxToolTurns?: number;
87
+ readonly signal?: AbortSignal;
88
+ }
89
+ //# sourceMappingURL=tool-turn-types.d.ts.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=tool-turn-types.js.map
@@ -0,0 +1,10 @@
1
+ import type { ProviderTurnAdapters, ProviderToolTurnInput, ProviderToolTurnResult, ProviderToolTurnOptions } from './tool-turn-types.js';
2
+ export type * from './tool-turn-types.js';
3
+ export { googleParametersOf, sanitizeGoogleSchema, findNumericEnumPaths, coerceNumericEnumStringsToNumbers } from './google-schema.js';
4
+ /** Existing provider loops, ready for host composition; callers may replace any adapter. */
5
+ export declare const providerTurnAdapters: ProviderTurnAdapters;
6
+ /** Runs one provider-neutral turn through the supplied adapters. The adapter end event takes precedence over a raw provider stop code.
7
+ * Local mapping is proportional to the descriptors, expanded schemas and emitted result parts; request and loop cost belongs to the adapter ports.
8
+ */
9
+ export declare function runProviderToolTurn(required: ProviderToolTurnInput, optional?: ProviderToolTurnOptions): Promise<ProviderToolTurnResult>;
10
+ //# sourceMappingURL=tool-turn.d.ts.map