@code-yeongyu/senpi-ai 2026.10.15 → 2026.10.16-2

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 (36) hide show
  1. package/dist/api/google-shared.js +3 -0
  2. package/dist/google-thinking-generation.d.ts +5 -0
  3. package/dist/google-thinking-generation.js +29 -0
  4. package/dist/index.d.ts +1 -0
  5. package/dist/index.js +1 -0
  6. package/dist/model-cost.d.ts +4 -0
  7. package/dist/model-cost.js +14 -0
  8. package/dist/models.d.ts +3 -1
  9. package/dist/models.js +11 -4
  10. package/dist/provider-diagnostic.d.ts +2 -2
  11. package/dist/provider-diagnostic.js +8 -1
  12. package/dist/providers/all.js +3 -1
  13. package/dist/providers/data/.manifest.json +1 -1
  14. package/dist/providers/data/fireworks.json +1 -1
  15. package/dist/providers/data/google-vertex.json +1 -1
  16. package/dist/providers/data/google.json +1 -1
  17. package/dist/providers/data/nvidia.json +1 -1
  18. package/dist/providers/data/opencode-go.json +1 -1
  19. package/dist/providers/data/opencode.json +1 -1
  20. package/dist/providers/data/opengateway.json +1 -1
  21. package/dist/providers/data/openrouter.json +1 -1
  22. package/dist/providers/data/venice.json +1 -1
  23. package/dist/providers/data/vercel-ai-gateway.json +1 -1
  24. package/dist/providers/data/xiaomi-token-plan-ams.json +1 -1
  25. package/dist/providers/data/xiaomi-token-plan-cn.json +1 -1
  26. package/dist/providers/data/xiaomi-token-plan-sgp.json +1 -1
  27. package/dist/providers/data/xiaomi.json +1 -1
  28. package/dist/providers/faux.d.ts +2 -0
  29. package/dist/providers/faux.js +4 -3
  30. package/dist/types.d.ts +9 -1
  31. package/dist/utils/provider-diagnostic-sources.d.ts +1 -0
  32. package/dist/utils/provider-diagnostic-sources.js +41 -3
  33. package/dist/utils/provider-diagnostic-vocabulary.d.ts +6 -0
  34. package/dist/utils/provider-diagnostic-vocabulary.js +26 -0
  35. package/dist/utils/tool-choice-fallback.js +4 -1
  36. package/package.json +2 -2
@@ -1 +1 @@
1
- {"openai-completions":{"chat:mimo-v2.5":{"id":"mimo-v2.5","name":"MiMo-V2.5","api":"openai-completions","provider":"xiaomi-token-plan-ams","baseUrl":"https://token-plan-ams.xiaomimimo.com/v1","compat":{"supportsStrictMode":true,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:mimo-v2.5-pro":{"id":"mimo-v2.5-pro","name":"MiMo-V2.5-Pro","api":"openai-completions","provider":"xiaomi-token-plan-ams","baseUrl":"https://token-plan-ams.xiaomimimo.com/v1","compat":{"supportsStrictMode":true,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"type":"chat"},"chat:mimo-v2.6-flash":{"id":"mimo-v2.6-flash","name":"MiMo-V2.6-Flash","api":"openai-completions","provider":"xiaomi-token-plan-ams","baseUrl":"https://token-plan-ams.xiaomimimo.com/v1","compat":{"supportsStrictMode":true,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:mimo-v2.6-pro":{"id":"mimo-v2.6-pro","name":"MiMo-V2.6-Pro","api":"openai-completions","provider":"xiaomi-token-plan-ams","baseUrl":"https://token-plan-ams.xiaomimimo.com/v1","compat":{"supportsStrictMode":true,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"}}}
1
+ {"openai-completions":{"chat:mimo-v2.6-flash":{"id":"mimo-v2.6-flash","name":"MiMo-V2.6-Flash","api":"openai-completions","provider":"xiaomi-token-plan-ams","baseUrl":"https://token-plan-ams.xiaomimimo.com/v1","compat":{"supportsStrictMode":true,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:mimo-v2.6-pro":{"id":"mimo-v2.6-pro","name":"MiMo-V2.6-Pro","api":"openai-completions","provider":"xiaomi-token-plan-ams","baseUrl":"https://token-plan-ams.xiaomimimo.com/v1","compat":{"supportsStrictMode":true,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"}}}
@@ -1 +1 @@
1
- {"openai-completions":{"chat:mimo-v2.5":{"id":"mimo-v2.5","name":"MiMo-V2.5","api":"openai-completions","provider":"xiaomi-token-plan-cn","baseUrl":"https://token-plan-cn.xiaomimimo.com/v1","compat":{"supportsStrictMode":true,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:mimo-v2.5-pro":{"id":"mimo-v2.5-pro","name":"MiMo-V2.5-Pro","api":"openai-completions","provider":"xiaomi-token-plan-cn","baseUrl":"https://token-plan-cn.xiaomimimo.com/v1","compat":{"supportsStrictMode":true,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"type":"chat"},"chat:mimo-v2.6-flash":{"id":"mimo-v2.6-flash","name":"MiMo-V2.6-Flash","api":"openai-completions","provider":"xiaomi-token-plan-cn","baseUrl":"https://token-plan-cn.xiaomimimo.com/v1","compat":{"supportsStrictMode":true,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:mimo-v2.6-pro":{"id":"mimo-v2.6-pro","name":"MiMo-V2.6-Pro","api":"openai-completions","provider":"xiaomi-token-plan-cn","baseUrl":"https://token-plan-cn.xiaomimimo.com/v1","compat":{"supportsStrictMode":true,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"}}}
1
+ {"openai-completions":{"chat:mimo-v2.6-flash":{"id":"mimo-v2.6-flash","name":"MiMo-V2.6-Flash","api":"openai-completions","provider":"xiaomi-token-plan-cn","baseUrl":"https://token-plan-cn.xiaomimimo.com/v1","compat":{"supportsStrictMode":true,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:mimo-v2.6-pro":{"id":"mimo-v2.6-pro","name":"MiMo-V2.6-Pro","api":"openai-completions","provider":"xiaomi-token-plan-cn","baseUrl":"https://token-plan-cn.xiaomimimo.com/v1","compat":{"supportsStrictMode":true,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"}}}
@@ -1 +1 @@
1
- {"openai-completions":{"chat:mimo-v2.5":{"id":"mimo-v2.5","name":"MiMo-V2.5","api":"openai-completions","provider":"xiaomi-token-plan-sgp","baseUrl":"https://token-plan-sgp.xiaomimimo.com/v1","compat":{"supportsStrictMode":true,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:mimo-v2.5-pro":{"id":"mimo-v2.5-pro","name":"MiMo-V2.5-Pro","api":"openai-completions","provider":"xiaomi-token-plan-sgp","baseUrl":"https://token-plan-sgp.xiaomimimo.com/v1","compat":{"supportsStrictMode":true,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"type":"chat"},"chat:mimo-v2.6-flash":{"id":"mimo-v2.6-flash","name":"MiMo-V2.6-Flash","api":"openai-completions","provider":"xiaomi-token-plan-sgp","baseUrl":"https://token-plan-sgp.xiaomimimo.com/v1","compat":{"supportsStrictMode":true,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:mimo-v2.6-pro":{"id":"mimo-v2.6-pro","name":"MiMo-V2.6-Pro","api":"openai-completions","provider":"xiaomi-token-plan-sgp","baseUrl":"https://token-plan-sgp.xiaomimimo.com/v1","compat":{"supportsStrictMode":true,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"}}}
1
+ {"openai-completions":{"chat:mimo-v2.6-flash":{"id":"mimo-v2.6-flash","name":"MiMo-V2.6-Flash","api":"openai-completions","provider":"xiaomi-token-plan-sgp","baseUrl":"https://token-plan-sgp.xiaomimimo.com/v1","compat":{"supportsStrictMode":true,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:mimo-v2.6-pro":{"id":"mimo-v2.6-pro","name":"MiMo-V2.6-Pro","api":"openai-completions","provider":"xiaomi-token-plan-sgp","baseUrl":"https://token-plan-sgp.xiaomimimo.com/v1","compat":{"supportsStrictMode":true,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text","image"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"}}}
@@ -1 +1 @@
1
- {"openai-completions":{"chat:mimo-v2.5":{"id":"mimo-v2.5","name":"MiMo-V2.5","api":"openai-completions","provider":"xiaomi","baseUrl":"https://api.xiaomimimo.com/v1","compat":{"supportsStrictMode":true,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text","image"],"cost":{"input":0.14,"output":0.28,"cacheRead":0.0028,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:mimo-v2.5-pro":{"id":"mimo-v2.5-pro","name":"MiMo-V2.5-Pro","api":"openai-completions","provider":"xiaomi","baseUrl":"https://api.xiaomimimo.com/v1","compat":{"supportsStrictMode":true,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text"],"cost":{"input":0.435,"output":0.87,"cacheRead":0.0036,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"type":"chat"},"chat:mimo-v2.5-pro-ultraspeed":{"id":"mimo-v2.5-pro-ultraspeed","name":"MiMo-V2.5-Pro-UltraSpeed","api":"openai-completions","provider":"xiaomi","baseUrl":"https://api.xiaomimimo.com/v1","compat":{"supportsStrictMode":true,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text"],"cost":{"input":1.305,"output":2.61,"cacheRead":0.0108,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"type":"chat"},"chat:mimo-v2.6-flash":{"id":"mimo-v2.6-flash","name":"MiMo-V2.6-Flash","api":"openai-completions","provider":"xiaomi","baseUrl":"https://api.xiaomimimo.com/v1","compat":{"supportsStrictMode":true,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text","image"],"cost":{"input":0.14,"output":0.28,"cacheRead":0.0028,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:mimo-v2.6-pro":{"id":"mimo-v2.6-pro","name":"MiMo-V2.6-Pro","api":"openai-completions","provider":"xiaomi","baseUrl":"https://api.xiaomimimo.com/v1","compat":{"supportsStrictMode":true,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text","image"],"cost":{"input":0.435,"output":0.87,"cacheRead":0.0036,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:mimo-v2.6-pro-ultraspeed":{"id":"mimo-v2.6-pro-ultraspeed","name":"MiMo-V2.6-Pro-UltraSpeed","api":"openai-completions","provider":"xiaomi","baseUrl":"https://api.xiaomimimo.com/v1","compat":{"supportsStrictMode":true,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text","image"],"cost":{"input":4.35,"output":8.7,"cacheRead":0.036,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"}}}
1
+ {"openai-completions":{"chat:mimo-v2.6-flash":{"id":"mimo-v2.6-flash","name":"MiMo-V2.6-Flash","api":"openai-completions","provider":"xiaomi","baseUrl":"https://api.xiaomimimo.com/v1","compat":{"supportsStrictMode":true,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text","image"],"cost":{"input":0.14,"output":0.28,"cacheRead":0.0028,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:mimo-v2.6-pro":{"id":"mimo-v2.6-pro","name":"MiMo-V2.6-Pro","api":"openai-completions","provider":"xiaomi","baseUrl":"https://api.xiaomimimo.com/v1","compat":{"supportsStrictMode":true,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text","image"],"cost":{"input":0.435,"output":0.87,"cacheRead":0.0036,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"},"chat:mimo-v2.6-pro-ultraspeed":{"id":"mimo-v2.6-pro-ultraspeed","name":"MiMo-V2.6-Pro-UltraSpeed","api":"openai-completions","provider":"xiaomi","baseUrl":"https://api.xiaomimimo.com/v1","compat":{"supportsStrictMode":true,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek","supportsDisabledThinking":false},"reasoning":true,"input":["text","image"],"cost":{"input":4.35,"output":8.7,"cacheRead":0.036,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"inputLimits":{"images":{"resize":{"maxWidth":2000,"maxHeight":2000,"maxBytes":4718592,"jpegQuality":80}}},"type":"chat"}}}
@@ -47,6 +47,8 @@ export interface RegisterFauxProviderOptions {
47
47
  pollAfterMs?: number;
48
48
  };
49
49
  tokensPerSecond?: number;
50
+ /** Headers every scripted response reports through `onResponse` (default none). */
51
+ responseHeaders?: Record<string, string>;
50
52
  schedulerHook?: () => void | Promise<void>;
51
53
  tokenSize?: {
52
54
  min?: number;
@@ -334,6 +334,7 @@ async function streamWithDeltas(stream, message, minTokenSize, maxTokenSize, tok
334
334
  export function createFauxCore(options) {
335
335
  const api = options.api ?? randomId(DEFAULT_API);
336
336
  const provider = options.provider ?? DEFAULT_PROVIDER;
337
+ const responseHeaders = options.responseHeaders ?? {};
337
338
  const minTokenSize = Math.max(1, Math.min(options.tokenSize?.min ?? DEFAULT_MIN_TOKEN_SIZE, options.tokenSize?.max ?? DEFAULT_MAX_TOKEN_SIZE));
338
339
  const maxTokenSize = Math.max(minTokenSize, options.tokenSize?.max ?? DEFAULT_MAX_TOKEN_SIZE);
339
340
  let pendingResponses = [];
@@ -385,7 +386,7 @@ export function createFauxCore(options) {
385
386
  });
386
387
  queueMicrotask(async () => {
387
388
  try {
388
- await streamOptions?.onResponse?.({ status: 200, headers: {} }, requestModel);
389
+ await streamOptions?.onResponse?.({ status: 200, headers: { ...responseHeaders } }, requestModel);
389
390
  if (!step) {
390
391
  let message = createErrorMessage(new Error("No more faux responses queued"), api, provider, requestModel.id);
391
392
  message = withUsageEstimate(message, context, streamOptions, promptCache);
@@ -430,7 +431,7 @@ export function createFauxCore(options) {
430
431
  state.deferredFetchCount++;
431
432
  queueMicrotask(async () => {
432
433
  try {
433
- await fetchOptions?.onResponse?.({ status: 200, headers: {} }, requestModel);
434
+ await fetchOptions?.onResponse?.({ status: 200, headers: { ...responseHeaders } }, requestModel);
434
435
  const entry = deferredResponses.get(handle.id);
435
436
  if (!entry ||
436
437
  entry.handle.provider !== handle.provider ||
@@ -469,7 +470,7 @@ export function createFauxCore(options) {
469
470
  const entry = deferredResponses.get(handle.id);
470
471
  if (entry)
471
472
  entry.cancelled = true;
472
- await cancelOptions?.onResponse?.({ status: 200, headers: {} }, requestModel);
473
+ await cancelOptions?.onResponse?.({ status: 200, headers: { ...responseHeaders } }, requestModel);
473
474
  };
474
475
  function getModel(requestedModelId) {
475
476
  if (!requestedModelId) {
package/dist/types.d.ts CHANGED
@@ -1108,10 +1108,18 @@ export interface ModelCostTier extends ModelCostRates {
1108
1108
  /** Use this tier for requests whose total input usage exceeds this token count. */
1109
1109
  inputTokensAbove: number;
1110
1110
  }
1111
- export interface ModelCost extends ModelCostRates {
1111
+ export interface ModelCostCard extends ModelCostRates {
1112
1112
  /** Request-wide pricing tiers. The highest matching input threshold applies to the full request. */
1113
1113
  tiers?: ModelCostTier[];
1114
1114
  }
1115
+ export interface ModelCostEffectiveRate extends ModelCostCard {
1116
+ /** ISO 8601 UTC instant from which this card replaces the base card and every earlier dated card. */
1117
+ effectiveFrom: string;
1118
+ }
1119
+ export interface ModelCost extends ModelCostCard {
1120
+ /** Scheduled list-price changes, each billed for requests at or after its `effectiveFrom`. */
1121
+ effectiveRates?: ModelCostEffectiveRate[];
1122
+ }
1115
1123
  export interface ModelImageResizeOptions {
1116
1124
  maxWidth?: number;
1117
1125
  maxHeight?: number;
@@ -14,6 +14,7 @@ export declare function anthropicProviderDiagnosticFromSseData(data: string): Pr
14
14
  * servers reuse it for coarse buckets that can contradict the precise code.
15
15
  */
16
16
  export declare function openAICompatibleProviderDiagnosticFromError(error: unknown): ProviderDiagnostic | undefined;
17
+ export declare function transportProviderDiagnosticFromError(error: unknown): ProviderDiagnostic | undefined;
17
18
  /**
18
19
  * Await one provider transport call and, if it rejects, attach the classifier's
19
20
  * verdict to the rejection. Only errors raised by the wrapped call are
@@ -1,5 +1,5 @@
1
1
  import { attachProviderDiagnostic } from "./provider-diagnostic-carrier.js";
2
- import { classifyProviderFailure } from "./provider-diagnostic-vocabulary.js";
2
+ import { buildProviderDiagnostic, categoryForTransportCode, classifyProviderFailure, } from "./provider-diagnostic-vocabulary.js";
3
3
  /** Largest SSE error envelope parsed for classification at all. */
4
4
  const SSE_ERROR_ENVELOPE_MAX_BYTES = 8_192;
5
5
  function isRecord(value) {
@@ -74,6 +74,44 @@ export function openAICompatibleProviderDiagnosticFromError(error) {
74
74
  return undefined;
75
75
  }
76
76
  }
77
+ /**
78
+ * A connection failure carries no HTTP status; it proves only that the request got
79
+ * no provider answer. Reads the error's own `code`, then `cause.code` (fetch
80
+ * wraps the socket error), against a closed allowlist. Messages are never read.
81
+ */
82
+ /** How many `cause` links a transport code is looked for through (the error itself counts as one). */
83
+ const TRANSPORT_CAUSE_DEPTH = 4;
84
+ export function transportProviderDiagnosticFromError(error) {
85
+ try {
86
+ if (!(error instanceof Error))
87
+ return undefined;
88
+ // SDK errors wrap the runtime's error: Bun puts the code one cause down, Node's fetch two
89
+ // (SDK error -> TypeError "fetch failed" -> { code }). Walk a bounded chain, reading only `code`;
90
+ // the SDK's own connection error class name is the fallback when no link carries a code.
91
+ let current = error;
92
+ let sdkConnectionError;
93
+ for (let depth = 0; depth < TRANSPORT_CAUSE_DEPTH && (isRecord(current) || current instanceof Error); depth++) {
94
+ const code = Reflect.get(current, "code");
95
+ if (typeof code === "string" && categoryForTransportCode(code) !== undefined)
96
+ return buildProviderDiagnostic({ category: "network", code, evidence: "structured_transport" });
97
+ // The SDKs keep `name` as "Error"; their class is what says connection error.
98
+ for (const name of current instanceof Error ? [current.name, current.constructor.name] : []) {
99
+ if (sdkConnectionError === undefined && categoryForTransportCode(name) !== undefined)
100
+ sdkConnectionError = name;
101
+ }
102
+ current = Reflect.get(current, "cause");
103
+ }
104
+ return sdkConnectionError === undefined
105
+ ? undefined
106
+ : buildProviderDiagnostic({ category: "network", code: sdkConnectionError, evidence: "structured_transport" });
107
+ }
108
+ catch {
109
+ return undefined;
110
+ }
111
+ }
112
+ function classifyWithTransport(classify, error) {
113
+ return classify(error) ?? transportProviderDiagnosticFromError(error);
114
+ }
77
115
  /**
78
116
  * Await one provider transport call and, if it rejects, attach the classifier's
79
117
  * verdict to the rejection. Only errors raised by the wrapped call are
@@ -85,7 +123,7 @@ export async function awaitProviderTransport(request, classify) {
85
123
  }
86
124
  catch (error) {
87
125
  if (typeof error === "object" && error !== null)
88
- attachProviderDiagnostic(error, classify(error));
126
+ attachProviderDiagnostic(error, classifyWithTransport(classify, error));
89
127
  throw error;
90
128
  }
91
129
  }
@@ -96,7 +134,7 @@ export async function* iterateProviderTransport(source, classify) {
96
134
  }
97
135
  catch (error) {
98
136
  if (typeof error === "object" && error !== null)
99
- attachProviderDiagnostic(error, classify(error));
137
+ attachProviderDiagnostic(error, classifyWithTransport(classify, error));
100
138
  throw error;
101
139
  }
102
140
  }
@@ -8,6 +8,12 @@ export declare const PROVIDER_DIAGNOSTIC_MAX_BYTES = 512;
8
8
  * exhaustion, so it stays `unknown`.
9
9
  */
10
10
  export declare function categoryForProviderCode(code: string): ProviderDiagnosticCategory | undefined;
11
+ /**
12
+ * Closed allowlist of transport failures: Node `errno` / undici `code` names, and the provider SDKs'
13
+ * connection error class names (`APIConnectionError`, `APIConnectionTimeoutError`). Read only from the
14
+ * error chain's `code` and `name` fields, never from message text.
15
+ */
16
+ export declare function categoryForTransportCode(code: string): ProviderDiagnosticCategory | undefined;
11
17
  /** The HTTP status a recognized token may arrive with; anything else is contradictory evidence. */
12
18
  export declare function isProviderCodeStatusCompatible(code: string, status: number): boolean;
13
19
  /** Status-only family. 402/403/429 alone cannot tell quota, auth and rate limit apart. */
@@ -32,6 +32,31 @@ export function categoryForProviderCode(code) {
32
32
  return undefined;
33
33
  }
34
34
  }
35
+ /**
36
+ * Closed allowlist of transport failures: Node `errno` / undici `code` names, and the provider SDKs'
37
+ * connection error class names (`APIConnectionError`, `APIConnectionTimeoutError`). Read only from the
38
+ * error chain's `code` and `name` fields, never from message text.
39
+ */
40
+ export function categoryForTransportCode(code) {
41
+ switch (code) {
42
+ case "ECONNRESET":
43
+ case "ECONNREFUSED":
44
+ case "ETIMEDOUT":
45
+ case "ENOTFOUND":
46
+ case "EAI_AGAIN":
47
+ case "EPIPE":
48
+ case "UND_ERR_SOCKET":
49
+ case "UND_ERR_CONNECT_TIMEOUT":
50
+ case "UND_ERR_HEADERS_TIMEOUT":
51
+ case "UND_ERR_BODY_TIMEOUT":
52
+ case "UND_ERR_CLOSED":
53
+ case "APIConnectionError":
54
+ case "APIConnectionTimeoutError":
55
+ return "network";
56
+ default:
57
+ return undefined;
58
+ }
59
+ }
35
60
  /** The HTTP status a recognized token may arrive with; anything else is contradictory evidence. */
36
61
  export function isProviderCodeStatusCompatible(code, status) {
37
62
  switch (code) {
@@ -80,6 +105,7 @@ export function isProviderDiagnosticCategory(value) {
80
105
  case "context_limit":
81
106
  case "invalid_request":
82
107
  case "provider_unavailable":
108
+ case "network":
83
109
  case "unknown":
84
110
  return true;
85
111
  default:
@@ -104,7 +104,10 @@ export function isForcedToolChoiceUnsupportedError(error, sentForcedToolChoice)
104
104
  const message = errorMessage(error);
105
105
  return (/tool[_\s-]?choices?\b.*?(not\s+(?:currently\s+)?compatible|incompatible|not\s+(?:currently\s+)?supported|unsupported)/is.test(message) ||
106
106
  /forces?\s+tool\s+use.*?(not\s+(?:currently\s+)?compatible|incompatible|not\s+(?:currently\s+)?supported|unsupported)/is.test(message) ||
107
- /does\s+not\s+support\s+forced\s+tool[_\s-]?choices?/is.test(message) ||
107
+ // "does not support forced tool_choice", and opencode-go's thinking models (senpi#3324): "Thinking
108
+ // mode does not support this tool_choice". Only these determiners, so a refusal of some other
109
+ // parameter that merely sits next to tool_choice never matches.
110
+ /does\s+not\s+support\s+(?:forced|this|the)\s+tool[_\s-]?choices?/is.test(message) ||
108
111
  // Auto-only tool-choice upstreams. OmniRoute serving opencode-go/muse-spark-1.3-contributor
109
112
  // (2026-09-27): "only `\"auto\"` is supported for `tool_choice`. `\"none\"`, `\"required\"`, and named
110
113
  // function choices are not currently supported". Kiro behind an OpenAI-compatible proxy
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/senpi-ai",
3
- "version": "2026.10.15",
3
+ "version": "2026.10.16-2",
4
4
  "description": "Unified LLM API with automatic model discovery and provider configuration",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -88,7 +88,7 @@
88
88
  "dependencies": {
89
89
  "@anthropic-ai/sdk": "0.127.0",
90
90
  "@aws-sdk/client-bedrock-runtime": "3.1136.0",
91
- "@earendil-works/pi-telemetry": "npm:@code-yeongyu/senpi-telemetry@2026.10.15",
91
+ "@earendil-works/pi-telemetry": "npm:@code-yeongyu/senpi-telemetry@2026.10.16-2",
92
92
  "@google/genai": "2.23.0",
93
93
  "@smithy/node-http-handler": "4.12.1",
94
94
  "http-proxy-agent": "9.1.0",