@to11ai/sdk 1.1.0 → 2.0.0-rc.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/dist/client.cjs +88 -18
- package/dist/client.d.ts +141 -39
- package/dist/client.js +94 -19
- package/dist/config.d.ts +9 -0
- package/dist/context.d.ts +124 -0
- package/dist/errors.cjs +18 -1
- package/dist/errors.d.ts +18 -1
- package/dist/errors.js +18 -1
- package/dist/gateway.cjs +65 -22
- package/dist/gateway.d.ts +65 -9
- package/dist/gateway.js +65 -22
- package/dist/generated/index.d.ts +1 -1
- package/dist/generated/types.gen.d.ts +1299 -167
- package/dist/generated/zod.gen.d.ts +393 -232
- package/dist/prompts/cache.d.ts +9 -10
- package/dist/prompts/resource.cjs +29 -67
- package/dist/prompts/resource.d.ts +52 -32
- package/dist/prompts/resource.js +30 -68
- package/dist/prompts/shape.d.ts +56 -0
- package/dist/prompts/types.d.ts +44 -31
- package/package.json +1 -1
- package/src/client.ts +337 -82
- package/src/config.ts +13 -0
- package/src/context.ts +198 -0
- package/src/errors.ts +33 -3
- package/src/gateway.ts +148 -33
- package/src/generated/index.ts +1 -1
- package/src/generated/types.gen.ts +1310 -167
- package/src/generated/zod.gen.ts +361 -271
- package/src/prompts/cache.ts +11 -15
- package/src/prompts/resource.ts +129 -142
- package/src/prompts/shape.ts +152 -0
- package/src/prompts/types.ts +45 -34
package/dist/prompts/cache.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { RenderedPrompt } from "./types";
|
|
2
2
|
export interface CacheConfig {
|
|
3
3
|
/** Time-to-live in seconds. Default: 300 (5 minutes) */
|
|
4
4
|
ttlSeconds?: number;
|
|
@@ -6,12 +6,11 @@ export interface CacheConfig {
|
|
|
6
6
|
maxEntries?: number;
|
|
7
7
|
}
|
|
8
8
|
/**
|
|
9
|
-
* The cache stores
|
|
10
|
-
* `fetch()` result. Both are JSON-cloneable; the cache is shape-agnostic.
|
|
9
|
+
* The cache stores enriched `render()` results, which are JSON-cloneable.
|
|
11
10
|
*/
|
|
12
|
-
export type
|
|
11
|
+
export type CacheableRendered = RenderedPrompt;
|
|
13
12
|
/**
|
|
14
|
-
* Build a canonical cache key
|
|
13
|
+
* Build a canonical base cache key from project/slug/labels/variables.
|
|
15
14
|
*
|
|
16
15
|
* - projectId is included to prevent cross-project cache collisions: a single
|
|
17
16
|
* PromptResource can serve multiple projects, so the same slug+labels must
|
|
@@ -24,7 +23,7 @@ export type CacheableResolved = ResolvedPrompt | FetchedPrompt;
|
|
|
24
23
|
*/
|
|
25
24
|
export declare function buildCacheKey(projectId: string, slug: string, labels: string[], variables?: Record<string, unknown>): string;
|
|
26
25
|
/**
|
|
27
|
-
* Build a cache key for an env-aware `
|
|
26
|
+
* Build a cache key for an env-aware `render()` call.
|
|
28
27
|
*
|
|
29
28
|
* Folds in `env` and `subject` ON TOP of the base
|
|
30
29
|
* project/slug/labels/variables key so two calls that differ only by
|
|
@@ -38,9 +37,9 @@ export declare function buildCacheKey(projectId: string, slug: string, labels: s
|
|
|
38
37
|
* caches as the same deterministic variant on repeat (D8); the
|
|
39
38
|
* weighted-no-subject bypass is handled in the resource, not here.
|
|
40
39
|
*/
|
|
41
|
-
export declare function
|
|
40
|
+
export declare function buildRenderCacheKey(projectId: string, slug: string, env: string, subject?: string, variables?: Record<string, unknown>): string;
|
|
42
41
|
/**
|
|
43
|
-
* In-memory LRU cache for
|
|
42
|
+
* In-memory LRU cache for RenderedPrompt objects.
|
|
44
43
|
*
|
|
45
44
|
* Uses a Map (insertion-ordered) as the backing store. On every access, the
|
|
46
45
|
* entry is deleted and re-inserted to maintain LRU order — oldest entries sit
|
|
@@ -51,8 +50,8 @@ export declare class PromptCache {
|
|
|
51
50
|
private readonly maxEntries;
|
|
52
51
|
private readonly store;
|
|
53
52
|
constructor(config?: CacheConfig);
|
|
54
|
-
get(key: string):
|
|
55
|
-
set(key: string, value:
|
|
53
|
+
get(key: string): CacheableRendered | undefined;
|
|
54
|
+
set(key: string, value: CacheableRendered): void;
|
|
56
55
|
delete(key: string): void;
|
|
57
56
|
clear(): void;
|
|
58
57
|
get size(): number;
|
|
@@ -46,17 +46,8 @@ var import_zod = require("zod");
|
|
|
46
46
|
var import_errors = require("../errors");
|
|
47
47
|
var import_zod2 = require("../generated/zod.gen");
|
|
48
48
|
var import_cache = require("./cache");
|
|
49
|
+
var import_shape = require("./shape");
|
|
49
50
|
var import_types = require("./types");
|
|
50
|
-
var zResolvedPromptLegacy = import_zod2.zResolvedPrompt.pick({
|
|
51
|
-
promptId: true,
|
|
52
|
-
versionId: true,
|
|
53
|
-
version: true,
|
|
54
|
-
labels: true,
|
|
55
|
-
contentHash: true,
|
|
56
|
-
rendered: true,
|
|
57
|
-
tools: true,
|
|
58
|
-
toolChoice: true
|
|
59
|
-
});
|
|
60
51
|
var zResolvedPromptEnvelope = import_zod2.zResolvedPrompt.partial({ releaseId: true }).extend({ strategy: import_zod.z.enum(["single", "weighted"]).optional() });
|
|
61
52
|
function unwrap(envelope) {
|
|
62
53
|
if (envelope.data === null || envelope.data === undefined) {
|
|
@@ -68,12 +59,12 @@ function getProjectPromptsPath(projectId) {
|
|
|
68
59
|
return `/v1/projects/${encodeURIComponent(projectId)}/prompts`;
|
|
69
60
|
}
|
|
70
61
|
function renderedToMessages(rendered) {
|
|
71
|
-
if (rendered.format
|
|
72
|
-
|
|
62
|
+
if (rendered.format !== "chat") {
|
|
63
|
+
throw new Error("[to11ai/sdk] Unsupported non-chat prompt format; author the prompt as chat blocks.");
|
|
73
64
|
}
|
|
74
|
-
return
|
|
65
|
+
return rendered.messages;
|
|
75
66
|
}
|
|
76
|
-
function normalizeResolvedEnvelope(raw) {
|
|
67
|
+
function normalizeResolvedEnvelope(raw, slug) {
|
|
77
68
|
const provenance = raw;
|
|
78
69
|
const result = {
|
|
79
70
|
messages: renderedToMessages(raw.rendered),
|
|
@@ -83,8 +74,9 @@ function normalizeResolvedEnvelope(raw) {
|
|
|
83
74
|
promptId: raw.promptId,
|
|
84
75
|
versionId: raw.versionId,
|
|
85
76
|
contentHash: raw.contentHash,
|
|
86
|
-
|
|
87
|
-
|
|
77
|
+
label: raw.label,
|
|
78
|
+
slug,
|
|
79
|
+
modelConfig: provenance.modelConfig
|
|
88
80
|
};
|
|
89
81
|
if (raw.tools != null && raw.tools.length > 0) {
|
|
90
82
|
result.tools = raw.tools;
|
|
@@ -97,11 +89,11 @@ function normalizeResolvedEnvelope(raw) {
|
|
|
97
89
|
}
|
|
98
90
|
return result;
|
|
99
91
|
}
|
|
100
|
-
function
|
|
101
|
-
if (
|
|
102
|
-
|
|
92
|
+
function liftFallbackToRendered(fallback, slug) {
|
|
93
|
+
if (!Array.isArray(fallback.messages)) {
|
|
94
|
+
throw new Error("[to11ai/sdk] `fallback` must be a RenderedPrompt (as returned by render()); the legacy resolve() shape is no longer supported.");
|
|
103
95
|
}
|
|
104
|
-
return
|
|
96
|
+
return { ...structuredClone(fallback), slug: fallback.slug || slug };
|
|
105
97
|
}
|
|
106
98
|
function getProjectPromptPath(projectId, promptId) {
|
|
107
99
|
return `${getProjectPromptsPath(projectId)}/${encodeURIComponent(promptId)}`;
|
|
@@ -139,11 +131,15 @@ class PromptResource {
|
|
|
139
131
|
cache;
|
|
140
132
|
projectId;
|
|
141
133
|
env;
|
|
134
|
+
format;
|
|
135
|
+
onUnknownRole;
|
|
142
136
|
constructor(transport, cacheConfig, config) {
|
|
143
137
|
this.transport = transport;
|
|
144
138
|
this.cache = new import_cache.PromptCache(cacheConfig);
|
|
145
139
|
this.projectId = config?.projectId;
|
|
146
140
|
this.env = config?.env;
|
|
141
|
+
this.format = config?.format;
|
|
142
|
+
this.onUnknownRole = config?.onUnknownRole;
|
|
147
143
|
}
|
|
148
144
|
async create(input) {
|
|
149
145
|
const { projectId, ...body } = input;
|
|
@@ -207,9 +203,15 @@ class PromptResource {
|
|
|
207
203
|
const envelope = await this.transport.request("GET", `${getProjectPromptPath(projectId, promptId)}/labels`);
|
|
208
204
|
return unwrap(envelope);
|
|
209
205
|
}
|
|
210
|
-
async
|
|
206
|
+
async render(slug, options = {}) {
|
|
207
|
+
const rendered = await this.resolveToRendered(slug, options);
|
|
208
|
+
return import_shape.shapePrompt(rendered, options.format ?? this.format, {
|
|
209
|
+
onUnknownRole: options.onUnknownRole ?? this.onUnknownRole
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
async resolveToRendered(slug, options = {}) {
|
|
211
213
|
if (this.projectId === undefined || this.projectId.trim() === "") {
|
|
212
|
-
throw new Error("[to11ai/sdk] `prompts.
|
|
214
|
+
throw new Error("[to11ai/sdk] `prompts.render()` requires a `projectId` on the client — pass it to createClient({ projectId, ... }).");
|
|
213
215
|
}
|
|
214
216
|
const env = options.env ?? this.env;
|
|
215
217
|
if (env === undefined) {
|
|
@@ -218,17 +220,11 @@ class PromptResource {
|
|
|
218
220
|
if (!import_types.ENV_SLUG_REGEX.test(env)) {
|
|
219
221
|
throw new Error(`[to11ai/sdk] \`env\` must match ${import_types.ENV_SLUG_REGEX} (lowercase-kebab, 1-63 chars). Received: ${JSON.stringify(env)}`);
|
|
220
222
|
}
|
|
221
|
-
const {
|
|
222
|
-
|
|
223
|
-
variables,
|
|
224
|
-
cache: useCache = true,
|
|
225
|
-
fallback,
|
|
226
|
-
developerRole
|
|
227
|
-
} = options;
|
|
228
|
-
const cacheKey = import_cache.buildFetchCacheKey(this.projectId, slug, env, subject, variables, developerRole);
|
|
223
|
+
const { subject, variables, cache: useCache = true, fallback } = options;
|
|
224
|
+
const cacheKey = import_cache.buildRenderCacheKey(this.projectId, slug, env, subject, variables);
|
|
229
225
|
if (useCache) {
|
|
230
226
|
const cached = this.cache.get(cacheKey);
|
|
231
|
-
if (cached
|
|
227
|
+
if (cached)
|
|
232
228
|
return structuredClone(cached);
|
|
233
229
|
}
|
|
234
230
|
const body = { slug, labels: [env] };
|
|
@@ -236,15 +232,13 @@ class PromptResource {
|
|
|
236
232
|
body.subject = subject;
|
|
237
233
|
if (variables !== undefined)
|
|
238
234
|
body.variables = variables;
|
|
239
|
-
if (developerRole !== undefined)
|
|
240
|
-
body.developerRole = developerRole;
|
|
241
235
|
try {
|
|
242
236
|
const envelope = await this.transport.request("POST", `${getProjectPromptsPath(this.projectId)}:resolve`, {
|
|
243
237
|
body,
|
|
244
238
|
decode: (data) => zResolvedPromptEnvelope.parse(data)
|
|
245
239
|
});
|
|
246
240
|
const raw = unwrap(envelope);
|
|
247
|
-
const result = normalizeResolvedEnvelope(raw);
|
|
241
|
+
const result = normalizeResolvedEnvelope(raw, slug);
|
|
248
242
|
const isWeighted = raw.strategy === "weighted" || result.variantName !== undefined;
|
|
249
243
|
const cacheable = !(isWeighted && subject === undefined);
|
|
250
244
|
if (useCache && cacheable) {
|
|
@@ -253,39 +247,7 @@ class PromptResource {
|
|
|
253
247
|
return result;
|
|
254
248
|
} catch (err) {
|
|
255
249
|
if (err instanceof import_errors.To11aiNetworkError && fallback !== undefined) {
|
|
256
|
-
return
|
|
257
|
-
}
|
|
258
|
-
throw err;
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
async resolve(input) {
|
|
262
|
-
const {
|
|
263
|
-
projectId,
|
|
264
|
-
slug,
|
|
265
|
-
labels,
|
|
266
|
-
variables,
|
|
267
|
-
cache: useCache = true,
|
|
268
|
-
fallback
|
|
269
|
-
} = input;
|
|
270
|
-
const cacheKey = import_cache.buildCacheKey(projectId, slug, labels, variables);
|
|
271
|
-
if (useCache) {
|
|
272
|
-
const cached = this.cache.get(cacheKey);
|
|
273
|
-
if (cached && !("messages" in cached))
|
|
274
|
-
return structuredClone(cached);
|
|
275
|
-
}
|
|
276
|
-
try {
|
|
277
|
-
const envelope = await this.transport.request("POST", `${getProjectPromptsPath(projectId)}:resolve`, {
|
|
278
|
-
body: { slug, labels, variables },
|
|
279
|
-
decode: (data) => zResolvedPromptLegacy.parse(data)
|
|
280
|
-
});
|
|
281
|
-
const result = unwrap(envelope);
|
|
282
|
-
if (useCache) {
|
|
283
|
-
this.cache.set(cacheKey, structuredClone(result));
|
|
284
|
-
}
|
|
285
|
-
return result;
|
|
286
|
-
} catch (err) {
|
|
287
|
-
if (err instanceof import_errors.To11aiNetworkError && fallback !== undefined) {
|
|
288
|
-
return fallback;
|
|
250
|
+
return liftFallbackToRendered(fallback, slug);
|
|
289
251
|
}
|
|
290
252
|
throw err;
|
|
291
253
|
}
|
|
@@ -1,27 +1,39 @@
|
|
|
1
1
|
import type { Transport } from "../transport";
|
|
2
2
|
import type { CacheConfig } from "./cache";
|
|
3
|
-
import type {
|
|
3
|
+
import type { AnthropicRenderedPrompt, OpenAiRenderedPrompt, RenderResult } from "./shape";
|
|
4
|
+
import type { ArchivePromptInput, ArchivePromptResult, CreateProjectPromptLabelInput, CreateProjectPromptLabelResult, CreatePromptInput, CreatePromptResult, CreatePromptVersionInput, CreatePromptVersionResult, DeleteProjectPromptLabelInput, DeleteProjectPromptLabelResult, GetProjectPromptLabelInput, GetProjectPromptLabelResult, GetPromptInput, GetPromptResult, GetPromptVersionInput, GetPromptVersionResult, ListLabelEventsInput, ListLabelEventsResult, ListProjectPromptLabelsInput, ListProjectPromptLabelsResult, ListProjectPromptLabelUsagesInput, ListProjectPromptLabelUsagesResult, ListPromptLabelsInput, ListPromptLabelsResult, ListPromptsInput, ListPromptsResult, ListPromptVersionsInput, ListPromptVersionsResult, MovePromptLabelInput, MovePromptLabelResult, PaginatedResult, RenderFormat, RenderOptions, UnknownRoleMode, UpdateProjectPromptLabelInput, UpdateProjectPromptLabelResult, UpdatePromptInput, UpdatePromptResult } from "./types";
|
|
4
5
|
export type { CacheConfig } from "./cache";
|
|
5
|
-
export type { ArchivePromptInput, ArchivePromptResult, BlockRenderRecord, ChatMessage, CreateProjectPromptLabelInput, CreateProjectPromptLabelResult, CreatePromptInput, CreatePromptResult, CreatePromptVersionInput, CreatePromptVersionResult, DeleteProjectPromptLabelInput, DeleteProjectPromptLabelResult,
|
|
6
|
+
export type { ArchivePromptInput, ArchivePromptResult, BlockRenderRecord, ChatMessage, CreateProjectPromptLabelInput, CreateProjectPromptLabelResult, CreatePromptInput, CreatePromptResult, CreatePromptVersionInput, CreatePromptVersionResult, DeleteProjectPromptLabelInput, DeleteProjectPromptLabelResult, GetProjectPromptLabelInput, GetProjectPromptLabelResult, GetPromptInput, GetPromptResult, GetPromptVersionInput, GetPromptVersionResult, ListLabelEventsInput, ListLabelEventsResult, ListProjectPromptLabelsInput, ListProjectPromptLabelsResult, ListProjectPromptLabelUsagesInput, ListProjectPromptLabelUsagesResult, ListPromptLabelsInput, ListPromptLabelsResult, ListPromptsInput, ListPromptsResult, ListPromptVersionsInput, ListPromptVersionsResult, MovePromptLabelInput, MovePromptLabelResult, PaginatedResult, PaginationInfo, PaletteToken, ProjectPromptLabel, ProjectPromptLabelUsage, Prompt, PromptFormat, PromptLabelEvent, PromptLabelPointer, PromptStatus, PromptVersion, RenderedChatMessage, RenderedPrompt, RenderFormat, RenderOptions, ResolvedPrompt, ResolvedPromptEnvelope, ResolvedToolCall, ResolvedToolDefinition, RowError, TextChatMessage, TextChatRole, UnknownRoleMode, UpdateProjectPromptLabelInput, UpdateProjectPromptLabelResult, UpdatePromptInput, UpdatePromptResult, } from "./types";
|
|
6
7
|
/**
|
|
7
|
-
* Init-time config for the env-aware `
|
|
8
|
+
* Init-time config for the env-aware `render()` surface (TO11-980 / S9).
|
|
8
9
|
*
|
|
9
10
|
* `projectId` and `env` come from `createClient`. `projectId` is required for
|
|
10
|
-
* `
|
|
11
|
-
* serving environment inherited by every `
|
|
11
|
+
* `render()` (it builds the project-scoped resolve path); `env` is the default
|
|
12
|
+
* serving environment inherited by every `render(slug)` call.
|
|
12
13
|
*/
|
|
13
14
|
export interface PromptResourceConfig {
|
|
14
|
-
/** Project the client is bound to. Required for `
|
|
15
|
+
/** Project the client is bound to. Required for `render()`; validated at createClient. */
|
|
15
16
|
projectId?: string;
|
|
16
|
-
/** Default serving env for `
|
|
17
|
+
/** Default serving env for `render()`. Validated against ENV_SLUG_REGEX at createClient. */
|
|
17
18
|
env?: string;
|
|
19
|
+
/** Default provider shape for `render()` output. Per-call override allowed. */
|
|
20
|
+
format?: RenderFormat;
|
|
21
|
+
/**
|
|
22
|
+
* Default unknown-role policy for `render({ format })` output conversion.
|
|
23
|
+
* Per-call override allowed; defaults to `"drop"`.
|
|
24
|
+
*/
|
|
25
|
+
onUnknownRole?: UnknownRoleMode;
|
|
18
26
|
}
|
|
19
|
-
export declare class PromptResource {
|
|
27
|
+
export declare class PromptResource<F extends RenderFormat | undefined = undefined> {
|
|
20
28
|
private readonly transport;
|
|
21
29
|
private readonly cache;
|
|
22
30
|
private readonly projectId;
|
|
23
31
|
private readonly env;
|
|
24
|
-
|
|
32
|
+
private readonly format;
|
|
33
|
+
private readonly onUnknownRole;
|
|
34
|
+
constructor(transport: Transport, cacheConfig?: CacheConfig, config?: Omit<PromptResourceConfig, "format"> & {
|
|
35
|
+
format?: F;
|
|
36
|
+
});
|
|
25
37
|
create(input: CreatePromptInput): Promise<CreatePromptResult>;
|
|
26
38
|
list(input: ListPromptsInput): Promise<PaginatedResult<ListPromptsResult>>;
|
|
27
39
|
get(input: GetPromptInput): Promise<GetPromptResult>;
|
|
@@ -33,35 +45,43 @@ export declare class PromptResource {
|
|
|
33
45
|
moveLabel(input: MovePromptLabelInput): Promise<MovePromptLabelResult>;
|
|
34
46
|
listLabels(input: ListPromptLabelsInput): Promise<ListPromptLabelsResult>;
|
|
35
47
|
/**
|
|
36
|
-
* Resolve a prompt for the client's configured
|
|
37
|
-
*
|
|
38
|
-
*
|
|
48
|
+
* Resolve and (optionally) shape a prompt for the client's configured
|
|
49
|
+
* `projectId` + `env`, in one control-plane request. With a `format` (per
|
|
50
|
+
* call or inherited from the client) the result is provider-shaped
|
|
51
|
+
* `{ messages, config, metadata }`; without one it is the neutral
|
|
52
|
+
* `RenderedPrompt`. Resolves by the client's configured `env`.
|
|
53
|
+
*
|
|
54
|
+
* @example Render an OpenAI-shaped prompt and send it through the gateway
|
|
55
|
+
* const prompt = await to11.prompts.render("weather-concierge", {
|
|
56
|
+
* variables: { city: "NYC" },
|
|
57
|
+
* });
|
|
58
|
+
* const res = await openai.chat.completions.create(
|
|
59
|
+
* { ...prompt.config, messages: prompt.messages },
|
|
60
|
+
* { headers: to11.turn().headers(prompt) },
|
|
61
|
+
* );
|
|
62
|
+
*/
|
|
63
|
+
render(slug: string, options: RenderOptions & {
|
|
64
|
+
format: "openai";
|
|
65
|
+
}): Promise<OpenAiRenderedPrompt>;
|
|
66
|
+
render(slug: string, options: RenderOptions & {
|
|
67
|
+
format: "anthropic";
|
|
68
|
+
}): Promise<AnthropicRenderedPrompt>;
|
|
69
|
+
render(slug: string, options?: RenderOptions): Promise<RenderResult<F>>;
|
|
70
|
+
/**
|
|
71
|
+
* Env-aware resolution → neutral `RenderedPrompt`. Carries the resolve /
|
|
72
|
+
* cache / offline-fallback logic; `render()` is the public shaping surface.
|
|
39
73
|
*
|
|
40
|
-
* - **env→label wire mapping
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* env slug (lowercase-kebab — a valid label name) is therefore sent as
|
|
44
|
-
* the single resolution label: body `{ slug, labels: [env], subject?,
|
|
45
|
-
* variables? }`.
|
|
74
|
+
* - **env→label wire mapping:** the resolve route is label-based
|
|
75
|
+
* (`/v1/projects/:projectId/prompts:resolve`, body `labels[]`); the
|
|
76
|
+
* resolved env slug is sent as the single resolution label.
|
|
46
77
|
* - **No silent fallback (R4):** if no env is resolvable (none at init AND
|
|
47
|
-
* none per call) this throws `EnvNotFoundError`
|
|
48
|
-
*
|
|
78
|
+
* none per call) this throws `EnvNotFoundError` CLIENT-side, eagerly,
|
|
79
|
+
* before any transport call.
|
|
49
80
|
* - **Cache (D8):** caches `single`-strategy releases and weighted releases
|
|
50
81
|
* WITH a `subject`; BYPASSES the cache for weighted releases with NO
|
|
51
82
|
* `subject` (a uniform-random assignment must not be pinned for the TTL).
|
|
52
|
-
*
|
|
53
|
-
* Prefer this over the deprecated `resolve()`.
|
|
54
|
-
*/
|
|
55
|
-
fetch(slug: string, options?: FetchPromptOptions): Promise<FetchedPrompt>;
|
|
56
|
-
/**
|
|
57
|
-
* @deprecated Use {@link PromptResource.fetch | `prompts.fetch(slug,
|
|
58
|
-
* options?)`} instead. `resolve()` is env-agnostic (no `env` / `subject`,
|
|
59
|
-
* no enriched release/variant provenance, no typed-env errors)
|
|
60
|
-
* and is retained only for back-compat. It is NOT subject to the R4
|
|
61
|
-
* no-silent-fallback env gate (it has no env concept). New code should
|
|
62
|
-
* configure `projectId` + `env` at `createClient` and call `fetch()`.
|
|
63
83
|
*/
|
|
64
|
-
|
|
84
|
+
private resolveToRendered;
|
|
65
85
|
/**
|
|
66
86
|
* List the project-level label registry.
|
|
67
87
|
*
|
package/dist/prompts/resource.js
CHANGED
|
@@ -2,18 +2,9 @@
|
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { EnvNotFoundError, To11aiNetworkError } from "../errors";
|
|
4
4
|
import { zResolvedPrompt } from "../generated/zod.gen";
|
|
5
|
-
import {
|
|
5
|
+
import { buildRenderCacheKey, PromptCache } from "./cache";
|
|
6
|
+
import { shapePrompt } from "./shape";
|
|
6
7
|
import { ENV_SLUG_REGEX } from "./types";
|
|
7
|
-
var zResolvedPromptLegacy = zResolvedPrompt.pick({
|
|
8
|
-
promptId: true,
|
|
9
|
-
versionId: true,
|
|
10
|
-
version: true,
|
|
11
|
-
labels: true,
|
|
12
|
-
contentHash: true,
|
|
13
|
-
rendered: true,
|
|
14
|
-
tools: true,
|
|
15
|
-
toolChoice: true
|
|
16
|
-
});
|
|
17
8
|
var zResolvedPromptEnvelope = zResolvedPrompt.partial({ releaseId: true }).extend({ strategy: z.enum(["single", "weighted"]).optional() });
|
|
18
9
|
function unwrap(envelope) {
|
|
19
10
|
if (envelope.data === null || envelope.data === undefined) {
|
|
@@ -25,12 +16,12 @@ function getProjectPromptsPath(projectId) {
|
|
|
25
16
|
return `/v1/projects/${encodeURIComponent(projectId)}/prompts`;
|
|
26
17
|
}
|
|
27
18
|
function renderedToMessages(rendered) {
|
|
28
|
-
if (rendered.format
|
|
29
|
-
|
|
19
|
+
if (rendered.format !== "chat") {
|
|
20
|
+
throw new Error("[to11ai/sdk] Unsupported non-chat prompt format; author the prompt as chat blocks.");
|
|
30
21
|
}
|
|
31
|
-
return
|
|
22
|
+
return rendered.messages;
|
|
32
23
|
}
|
|
33
|
-
function normalizeResolvedEnvelope(raw) {
|
|
24
|
+
function normalizeResolvedEnvelope(raw, slug) {
|
|
34
25
|
const provenance = raw;
|
|
35
26
|
const result = {
|
|
36
27
|
messages: renderedToMessages(raw.rendered),
|
|
@@ -40,8 +31,9 @@ function normalizeResolvedEnvelope(raw) {
|
|
|
40
31
|
promptId: raw.promptId,
|
|
41
32
|
versionId: raw.versionId,
|
|
42
33
|
contentHash: raw.contentHash,
|
|
43
|
-
|
|
44
|
-
|
|
34
|
+
label: raw.label,
|
|
35
|
+
slug,
|
|
36
|
+
modelConfig: provenance.modelConfig
|
|
45
37
|
};
|
|
46
38
|
if (raw.tools != null && raw.tools.length > 0) {
|
|
47
39
|
result.tools = raw.tools;
|
|
@@ -54,11 +46,11 @@ function normalizeResolvedEnvelope(raw) {
|
|
|
54
46
|
}
|
|
55
47
|
return result;
|
|
56
48
|
}
|
|
57
|
-
function
|
|
58
|
-
if (
|
|
59
|
-
|
|
49
|
+
function liftFallbackToRendered(fallback, slug) {
|
|
50
|
+
if (!Array.isArray(fallback.messages)) {
|
|
51
|
+
throw new Error("[to11ai/sdk] `fallback` must be a RenderedPrompt (as returned by render()); the legacy resolve() shape is no longer supported.");
|
|
60
52
|
}
|
|
61
|
-
return
|
|
53
|
+
return { ...structuredClone(fallback), slug: fallback.slug || slug };
|
|
62
54
|
}
|
|
63
55
|
function getProjectPromptPath(projectId, promptId) {
|
|
64
56
|
return `${getProjectPromptsPath(projectId)}/${encodeURIComponent(promptId)}`;
|
|
@@ -96,11 +88,15 @@ class PromptResource {
|
|
|
96
88
|
cache;
|
|
97
89
|
projectId;
|
|
98
90
|
env;
|
|
91
|
+
format;
|
|
92
|
+
onUnknownRole;
|
|
99
93
|
constructor(transport, cacheConfig, config) {
|
|
100
94
|
this.transport = transport;
|
|
101
95
|
this.cache = new PromptCache(cacheConfig);
|
|
102
96
|
this.projectId = config?.projectId;
|
|
103
97
|
this.env = config?.env;
|
|
98
|
+
this.format = config?.format;
|
|
99
|
+
this.onUnknownRole = config?.onUnknownRole;
|
|
104
100
|
}
|
|
105
101
|
async create(input) {
|
|
106
102
|
const { projectId, ...body } = input;
|
|
@@ -164,9 +160,15 @@ class PromptResource {
|
|
|
164
160
|
const envelope = await this.transport.request("GET", `${getProjectPromptPath(projectId, promptId)}/labels`);
|
|
165
161
|
return unwrap(envelope);
|
|
166
162
|
}
|
|
167
|
-
async
|
|
163
|
+
async render(slug, options = {}) {
|
|
164
|
+
const rendered = await this.resolveToRendered(slug, options);
|
|
165
|
+
return shapePrompt(rendered, options.format ?? this.format, {
|
|
166
|
+
onUnknownRole: options.onUnknownRole ?? this.onUnknownRole
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
async resolveToRendered(slug, options = {}) {
|
|
168
170
|
if (this.projectId === undefined || this.projectId.trim() === "") {
|
|
169
|
-
throw new Error("[to11ai/sdk] `prompts.
|
|
171
|
+
throw new Error("[to11ai/sdk] `prompts.render()` requires a `projectId` on the client — pass it to createClient({ projectId, ... }).");
|
|
170
172
|
}
|
|
171
173
|
const env = options.env ?? this.env;
|
|
172
174
|
if (env === undefined) {
|
|
@@ -175,17 +177,11 @@ class PromptResource {
|
|
|
175
177
|
if (!ENV_SLUG_REGEX.test(env)) {
|
|
176
178
|
throw new Error(`[to11ai/sdk] \`env\` must match ${ENV_SLUG_REGEX} (lowercase-kebab, 1-63 chars). Received: ${JSON.stringify(env)}`);
|
|
177
179
|
}
|
|
178
|
-
const {
|
|
179
|
-
|
|
180
|
-
variables,
|
|
181
|
-
cache: useCache = true,
|
|
182
|
-
fallback,
|
|
183
|
-
developerRole
|
|
184
|
-
} = options;
|
|
185
|
-
const cacheKey = buildFetchCacheKey(this.projectId, slug, env, subject, variables, developerRole);
|
|
180
|
+
const { subject, variables, cache: useCache = true, fallback } = options;
|
|
181
|
+
const cacheKey = buildRenderCacheKey(this.projectId, slug, env, subject, variables);
|
|
186
182
|
if (useCache) {
|
|
187
183
|
const cached = this.cache.get(cacheKey);
|
|
188
|
-
if (cached
|
|
184
|
+
if (cached)
|
|
189
185
|
return structuredClone(cached);
|
|
190
186
|
}
|
|
191
187
|
const body = { slug, labels: [env] };
|
|
@@ -193,15 +189,13 @@ class PromptResource {
|
|
|
193
189
|
body.subject = subject;
|
|
194
190
|
if (variables !== undefined)
|
|
195
191
|
body.variables = variables;
|
|
196
|
-
if (developerRole !== undefined)
|
|
197
|
-
body.developerRole = developerRole;
|
|
198
192
|
try {
|
|
199
193
|
const envelope = await this.transport.request("POST", `${getProjectPromptsPath(this.projectId)}:resolve`, {
|
|
200
194
|
body,
|
|
201
195
|
decode: (data) => zResolvedPromptEnvelope.parse(data)
|
|
202
196
|
});
|
|
203
197
|
const raw = unwrap(envelope);
|
|
204
|
-
const result = normalizeResolvedEnvelope(raw);
|
|
198
|
+
const result = normalizeResolvedEnvelope(raw, slug);
|
|
205
199
|
const isWeighted = raw.strategy === "weighted" || result.variantName !== undefined;
|
|
206
200
|
const cacheable = !(isWeighted && subject === undefined);
|
|
207
201
|
if (useCache && cacheable) {
|
|
@@ -210,39 +204,7 @@ class PromptResource {
|
|
|
210
204
|
return result;
|
|
211
205
|
} catch (err) {
|
|
212
206
|
if (err instanceof To11aiNetworkError && fallback !== undefined) {
|
|
213
|
-
return
|
|
214
|
-
}
|
|
215
|
-
throw err;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
async resolve(input) {
|
|
219
|
-
const {
|
|
220
|
-
projectId,
|
|
221
|
-
slug,
|
|
222
|
-
labels,
|
|
223
|
-
variables,
|
|
224
|
-
cache: useCache = true,
|
|
225
|
-
fallback
|
|
226
|
-
} = input;
|
|
227
|
-
const cacheKey = buildCacheKey(projectId, slug, labels, variables);
|
|
228
|
-
if (useCache) {
|
|
229
|
-
const cached = this.cache.get(cacheKey);
|
|
230
|
-
if (cached && !("messages" in cached))
|
|
231
|
-
return structuredClone(cached);
|
|
232
|
-
}
|
|
233
|
-
try {
|
|
234
|
-
const envelope = await this.transport.request("POST", `${getProjectPromptsPath(projectId)}:resolve`, {
|
|
235
|
-
body: { slug, labels, variables },
|
|
236
|
-
decode: (data) => zResolvedPromptLegacy.parse(data)
|
|
237
|
-
});
|
|
238
|
-
const result = unwrap(envelope);
|
|
239
|
-
if (useCache) {
|
|
240
|
-
this.cache.set(cacheKey, structuredClone(result));
|
|
241
|
-
}
|
|
242
|
-
return result;
|
|
243
|
-
} catch (err) {
|
|
244
|
-
if (err instanceof To11aiNetworkError && fallback !== undefined) {
|
|
245
|
-
return fallback;
|
|
207
|
+
return liftFallbackToRendered(fallback, slug);
|
|
246
208
|
}
|
|
247
209
|
throw err;
|
|
248
210
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format-at-load shaping: turn a neutral `RenderedPrompt` into a provider-shaped
|
|
3
|
+
* `{ messages, config, metadata }` result the caller spreads into their own
|
|
4
|
+
* provider `create()` call. Header-only — this only reshapes data, it never
|
|
5
|
+
* sends a request. See docs/product-specs/2026-07-14-to11-2691-sdk-simpler-setup.md.
|
|
6
|
+
*/
|
|
7
|
+
import { type AnthropicMessage, type AnthropicTool, type AnthropicToolChoice, type ConvertMessagesOptions, type OpenAIChatMessage, type OpenAITool, type OpenAIToolChoice } from "../gateway";
|
|
8
|
+
import type { RenderedPrompt, RenderFormat } from "./types";
|
|
9
|
+
/** Model params passed through verbatim from the resolved version's modelConfig. */
|
|
10
|
+
export interface PromptConfig {
|
|
11
|
+
model?: string;
|
|
12
|
+
temperature?: number;
|
|
13
|
+
max_tokens?: number;
|
|
14
|
+
/** Any additional stored model-config keys are passed through unchanged. */
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
}
|
|
17
|
+
/** Prompt provenance for `turn.headers()` — kept apart from the request body. */
|
|
18
|
+
export interface PromptMetadata {
|
|
19
|
+
promptId: string;
|
|
20
|
+
versionId: string;
|
|
21
|
+
version: number;
|
|
22
|
+
releaseId: string | null;
|
|
23
|
+
/** The single label the prompt resolved through (env slug today). */
|
|
24
|
+
label: string;
|
|
25
|
+
/** The prompt's human-readable slug — surfaced as `x-to11-prompt-slug`. */
|
|
26
|
+
slug: string;
|
|
27
|
+
variantName?: string;
|
|
28
|
+
}
|
|
29
|
+
/** OpenAI-shaped render result: spread `{ ...config, messages }` into create(). */
|
|
30
|
+
export interface OpenAiRenderedPrompt {
|
|
31
|
+
messages: OpenAIChatMessage[];
|
|
32
|
+
config: PromptConfig;
|
|
33
|
+
metadata: PromptMetadata;
|
|
34
|
+
/** Authored tools, provider-shaped. Present only when the prompt declares tools. */
|
|
35
|
+
tools?: OpenAITool[];
|
|
36
|
+
/** Authored tool-choice directive. Present only when the prompt sets one. */
|
|
37
|
+
tool_choice?: OpenAIToolChoice;
|
|
38
|
+
}
|
|
39
|
+
/** Anthropic-shaped render result: system/developer folded into `system`. */
|
|
40
|
+
export interface AnthropicRenderedPrompt {
|
|
41
|
+
/** Folded system/developer instruction text (Anthropic's top-level `system`). */
|
|
42
|
+
system?: string;
|
|
43
|
+
messages: AnthropicMessage[];
|
|
44
|
+
config: PromptConfig;
|
|
45
|
+
metadata: PromptMetadata;
|
|
46
|
+
/** Authored tools, provider-shaped. Present only when the prompt declares tools. */
|
|
47
|
+
tools?: AnthropicTool[];
|
|
48
|
+
/** Authored tool-choice directive. Present only when the prompt sets one. */
|
|
49
|
+
tool_choice?: AnthropicToolChoice;
|
|
50
|
+
}
|
|
51
|
+
/** The render return type for a given client/call format. */
|
|
52
|
+
export type RenderResult<F extends RenderFormat | undefined> = F extends "openai" ? OpenAiRenderedPrompt : F extends "anthropic" ? AnthropicRenderedPrompt : RenderedPrompt;
|
|
53
|
+
export declare function shapeOpenAI(prompt: RenderedPrompt, options?: ConvertMessagesOptions): OpenAiRenderedPrompt;
|
|
54
|
+
export declare function shapeAnthropic(prompt: RenderedPrompt, options?: ConvertMessagesOptions): AnthropicRenderedPrompt;
|
|
55
|
+
/** Shape a fetched prompt for `format`, or return it neutral when unset. */
|
|
56
|
+
export declare function shapePrompt(prompt: RenderedPrompt, format: RenderFormat | undefined, options?: ConvertMessagesOptions): RenderedPrompt | OpenAiRenderedPrompt | AnthropicRenderedPrompt;
|