@absolutejs/ai 0.3.1 → 0.3.2

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 CHANGED
@@ -6,6 +6,12 @@ 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.3.2 — 2026-10-01
10
+
11
+ ### Fixed
12
+
13
+ - **Give structured-output repair bounded field diagnostics for TypeBox and Zod validation failures; expose StructuredOutputError with attempts, cause and accumulated usage when repair is exhausted.** (`generateObjectAI`, `StructuredOutputError`)
14
+
9
15
  ## 0.3.1 — 2026-09-29
10
16
 
11
17
  ### Fixed
package/changelog.json CHANGED
@@ -2,6 +2,20 @@
2
2
  "contract": 1,
3
3
  "name": "@absolutejs/ai",
4
4
  "releases": [
5
+ {
6
+ "changes": [
7
+ {
8
+ "kind": "fixed",
9
+ "summary": "Give structured-output repair bounded field diagnostics for TypeBox and Zod validation failures; expose StructuredOutputError with attempts, cause and accumulated usage when repair is exhausted.",
10
+ "symbols": [
11
+ "generateObjectAI",
12
+ "StructuredOutputError"
13
+ ]
14
+ }
15
+ ],
16
+ "date": "2026-10-01",
17
+ "version": "0.3.2"
18
+ },
5
19
  {
6
20
  "changes": [
7
21
  {
package/dist/ai/index.js CHANGED
@@ -4124,6 +4124,37 @@ var openrouterMessages = (config2) => {
4124
4124
  return withOpenRouterPolicy(provider, allowedModels, allowedPresets);
4125
4125
  };
4126
4126
 
4127
+ // src/ai/structuredOutputError.ts
4128
+ var record = (value) => typeof value === "object" && value !== null;
4129
+ var structuredOutputDiagnostics = (error) => {
4130
+ const source = record(error) && record(error.cause) ? error.cause : error;
4131
+ const issues = record(source) ? source.errors ?? source.issues : undefined;
4132
+ if (Array.isArray(issues)) {
4133
+ const details = issues.slice(0, 10).filter(record).map((issue) => {
4134
+ const path = typeof issue.instancePath === "string" ? issue.instancePath : Array.isArray(issue.path) ? issue.path.join(".") : "/";
4135
+ const expected = record(issue.params) ? issue.params.type : issue.expected;
4136
+ const message = typeof expected === "string" ? `must be ${expected}` : typeof issue.keyword === "string" ? `failed ${issue.keyword} validation` : typeof issue.code === "string" ? `failed ${issue.code} validation` : "does not satisfy the schema";
4137
+ return `${path.slice(0, 160) || "/"}: ${message.slice(0, 160)}`;
4138
+ });
4139
+ if (details.length)
4140
+ return details.join("; ").slice(0, 1500);
4141
+ }
4142
+ return (error instanceof Error ? error.message : "Output does not satisfy the schema").slice(0, 1500);
4143
+ };
4144
+
4145
+ class StructuredOutputError extends Error {
4146
+ reason;
4147
+ attempts;
4148
+ usage;
4149
+ code = "AI_STRUCTURED_OUTPUT_INVALID";
4150
+ constructor(reason, attempts, usage, cause) {
4151
+ super(`Structured AI output failed after ${attempts} attempt(s): ${structuredOutputDiagnostics(cause)}`, { cause });
4152
+ this.reason = reason;
4153
+ this.attempts = attempts;
4154
+ this.usage = usage;
4155
+ this.name = "StructuredOutputError";
4156
+ }
4157
+ }
4127
4158
  // src/plugins/aiChat.ts
4128
4159
  import { Elysia } from "elysia";
4129
4160
  import { websocket } from "elysia/websocket";
@@ -5901,7 +5932,10 @@ var generateObjectAI = async (options) => {
5901
5932
  const messages = [...options.messages];
5902
5933
  let usage;
5903
5934
  let lastError;
5935
+ let reason = "missing_tool";
5936
+ let attempts = 0;
5904
5937
  for (let attempt = 0;attempt <= maxRepairAttempts; attempt += 1) {
5938
+ attempts += 1;
5905
5939
  const result = await generateAI({
5906
5940
  contextPolicy: options.contextPolicy,
5907
5941
  cacheSystemPrompt: options.cacheSystemPrompt,
@@ -5925,14 +5959,16 @@ var generateObjectAI = async (options) => {
5925
5959
  let failure;
5926
5960
  let object;
5927
5961
  if (!call) {
5962
+ reason = "missing_tool";
5928
5963
  lastError = new Error(`generateObjectAI: model did not call the "${toolName}" tool`);
5929
5964
  failure = `You did not call the "${toolName}" tool. Call it exactly once with the structured result.`;
5930
5965
  } else {
5931
5966
  try {
5932
5967
  object = options.validate ? options.validate(call.input) : call.input;
5933
5968
  } catch (error) {
5969
+ reason = "validation";
5934
5970
  lastError = error;
5935
- failure = `Your "${toolName}" output failed validation: ${error instanceof Error ? error.message : String(error)}. Call "${toolName}" again with corrected output that satisfies the schema.`;
5971
+ failure = `Your "${toolName}" output failed validation: ${structuredOutputDiagnostics(error)}. Call "${toolName}" again with corrected output that satisfies the schema.`;
5936
5972
  }
5937
5973
  }
5938
5974
  if (failure === undefined)
@@ -5953,7 +5989,7 @@ var generateObjectAI = async (options) => {
5953
5989
  } else
5954
5990
  messages.push({ content: failure, role: "user" });
5955
5991
  }
5956
- throw lastError instanceof Error ? lastError : new Error(`generateObjectAI: failed to produce valid output`);
5992
+ throw new StructuredOutputError(reason, attempts, usage, lastError);
5957
5993
  };
5958
5994
 
5959
5995
  // src/ai/streamAIWithTools.ts
@@ -8395,7 +8431,7 @@ var AVAILABLE_COMPONENT_STATUSES = new Set([
8395
8431
  ]);
8396
8432
  var AVAILABLE_PAGE_INDICATORS = new Set(["none", "minor"]);
8397
8433
  var isRecord7 = (value) => typeof value === "object" && value !== null;
8398
- var readString = (record, key) => typeof record[key] === "string" ? record[key] : "";
8434
+ var readString = (record2, key) => typeof record2[key] === "string" ? record2[key] : "";
8399
8435
  var findComponentStatus = (body, componentName) => {
8400
8436
  if (!isRecord7(body) || !Array.isArray(body.components))
8401
8437
  return null;
@@ -8697,7 +8733,7 @@ var boundary = (text, offset) => {
8697
8733
  const next = text.charCodeAt(offset);
8698
8734
  return code >= 55296 && code <= 56319 && next >= 56320 && next <= 57343 ? offset - 1 : offset;
8699
8735
  };
8700
- var record = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
8736
+ var record2 = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
8701
8737
  var createAITextSource = (messages) => {
8702
8738
  const sources = messages.map((message, index) => {
8703
8739
  if (typeof message.content !== "string")
@@ -8764,7 +8800,7 @@ var createAITextSource = (messages) => {
8764
8800
  additionalProperties: false
8765
8801
  },
8766
8802
  handler: (input) => {
8767
- const value = record(input);
8803
+ const value = record2(input);
8768
8804
  if (typeof value.query !== "string")
8769
8805
  return "Provide a text query.";
8770
8806
  return JSON.stringify({
@@ -8787,7 +8823,7 @@ var createAITextSource = (messages) => {
8787
8823
  additionalProperties: false
8788
8824
  },
8789
8825
  handler: (input) => {
8790
- const value = record(input);
8826
+ const value = record2(input);
8791
8827
  if (typeof value.sourceId !== "string" || typeof value.start !== "number")
8792
8828
  return "Provide a source ID and start offset.";
8793
8829
  return JSON.stringify({
@@ -8872,6 +8908,7 @@ export {
8872
8908
  PROVIDER_STATUS_PAGES,
8873
8909
  ProviderError,
8874
8910
  STAT_TILES_MAX,
8911
+ StructuredOutputError,
8875
8912
  TABLE_MAX_COLUMNS,
8876
8913
  TABLE_MAX_ROWS,
8877
8914
  UI_ACTIONS_MAX,
@@ -8960,5 +8997,5 @@ export {
8960
8997
  xai
8961
8998
  };
8962
8999
 
8963
- //# debugId=76B9C09CA62B3EF264756E2164756E21
9000
+ //# debugId=420F3EDB38FAC4DB64756E2164756E21
8964
9001
  //# sourceMappingURL=index.js.map