@absolutejs/ai 0.1.3 → 0.2.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.
- package/CHANGELOG.md +7 -0
- package/README.md +18 -0
- package/changelog.json +21 -0
- package/dist/ai/index.js +45 -4
- package/dist/ai/index.js.map +6 -5
- package/dist/src/ai/index.d.ts +1 -0
- package/dist/src/ai/providerRouter.d.ts +4 -0
- package/dist/src/ai/streamAIWithTools.d.ts +2 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,13 @@ This file is generated by `absolute-changelog` from the entries in
|
|
|
6
6
|
`changelog/`. Edit an entry, not this file — and add new ones under
|
|
7
7
|
`changelog/unreleased/`.
|
|
8
8
|
|
|
9
|
+
## 0.2.0 — 2026-09-16
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **Expose each tool-loop turn response metadata so consumers can price the actual served processing tier** (`streamAIWithTools`, `StreamAIWithToolsEvent`)
|
|
14
|
+
- **Route exact model IDs to the same provider for token counting, capacity checks, preparation and generation** (`createAIProviderRouter`)
|
|
15
|
+
|
|
9
16
|
## 0.1.3 — 2026-09-16
|
|
10
17
|
|
|
11
18
|
### Fixed
|
package/README.md
CHANGED
|
@@ -496,3 +496,21 @@ its explicit `false` remains an opt-out unless `contextPolicy` is supplied.
|
|
|
496
496
|
Applications should surface typed failures with saved-input retry UI. These
|
|
497
497
|
changes do not guarantee detection of every provider-side accounting discrepancy
|
|
498
498
|
or provide exactly-once external execution after a process crash.
|
|
499
|
+
|
|
500
|
+
### Models from different providers
|
|
501
|
+
|
|
502
|
+
`createAIProviderRouter` routes exact model IDs for generation, token counting and
|
|
503
|
+
capacity checks. It snapshots the route map and fails explicitly for unknown
|
|
504
|
+
models or a route without counting support. It does not choose a model or add a
|
|
505
|
+
fallback. For example, preparation and final answering can use different vendors:
|
|
506
|
+
|
|
507
|
+
```ts
|
|
508
|
+
const provider = createAIProviderRouter({
|
|
509
|
+
"claude-haiku-4-5-20251001": anthropicProvider,
|
|
510
|
+
"gpt-5.6-luna": openaiResponsesProvider,
|
|
511
|
+
});
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
`streamAIWithTools` includes each completed turn's provider response `metadata`
|
|
515
|
+
on its `turn` event. Price that turn using the returned `serviceTier`, when
|
|
516
|
+
available, rather than assuming that the requested processing tier was served.
|
package/changelog.json
CHANGED
|
@@ -2,6 +2,27 @@
|
|
|
2
2
|
"contract": 1,
|
|
3
3
|
"name": "@absolutejs/ai",
|
|
4
4
|
"releases": [
|
|
5
|
+
{
|
|
6
|
+
"changes": [
|
|
7
|
+
{
|
|
8
|
+
"kind": "added",
|
|
9
|
+
"summary": "Expose each tool-loop turn response metadata so consumers can price the actual served processing tier",
|
|
10
|
+
"symbols": [
|
|
11
|
+
"streamAIWithTools",
|
|
12
|
+
"StreamAIWithToolsEvent"
|
|
13
|
+
]
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"kind": "added",
|
|
17
|
+
"summary": "Route exact model IDs to the same provider for token counting, capacity checks, preparation and generation",
|
|
18
|
+
"symbols": [
|
|
19
|
+
"createAIProviderRouter"
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
"date": "2026-09-16",
|
|
24
|
+
"version": "0.2.0"
|
|
25
|
+
},
|
|
5
26
|
{
|
|
6
27
|
"changes": [
|
|
7
28
|
{
|
package/dist/ai/index.js
CHANGED
|
@@ -5832,6 +5832,7 @@ var streamAIWithTools = async function* (options) {
|
|
|
5832
5832
|
let thinking = null;
|
|
5833
5833
|
let stopReason;
|
|
5834
5834
|
let turnUsage;
|
|
5835
|
+
let turnMetadata;
|
|
5835
5836
|
let completed = false;
|
|
5836
5837
|
for await (const chunk of stream) {
|
|
5837
5838
|
if (base.signal?.aborted)
|
|
@@ -5877,19 +5878,30 @@ var streamAIWithTools = async function* (options) {
|
|
|
5877
5878
|
thinking = flushThinking3(blocks, thinking);
|
|
5878
5879
|
stopReason = chunk.stopReason;
|
|
5879
5880
|
turnUsage = chunk.usage;
|
|
5881
|
+
turnMetadata = chunk.metadata;
|
|
5880
5882
|
completed = true;
|
|
5881
5883
|
}
|
|
5882
5884
|
}
|
|
5883
5885
|
thinking = flushThinking3(blocks, thinking);
|
|
5884
5886
|
if (policy !== false && !completed)
|
|
5885
5887
|
throw new AIInputError("capacity_unavailable", "The model response was interrupted before completion. Preserve the original input for retry.");
|
|
5886
|
-
return {
|
|
5888
|
+
return {
|
|
5889
|
+
blocks,
|
|
5890
|
+
pending,
|
|
5891
|
+
stopReason,
|
|
5892
|
+
usage: turnUsage,
|
|
5893
|
+
metadata: turnMetadata
|
|
5894
|
+
};
|
|
5887
5895
|
};
|
|
5888
5896
|
while (turn < maxTurns) {
|
|
5889
5897
|
turn += 1;
|
|
5890
5898
|
const outcome = yield* streamOneTurn();
|
|
5891
5899
|
usage = mergeUsage(usage, outcome.usage);
|
|
5892
|
-
yield {
|
|
5900
|
+
yield {
|
|
5901
|
+
type: "turn",
|
|
5902
|
+
usage: outcome.usage,
|
|
5903
|
+
...outcome.metadata ? { metadata: outcome.metadata } : {}
|
|
5904
|
+
};
|
|
5893
5905
|
const { blocks, pending } = outcome;
|
|
5894
5906
|
allToolCalls.push(...pending);
|
|
5895
5907
|
if (outcome.stopReason === "pause_turn" && turn < maxTurns && base.signal?.aborted !== true) {
|
|
@@ -5939,7 +5951,11 @@ var streamAIWithTools = async function* (options) {
|
|
|
5939
5951
|
turn += 1;
|
|
5940
5952
|
const final = yield* streamOneTurn("none");
|
|
5941
5953
|
usage = mergeUsage(usage, final.usage);
|
|
5942
|
-
yield {
|
|
5954
|
+
yield {
|
|
5955
|
+
type: "turn",
|
|
5956
|
+
usage: final.usage,
|
|
5957
|
+
...final.metadata ? { metadata: final.metadata } : {}
|
|
5958
|
+
};
|
|
5943
5959
|
allToolCalls.push(...final.pending);
|
|
5944
5960
|
break;
|
|
5945
5961
|
}
|
|
@@ -8597,6 +8613,30 @@ var createAIStoredToolResultRecovery = (toolNames) => async ({ params }) => {
|
|
|
8597
8613
|
})
|
|
8598
8614
|
}));
|
|
8599
8615
|
};
|
|
8616
|
+
// src/ai/providerRouter.ts
|
|
8617
|
+
var createAIProviderRouter = (routes) => {
|
|
8618
|
+
const providers = new Map(Object.entries(routes));
|
|
8619
|
+
const resolve = (params) => {
|
|
8620
|
+
params.signal?.throwIfAborted();
|
|
8621
|
+
const provider = providers.get(params.model);
|
|
8622
|
+
if (!provider)
|
|
8623
|
+
throw new AIInputError("capacity_unavailable", `No provider route for model ${params.model}.`);
|
|
8624
|
+
return provider;
|
|
8625
|
+
};
|
|
8626
|
+
const capacity = (params) => {
|
|
8627
|
+
const result = resolve(params).inputCapacity;
|
|
8628
|
+
if (!result)
|
|
8629
|
+
throw new AIInputError("capacity_unavailable", `The provider for ${params.model} does not expose model capacity and token counting.`);
|
|
8630
|
+
return result;
|
|
8631
|
+
};
|
|
8632
|
+
return {
|
|
8633
|
+
inputCapacity: {
|
|
8634
|
+
getLimits: async (params) => capacity(params).getLimits(params),
|
|
8635
|
+
countTokens: async (params) => capacity(params).countTokens(params)
|
|
8636
|
+
},
|
|
8637
|
+
stream: (params) => resolve(params).stream(params)
|
|
8638
|
+
};
|
|
8639
|
+
};
|
|
8600
8640
|
export {
|
|
8601
8641
|
AIInputError,
|
|
8602
8642
|
BUILTIN_UI_CARDS,
|
|
@@ -8630,6 +8670,7 @@ export {
|
|
|
8630
8670
|
configureProviderResilience,
|
|
8631
8671
|
confirmCard,
|
|
8632
8672
|
createAIConnection,
|
|
8673
|
+
createAIProviderRouter,
|
|
8633
8674
|
createAIStoredToolResultRecovery,
|
|
8634
8675
|
createAIStream,
|
|
8635
8676
|
createAITextSource,
|
|
@@ -8706,5 +8747,5 @@ export {
|
|
|
8706
8747
|
xai
|
|
8707
8748
|
};
|
|
8708
8749
|
|
|
8709
|
-
//# debugId=
|
|
8750
|
+
//# debugId=0CA4631EC8525EB564756E2164756E21
|
|
8710
8751
|
//# sourceMappingURL=index.js.map
|