@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 +1 -2
- package/dist/codec.mjs +1 -2
- package/dist/index.d.mts +0 -2
- package/dist/index.mjs +1 -2
- package/dist/lifecycle.mjs +1 -2
- package/dist/metrics.mjs +1 -2
- package/dist/operations.mjs +1 -2
- package/dist/telemetry.mjs +19 -3
- package/dist/telemetry.mjs.map +1 -1
- package/dist/types.d.mts +0 -2
- package/dist/types.mjs +1 -2
- package/package.json +4 -4
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
package/dist/lifecycle.mjs
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
package/dist/operations.mjs
CHANGED
|
@@ -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
|
-
|
|
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
|
package/dist/telemetry.mjs
CHANGED
|
@@ -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
|
-
|
|
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(
|
|
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
|
package/dist/telemetry.mjs.map
CHANGED
|
@@ -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(
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
72
|
-
"zod": "^4.
|
|
71
|
+
"vitest": "^5.0.5",
|
|
72
|
+
"zod": "^4.6.7"
|
|
73
73
|
},
|
|
74
74
|
"engines": {
|
|
75
75
|
"node": ">=24"
|