@absolutejs/voice 0.0.22-beta.675 → 0.0.22-beta.676
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 +13 -0
- package/changelog.json +19 -0
- package/dist/client/htmxBootstrap.js +1 -1
- package/dist/embed/index.js +1 -1
- package/dist/index.js +29 -5
- package/dist/testing/index.js +29 -5
- package/package.json +8 -4
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@absolutejs/voice`.
|
|
4
|
+
|
|
5
|
+
This file is generated by `absolute-changelog` from the entries in
|
|
6
|
+
`changelog/`. Edit an entry, not this file — and add new ones under
|
|
7
|
+
`changelog/unreleased/`.
|
|
8
|
+
|
|
9
|
+
## 0.0.22-beta.676 — 2026-09-16
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- **Surface failed and incomplete OpenAI response streams as errors so voice provider fallback can recover without executing partial tool calls.** (`createOpenAIVoiceAssistantModel`)
|
package/changelog.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"contract": 1,
|
|
3
|
+
"name": "@absolutejs/voice",
|
|
4
|
+
"releases": [
|
|
5
|
+
{
|
|
6
|
+
"changes": [
|
|
7
|
+
{
|
|
8
|
+
"kind": "fixed",
|
|
9
|
+
"summary": "Surface failed and incomplete OpenAI response streams as errors so voice provider fallback can recover without executing partial tool calls.",
|
|
10
|
+
"symbols": [
|
|
11
|
+
"createOpenAIVoiceAssistantModel"
|
|
12
|
+
]
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
"date": "2026-09-16",
|
|
16
|
+
"version": "0.0.22-beta.676"
|
|
17
|
+
}
|
|
18
|
+
]
|
|
19
|
+
}
|
|
@@ -316,7 +316,7 @@ var serverMessageToAction = (message) => {
|
|
|
316
316
|
}
|
|
317
317
|
};
|
|
318
318
|
|
|
319
|
-
// node_modules/@absolutejs/media/dist/index.js
|
|
319
|
+
// ../../home/alexkahn/abs/voice/node_modules/@absolutejs/media/dist/index.js
|
|
320
320
|
var TAU = Math.PI * 2;
|
|
321
321
|
var pushIssue = (issues, severity, code, message) => {
|
|
322
322
|
issues.push({ code, message, severity });
|
package/dist/embed/index.js
CHANGED
|
@@ -313,7 +313,7 @@ var serverMessageToAction = (message) => {
|
|
|
313
313
|
}
|
|
314
314
|
};
|
|
315
315
|
|
|
316
|
-
// node_modules/@absolutejs/media/dist/index.js
|
|
316
|
+
// ../../home/alexkahn/abs/voice/node_modules/@absolutejs/media/dist/index.js
|
|
317
317
|
var TAU = Math.PI * 2;
|
|
318
318
|
var pushIssue = (issues, severity, code, message) => {
|
|
319
319
|
issues.push({ code, message, severity });
|
package/dist/index.js
CHANGED
|
@@ -46434,7 +46434,7 @@ var sleep7 = (ms) => new Promise((resolve2) => {
|
|
|
46434
46434
|
setTimeout(resolve2, ms);
|
|
46435
46435
|
});
|
|
46436
46436
|
var errorMessage = (error) => error instanceof Error ? error.message : String(error);
|
|
46437
|
-
var defaultIsRateLimitError = (error) => /(\b429\b|rate limit|quota|too many requests)/i.test(errorMessage(error));
|
|
46437
|
+
var defaultIsRateLimitError = (error) => /(\b429\b|rate[ _-]limit|quota|too many requests)/i.test(errorMessage(error));
|
|
46438
46438
|
var normalizeRouteOutput = (output) => {
|
|
46439
46439
|
const result = {};
|
|
46440
46440
|
if (typeof output.assistantText === "string") {
|
|
@@ -46991,6 +46991,15 @@ var finalizeToolCalls = (calls) => [...calls.values()].filter((call) => call.nam
|
|
|
46991
46991
|
id: call.id,
|
|
46992
46992
|
name: call.name
|
|
46993
46993
|
}));
|
|
46994
|
+
var openAIResponseError = (response) => {
|
|
46995
|
+
if (response.status === "failed") {
|
|
46996
|
+
return new Error(`OpenAI voice assistant model failed: ${response.code ?? "response_failed"}: ${response.message ?? "Provider response failed"}`);
|
|
46997
|
+
}
|
|
46998
|
+
if (response.status === "incomplete") {
|
|
46999
|
+
return new Error(`OpenAI voice assistant model incomplete: ${response.incompleteReason ?? "unknown reason"}`);
|
|
47000
|
+
}
|
|
47001
|
+
return;
|
|
47002
|
+
};
|
|
46994
47003
|
var consumeOpenAIResponsesStream = async (response, onTextDelta, abortOptions) => {
|
|
46995
47004
|
let assistantText = "";
|
|
46996
47005
|
let usage;
|
|
@@ -46998,11 +47007,17 @@ var consumeOpenAIResponsesStream = async (response, onTextDelta, abortOptions) =
|
|
|
46998
47007
|
let incompleteReason;
|
|
46999
47008
|
let refusal = "";
|
|
47000
47009
|
let failureMessage;
|
|
47010
|
+
let streamError;
|
|
47001
47011
|
let outputItems = 0;
|
|
47002
47012
|
const calls = new Map;
|
|
47003
47013
|
await readServerSentEvents(response, (event) => {
|
|
47004
47014
|
const type = typeof event.type === "string" ? event.type : "";
|
|
47005
47015
|
const item = event.item;
|
|
47016
|
+
if (type === "error") {
|
|
47017
|
+
const code = typeof event.code === "string" ? event.code : "stream_error";
|
|
47018
|
+
const message = typeof event.message === "string" ? event.message : "Provider stream failed";
|
|
47019
|
+
streamError = new Error(`OpenAI voice assistant model failed: ${code}: ${message}`);
|
|
47020
|
+
}
|
|
47006
47021
|
if (type === "response.output_item.added") {
|
|
47007
47022
|
outputItems += 1;
|
|
47008
47023
|
}
|
|
@@ -47031,9 +47046,7 @@ var consumeOpenAIResponsesStream = async (response, onTextDelta, abortOptions) =
|
|
|
47031
47046
|
if (completed?.usage && typeof completed.usage === "object") {
|
|
47032
47047
|
usage = completed.usage;
|
|
47033
47048
|
}
|
|
47034
|
-
|
|
47035
|
-
status = completed.status;
|
|
47036
|
-
}
|
|
47049
|
+
status = typeof completed?.status === "string" ? completed.status : type.slice("response.".length);
|
|
47037
47050
|
const incomplete = completed?.incomplete_details;
|
|
47038
47051
|
if (typeof incomplete?.reason === "string") {
|
|
47039
47052
|
incompleteReason = incomplete.reason;
|
|
@@ -47042,6 +47055,12 @@ var consumeOpenAIResponsesStream = async (response, onTextDelta, abortOptions) =
|
|
|
47042
47055
|
if (typeof failure?.message === "string") {
|
|
47043
47056
|
failureMessage = failure.message;
|
|
47044
47057
|
}
|
|
47058
|
+
streamError ??= openAIResponseError({
|
|
47059
|
+
code: typeof failure?.code === "string" ? failure.code : undefined,
|
|
47060
|
+
incompleteReason,
|
|
47061
|
+
message: failureMessage,
|
|
47062
|
+
status: type === "response.completed" ? status : type.slice("response.".length)
|
|
47063
|
+
});
|
|
47045
47064
|
}
|
|
47046
47065
|
}, abortOptions);
|
|
47047
47066
|
return {
|
|
@@ -47051,6 +47070,7 @@ var consumeOpenAIResponsesStream = async (response, onTextDelta, abortOptions) =
|
|
|
47051
47070
|
outputItems,
|
|
47052
47071
|
refusal: refusal || undefined,
|
|
47053
47072
|
status,
|
|
47073
|
+
streamError,
|
|
47054
47074
|
toolCalls: finalizeToolCalls(calls),
|
|
47055
47075
|
usage
|
|
47056
47076
|
};
|
|
@@ -47119,6 +47139,7 @@ var createOpenAIVoiceAssistantModel = (options) => {
|
|
|
47119
47139
|
let refusal;
|
|
47120
47140
|
let failureMessage;
|
|
47121
47141
|
let outputItems = 0;
|
|
47142
|
+
let streamError;
|
|
47122
47143
|
let firstDeltaSeen = false;
|
|
47123
47144
|
const onTextDelta = input.onTextDelta ? (delta) => {
|
|
47124
47145
|
if (!firstDeltaSeen) {
|
|
@@ -47136,7 +47157,8 @@ var createOpenAIVoiceAssistantModel = (options) => {
|
|
|
47136
47157
|
incompleteReason,
|
|
47137
47158
|
refusal,
|
|
47138
47159
|
failureMessage,
|
|
47139
|
-
outputItems
|
|
47160
|
+
outputItems,
|
|
47161
|
+
streamError
|
|
47140
47162
|
} = await consumeOpenAIResponsesStream(response, onTextDelta, {
|
|
47141
47163
|
signal: ac.signal,
|
|
47142
47164
|
inactivityMs: options.streamInactivityMs ?? 1e4
|
|
@@ -47160,6 +47182,8 @@ var createOpenAIVoiceAssistantModel = (options) => {
|
|
|
47160
47182
|
if (usage) {
|
|
47161
47183
|
await options.onUsage?.(usage);
|
|
47162
47184
|
}
|
|
47185
|
+
if (streamError)
|
|
47186
|
+
throw streamError;
|
|
47163
47187
|
return {
|
|
47164
47188
|
...assistantText ? { assistantText } : {},
|
|
47165
47189
|
...toolCalls.length ? { toolCalls } : {},
|
package/dist/testing/index.js
CHANGED
|
@@ -5321,7 +5321,7 @@ var sleep = (ms) => new Promise((resolve2) => {
|
|
|
5321
5321
|
setTimeout(resolve2, ms);
|
|
5322
5322
|
});
|
|
5323
5323
|
var errorMessage = (error) => error instanceof Error ? error.message : String(error);
|
|
5324
|
-
var defaultIsRateLimitError = (error) => /(\b429\b|rate limit|quota|too many requests)/i.test(errorMessage(error));
|
|
5324
|
+
var defaultIsRateLimitError = (error) => /(\b429\b|rate[ _-]limit|quota|too many requests)/i.test(errorMessage(error));
|
|
5325
5325
|
var normalizeRouteOutput = (output) => {
|
|
5326
5326
|
const result = {};
|
|
5327
5327
|
if (typeof output.assistantText === "string") {
|
|
@@ -5878,6 +5878,15 @@ var finalizeToolCalls = (calls) => [...calls.values()].filter((call) => call.nam
|
|
|
5878
5878
|
id: call.id,
|
|
5879
5879
|
name: call.name
|
|
5880
5880
|
}));
|
|
5881
|
+
var openAIResponseError = (response) => {
|
|
5882
|
+
if (response.status === "failed") {
|
|
5883
|
+
return new Error(`OpenAI voice assistant model failed: ${response.code ?? "response_failed"}: ${response.message ?? "Provider response failed"}`);
|
|
5884
|
+
}
|
|
5885
|
+
if (response.status === "incomplete") {
|
|
5886
|
+
return new Error(`OpenAI voice assistant model incomplete: ${response.incompleteReason ?? "unknown reason"}`);
|
|
5887
|
+
}
|
|
5888
|
+
return;
|
|
5889
|
+
};
|
|
5881
5890
|
var consumeOpenAIResponsesStream = async (response, onTextDelta, abortOptions) => {
|
|
5882
5891
|
let assistantText = "";
|
|
5883
5892
|
let usage;
|
|
@@ -5885,11 +5894,17 @@ var consumeOpenAIResponsesStream = async (response, onTextDelta, abortOptions) =
|
|
|
5885
5894
|
let incompleteReason;
|
|
5886
5895
|
let refusal = "";
|
|
5887
5896
|
let failureMessage;
|
|
5897
|
+
let streamError;
|
|
5888
5898
|
let outputItems = 0;
|
|
5889
5899
|
const calls = new Map;
|
|
5890
5900
|
await readServerSentEvents(response, (event) => {
|
|
5891
5901
|
const type = typeof event.type === "string" ? event.type : "";
|
|
5892
5902
|
const item = event.item;
|
|
5903
|
+
if (type === "error") {
|
|
5904
|
+
const code = typeof event.code === "string" ? event.code : "stream_error";
|
|
5905
|
+
const message = typeof event.message === "string" ? event.message : "Provider stream failed";
|
|
5906
|
+
streamError = new Error(`OpenAI voice assistant model failed: ${code}: ${message}`);
|
|
5907
|
+
}
|
|
5893
5908
|
if (type === "response.output_item.added") {
|
|
5894
5909
|
outputItems += 1;
|
|
5895
5910
|
}
|
|
@@ -5918,9 +5933,7 @@ var consumeOpenAIResponsesStream = async (response, onTextDelta, abortOptions) =
|
|
|
5918
5933
|
if (completed?.usage && typeof completed.usage === "object") {
|
|
5919
5934
|
usage = completed.usage;
|
|
5920
5935
|
}
|
|
5921
|
-
|
|
5922
|
-
status = completed.status;
|
|
5923
|
-
}
|
|
5936
|
+
status = typeof completed?.status === "string" ? completed.status : type.slice("response.".length);
|
|
5924
5937
|
const incomplete = completed?.incomplete_details;
|
|
5925
5938
|
if (typeof incomplete?.reason === "string") {
|
|
5926
5939
|
incompleteReason = incomplete.reason;
|
|
@@ -5929,6 +5942,12 @@ var consumeOpenAIResponsesStream = async (response, onTextDelta, abortOptions) =
|
|
|
5929
5942
|
if (typeof failure?.message === "string") {
|
|
5930
5943
|
failureMessage = failure.message;
|
|
5931
5944
|
}
|
|
5945
|
+
streamError ??= openAIResponseError({
|
|
5946
|
+
code: typeof failure?.code === "string" ? failure.code : undefined,
|
|
5947
|
+
incompleteReason,
|
|
5948
|
+
message: failureMessage,
|
|
5949
|
+
status: type === "response.completed" ? status : type.slice("response.".length)
|
|
5950
|
+
});
|
|
5932
5951
|
}
|
|
5933
5952
|
}, abortOptions);
|
|
5934
5953
|
return {
|
|
@@ -5938,6 +5957,7 @@ var consumeOpenAIResponsesStream = async (response, onTextDelta, abortOptions) =
|
|
|
5938
5957
|
outputItems,
|
|
5939
5958
|
refusal: refusal || undefined,
|
|
5940
5959
|
status,
|
|
5960
|
+
streamError,
|
|
5941
5961
|
toolCalls: finalizeToolCalls(calls),
|
|
5942
5962
|
usage
|
|
5943
5963
|
};
|
|
@@ -6006,6 +6026,7 @@ var createOpenAIVoiceAssistantModel = (options) => {
|
|
|
6006
6026
|
let refusal;
|
|
6007
6027
|
let failureMessage;
|
|
6008
6028
|
let outputItems = 0;
|
|
6029
|
+
let streamError;
|
|
6009
6030
|
let firstDeltaSeen = false;
|
|
6010
6031
|
const onTextDelta = input.onTextDelta ? (delta) => {
|
|
6011
6032
|
if (!firstDeltaSeen) {
|
|
@@ -6023,7 +6044,8 @@ var createOpenAIVoiceAssistantModel = (options) => {
|
|
|
6023
6044
|
incompleteReason,
|
|
6024
6045
|
refusal,
|
|
6025
6046
|
failureMessage,
|
|
6026
|
-
outputItems
|
|
6047
|
+
outputItems,
|
|
6048
|
+
streamError
|
|
6027
6049
|
} = await consumeOpenAIResponsesStream(response, onTextDelta, {
|
|
6028
6050
|
signal: ac.signal,
|
|
6029
6051
|
inactivityMs: options.streamInactivityMs ?? 1e4
|
|
@@ -6047,6 +6069,8 @@ var createOpenAIVoiceAssistantModel = (options) => {
|
|
|
6047
6069
|
if (usage) {
|
|
6048
6070
|
await options.onUsage?.(usage);
|
|
6049
6071
|
}
|
|
6072
|
+
if (streamError)
|
|
6073
|
+
throw streamError;
|
|
6050
6074
|
return {
|
|
6051
6075
|
...assistantText ? { assistantText } : {},
|
|
6052
6076
|
...toolCalls.length ? { toolCalls } : {},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@absolutejs/voice",
|
|
3
|
-
"version": "0.0.22-beta.
|
|
3
|
+
"version": "0.0.22-beta.676",
|
|
4
4
|
"description": "Voice primitives and Elysia plugin for AbsoluteJS",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -11,8 +11,10 @@
|
|
|
11
11
|
"url": "https://github.com/absolutejs/voice/issues"
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
14
|
-
"
|
|
15
|
-
"README.md"
|
|
14
|
+
"CHANGELOG.md",
|
|
15
|
+
"README.md",
|
|
16
|
+
"changelog.json",
|
|
17
|
+
"dist"
|
|
16
18
|
],
|
|
17
19
|
"main": "./dist/index.js",
|
|
18
20
|
"types": "./dist/index.d.ts",
|
|
@@ -33,7 +35,8 @@
|
|
|
33
35
|
"test:openai": "bun test ./test/live/openai.live.test.ts",
|
|
34
36
|
"typecheck": "absolute typecheck",
|
|
35
37
|
"verify-package": "absolute-manifest verify-package",
|
|
36
|
-
"check:package": "bun run format && bun run typecheck && bun run test && bun run verify-package && bun run build"
|
|
38
|
+
"check:package": "bun run format && bun run typecheck && bun run test && bun run verify-package && bun run build && absolute-changelog check",
|
|
39
|
+
"prepublishOnly": "bun run check:package"
|
|
37
40
|
},
|
|
38
41
|
"exports": {
|
|
39
42
|
".": {
|
|
@@ -148,6 +151,7 @@
|
|
|
148
151
|
"devDependencies": {
|
|
149
152
|
"@absolutejs/absolute": "0.20.0-beta.0",
|
|
150
153
|
"@absolutejs/ai": "0.0.47",
|
|
154
|
+
"@absolutejs/changelog": "^0.6.0",
|
|
151
155
|
"@angular/core": "22.0.8",
|
|
152
156
|
"@electric-sql/pglite": "^0.4.5",
|
|
153
157
|
"@eslint/js": "^10.0.1",
|