@storyshelf/ai 0.7.0 → 0.8.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/dist/client.mjs CHANGED
@@ -2,7 +2,7 @@ import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
4
  import { TASK_DEFAULTS } from "./types.mjs";
5
- //#region src/client.ts
5
+ // src/client.ts
6
6
  /** True for the object form `{ model, ... }` (a bare model has a spec version). */
7
7
  function isObjectSlot(slot) {
8
8
  return typeof slot === "object" && slot !== null && "model" in slot && !("specificationVersion" in slot);
@@ -62,7 +62,6 @@ function pickDefaultProfile(options) {
62
62
  const names = Object.keys(options.profiles);
63
63
  return options.defaultProfile ?? (names.includes("default") ? "default" : names[0] ?? "");
64
64
  }
65
- //#endregion
66
65
  export { effectiveSlot, modelId, pickDefaultProfile, resolveSlot, validateOptions };
67
66
 
68
67
  //# sourceMappingURL=client.mjs.map
package/dist/codec.mjs CHANGED
@@ -3,7 +3,7 @@ import "node:url";
3
3
  import.meta.url;
4
4
  import { APICallError, JSONParseError, NoObjectGeneratedError, Output, TypeValidationError, generateText } from "ai";
5
5
  import { AiError } from "@storyshelf/core/ai";
6
- //#region src/codec.ts
6
+ // src/codec.ts
7
7
  /** Evidence → messages, one structured call, one schema-repair retry. */
8
8
  function userMessage(evidence, withImages) {
9
9
  const images = withImages ? evidence.images : [];
@@ -122,7 +122,6 @@ async function runStructured(call) {
122
122
  imagesSent
123
123
  };
124
124
  }
125
- //#endregion
126
125
  export { isSchemaFailure, runStructured, toAiError, toUsage };
127
126
 
128
127
  //# sourceMappingURL=codec.mjs.map
package/dist/index.d.mts CHANGED
@@ -2,9 +2,7 @@ import __tsdown_shims_path from 'node:path';
2
2
  import __tsdown_shims_url from 'node:url';
3
3
  import { BudgetOptions, CreateAiOptions, ModelSlot, ProfileConfig, ProfileModels, SlotProviderOptions } from "./types.mjs";
4
4
  import { Ai } from "@storyshelf/core/ai";
5
- //#region src/index.d.ts
6
5
  /** Create the AI surface from named profiles of deployer-supplied models. */
7
6
  declare function createAi<const P extends string>(options: CreateAiOptions<P>): Ai;
8
- //#endregion
9
7
  export { type BudgetOptions, type CreateAiOptions, type ModelSlot, type ProfileConfig, type ProfileModels, type SlotProviderOptions, createAi };
10
8
  //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs CHANGED
@@ -4,7 +4,7 @@ import.meta.url;
4
4
  import { modelId, pickDefaultProfile, validateOptions } from "./client.mjs";
5
5
  import { health, setup } from "./lifecycle.mjs";
6
6
  import { slotFor, summarize } from "./operations.mjs";
7
- //#region src/index.ts
7
+ // src/index.ts
8
8
  /** Create the AI surface from named profiles of deployer-supplied models. */
9
9
  function createAi(options) {
10
10
  validateOptions(options);
@@ -51,7 +51,6 @@ function otelEnabled(override) {
51
51
  const env = process.env;
52
52
  return env["OTEL_SDK_DISABLED"] !== "true" && (Boolean(env["OTEL_EXPORTER_OTLP_ENDPOINT"]) || env["OTEL_DENO"] === "true");
53
53
  }
54
- //#endregion
55
54
  export { createAi };
56
55
 
57
56
  //# sourceMappingURL=index.mjs.map
@@ -3,7 +3,7 @@ import "node:url";
3
3
  import.meta.url;
4
4
  import { effectiveSlot, modelId } from "./client.mjs";
5
5
  import { registerOtelOnce } from "./telemetry.mjs";
6
- //#region src/lifecycle.ts
6
+ // src/lifecycle.ts
7
7
  const SUPPORTED_SPECS = /* @__PURE__ */ new Set([
8
8
  "v2",
9
9
  "v3",
@@ -37,7 +37,6 @@ async function health(state) {
37
37
  detail: `unsupported model specification: ${bad.join(", ")}`
38
38
  };
39
39
  }
40
- //#endregion
41
40
  export { health, setup, unsupportedModels };
42
41
 
43
42
  //# sourceMappingURL=lifecycle.mjs.map
package/dist/metrics.mjs CHANGED
@@ -2,7 +2,7 @@ import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
4
  import { metrics } from "@opentelemetry/api";
5
- //#region src/metrics.ts
5
+ // src/metrics.ts
6
6
  /** Bounded-cardinality OTEL instruments (task + outcome only; ADR 0016 §8). */
7
7
  let cached;
8
8
  function instruments() {
@@ -28,7 +28,6 @@ function recordSummarize(task, outcome, durationMs, tokens) {
28
28
  tokenHistogram.record(tokens, attributes);
29
29
  (outcome === "ok" ? completed : failed).add(1, { "ai.task": task });
30
30
  }
31
- //#endregion
32
31
  export { recordSummarize };
33
32
 
34
33
  //# sourceMappingURL=metrics.mjs.map
@@ -6,7 +6,7 @@ import { withSpan } from "./telemetry.mjs";
6
6
  import { runStructured, toAiError } from "./codec.mjs";
7
7
  import { recordSummarize } from "./metrics.mjs";
8
8
  import { AiError } from "@storyshelf/core/ai";
9
- //#region src/operations.ts
9
+ // src/operations.ts
10
10
  /** `summarize`: profile resolution, vision fallback, timeout and spans. */
11
11
  /** Resolve the requested profile; unknown names fall back with a warning. */
12
12
  function resolveProfile(state, requested) {
@@ -117,7 +117,6 @@ async function summarize(state, input, logger) {
117
117
  "ai.model": ctx.model
118
118
  });
119
119
  }
120
- //#endregion
121
120
  export { resolveProfile, slotFor, summarize };
122
121
 
123
122
  //# sourceMappingURL=operations.mjs.map
@@ -3,8 +3,9 @@ import "node:url";
3
3
  import.meta.url;
4
4
  import { OpenTelemetry } from "@ai-sdk/otel";
5
5
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
6
+ import { HttpError, redactSecrets } from "@storyshelf/core/utils";
6
7
  import { registerTelemetry } from "ai";
7
- //#region src/telemetry.ts
8
+ // src/telemetry.ts
8
9
  /** OTEL wiring: idempotent integration registration and a local span helper. */
9
10
  let registered = false;
10
11
  /** Register the SDK's OpenTelemetry integration once per process. */
@@ -14,6 +15,22 @@ function registerOtelOnce() {
14
15
  registerTelemetry(new OpenTelemetry());
15
16
  }
16
17
  /**
18
+ * What a span records of a caught error: a copy with the same `name` and a `redactSecrets` message
19
+ * (connection strings, tokens and keys stay out of exported spans), and for an `HttpError` its
20
+ * status only, never the response body. The caller still gets the original error rethrown.
21
+ * Intentional copy of core's `spanException` (ADR 0015 §5 no-cycle rule: do not deduplicate).
22
+ */
23
+ function recordedError(error) {
24
+ if (!(error instanceof Error)) return redactSecrets(String(error));
25
+ const message = error instanceof HttpError ? `HTTP ${String(error.status)}` : redactSecrets(error.message);
26
+ const copy = new Error(message);
27
+ copy.name = error.name;
28
+ const header = `${error.name}: ${error.message}`;
29
+ const frames = error.stack?.startsWith(header) ? error.stack.slice(header.length) : "";
30
+ copy.stack = `${error.name}: ${message}${redactSecrets(frames)}`;
31
+ return copy;
32
+ }
33
+ /**
17
34
  * Run `fn` inside an internal span (intentional copy of the core/observability
18
35
  * helper: ADR 0015 §5 no-cycle rule — do not deduplicate).
19
36
  */
@@ -25,7 +42,7 @@ async function withSpan(name, fn, attributes) {
25
42
  try {
26
43
  return await fn(span);
27
44
  } catch (error) {
28
- span.recordException(error instanceof Error ? error : String(error));
45
+ span.recordException(recordedError(error));
29
46
  span.setStatus({ code: SpanStatusCode.ERROR });
30
47
  throw error;
31
48
  } finally {
@@ -33,7 +50,6 @@ async function withSpan(name, fn, attributes) {
33
50
  }
34
51
  });
35
52
  }
36
- //#endregion
37
53
  export { registerOtelOnce, withSpan };
38
54
 
39
55
  //# sourceMappingURL=telemetry.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"telemetry.mjs","names":[],"sources":["../src/telemetry.ts"],"sourcesContent":["/** OTEL wiring: idempotent integration registration and a local span helper. */\nimport { OpenTelemetry } from \"@ai-sdk/otel\";\nimport { SpanKind, SpanStatusCode, trace, type Attributes, type Span } from \"@opentelemetry/api\";\nimport { registerTelemetry } from \"ai\";\n\nlet registered = false;\n\n/** Register the SDK's OpenTelemetry integration once per process. */\nexport function registerOtelOnce(): void {\n if (registered) {\n return;\n }\n registered = true;\n registerTelemetry(new OpenTelemetry());\n}\n\n/** Test hook: forget the registration flag. */\nexport function resetOtelRegistrationForTests(): void {\n registered = false;\n}\n\n/**\n * Run `fn` inside an internal span (intentional copy of the core/observability\n * helper: ADR 0015 §5 no-cycle rule — do not deduplicate).\n */\nexport async function withSpan<T>(\n name: string,\n fn: (span: Span) => Promise<T>,\n attributes?: Attributes,\n): Promise<T> {\n const tracer = trace.getTracer(\"storyshelf.ai\");\n return await tracer.startActiveSpan(\n name,\n { kind: SpanKind.INTERNAL, attributes },\n async (span) => {\n try {\n return await fn(span);\n } catch (error) {\n span.recordException(error instanceof Error ? error : String(error));\n span.setStatus({ code: SpanStatusCode.ERROR });\n throw error;\n } finally {\n span.end();\n }\n },\n );\n}\n"],"mappings":";;;;;;;;AAKA,IAAI,aAAa;;AAGjB,SAAgB,mBAAyB;CACvC,IAAI,YACF;CAEF,aAAa;CACb,kBAAkB,IAAI,cAAc,CAAC;AACvC;;;;;AAWA,eAAsB,SACpB,MACA,IACA,YACY;CAEZ,OAAO,MADQ,MAAM,UAAU,eACb,CAAC,CAAC,gBAClB,MACA;EAAE,MAAM,SAAS;EAAU;CAAW,GACtC,OAAO,SAAS;EACd,IAAI;GACF,OAAO,MAAM,GAAG,IAAI;EACtB,SAAS,OAAO;GACd,KAAK,gBAAgB,iBAAiB,QAAQ,QAAQ,OAAO,KAAK,CAAC;GACnE,KAAK,UAAU,EAAE,MAAM,eAAe,MAAM,CAAC;GAC7C,MAAM;EACR,UAAU;GACR,KAAK,IAAI;EACX;CACF,CACF;AACF"}
1
+ {"version":3,"file":"telemetry.mjs","names":[],"sources":["../src/telemetry.ts"],"sourcesContent":["/** OTEL wiring: idempotent integration registration and a local span helper. */\nimport { OpenTelemetry } from \"@ai-sdk/otel\";\nimport { SpanKind, SpanStatusCode, trace, type Attributes, type Span } from \"@opentelemetry/api\";\nimport { HttpError, redactSecrets } from \"@storyshelf/core/utils\";\nimport { registerTelemetry } from \"ai\";\n\nlet registered = false;\n\n/** Register the SDK's OpenTelemetry integration once per process. */\nexport function registerOtelOnce(): void {\n if (registered) {\n return;\n }\n registered = true;\n registerTelemetry(new OpenTelemetry());\n}\n\n/** Test hook: forget the registration flag. */\nexport function resetOtelRegistrationForTests(): void {\n registered = false;\n}\n\n/**\n * What a span records of a caught error: a copy with the same `name` and a `redactSecrets` message\n * (connection strings, tokens and keys stay out of exported spans), and for an `HttpError` its\n * status only, never the response body. The caller still gets the original error rethrown.\n * Intentional copy of core's `spanException` (ADR 0015 §5 no-cycle rule: do not deduplicate).\n */\nfunction recordedError(error: unknown): Error | string {\n if (!(error instanceof Error)) {\n return redactSecrets(String(error));\n }\n const message =\n error instanceof HttpError ? `HTTP ${String(error.status)}` : redactSecrets(error.message);\n const copy = new Error(message);\n copy.name = error.name;\n const header = `${error.name}: ${error.message}`;\n const frames = error.stack?.startsWith(header) ? error.stack.slice(header.length) : \"\";\n copy.stack = `${error.name}: ${message}${redactSecrets(frames)}`;\n return copy;\n}\n\n/**\n * Run `fn` inside an internal span (intentional copy of the core/observability\n * helper: ADR 0015 §5 no-cycle rule — do not deduplicate).\n */\nexport async function withSpan<T>(\n name: string,\n fn: (span: Span) => Promise<T>,\n attributes?: Attributes,\n): Promise<T> {\n const tracer = trace.getTracer(\"storyshelf.ai\");\n return await tracer.startActiveSpan(\n name,\n { kind: SpanKind.INTERNAL, attributes },\n async (span) => {\n try {\n return await fn(span);\n } catch (error) {\n span.recordException(recordedError(error));\n span.setStatus({ code: SpanStatusCode.ERROR });\n throw error;\n } finally {\n span.end();\n }\n },\n );\n}\n"],"mappings":";;;;;;;;;AAMA,IAAI,aAAa;;AAGjB,SAAgB,mBAAyB;CACvC,IAAI,YACF;CAEF,aAAa;CACb,kBAAkB,IAAI,cAAc,CAAC;AACvC;;;;;;;AAaA,SAAS,cAAc,OAAgC;CACrD,IAAI,EAAE,iBAAiB,QACrB,OAAO,cAAc,OAAO,KAAK,CAAC;CAEpC,MAAM,UACJ,iBAAiB,YAAY,QAAQ,OAAO,MAAM,MAAM,MAAM,cAAc,MAAM,OAAO;CAC3F,MAAM,OAAO,IAAI,MAAM,OAAO;CAC9B,KAAK,OAAO,MAAM;CAClB,MAAM,SAAS,GAAG,MAAM,KAAK,IAAI,MAAM;CACvC,MAAM,SAAS,MAAM,OAAO,WAAW,MAAM,IAAI,MAAM,MAAM,MAAM,OAAO,MAAM,IAAI;CACpF,KAAK,QAAQ,GAAG,MAAM,KAAK,IAAI,UAAU,cAAc,MAAM;CAC7D,OAAO;AACT;;;;;AAMA,eAAsB,SACpB,MACA,IACA,YACY;CAEZ,OAAO,MADQ,MAAM,UAAU,eACb,CAAC,CAAC,gBAClB,MACA;EAAE,MAAM,SAAS;EAAU;CAAW,GACtC,OAAO,SAAS;EACd,IAAI;GACF,OAAO,MAAM,GAAG,IAAI;EACtB,SAAS,OAAO;GACd,KAAK,gBAAgB,cAAc,KAAK,CAAC;GACzC,KAAK,UAAU,EAAE,MAAM,eAAe,MAAM,CAAC;GAC7C,MAAM;EACR,UAAU;GACR,KAAK,IAAI;EACX;CACF,CACF;AACF"}
package/dist/types.d.mts CHANGED
@@ -2,7 +2,6 @@ import __tsdown_shims_path from 'node:path';
2
2
  import __tsdown_shims_url from 'node:url';
3
3
  import { LanguageModel, generateText } from "ai";
4
4
  import { EvidenceLimits } from "@storyshelf/core/insights";
5
- //#region src/types.d.ts
6
5
  /** Provider-specific call settings, forwarded unchanged (opaque to this package). */
7
6
  type SlotProviderOptions = NonNullable<Parameters<typeof generateText>[0]["providerOptions"]>;
8
7
  /** A model, or a model with per-slot overrides. */
@@ -49,6 +48,5 @@ interface CreateAiOptions<P extends string> {
49
48
  /** Evidence limit overrides (ADR 0016 §5 defaults otherwise). */
50
49
  limits?: Partial<EvidenceLimits>;
51
50
  }
52
- //#endregion
53
51
  export { BudgetOptions, CreateAiOptions, ModelSlot, ProfileConfig, ProfileModels, SlotProviderOptions };
54
52
  //# sourceMappingURL=types.d.mts.map
package/dist/types.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
- //#region src/types.ts
4
+ // src/types.ts
5
5
  /** Task token/time defaults. */
6
6
  const TASK_DEFAULTS = {
7
7
  triage: {
@@ -13,7 +13,6 @@ const TASK_DEFAULTS = {
13
13
  timeoutMs: 18e4
14
14
  }
15
15
  };
16
- //#endregion
17
16
  export { TASK_DEFAULTS };
18
17
 
19
18
  //# sourceMappingURL=types.mjs.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@storyshelf/ai",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "StoryShelf AI insights engine on the Vercel AI SDK: build triage and project health (providers are supplied by the deployer).",
5
5
  "keywords": [
6
6
  "ai",
@@ -54,7 +54,7 @@
54
54
  "dependencies": {
55
55
  "@ai-sdk/otel": "1.0.133",
56
56
  "@opentelemetry/api": "^1.9.0",
57
- "@storyshelf/core": "0.7.0",
57
+ "@storyshelf/core": "0.8.0",
58
58
  "ai": "7.0.133"
59
59
  },
60
60
  "devDependencies": {
@@ -68,8 +68,8 @@
68
68
  "oxlint-tsgolint": "^7.0.2001",
69
69
  "tsdown": "^0.22.14",
70
70
  "typescript": "^7.0.2",
71
- "vitest": "^5.0.0",
72
- "zod": "^4.2.0"
71
+ "vitest": "^5.0.5",
72
+ "zod": "^4.6.7"
73
73
  },
74
74
  "engines": {
75
75
  "node": ">=24"