@x12i/ai-dispatcher 3.2.0 → 3.3.1
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.
- package/README.md +22 -17
- package/dist/index.cjs +412 -106
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +22 -6
- package/dist/index.d.ts +22 -6
- package/dist/index.js +405 -104
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# @x12i/ai-dispatcher
|
|
2
2
|
|
|
3
|
-
One request shape for OpenRouter, AWS Bedrock, the OpenAI Responses API, and Cloudflare AI. You send the same request shape. The package picks the provider, and `@x12i/ai-profiles@5.
|
|
3
|
+
One request shape for OpenRouter, AWS Bedrock, the OpenAI Responses API, and Cloudflare AI. You send the same request shape. The package picks the provider, and `@x12i/ai-profiles@5.6.0` turns `reasoningEffort` into that provider's wire fields. Callers do not map effort levels onto provider fields or parse provider reasoning channels.
|
|
4
4
|
|
|
5
5
|
**Implemented providers:** `openrouter`, `bedrock`, `openai`, `cloudflare`. Any other provider throws `PROVIDER_NOT_IMPLEMENTED`.
|
|
6
6
|
|
|
7
|
-
The package is `@x12i/ai-dispatcher` 3.
|
|
7
|
+
The package is `@x12i/ai-dispatcher` 3.3.1. It runs on Node 22 or newer and publishes ESM and CommonJS from the same entry.
|
|
8
8
|
|
|
9
9
|
Connected MCP servers can be passed to `createAiDispatcher`. `run()` and `compile()` expose those tools to the model. `executeStreamingChat` does not. Details are in [MCP tools](#mcp-tools).
|
|
10
10
|
|
|
@@ -14,11 +14,11 @@ Connected MCP servers can be passed to `createAiDispatcher`. `run()` and `compil
|
|
|
14
14
|
npm install @x12i/ai-dispatcher
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
The package depends on `@x12i/ai-input@1.1.0`, `@x12i/ai-profiles@5.
|
|
17
|
+
The package depends on `@x12i/ai-input@1.1.0`, `@x12i/ai-profiles@5.6.0`, `@x12i/provider-metadata@^1.2.1`, `@x12i/openrouter-runtime@^2.3.0`, and `@x12i/bedrock-runtime@^2.2.2`. `@x12i/ai-catalogs@1.3.0` comes in through profiles. `gpt-tokenizer` and `ajv` are optional peers of `@x12i/ai-input` and are not installed with the dispatcher. `registerHostIntents` and `resolveAIProfile` are re-exported from this package so a host uses the same `@x12i/ai-profiles` copy the dispatcher resolves with.
|
|
18
18
|
|
|
19
19
|
## AI registry
|
|
20
20
|
|
|
21
|
-
`@x12i/ai-profiles@5.
|
|
21
|
+
`@x12i/ai-profiles@5.6.0` loads `GET /v1/datasets/profiles` and `GET /v1/datasets/catalog` from `https://ai-registry.app.x12i.com`. A successful response is used as-is and cached briefly. If the registry is unreachable, the JSON shipped in the npm package is used. Do not set `AI_REGISTRY_SOURCE`. Override the origin only when you proxy it: `AI_REGISTRY_URL`.
|
|
22
22
|
|
|
23
23
|
`resolveReasoning` still reads the bundled reasoning catalog. Profile names such as `cheap/default` resolve through the live registry:
|
|
24
24
|
|
|
@@ -70,12 +70,12 @@ Use model ids that belong to the selected catalog target. An OpenRouter id is no
|
|
|
70
70
|
| `openai` | `gpt-5.4` | `reasoning.effort: "low"` on the Responses body |
|
|
71
71
|
| `cloudflare` | `openai/gpt-5.4` | `reasoning.effort: "low"` on the Cloudflare Responses body |
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
The model catalog decides which efforts a model accepts. `@x12i/ai-profiles@5.6.0` still supplies the wire shape: response paths, stream keys, usage paths, and where the effort is written. The effort string itself is not rewritten.
|
|
74
74
|
|
|
75
|
-
- OpenRouter
|
|
75
|
+
- OpenRouter `openai/gpt-6-astra` at `xhigh` sends `reasoning.effort: "xhigh"`. `max` sends `max`.
|
|
76
|
+
- `minimal` and `none` on Astra fail with `EFFORT_UNSUPPORTED`. Set `degradeReasoningEffort: true` to keep a mapping substitution. The resolution then records `requestedEffort`, `sentEffort`, and `outcome: "degraded"`.
|
|
76
77
|
- OpenRouter `aion-labs/aion-2.0` is `ignored` with an empty reasoning body. The call still runs.
|
|
77
|
-
- Bedrock `anthropic.claude-fable-5-1`
|
|
78
|
-
- OpenAI `gpt-5.4` + `max` is `applied` and sends `reasoning.effort: "max"`.
|
|
78
|
+
- Bedrock `anthropic.claude-fable-5-1` at `max` sends `output_config.effort: "max"`, because the catalog lists `max`.
|
|
79
79
|
- OpenAI `gpt-4o` is `ignored`. The Responses call still runs.
|
|
80
80
|
|
|
81
81
|
The type `AiProviderId` also lists `anthropic`, `google`, `azure`, `groq`, `mistral`, `cohere`, `together`, `fireworks`, `xai`, `deepseek`, and `custom`. Passing any of those throws `PROVIDER_NOT_IMPLEMENTED`.
|
|
@@ -276,7 +276,7 @@ Text blocks in an MCP result are joined and returned to the model. `isError: tru
|
|
|
276
276
|
|
|
277
277
|
## Reasoning effort
|
|
278
278
|
|
|
279
|
-
`reasoningEffort` is
|
|
279
|
+
`reasoningEffort` is the effort name to send. It is valid when that model's `reasoning.supportedEfforts` lists it. An effort the model does not list fails with `EFFORT_UNSUPPORTED`. The error names the model, the requested effort, and the supported list. Unknown model ids still fail with `UNKNOWN_MODEL`. Set `degradeReasoningEffort: true` to allow the mapping's substitution. The call then records both efforts and `outcome: "degraded"`.
|
|
280
280
|
|
|
281
281
|
| Request | Catalog |
|
|
282
282
|
| --- | --- |
|
|
@@ -294,8 +294,8 @@ An OpenRouter `reasoning` object on a Bedrock call is not a Bedrock control. Wit
|
|
|
294
294
|
|
|
295
295
|
Outcomes:
|
|
296
296
|
|
|
297
|
-
- `applied` — the
|
|
298
|
-
- `degraded` — the
|
|
297
|
+
- `applied` — the checked effort was written as requested.
|
|
298
|
+
- `degraded` — `degradeReasoningEffort` was set and the mapping wrote a different listed effort. The call still runs.
|
|
299
299
|
- `ignored` — the model has no reasoning control. The call still runs with an empty catalog body.
|
|
300
300
|
|
|
301
301
|
Unknown models and missing mappings throw. The error keeps the catalog `code` and `details`, including `UNKNOWN_MODEL` and `REASONING_MAPPING_MISSING`. `reasoningEffort` without any model id throws `REASONING_MODEL_REQUIRED`.
|
|
@@ -315,21 +315,25 @@ The dispatcher does not rank efforts, invent token budgets, or rewrite `maxToken
|
|
|
315
315
|
```ts
|
|
316
316
|
{
|
|
317
317
|
requestedEffort: "max",
|
|
318
|
+
sentEffort: "max",
|
|
319
|
+
reportedEffort: "xhigh",
|
|
318
320
|
target: "openrouter",
|
|
319
|
-
requestedModel: "
|
|
320
|
-
effectiveModel: "
|
|
321
|
-
outcome: "
|
|
321
|
+
requestedModel: "openai/gpt-6-astra",
|
|
322
|
+
effectiveModel: "openai/gpt-6-astra",
|
|
323
|
+
outcome: "applied",
|
|
322
324
|
bypassed: false
|
|
323
325
|
}
|
|
324
326
|
```
|
|
325
327
|
|
|
328
|
+
`reportedEffort` is set when the provider returns an effort. A gateway can echo `max` back as `xhigh`. `sentEffort` is omitted when the mapping ignores the model and writes no effort.
|
|
329
|
+
|
|
326
330
|
The same record is on `compile()` output, `stream.start`, and `stream.done`.
|
|
327
331
|
|
|
328
332
|
The rest of the response is the runtime shape: `id`, `status` (`completed`, `failed`, `requires_action`, `policy_violation`), `apiMode`, `model`, `messages`, `citations`, `images`, `patches`, `toolUsage`, `finishReason`, `warnings`, `errors`, `raw`, and `metadata`. Direct OpenAI sets `apiMode` to `"responses"` and returns function calls as `requires_action` without running them. Cloudflare Responses does the same. Cloudflare chat, messages, and run report `apiMode: "chat"`.
|
|
329
333
|
|
|
330
334
|
Streaming emits `stream.reasoning.delta` for thought text. That text is not copied into `stream.text.delta`, tool-argument deltas, or structured-output text. If a future catalog asks for think-tag stripping, tags are split out of answer deltas before those deltas are yielded.
|
|
331
335
|
|
|
332
|
-
The dispatcher does not store conversation history. When a directive lists history fields to drop, callers pass those paths to `stripReasoningHistoryFields(message, paths)`. The helper clones the message, deletes only those pointers, and is safe to call twice. Catalog 5.
|
|
336
|
+
The dispatcher does not store conversation history. When a directive lists history fields to drop, callers pass those paths to `stripReasoningHistoryFields(message, paths)`. The helper clones the message, deletes only those pointers, and is safe to call twice. Catalog 5.6.0 paths are empty, so a real directive deletes nothing.
|
|
333
337
|
|
|
334
338
|
## Streaming
|
|
335
339
|
|
|
@@ -500,6 +504,7 @@ Catalog failures throw `AiDispatcherError` with `code`, `message`, and the catal
|
|
|
500
504
|
| `PROVIDER_REQUIRED` | No provider string is available |
|
|
501
505
|
| `PROVIDER_ADAPTER_MISSING` | An implemented provider has no adapter |
|
|
502
506
|
| `REASONING_MODEL_REQUIRED` | `reasoningEffort` is set and no model id is available |
|
|
507
|
+
| `EFFORT_UNSUPPORTED` | The model's `supportedEfforts` does not list the requested effort, and `degradeReasoningEffort` is not set |
|
|
503
508
|
| `REASONING_PREFIX_UNSUPPORTED` | A catalog prompt prefix has no user text to attach to |
|
|
504
509
|
| `UNSUPPORTED_REQUEST_FIELD` | A field cannot be sent on the selected provider |
|
|
505
510
|
| `MODEL_REQUIRED` | Direct OpenAI or Cloudflare has no model id |
|
|
@@ -529,14 +534,14 @@ Pass `logger` on the dispatcher. `run` and `executeStreamingChat` emit `ai-dispa
|
|
|
529
534
|
|
|
530
535
|
## Limitations
|
|
531
536
|
|
|
532
|
-
- Catalog 5.
|
|
537
|
+
- Catalog 5.6.0 does not currently emit a prompt prefix, a replacement model, think-tag stripping, history deletions, or a reasoning token budget. Those paths exist for the directive type and are covered by synthetic tests.
|
|
533
538
|
- Prompt caching is a dispatcher profile, not an `@x12i/ai-profiles` field. It writes one breakpoint after `system` or `instructions`. It does not place extra breakpoints on tools or on a prefix that changes in the middle of the call.
|
|
534
539
|
- Provenance notes about output-token headroom are not enforced, because the resolver does not return them as fields.
|
|
535
540
|
- OpenRouter server tools, `apiMode: "chat"`, and `rawOpenRouterOverrides` stay on OpenRouter. Bedrock, direct OpenAI, and Cloudflare reject the server-tool fields and `rawOpenRouterOverrides` keys other than `metadata`. Cloudflare accepts `apiMode: "chat"` as the chat-completions endpoint.
|
|
536
541
|
- Direct OpenAI and Cloudflare streaming do not run the function-tool loop. MCP tools are not attached to `executeStreamingChat` on any provider. Cloudflare `/ai/run` does not stream.
|
|
537
542
|
- OpenRouter advisor, subagent, and fusion cannot call MCP sessions registered on the dispatcher.
|
|
538
543
|
- Bedrock `run()` returns a failed response for `UNSUPPORTED_CONTENT`. `compile()` throws that error.
|
|
539
|
-
- Live provider calls are not part of the package test suite. Tests mock HTTP and the Bedrock client and use the real 5.
|
|
544
|
+
- Live provider calls are not part of the package test suite. Tests mock HTTP and the Bedrock client and use the real 5.6.0 reasoning catalog for contract cases.
|
|
540
545
|
- Input preparation does not claim release gate 9. Automatic TOON and `shared-v1` stay on compact outline or the original string until the caller passes a matching approval and a tokenizer. `codec: "toon"` sends TOON as a caller choice. `codec: "json"` and `mode: "raw"` keep JSON.
|
|
541
546
|
- `gpt-tokenizer` and `ajv` are not installed. A `gpt:*` tokenizer is loaded only when that call requests it.
|
|
542
547
|
- The dispatcher does not read `AI_INPUT_*` or a `.env` file for input preparation.
|