@code-yeongyu/senpi-ai 2026.9.12-3 → 2026.9.12

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 (109) hide show
  1. package/README.md +4 -39
  2. package/dist/api/anthropic-messages.d.ts.map +1 -1
  3. package/dist/api/anthropic-messages.js +1 -8
  4. package/dist/api/anthropic-messages.js.map +1 -1
  5. package/dist/api/cloudflare-gateway-binding.d.ts +69 -0
  6. package/dist/api/cloudflare-gateway-binding.d.ts.map +1 -0
  7. package/dist/api/cloudflare-gateway-binding.js +159 -0
  8. package/dist/api/cloudflare-gateway-binding.js.map +1 -0
  9. package/dist/api/cursor-agent/measure.d.ts +0 -11
  10. package/dist/api/cursor-agent/measure.d.ts.map +1 -1
  11. package/dist/api/cursor-agent/measure.js +0 -18
  12. package/dist/api/cursor-agent/measure.js.map +1 -1
  13. package/dist/api/cursor-agent.d.ts +1 -1
  14. package/dist/api/cursor-agent.d.ts.map +1 -1
  15. package/dist/api/cursor-agent.js +1 -5
  16. package/dist/api/cursor-agent.js.map +1 -1
  17. package/dist/api/mistral-conversations.js +1 -4
  18. package/dist/api/mistral-conversations.js.map +1 -1
  19. package/dist/api/openai-codex-responses.d.ts.map +1 -1
  20. package/dist/api/openai-codex-responses.js +3 -6
  21. package/dist/api/openai-codex-responses.js.map +1 -1
  22. package/dist/api/openai-responses-shared.d.ts.map +1 -1
  23. package/dist/api/openai-responses-shared.js +1 -4
  24. package/dist/api/openai-responses-shared.js.map +1 -1
  25. package/dist/api/openai-responses.d.ts.map +1 -1
  26. package/dist/api/openai-responses.js +3 -13
  27. package/dist/api/openai-responses.js.map +1 -1
  28. package/dist/cursor/store-migration.d.ts.map +1 -1
  29. package/dist/cursor/store-migration.js +1 -2
  30. package/dist/cursor/store-migration.js.map +1 -1
  31. package/dist/index.d.ts +1 -2
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +1 -2
  34. package/dist/index.js.map +1 -1
  35. package/dist/models.d.ts +0 -1
  36. package/dist/models.d.ts.map +1 -1
  37. package/dist/models.js +2 -5
  38. package/dist/models.js.map +1 -1
  39. package/dist/openai-responses-compat.d.ts +1 -1
  40. package/dist/openai-responses-compat.d.ts.map +1 -1
  41. package/dist/openai-responses-compat.js.map +1 -1
  42. package/dist/providers/cloudflare-ai-gateway.d.ts.map +1 -1
  43. package/dist/providers/cloudflare-ai-gateway.js +0 -4
  44. package/dist/providers/cloudflare-ai-gateway.js.map +1 -1
  45. package/dist/providers/cursor.d.ts.map +1 -1
  46. package/dist/providers/cursor.js +1 -2
  47. package/dist/providers/cursor.js.map +1 -1
  48. package/dist/providers/data/.manifest.json +1 -1
  49. package/dist/providers/data/azure-openai-responses.json +1 -1
  50. package/dist/providers/data/baseten.json +1 -1
  51. package/dist/providers/data/deepseek.json +1 -1
  52. package/dist/providers/data/fireworks.json +1 -1
  53. package/dist/providers/data/github-copilot.json +1 -1
  54. package/dist/providers/data/openai-codex.json +1 -1
  55. package/dist/providers/data/openrouter.json +1 -1
  56. package/dist/providers/data/qwen-token-plan-cn.json +1 -1
  57. package/dist/providers/data/qwen-token-plan-individual.json +1 -1
  58. package/dist/providers/data/qwen-token-plan.json +1 -1
  59. package/dist/providers/data/xai.json +1 -1
  60. package/dist/providers/faux.js +5 -5
  61. package/dist/providers/faux.js.map +1 -1
  62. package/dist/providers/opencode-go.d.ts.map +1 -1
  63. package/dist/providers/opencode-go.js +3 -4
  64. package/dist/providers/opencode-go.js.map +1 -1
  65. package/dist/providers/opencode.d.ts.map +1 -1
  66. package/dist/providers/opencode.js +4 -5
  67. package/dist/providers/opencode.js.map +1 -1
  68. package/dist/types.d.ts +6 -16
  69. package/dist/types.d.ts.map +1 -1
  70. package/dist/types.js.map +1 -1
  71. package/dist/utils/event-stream.d.ts.map +1 -1
  72. package/dist/utils/event-stream.js +5 -25
  73. package/dist/utils/event-stream.js.map +1 -1
  74. package/dist/utils/prompt-cache-ttl.d.ts +1 -1
  75. package/dist/utils/prompt-cache-ttl.d.ts.map +1 -1
  76. package/dist/utils/prompt-cache-ttl.js +1 -5
  77. package/dist/utils/prompt-cache-ttl.js.map +1 -1
  78. package/dist/utils/retry-profile/types.d.ts +1 -10
  79. package/dist/utils/retry-profile/types.d.ts.map +1 -1
  80. package/dist/utils/retry-profile/types.js.map +1 -1
  81. package/dist/utils/retry.d.ts +2 -13
  82. package/dist/utils/retry.d.ts.map +1 -1
  83. package/dist/utils/retry.js +7 -18
  84. package/dist/utils/retry.js.map +1 -1
  85. package/dist/utils/uuid.d.ts +2 -2
  86. package/dist/utils/uuid.d.ts.map +1 -1
  87. package/dist/utils/uuid.js +31 -36
  88. package/dist/utils/uuid.js.map +1 -1
  89. package/package.json +6 -6
  90. package/dist/api/cloudflare-ai-binding.d.ts +0 -77
  91. package/dist/api/cloudflare-ai-binding.d.ts.map +0 -1
  92. package/dist/api/cloudflare-ai-binding.js +0 -72
  93. package/dist/api/cloudflare-ai-binding.js.map +0 -1
  94. package/dist/cursor/context-limit-store.d.ts +0 -32
  95. package/dist/cursor/context-limit-store.d.ts.map +0 -1
  96. package/dist/cursor/context-limit-store.js +0 -62
  97. package/dist/cursor/context-limit-store.js.map +0 -1
  98. package/dist/providers/opencode-headers.d.ts +0 -4
  99. package/dist/providers/opencode-headers.d.ts.map +0 -1
  100. package/dist/providers/opencode-headers.js +0 -22
  101. package/dist/providers/opencode-headers.js.map +0 -1
  102. package/dist/utils/assistant-message-frame.d.ts +0 -77
  103. package/dist/utils/assistant-message-frame.d.ts.map +0 -1
  104. package/dist/utils/assistant-message-frame.js +0 -427
  105. package/dist/utils/assistant-message-frame.js.map +0 -1
  106. package/dist/utils/cursor-context-limit.d.ts +0 -12
  107. package/dist/utils/cursor-context-limit.d.ts.map +0 -1
  108. package/dist/utils/cursor-context-limit.js +0 -93
  109. package/dist/utils/cursor-context-limit.js.map +0 -1
package/README.md CHANGED
@@ -26,7 +26,6 @@ Unified LLM API with provider collections, automatic auth resolution, token and
26
26
  - [Streaming Tool Calls with Partial JSON](#streaming-tool-calls-with-partial-json)
27
27
  - [Validating Tool Arguments](#validating-tool-arguments)
28
28
  - [Complete Event Reference](#complete-event-reference)
29
- - [Compact Assistant Message Frames](#compact-assistant-message-frames)
30
29
  - [Image Input](#image-input)
31
30
  - [Image Generation](#image-generation)
32
31
  - [Thinking/Reasoning](#thinkingreasoning)
@@ -663,10 +662,6 @@ for await (const event of s) {
663
662
 
664
663
  ### Complete Event Reference
665
664
 
666
- Successful generation follows `start → updates* → done`. A failure after generation starts follows `start → updates* → error`. Request setup may fail before generation starts, in which case the stream contains only `error`; `done` and update events are invalid before `start`. Direct API `streamSimple()` calls throw synchronously when request auth is missing.
667
-
668
- Every non-terminal event's `partial` is the shared live response-so-far helper. It is intentionally not an event-time snapshot: providers may mutate the same message and content blocks as generation advances, including while older events wait in the stream queue. Inspect it when handling an event instead of retaining it as historical state. Text and ordinary thinking blocks are empty when their `*_start` event is emitted and grow only through matching `*_delta` events until the authoritative `*_end`; redacted thinking may be complete at start and emit no deltas. Tool-call arguments at `toolcall_start` are provider-specific; `toolcall_delta` carries subsequent JSON updates.
669
-
670
665
  All streaming events emitted during assistant message generation:
671
666
 
672
667
  | Event Type | Description | Key Properties |
@@ -680,40 +675,12 @@ All streaming events emitted during assistant message generation:
680
675
  | `thinking_end` | Thinking block complete | `content`: Full thinking, `contentIndex`: Position |
681
676
  | `toolcall_start` | Tool call begins | `contentIndex`: Position in content array |
682
677
  | `toolcall_delta` | Tool arguments streaming | `delta`: JSON chunk, `partial.content[contentIndex].arguments`: Partial parsed args |
683
- | `toolcall_end` | Tool call complete | `toolCall`: Complete, but not schema-validated, tool call with `id`, `name`, `arguments` |
678
+ | `toolcall_end` | Tool call complete | `toolCall`: Complete validated tool call with `id`, `name`, `arguments` |
684
679
  | `done` | Stream complete | `reason`: Stop reason ("stop", "length", "toolUse"), `message`: Final assistant message |
685
680
  | `error` | Error occurred | `reason`: Error type ("error" or "aborted"), `error`: AssistantMessage with partial content |
686
681
 
687
682
  Streaming events for different content blocks are not guaranteed to be contiguous. Providers may emit deltas for text, thinking, and tool calls in the same upstream chunk, and pi may surface corresponding events interleaved, for example `text_start`, `text_delta`, `toolcall_start`, `text_delta`, `toolcall_delta`. Consumers must use `contentIndex` to associate each delta/end event with its block and must not assume that a block's `*_start`/`*_delta`/`*_end` sequence is uninterrupted by events for other blocks.
688
683
 
689
- ### Compact Assistant Message Frames
690
-
691
- `AssistantMessageFrameEncoder` converts one stream into compact, persistable `AssistantMessageFrame` values. Create one encoder per stream and feed it every event in order. The encoder understands that `partial` is live: a block-start event consumed after the provider has already queued later deltas snapshots the current block once, and covered queued text/thinking deltas produce no duplicate frame. It retains only per-open-block counters plus, temporarily, the raw prefix needed to synchronize an already-advanced tool call. It never clones the growing full partial per token.
692
-
693
- The start frame contains message metadata with empty content. Text and thinking frames store each generated character at most once before the authoritative end frame. Tool calls that were already advanced when their start event was consumed use one compact JSON checkpoint before ordinary deltas resume. Terminal `done` and `error` events produce no frame because final message settlement is separate. A pre-generation `error` therefore produces no frames.
694
-
695
- `reduceAssistantMessageFrames()` is the canonical pure reducer. It reconstructs text, thinking, and tool-call arguments, including interleaved blocks identified by `contentIndex`, and rejects malformed sequences. It performs a single pass over the iterable and returns `undefined` when there is no start frame. End frames replace blocks with the provider's authoritative completed content and metadata. The reducer does not validate tool arguments against a TypeBox schema; call `validateToolCall` before execution.
696
-
697
- ```typescript
698
- import {
699
- AssistantMessageFrameEncoder,
700
- reduceAssistantMessageFrames,
701
- type AssistantMessageFrame,
702
- } from '@earendil-works/pi-ai';
703
-
704
- const encoder = new AssistantMessageFrameEncoder();
705
- const frames: AssistantMessageFrame[] = [];
706
- for await (const event of s) {
707
- const frame = encoder.encode(event);
708
- if (frame) frames.push(frame);
709
- }
710
-
711
- const reconstructedPartial = reduceAssistantMessageFrames(frames);
712
- const finalMessage = await s.result(); // Persist terminal settlement separately.
713
- ```
714
-
715
- An encoder rejects duplicate starts, updates before start, `done` before start, events after a terminal event, duplicate block starts, and block-kind mismatches. An `error` before start is valid and returns no frame.
716
-
717
684
  ## Image Input
718
685
 
719
686
  Models with vision capabilities can process images. You can check if a model supports images via the `input` property. If you pass images to a non-vision model, they are silently ignored.
@@ -938,7 +905,7 @@ Every `AssistantMessage` includes a `stopReason` field that indicates how the ge
938
905
 
939
906
  ## Error Handling
940
907
 
941
- Request failures after a stream is returned never throw: when a request ends with an error (including aborts and tool call validation errors), the streaming API emits an error event and the final message carries the details. Setup failures may emit `error` without `start`; failures after generation begins emit `start`, any observed updates, then `error`. Direct API `streamSimple()` calls throw synchronously when request auth is missing:
908
+ Request failures never throw out of the stream functions: when a request ends with an error (including aborts and tool call validation errors), the streaming API emits an error event and the final message carries the details:
942
909
 
943
910
  ```typescript
944
911
  // In streaming
@@ -960,7 +927,7 @@ if (message.stopReason === 'error' || message.stopReason === 'aborted') {
960
927
  }
961
928
  ```
962
929
 
963
- When using a provider collection, auth failures (OAuth refresh failed, unknown provider) surface as a stream error with `stopReason: "error"`. Direct API `streamSimple()` calls instead throw synchronously when their required auth is absent.
930
+ Auth failures (no key configured, OAuth refresh failed, unknown provider) surface the same way: as a stream error with `stopReason: "error"`.
964
931
 
965
932
  ### Aborting Requests
966
933
 
@@ -1220,7 +1187,7 @@ interface OpenAICompletionsCompat {
1220
1187
  supportsUsageInStreaming?: boolean; // Whether provider supports `stream_options: { include_usage: true }` (default: true)
1221
1188
  supportsStrictMode?: boolean; // Whether provider supports `strict` in tool definitions (default: true)
1222
1189
  supportsOpenAIGrammarTools?: boolean; // Whether to emit OpenAI custom Lark/regex grammar tools; false falls back to normal function tools (default: false; the generated catalog enables it for capable models)
1223
- sendSessionAffinityHeaders?: boolean; // Send session-affinity data from `sessionId` (default: true for OpenRouter, false otherwise)
1190
+ sendSessionAffinityHeaders?: boolean; // Send session-affinity data from `sessionId` (default: false)
1224
1191
  sessionAffinityFormat?: 'openai' | 'openai-nosession' | 'openrouter'; // Format for session affinity: 'openai' uses `prompt_cache_key`, `session_id`, `x-client-request-id`, and `x-session-affinity`; 'openai-nosession' uses `prompt_cache_key`, `x-client-request-id`, and `x-session-affinity`; 'openrouter' uses `x-session-id` (default: auto-detected)
1225
1192
  maxTokensField?: 'max_completion_tokens' | 'max_tokens'; // Which field name to use (default: max_completion_tokens)
1226
1193
  requiresToolResultName?: boolean; // Whether tool results require the `name` field (default: false)
@@ -1246,8 +1213,6 @@ interface OpenAIResponsesCompat {
1246
1213
  }
1247
1214
  ```
1248
1215
 
1249
- OpenRouter requests send `x-session-id` from `sessionId` when prompt caching is enabled. Chat Completions and Anthropic Messages both auto-detect OpenRouter endpoints unless `sendSessionAffinityHeaders` is explicitly false. On Anthropic-compatible models, `sessionAffinityFormat: "openrouter"` selects `x-session-id`; when unset, the existing `x-session-affinity` format is used. Explicit request headers take precedence over generated headers.
1250
-
1251
1216
  If `compat` is not set, the library falls back to URL-based detection. If `compat` is partially set, unspecified fields use the detected defaults. This is useful for:
1252
1217
 
1253
1218
  - **LiteLLM proxies**: May not support `store` field
@@ -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,EAMX,+BAA+B,EAK/B,MAAM,uDAAuD,CAAC;AAG/D,OAAO,KAAK,EACX,wBAAwB,EAKxB,OAAO,EAGP,KAAK,EAGL,mBAAmB,EAEnB,cAAc,EACd,aAAa,EAGb,IAAI,EAIJ,MAAM,aAAa,CAAC;AAsCrB,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AA0ElE,eAAO,MAAM,gBAAgB,SAAU,MAAM,WAC2B,CAAC;AACzE,eAAO,MAAM,kBAAkB,SAAU,MAAM,UAAU,IAAI,EAAE,WAS9D,CAAC;AA4EF,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;AAE1E,MAAM,MAAM,wBAAwB,GAAG,YAAY,GAAG,SAAS,CAAC;AA+FhE,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,wEAAwE;IACxE,gBAAgB,CAAC,EAAE,wBAAwB,CAAC;IAC5C;;;;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;AAmvBD,eAAO,MAAM,MAAM,EAAE,cAAc,CAAC,oBAAoB,EAAE,gBAAgB,CAudzE,CAAC;AAyFF,eAAO,MAAM,YAAY,EAAE,cAAc,CAAC,oBAAoB,EAAE,mBAAmB,CA+ClF,CAAC;AAmJF,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,EAMX,+BAA+B,EAK/B,MAAM,uDAAuD,CAAC;AAG/D,OAAO,KAAK,EACX,wBAAwB,EAKxB,OAAO,EAGP,KAAK,EAGL,mBAAmB,EAEnB,cAAc,EACd,aAAa,EAGb,IAAI,EAIJ,MAAM,aAAa,CAAC;AAsCrB,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AA0ElE,eAAO,MAAM,gBAAgB,SAAU,MAAM,WAC2B,CAAC;AACzE,eAAO,MAAM,kBAAkB,SAAU,MAAM,UAAU,IAAI,EAAE,WAS9D,CAAC;AA4EF,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;AAE1E,MAAM,MAAM,wBAAwB,GAAG,YAAY,GAAG,SAAS,CAAC;AA+FhE,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,wEAAwE;IACxE,gBAAgB,CAAC,EAAE,wBAAwB,CAAC;IAC5C;;;;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;AAmvBD,eAAO,MAAM,MAAM,EAAE,cAAc,CAAC,oBAAoB,EAAE,gBAAgB,CAudzE,CAAC;AAyFF,eAAO,MAAM,YAAY,EAAE,cAAc,CAAC,oBAAoB,EAAE,mBAAmB,CA+ClF,CAAC;AA6IF,wBAAgB,mCAAmC,CAClD,KAAK,EAAE,KAAK,CAAC,oBAAoB,CAAC,EAClC,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,gBAAgB,GACxB,+BAA+B,CAkBjC"}
@@ -1432,14 +1432,7 @@ function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStre
1432
1432
  return { client, isOAuthToken: true };
1433
1433
  }
1434
1434
  // API key auth
1435
- const affinityCompat = getAnthropicCompat(model);
1436
- const sessionAffinityHeaders = {};
1437
- if (sessionId && affinityCompat.sendSessionAffinityHeaders) {
1438
- // OpenRouter routes prompt-cache affinity through its own header name and
1439
- // rejects x-session-affinity (earendil-works/pi#9102).
1440
- const header = affinityCompat.sessionAffinityFormat === "openrouter" ? "x-session-id" : "x-session-affinity";
1441
- sessionAffinityHeaders[header] = sessionId;
1442
- }
1435
+ const sessionAffinityHeaders = sessionId && getAnthropicCompat(model).sendSessionAffinityHeaders ? { "x-session-affinity": sessionId } : {};
1443
1436
  const client = new Anthropic({
1444
1437
  apiKey: apiKey ?? null,
1445
1438
  authToken: null,