@absolutejs/voice 0.0.22-beta.675 → 0.0.22-beta.677

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,19 @@
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.677 — 2026-09-16
10
+
11
+ ### Fixed
12
+
13
+ - **Preserve nested OpenAI stream error codes and messages so token rate limits activate provider fallback and cooldowns.** (`createOpenAIVoiceAssistantModel`)
14
+
15
+ ## 0.0.22-beta.676 — 2026-09-16
16
+
17
+ ### Fixed
18
+
19
+ - **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,32 @@
1
+ {
2
+ "contract": 1,
3
+ "name": "@absolutejs/voice",
4
+ "releases": [
5
+ {
6
+ "changes": [
7
+ {
8
+ "kind": "fixed",
9
+ "summary": "Preserve nested OpenAI stream error codes and messages so token rate limits activate provider fallback and cooldowns.",
10
+ "symbols": [
11
+ "createOpenAIVoiceAssistantModel"
12
+ ]
13
+ }
14
+ ],
15
+ "date": "2026-09-16",
16
+ "version": "0.0.22-beta.677"
17
+ },
18
+ {
19
+ "changes": [
20
+ {
21
+ "kind": "fixed",
22
+ "summary": "Surface failed and incomplete OpenAI response streams as errors so voice provider fallback can recover without executing partial tool calls.",
23
+ "symbols": [
24
+ "createOpenAIVoiceAssistantModel"
25
+ ]
26
+ }
27
+ ],
28
+ "date": "2026-09-16",
29
+ "version": "0.0.22-beta.676"
30
+ }
31
+ ]
32
+ }
@@ -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,18 @@ 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 nested = event.error && typeof event.error === "object" ? event.error : undefined;
47018
+ const code = typeof event.code === "string" ? event.code : typeof nested?.code === "string" ? nested.code : "stream_error";
47019
+ const message = typeof event.message === "string" ? event.message : typeof nested?.message === "string" ? nested.message : "Provider stream failed";
47020
+ streamError = new Error(`OpenAI voice assistant model failed: ${code}: ${message}`);
47021
+ }
47006
47022
  if (type === "response.output_item.added") {
47007
47023
  outputItems += 1;
47008
47024
  }
@@ -47031,9 +47047,7 @@ var consumeOpenAIResponsesStream = async (response, onTextDelta, abortOptions) =
47031
47047
  if (completed?.usage && typeof completed.usage === "object") {
47032
47048
  usage = completed.usage;
47033
47049
  }
47034
- if (typeof completed?.status === "string") {
47035
- status = completed.status;
47036
- }
47050
+ status = typeof completed?.status === "string" ? completed.status : type.slice("response.".length);
47037
47051
  const incomplete = completed?.incomplete_details;
47038
47052
  if (typeof incomplete?.reason === "string") {
47039
47053
  incompleteReason = incomplete.reason;
@@ -47042,6 +47056,12 @@ var consumeOpenAIResponsesStream = async (response, onTextDelta, abortOptions) =
47042
47056
  if (typeof failure?.message === "string") {
47043
47057
  failureMessage = failure.message;
47044
47058
  }
47059
+ streamError ??= openAIResponseError({
47060
+ code: typeof failure?.code === "string" ? failure.code : undefined,
47061
+ incompleteReason,
47062
+ message: failureMessage,
47063
+ status: type === "response.completed" ? status : type.slice("response.".length)
47064
+ });
47045
47065
  }
47046
47066
  }, abortOptions);
47047
47067
  return {
@@ -47051,6 +47071,7 @@ var consumeOpenAIResponsesStream = async (response, onTextDelta, abortOptions) =
47051
47071
  outputItems,
47052
47072
  refusal: refusal || undefined,
47053
47073
  status,
47074
+ streamError,
47054
47075
  toolCalls: finalizeToolCalls(calls),
47055
47076
  usage
47056
47077
  };
@@ -47119,6 +47140,7 @@ var createOpenAIVoiceAssistantModel = (options) => {
47119
47140
  let refusal;
47120
47141
  let failureMessage;
47121
47142
  let outputItems = 0;
47143
+ let streamError;
47122
47144
  let firstDeltaSeen = false;
47123
47145
  const onTextDelta = input.onTextDelta ? (delta) => {
47124
47146
  if (!firstDeltaSeen) {
@@ -47136,7 +47158,8 @@ var createOpenAIVoiceAssistantModel = (options) => {
47136
47158
  incompleteReason,
47137
47159
  refusal,
47138
47160
  failureMessage,
47139
- outputItems
47161
+ outputItems,
47162
+ streamError
47140
47163
  } = await consumeOpenAIResponsesStream(response, onTextDelta, {
47141
47164
  signal: ac.signal,
47142
47165
  inactivityMs: options.streamInactivityMs ?? 1e4
@@ -47160,6 +47183,8 @@ var createOpenAIVoiceAssistantModel = (options) => {
47160
47183
  if (usage) {
47161
47184
  await options.onUsage?.(usage);
47162
47185
  }
47186
+ if (streamError)
47187
+ throw streamError;
47163
47188
  return {
47164
47189
  ...assistantText ? { assistantText } : {},
47165
47190
  ...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,18 @@ 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 nested = event.error && typeof event.error === "object" ? event.error : undefined;
5905
+ const code = typeof event.code === "string" ? event.code : typeof nested?.code === "string" ? nested.code : "stream_error";
5906
+ const message = typeof event.message === "string" ? event.message : typeof nested?.message === "string" ? nested.message : "Provider stream failed";
5907
+ streamError = new Error(`OpenAI voice assistant model failed: ${code}: ${message}`);
5908
+ }
5893
5909
  if (type === "response.output_item.added") {
5894
5910
  outputItems += 1;
5895
5911
  }
@@ -5918,9 +5934,7 @@ var consumeOpenAIResponsesStream = async (response, onTextDelta, abortOptions) =
5918
5934
  if (completed?.usage && typeof completed.usage === "object") {
5919
5935
  usage = completed.usage;
5920
5936
  }
5921
- if (typeof completed?.status === "string") {
5922
- status = completed.status;
5923
- }
5937
+ status = typeof completed?.status === "string" ? completed.status : type.slice("response.".length);
5924
5938
  const incomplete = completed?.incomplete_details;
5925
5939
  if (typeof incomplete?.reason === "string") {
5926
5940
  incompleteReason = incomplete.reason;
@@ -5929,6 +5943,12 @@ var consumeOpenAIResponsesStream = async (response, onTextDelta, abortOptions) =
5929
5943
  if (typeof failure?.message === "string") {
5930
5944
  failureMessage = failure.message;
5931
5945
  }
5946
+ streamError ??= openAIResponseError({
5947
+ code: typeof failure?.code === "string" ? failure.code : undefined,
5948
+ incompleteReason,
5949
+ message: failureMessage,
5950
+ status: type === "response.completed" ? status : type.slice("response.".length)
5951
+ });
5932
5952
  }
5933
5953
  }, abortOptions);
5934
5954
  return {
@@ -5938,6 +5958,7 @@ var consumeOpenAIResponsesStream = async (response, onTextDelta, abortOptions) =
5938
5958
  outputItems,
5939
5959
  refusal: refusal || undefined,
5940
5960
  status,
5961
+ streamError,
5941
5962
  toolCalls: finalizeToolCalls(calls),
5942
5963
  usage
5943
5964
  };
@@ -6006,6 +6027,7 @@ var createOpenAIVoiceAssistantModel = (options) => {
6006
6027
  let refusal;
6007
6028
  let failureMessage;
6008
6029
  let outputItems = 0;
6030
+ let streamError;
6009
6031
  let firstDeltaSeen = false;
6010
6032
  const onTextDelta = input.onTextDelta ? (delta) => {
6011
6033
  if (!firstDeltaSeen) {
@@ -6023,7 +6045,8 @@ var createOpenAIVoiceAssistantModel = (options) => {
6023
6045
  incompleteReason,
6024
6046
  refusal,
6025
6047
  failureMessage,
6026
- outputItems
6048
+ outputItems,
6049
+ streamError
6027
6050
  } = await consumeOpenAIResponsesStream(response, onTextDelta, {
6028
6051
  signal: ac.signal,
6029
6052
  inactivityMs: options.streamInactivityMs ?? 1e4
@@ -6047,6 +6070,8 @@ var createOpenAIVoiceAssistantModel = (options) => {
6047
6070
  if (usage) {
6048
6071
  await options.onUsage?.(usage);
6049
6072
  }
6073
+ if (streamError)
6074
+ throw streamError;
6050
6075
  return {
6051
6076
  ...assistantText ? { assistantText } : {},
6052
6077
  ...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.677",
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",