@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 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 });
@@ -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
- if (typeof completed?.status === "string") {
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 } : {},
@@ -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
- if (typeof completed?.status === "string") {
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.675",
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
- "dist",
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",