@code-yeongyu/senpi-ai 2026.8.13 → 2026.8.16

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 (113) hide show
  1. package/README.md +2 -0
  2. package/dist/api/anthropic-messages.d.ts.map +1 -1
  3. package/dist/api/anthropic-messages.js +40 -14
  4. package/dist/api/anthropic-messages.js.map +1 -1
  5. package/dist/api/bedrock-converse-stream.d.ts.map +1 -1
  6. package/dist/api/bedrock-converse-stream.js +16 -4
  7. package/dist/api/bedrock-converse-stream.js.map +1 -1
  8. package/dist/api/cloudflare-gateway-binding.d.ts +69 -0
  9. package/dist/api/cloudflare-gateway-binding.d.ts.map +1 -0
  10. package/dist/api/cloudflare-gateway-binding.js +159 -0
  11. package/dist/api/cloudflare-gateway-binding.js.map +1 -0
  12. package/dist/api/constrained-sampling.d.ts +3 -0
  13. package/dist/api/constrained-sampling.d.ts.map +1 -1
  14. package/dist/api/constrained-sampling.js +125 -5
  15. package/dist/api/constrained-sampling.js.map +1 -1
  16. package/dist/api/google-generative-ai.js +7 -3
  17. package/dist/api/google-generative-ai.js.map +1 -1
  18. package/dist/api/google-shared.d.ts +1 -1
  19. package/dist/api/google-shared.d.ts.map +1 -1
  20. package/dist/api/google-shared.js +13 -9
  21. package/dist/api/google-shared.js.map +1 -1
  22. package/dist/api/google-vertex.js +7 -3
  23. package/dist/api/google-vertex.js.map +1 -1
  24. package/dist/api/mistral-conversations.d.ts +1 -1
  25. package/dist/api/mistral-conversations.d.ts.map +1 -1
  26. package/dist/api/mistral-conversations.js +208 -42
  27. package/dist/api/mistral-conversations.js.map +1 -1
  28. package/dist/api/openai-codex-responses.d.ts.map +1 -1
  29. package/dist/api/openai-codex-responses.js +13 -4
  30. package/dist/api/openai-codex-responses.js.map +1 -1
  31. package/dist/api/openai-completions.d.ts.map +1 -1
  32. package/dist/api/openai-completions.js +10 -7
  33. package/dist/api/openai-completions.js.map +1 -1
  34. package/dist/api/openai-responses-shared.d.ts +1 -0
  35. package/dist/api/openai-responses-shared.d.ts.map +1 -1
  36. package/dist/api/openai-responses-shared.js +31 -7
  37. package/dist/api/openai-responses-shared.js.map +1 -1
  38. package/dist/api/openai-responses.d.ts.map +1 -1
  39. package/dist/api/openai-responses.js +8 -1
  40. package/dist/api/openai-responses.js.map +1 -1
  41. package/dist/auth/oauth/cursor.d.ts +16 -0
  42. package/dist/auth/oauth/cursor.d.ts.map +1 -0
  43. package/dist/auth/oauth/cursor.js +234 -0
  44. package/dist/auth/oauth/cursor.js.map +1 -0
  45. package/dist/auth/oauth/github-copilot.d.ts.map +1 -1
  46. package/dist/auth/oauth/github-copilot.js +6 -3
  47. package/dist/auth/oauth/github-copilot.js.map +1 -1
  48. package/dist/auth/oauth/load.d.ts +2 -0
  49. package/dist/auth/oauth/load.d.ts.map +1 -1
  50. package/dist/auth/oauth/load.js +5 -0
  51. package/dist/auth/oauth/load.js.map +1 -1
  52. package/dist/auth/resolve.js +44 -9
  53. package/dist/auth/resolve.js.map +1 -1
  54. package/dist/auth/types.d.ts +2 -0
  55. package/dist/auth/types.d.ts.map +1 -1
  56. package/dist/auth/types.js.map +1 -1
  57. package/dist/bun-oauth.d.ts.map +1 -1
  58. package/dist/bun-oauth.js +2 -0
  59. package/dist/bun-oauth.js.map +1 -1
  60. package/dist/image-models.generated.d.ts +15 -0
  61. package/dist/image-models.generated.d.ts.map +1 -1
  62. package/dist/image-models.generated.js +15 -0
  63. package/dist/image-models.generated.js.map +1 -1
  64. package/dist/providers/all.d.ts.map +1 -1
  65. package/dist/providers/all.js +2 -0
  66. package/dist/providers/all.js.map +1 -1
  67. package/dist/providers/cursor.d.ts +15 -0
  68. package/dist/providers/cursor.d.ts.map +1 -0
  69. package/dist/providers/cursor.js +32 -0
  70. package/dist/providers/cursor.js.map +1 -0
  71. package/dist/providers/data/.manifest.json +1 -1
  72. package/dist/providers/data/alibaba-token-plan.json +1 -1
  73. package/dist/providers/data/baseten.json +1 -1
  74. package/dist/providers/data/cloudflare-ai-gateway.json +1 -1
  75. package/dist/providers/data/cloudflare-workers-ai.json +1 -1
  76. package/dist/providers/data/deepseek.json +1 -1
  77. package/dist/providers/data/fireworks.json +1 -1
  78. package/dist/providers/data/github-copilot.json +1 -1
  79. package/dist/providers/data/google-vertex.json +1 -1
  80. package/dist/providers/data/google.json +1 -1
  81. package/dist/providers/data/huggingface.json +1 -1
  82. package/dist/providers/data/kimi-coding.json +1 -1
  83. package/dist/providers/data/nvidia.json +1 -1
  84. package/dist/providers/data/openai-codex.json +1 -1
  85. package/dist/providers/data/openai.json +1 -1
  86. package/dist/providers/data/opencode-go.json +1 -1
  87. package/dist/providers/data/opencode.json +1 -1
  88. package/dist/providers/data/openrouter.json +1 -1
  89. package/dist/providers/data/qwen-token-plan-cn.json +1 -1
  90. package/dist/providers/data/qwen-token-plan.json +1 -1
  91. package/dist/providers/data/vercel-ai-gateway.json +1 -1
  92. package/dist/providers/data/zai-coding-cn.json +1 -1
  93. package/dist/providers/data/zai.json +1 -1
  94. package/dist/types.d.ts +14 -3
  95. package/dist/types.d.ts.map +1 -1
  96. package/dist/types.js.map +1 -1
  97. package/dist/utils/overflow.d.ts.map +1 -1
  98. package/dist/utils/overflow.js +2 -0
  99. package/dist/utils/overflow.js.map +1 -1
  100. package/dist/utils/pi-user-agent.d.ts +2 -0
  101. package/dist/utils/pi-user-agent.d.ts.map +1 -0
  102. package/dist/utils/pi-user-agent.js +12 -0
  103. package/dist/utils/pi-user-agent.js.map +1 -0
  104. package/dist/utils/prompt-cache-ttl.d.ts.map +1 -1
  105. package/dist/utils/prompt-cache-ttl.js +3 -2
  106. package/dist/utils/prompt-cache-ttl.js.map +1 -1
  107. package/dist/utils/retry.d.ts.map +1 -1
  108. package/dist/utils/retry.js +1 -0
  109. package/dist/utils/retry.js.map +1 -1
  110. package/dist/utils/validation.d.ts.map +1 -1
  111. package/dist/utils/validation.js +34 -0
  112. package/dist/utils/validation.js.map +1 -1
  113. package/package.json +2 -2
package/README.md CHANGED
@@ -90,6 +90,7 @@ Unified LLM API with provider collections, automatic auth resolution, token and
90
90
  - **Qwen Token Plan** (separate Individual and existing catalogs, with a separate China provider)
91
91
  - **Xiaomi MiMo** (defaults to API billing endpoint, with separate Token Plan providers for `cn`/`ams`/`sgp` regions)
92
92
  - **Alibaba Token Plan** (Alibaba Cloud Model Studio prepaid Token Plan, OpenAI-compatible `ap-southeast-1` endpoint)
93
+ - **Cursor** (Pro/Ultra/Teams subscription, OAuth authentication only — the Cursor chat protocol is not ported yet, see below)
93
94
  - **Any other OpenAI-compatible API**: local Ollama, vLLM, LM Studio, etc.
94
95
 
95
96
  ## Installation
@@ -1483,6 +1484,7 @@ Several providers support OAuth authentication instead of static API keys:
1483
1484
  - **OpenAI Codex** (ChatGPT Plus/Pro subscription, access to GPT-5.x Codex models)
1484
1485
  - **GitHub Copilot** (Copilot subscription)
1485
1486
  - **OpenRouter** (OAuth PKCE that mints a user-controlled API key)
1487
+ - **Cursor** (Pro/Ultra/Teams subscription; browser deep-link + poll flow. Login, refresh, and credential storage are fully functional, but the provider exposes no models until the Cursor Connect-RPC chat protocol is ported — the stored access token resolves through `models.getAuth("cursor")` for external integrations)
1486
1488
 
1487
1489
  Each of these providers carries an `OAuthAuth` on `provider.auth.oauth` with three operations: `login(interaction)` uses the provider-neutral `AuthInteraction.prompt()`/`notify()` protocol and returns a credential, `refresh(credential, signal)` refreshes expiring credentials when applicable, and `toAuth(credential)` derives request auth (GitHub Copilot's per-account base URL comes from here). Provider login interactions and refresh calls always carry a concrete abort signal. Refresh is automatic: `models.getAuth(providerId)` and request paths refresh expired tokens under a credential-store lock, so concurrent requests and processes cannot double-refresh. OpenRouter's OAuth flow instead returns a permanent API key, so its refresh operation is a no-op.
1488
1490
 
@@ -1 +1 @@
1
- {"version":3,"file":"anthropic-messages.d.ts","sourceRoot":"","sources":["../../src/api/anthropic-messages.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAC1C,OAAO,KAAK,EAGX,+BAA+B,EAK/B,MAAM,yCAAyC,CAAC;AAEjD,OAAO,KAAK,EAKX,OAAO,EAGP,KAAK,EAGL,mBAAmB,EAEnB,cAAc,EACd,aAAa,EAOb,MAAM,aAAa,CAAC;AAkCrB,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AA6JlE,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;AAE1E,MAAM,MAAM,wBAAwB,GAAG,YAAY,GAAG,SAAS,CAAC;AAoEhE,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACtD;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB;;;;;;;;;;;OAWG;IACH,eAAe,CAAC,EAAE,wBAAwB,CAAC;IAC3C;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACtE;;;;OAIG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;CACnB;AA4zBD,eAAO,MAAM,MAAM,EAAE,cAAc,CAAC,oBAAoB,EAAE,gBAAgB,CA6ZzE,CAAC;AA0FF,eAAO,MAAM,YAAY,EAAE,cAAc,CAAC,oBAAoB,EAAE,mBAAmB,CA2ClF,CAAC;AAsIF,wBAAgB,mCAAmC,CAClD,KAAK,EAAE,KAAK,CAAC,oBAAoB,CAAC,EAClC,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,gBAAgB,GACxB,+BAA+B,CAkBjC"}
1
+ {"version":3,"file":"anthropic-messages.d.ts","sourceRoot":"","sources":["../../src/api/anthropic-messages.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAC1C,OAAO,KAAK,EAGX,+BAA+B,EAK/B,MAAM,yCAAyC,CAAC;AAEjD,OAAO,KAAK,EAKX,OAAO,EAGP,KAAK,EAGL,mBAAmB,EAEnB,cAAc,EACd,aAAa,EAOb,MAAM,aAAa,CAAC;AAmCrB,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AA6JlE,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;AAE1E,MAAM,MAAM,wBAAwB,GAAG,YAAY,GAAG,SAAS,CAAC;AAoEhE,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACtD;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB;;;;;;;;;;;OAWG;IACH,eAAe,CAAC,EAAE,wBAAwB,CAAC;IAC3C;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACtE;;;;OAIG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;CACnB;AA+1BD,eAAO,MAAM,MAAM,EAAE,cAAc,CAAC,oBAAoB,EAAE,gBAAgB,CA2ZzE,CAAC;AA0FF,eAAO,MAAM,YAAY,EAAE,cAAc,CAAC,oBAAoB,EAAE,mBAAmB,CAyClF,CAAC;AAyIF,wBAAgB,mCAAmC,CAClD,KAAK,EAAE,KAAK,CAAC,oBAAoB,CAAC,EAClC,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,gBAAgB,GACxB,+BAA+B,CAkBjC"}
@@ -6,6 +6,7 @@ import { splitDeferredTools } from "../utils/deferred-tools.js";
6
6
  import { AssistantMessageEventStream } from "../utils/event-stream.js";
7
7
  import { headersToRecord, providerHeadersToRecord } from "../utils/headers.js";
8
8
  import { parseJsonWithRepair, parseStreamingJson } from "../utils/json-parse.js";
9
+ import { getPiUserAgent } from "../utils/pi-user-agent.js";
9
10
  import { getAnthropicCompat, isAnthropicApiBaseUrl } from "../utils/prompt-cache-ttl.js";
10
11
  import { getProviderEnvValue } from "../utils/provider-env.js";
11
12
  import { retryProviderRequest } from "../utils/provider-retry.js";
@@ -18,7 +19,7 @@ import { resolveRootObjectSchema } from "../utils/tool-schema-compat.js";
18
19
  import { demotedToolCallText, demotedToolResultText } from "../utils/unavailable-tool-text.js";
19
20
  import { sanitizeAnthropicToolPairs } from "./anthropic-tool-pairs.js";
20
21
  import { resolveCloudflareBaseUrl } from "./cloudflare.js";
21
- import { resolveJsonSchemaStrictSampling } from "./constrained-sampling.js";
22
+ import { getJsonSchemaToolParameters, resolveJsonSchemaStrictSampling } from "./constrained-sampling.js";
22
23
  import { buildCopilotDynamicHeaders, hasCopilotVisionInput } from "./github-copilot-headers.js";
23
24
  import { ANTHROPIC_RESERVED_BODY_KEYS, adjustMaxTokensForThinking, buildBaseOptions, clampMaxTokensToContext, } from "./simple-options.js";
24
25
  import { transformMessages } from "./transform-messages.js";
@@ -197,8 +198,36 @@ function mergeHeaders(...headerSources) {
197
198
  }
198
199
  return merged;
199
200
  }
200
- function hasAuthorizationHeader(headers) {
201
- return Object.keys(headers ?? {}).some((name) => name.toLowerCase() === "authorization");
201
+ function mergeClientHeaders(model, ...headerSources) {
202
+ const merged = mergeHeaders(...headerSources);
203
+ if (model.provider === "kimi-coding") {
204
+ for (const name of Object.keys(merged)) {
205
+ if (name.toLowerCase() === "user-agent")
206
+ delete merged[name];
207
+ }
208
+ merged["User-Agent"] = getPiUserAgent();
209
+ }
210
+ return merged;
211
+ }
212
+ function hasHeader(headers, name) {
213
+ if (!headers)
214
+ return false;
215
+ const expected = name.toLowerCase();
216
+ for (const [key, value] of Object.entries(headers)) {
217
+ if (key.toLowerCase() === expected && value !== null && value.trim().length > 0)
218
+ return true;
219
+ }
220
+ return false;
221
+ }
222
+ function assertRequestAuth(provider, apiKey, headers) {
223
+ if (apiKey)
224
+ return;
225
+ if (hasHeader(headers, "authorization") ||
226
+ hasHeader(headers, "x-api-key") ||
227
+ hasHeader(headers, "cf-aig-authorization")) {
228
+ return;
229
+ }
230
+ throw new Error(`No API key for provider: ${provider}`);
202
231
  }
203
232
  function isRecord(value) {
204
233
  return typeof value === "object" && value !== null;
@@ -901,9 +930,7 @@ export const stream = (model, context, options) => {
901
930
  else {
902
931
  const apiKey = options?.apiKey;
903
932
  const optionsHeaders = providerHeadersToRecord(options?.headers);
904
- if (!apiKey && !hasAuthorizationHeader(optionsHeaders)) {
905
- throw new Error(`No API key for provider: ${model.provider}`);
906
- }
933
+ assertRequestAuth(model.provider, apiKey, optionsHeaders);
907
934
  let copilotDynamicHeaders;
908
935
  if (model.provider === "github-copilot") {
909
936
  const hasImages = hasCopilotVisionInput(context.messages);
@@ -1329,9 +1356,7 @@ function mapThinkingLevelToEffort(model, level) {
1329
1356
  }
1330
1357
  export const streamSimple = (model, context, options) => {
1331
1358
  const apiKey = options?.apiKey;
1332
- if (!apiKey && !hasAuthorizationHeader(providerHeadersToRecord(options?.headers))) {
1333
- throw new Error(`No API key for provider: ${model.provider}`);
1334
- }
1359
+ assertRequestAuth(model.provider, apiKey, providerHeadersToRecord(options?.headers));
1335
1360
  const base = buildBaseOptions(model, context, options, options?.apiKey);
1336
1361
  if (!options?.reasoning) {
1337
1362
  return stream(model, context, { ...base, thinkingEnabled: false });
@@ -1396,7 +1421,7 @@ function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStre
1396
1421
  baseURL: model.baseUrl,
1397
1422
  dangerouslyAllowBrowser: true,
1398
1423
  fetch,
1399
- defaultHeaders: sanitizeAdaptiveThinkingHeaders(model, mergeHeaders({
1424
+ defaultHeaders: sanitizeAdaptiveThinkingHeaders(model, mergeClientHeaders(model, {
1400
1425
  accept: "application/json",
1401
1426
  "anthropic-dangerous-direct-browser-access": "true",
1402
1427
  ...(betaFeatures.length > 0 ? { "anthropic-beta": betaFeatures.join(",") } : {}),
@@ -1412,7 +1437,7 @@ function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStre
1412
1437
  baseURL: model.baseUrl,
1413
1438
  dangerouslyAllowBrowser: true,
1414
1439
  fetch,
1415
- defaultHeaders: sanitizeAdaptiveThinkingHeaders(model, mergeHeaders({
1440
+ defaultHeaders: sanitizeAdaptiveThinkingHeaders(model, mergeClientHeaders(model, {
1416
1441
  accept: "application/json",
1417
1442
  "anthropic-dangerous-direct-browser-access": "true",
1418
1443
  "anthropic-beta": ["claude-code-20250219", "oauth-2025-04-20", ...betaFeatures].join(","),
@@ -1430,7 +1455,7 @@ function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStre
1430
1455
  baseURL: model.baseUrl,
1431
1456
  dangerouslyAllowBrowser: true,
1432
1457
  fetch,
1433
- defaultHeaders: sanitizeAdaptiveThinkingHeaders(model, mergeHeaders({
1458
+ defaultHeaders: sanitizeAdaptiveThinkingHeaders(model, mergeClientHeaders(model, {
1434
1459
  accept: "application/json",
1435
1460
  "anthropic-dangerous-direct-browser-access": "true",
1436
1461
  ...(betaFeatures.length > 0 ? { "anthropic-beta": betaFeatures.join(",") } : {}),
@@ -1845,9 +1870,10 @@ function convertTools(tools, isOAuthToken, supportsEagerToolInputStreaming, supp
1845
1870
  return [];
1846
1871
  return tools.map((tool, index) => {
1847
1872
  const strict = resolveJsonSchemaStrictSampling(tool, supportsStrictTools);
1873
+ const parameters = getJsonSchemaToolParameters(tool, strict);
1848
1874
  // A root union carries no top-level properties, so reading them directly
1849
1875
  // would advertise the tool to the model as taking no arguments at all.
1850
- const schema = resolveRootObjectSchema(tool.parameters);
1876
+ const schema = resolveRootObjectSchema(parameters);
1851
1877
  const legacyInputSchema = {
1852
1878
  type: "object",
1853
1879
  properties: schema.properties ?? {},
@@ -1855,7 +1881,7 @@ function convertTools(tools, isOAuthToken, supportsEagerToolInputStreaming, supp
1855
1881
  };
1856
1882
  const inputSchema = strict === true
1857
1883
  ? {
1858
- ...tool.parameters,
1884
+ ...parameters,
1859
1885
  ...legacyInputSchema,
1860
1886
  }
1861
1887
  : legacyInputSchema;