@to11ai/sdk 1.1.0 → 2.0.0-rc.10

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.
@@ -1,20 +1,13 @@
1
1
  // src/prompts/resource.ts
2
- import { z } from "zod";
3
- import { EnvNotFoundError, To11aiNetworkError } from "../errors";
2
+ import {
3
+ MissingLabelError,
4
+ To11aiApiError,
5
+ To11aiNetworkError
6
+ } from "../errors";
4
7
  import { zResolvedPrompt } from "../generated/zod.gen";
5
- import { buildCacheKey, buildFetchCacheKey, PromptCache } from "./cache";
8
+ import { shapePrompt } from "./shape";
6
9
  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
- var zResolvedPromptEnvelope = zResolvedPrompt.partial({ releaseId: true }).extend({ strategy: z.enum(["single", "weighted"]).optional() });
10
+ var zResolvedPromptEnvelope = zResolvedPrompt.partial({ releaseId: true });
18
11
  function unwrap(envelope) {
19
12
  if (envelope.data === null || envelope.data === undefined) {
20
13
  throw new Error("API returned success but data is null");
@@ -25,12 +18,12 @@ function getProjectPromptsPath(projectId) {
25
18
  return `/v1/projects/${encodeURIComponent(projectId)}/prompts`;
26
19
  }
27
20
  function renderedToMessages(rendered) {
28
- if (rendered.format === "chat") {
29
- return rendered.messages;
21
+ if (rendered.format !== "chat") {
22
+ throw new Error("[to11ai/sdk] Unsupported non-chat prompt format; author the prompt as chat blocks.");
30
23
  }
31
- return [{ role: "user", content: rendered.text }];
24
+ return rendered.messages;
32
25
  }
33
- function normalizeResolvedEnvelope(raw) {
26
+ function normalizeResolvedEnvelope(raw, slug) {
34
27
  const provenance = raw;
35
28
  const result = {
36
29
  messages: renderedToMessages(raw.rendered),
@@ -40,8 +33,9 @@ function normalizeResolvedEnvelope(raw) {
40
33
  promptId: raw.promptId,
41
34
  versionId: raw.versionId,
42
35
  contentHash: raw.contentHash,
43
- labels: raw.labels,
44
- rendered: raw.rendered
36
+ label: raw.label,
37
+ slug,
38
+ modelConfig: provenance.modelConfig
45
39
  };
46
40
  if (raw.tools != null && raw.tools.length > 0) {
47
41
  result.tools = raw.tools;
@@ -54,11 +48,11 @@ function normalizeResolvedEnvelope(raw) {
54
48
  }
55
49
  return result;
56
50
  }
57
- function liftFallbackToFetched(fallback) {
58
- if ("messages" in fallback) {
59
- return structuredClone(fallback);
51
+ function liftFallbackToRendered(fallback, slug) {
52
+ if (!Array.isArray(fallback.messages)) {
53
+ throw new Error("[to11ai/sdk] `fallback` must be a RenderedPrompt (as returned by render()); the legacy resolve() shape is no longer supported.");
60
54
  }
61
- return normalizeResolvedEnvelope(fallback);
55
+ return { ...structuredClone(fallback), slug: fallback.slug || slug };
62
56
  }
63
57
  function getProjectPromptPath(projectId, promptId) {
64
58
  return `${getProjectPromptsPath(projectId)}/${encodeURIComponent(promptId)}`;
@@ -93,22 +87,33 @@ function buildLabelEventsQuery(input) {
93
87
 
94
88
  class PromptResource {
95
89
  transport;
96
- cache;
97
90
  projectId;
98
91
  env;
99
- constructor(transport, cacheConfig, config) {
92
+ format;
93
+ onUnknownRole;
94
+ constructor(transport, config) {
100
95
  this.transport = transport;
101
- 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;
100
+ }
101
+ resolveProjectId(perCall) {
102
+ const projectId = perCall ?? this.projectId;
103
+ if (projectId === undefined || projectId.trim() === "") {
104
+ throw new Error("[to11ai/sdk] this call needs a `projectId` — pass it on the call or bind one via createClient({ projectId, ... }).");
105
+ }
106
+ return projectId.trim();
104
107
  }
105
108
  async create(input) {
106
- const { projectId, ...body } = input;
109
+ const { projectId: perCallProjectId, ...body } = input;
110
+ const projectId = this.resolveProjectId(perCallProjectId);
107
111
  const envelope = await this.transport.request("POST", getProjectPromptsPath(projectId), { body });
108
112
  return unwrap(envelope);
109
113
  }
110
- async list(input) {
111
- const { projectId, ...queryRest } = input;
114
+ async list(input = {}) {
115
+ const { projectId: perCallProjectId, ...queryRest } = input;
116
+ const projectId = this.resolveProjectId(perCallProjectId);
112
117
  const envelope = await this.transport.request("GET", getProjectPromptsPath(projectId), {
113
118
  query: {
114
119
  ...queryRest
@@ -125,146 +130,111 @@ class PromptResource {
125
130
  return { items, pagination };
126
131
  }
127
132
  async get(input) {
128
- const { projectId, promptId } = input;
133
+ const { projectId: perCallProjectId, promptId } = input;
134
+ const projectId = this.resolveProjectId(perCallProjectId);
129
135
  const envelope = await this.transport.request("GET", getProjectPromptPath(projectId, promptId));
130
136
  return unwrap(envelope);
131
137
  }
132
138
  async update(input) {
133
- const { projectId, promptId, ...body } = input;
139
+ const { projectId: perCallProjectId, promptId, ...body } = input;
140
+ const projectId = this.resolveProjectId(perCallProjectId);
134
141
  const envelope = await this.transport.request("PATCH", getProjectPromptPath(projectId, promptId), { body });
135
142
  return unwrap(envelope);
136
143
  }
137
144
  async archive(input) {
138
- const { projectId, promptId } = input;
145
+ const { projectId: perCallProjectId, promptId } = input;
146
+ const projectId = this.resolveProjectId(perCallProjectId);
139
147
  const envelope = await this.transport.request("DELETE", getProjectPromptPath(projectId, promptId));
140
148
  return unwrap(envelope);
141
149
  }
142
150
  async createVersion(input) {
143
- const { projectId, promptId, ...body } = input;
151
+ const { projectId: perCallProjectId, promptId, ...body } = input;
152
+ const projectId = this.resolveProjectId(perCallProjectId);
144
153
  const envelope = await this.transport.request("POST", `${getProjectPromptPath(projectId, promptId)}/versions`, { body });
145
154
  return unwrap(envelope);
146
155
  }
147
156
  async listVersions(input) {
148
- const { projectId, promptId } = input;
157
+ const { projectId: perCallProjectId, promptId } = input;
158
+ const projectId = this.resolveProjectId(perCallProjectId);
149
159
  const envelope = await this.transport.request("GET", `${getProjectPromptPath(projectId, promptId)}/versions`);
150
160
  return unwrap(envelope);
151
161
  }
152
162
  async getVersion(input) {
153
- const { projectId, promptId, versionNumber } = input;
163
+ const { projectId: perCallProjectId, promptId, versionNumber } = input;
164
+ const projectId = this.resolveProjectId(perCallProjectId);
154
165
  const envelope = await this.transport.request("GET", `${getProjectPromptPath(projectId, promptId)}/versions/${encodeURIComponent(String(versionNumber))}`);
155
166
  return unwrap(envelope);
156
167
  }
157
168
  async moveLabel(input) {
158
- const { projectId, promptId, label, ...body } = input;
169
+ const { projectId: perCallProjectId, promptId, label, ...body } = input;
170
+ const projectId = this.resolveProjectId(perCallProjectId);
159
171
  const envelope = await this.transport.request("PUT", `${getProjectPromptPath(projectId, promptId)}/labels/${encodeURIComponent(label)}`, { body });
160
172
  return unwrap(envelope);
161
173
  }
162
174
  async listLabels(input) {
163
- const { projectId, promptId } = input;
175
+ const { projectId: perCallProjectId, promptId } = input;
176
+ const projectId = this.resolveProjectId(perCallProjectId);
164
177
  const envelope = await this.transport.request("GET", `${getProjectPromptPath(projectId, promptId)}/labels`);
165
178
  return unwrap(envelope);
166
179
  }
167
- async fetch(slug, options = {}) {
180
+ async render(slug, options = {}) {
181
+ const rendered = await this.resolveToRendered(slug, options);
182
+ return shapePrompt(rendered, options.format ?? this.format, {
183
+ onUnknownRole: options.onUnknownRole ?? this.onUnknownRole
184
+ });
185
+ }
186
+ async resolveToRendered(slug, options = {}) {
168
187
  if (this.projectId === undefined || this.projectId.trim() === "") {
169
- throw new Error("[to11ai/sdk] `prompts.fetch()` requires a `projectId` on the client — pass it to createClient({ projectId, ... }).");
188
+ throw new Error("[to11ai/sdk] `prompts.render()` requires a `projectId` on the client — pass it to createClient({ projectId, ... }).");
170
189
  }
171
- const env = options.env ?? this.env;
172
- if (env === undefined) {
173
- throw EnvNotFoundError.missing();
190
+ const label = options.label ?? this.env;
191
+ if (label === undefined) {
192
+ throw new MissingLabelError;
174
193
  }
175
- if (!ENV_SLUG_REGEX.test(env)) {
176
- throw new Error(`[to11ai/sdk] \`env\` must match ${ENV_SLUG_REGEX} (lowercase-kebab, 1-63 chars). Received: ${JSON.stringify(env)}`);
194
+ if (!ENV_SLUG_REGEX.test(label)) {
195
+ throw new Error(`[to11ai/sdk] \`label\` must match ${ENV_SLUG_REGEX} (lowercase-kebab, 1-63 chars). Received: ${JSON.stringify(label)}`);
177
196
  }
178
- const {
179
- subject,
180
- variables,
181
- cache: useCache = true,
182
- fallback,
183
- developerRole
184
- } = options;
185
- const cacheKey = buildFetchCacheKey(this.projectId, slug, env, subject, variables, developerRole);
186
- if (useCache) {
187
- const cached = this.cache.get(cacheKey);
188
- if (cached && "messages" in cached)
189
- return structuredClone(cached);
190
- }
191
- const body = { slug, labels: [env] };
192
- if (subject !== undefined)
193
- body.subject = subject;
197
+ const { variables, fallback } = options;
198
+ const body = {};
194
199
  if (variables !== undefined)
195
200
  body.variables = variables;
196
- if (developerRole !== undefined)
197
- body.developerRole = developerRole;
198
201
  try {
199
- const envelope = await this.transport.request("POST", `${getProjectPromptsPath(this.projectId)}:resolve`, {
202
+ const envelope = await this.transport.request("POST", `${getProjectPromptsPath(this.projectId)}/by-slug/${encodeURIComponent(slug)}/labels/${encodeURIComponent(label)}/render`, {
200
203
  body,
201
204
  decode: (data) => zResolvedPromptEnvelope.parse(data)
202
205
  });
203
206
  const raw = unwrap(envelope);
204
- const result = normalizeResolvedEnvelope(raw);
205
- const isWeighted = raw.strategy === "weighted" || result.variantName !== undefined;
206
- const cacheable = !(isWeighted && subject === undefined);
207
- if (useCache && cacheable) {
208
- this.cache.set(cacheKey, structuredClone(result));
209
- }
210
- return result;
211
- } catch (err) {
212
- if (err instanceof To11aiNetworkError && fallback !== undefined) {
213
- return liftFallbackToFetched(fallback);
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;
207
+ return normalizeResolvedEnvelope(raw, slug);
243
208
  } catch (err) {
244
- if (err instanceof To11aiNetworkError && fallback !== undefined) {
245
- return fallback;
209
+ const transient = err instanceof To11aiNetworkError || err instanceof To11aiApiError && err.statusCode >= 500;
210
+ if (transient && fallback !== undefined) {
211
+ return liftFallbackToRendered(fallback, slug);
246
212
  }
247
213
  throw err;
248
214
  }
249
215
  }
250
- async listProjectLabels(input) {
251
- const { projectId, includeArchived } = input;
216
+ async listProjectLabels(input = {}) {
217
+ const { projectId: perCallProjectId, includeArchived } = input;
218
+ const projectId = this.resolveProjectId(perCallProjectId);
252
219
  const envelope = await this.transport.request("GET", getProjectPromptLabelsPath(projectId), {
253
220
  query: includeArchived ? { includeArchived: "true" } : undefined
254
221
  });
255
222
  return unwrap(envelope);
256
223
  }
257
224
  async createProjectLabel(input) {
258
- const { projectId, ...body } = input;
225
+ const { projectId: perCallProjectId, ...body } = input;
226
+ const projectId = this.resolveProjectId(perCallProjectId);
259
227
  const envelope = await this.transport.request("POST", getProjectPromptLabelsPath(projectId), { body });
260
228
  return unwrap(envelope);
261
229
  }
262
230
  async getProjectLabel(input) {
263
- const envelope = await this.transport.request("GET", getProjectPromptLabelPath(input.projectId, input.label));
231
+ const projectId = this.resolveProjectId(input.projectId);
232
+ const envelope = await this.transport.request("GET", getProjectPromptLabelPath(projectId, input.label));
264
233
  return unwrap(envelope);
265
234
  }
266
235
  async updateProjectLabel(input) {
267
- const { projectId, label, ...rest } = input;
236
+ const { projectId: perCallProjectId, label, ...rest } = input;
237
+ const projectId = this.resolveProjectId(perCallProjectId);
268
238
  const body = {};
269
239
  if (rest.isDefault !== undefined)
270
240
  body.isDefault = rest.isDefault;
@@ -276,15 +246,16 @@ class PromptResource {
276
246
  return unwrap(envelope);
277
247
  }
278
248
  async deleteProjectLabel(input) {
279
- const envelope = await this.transport.request("DELETE", getProjectPromptLabelPath(input.projectId, input.label));
249
+ const projectId = this.resolveProjectId(input.projectId);
250
+ const envelope = await this.transport.request("DELETE", getProjectPromptLabelPath(projectId, input.label));
280
251
  return unwrap(envelope);
281
252
  }
282
253
  async listProjectLabelUsages(input) {
283
- const envelope = await this.transport.request("GET", `${getProjectPromptLabelPath(input.projectId, input.label)}/usages`);
254
+ const envelope = await this.transport.request("GET", `${getProjectPromptLabelPath(this.resolveProjectId(input.projectId), input.label)}/usages`);
284
255
  return unwrap(envelope);
285
256
  }
286
257
  async listLabelEvents(input) {
287
- const projectSeg = encodeURIComponent(input.projectId);
258
+ const projectSeg = encodeURIComponent(this.resolveProjectId(input.projectId));
288
259
  let path;
289
260
  switch (input.scope) {
290
261
  case "label":
@@ -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 rendered prompt for `format`, or return it neutral when unset. */
56
+ export declare function shapePrompt(prompt: RenderedPrompt, format: RenderFormat | undefined, options?: ConvertMessagesOptions): RenderedPrompt | OpenAiRenderedPrompt | AnthropicRenderedPrompt;
@@ -1,4 +1,4 @@
1
- import type { ProjectPromptLabel as GenProjectPromptLabel, ProjectPromptLabelUsage as GenProjectPromptLabelUsage, Prompt as GenPrompt, PromptLabelEvent as GenPromptLabelEvent, PromptLabelPointer as GenPromptLabelPointer, PromptVersion as GenPromptVersion, RenderedChatPrompt as GenRenderedChatPrompt, RenderedPrompt as GenRenderedPrompt, ResolvedPrompt as GenResolvedPrompt, ResolvedToolCall as GenResolvedToolCall, ResolvedToolDefinition as GenResolvedToolDefinition } from "../generated/types.gen";
1
+ import type { ProjectPromptLabel as GenProjectPromptLabel, ProjectPromptLabelUsage as GenProjectPromptLabelUsage, Prompt as GenPrompt, PromptLabelEvent as GenPromptLabelEvent, PromptLabelPointer as GenPromptLabelPointer, PromptVersion as GenPromptVersion, RenderedChatPrompt as GenRenderedChatPrompt, ResolvedPrompt as GenResolvedPrompt, ResolvedToolCall as GenResolvedToolCall, ResolvedToolDefinition as GenResolvedToolDefinition } from "../generated/types.gen";
2
2
  export interface RowError {
3
3
  path: ReadonlyArray<string | number>;
4
4
  code: string;
@@ -9,15 +9,23 @@ export type PromptStatus = Prompt["status"];
9
9
  export type PromptVersion = GenPromptVersion;
10
10
  export type PromptFormat = PromptVersion["format"];
11
11
  export type PromptLabelPointer = GenPromptLabelPointer;
12
- export type TextChatRole = "system" | "user" | "assistant" | "developer";
13
- export interface TextChatMessage {
14
- role: TextChatRole;
12
+ export type ChatRole = "system" | "user" | "assistant" | "developer";
13
+ export interface ChatMessage {
14
+ role: ChatRole;
15
15
  content: string;
16
16
  disabled?: boolean;
17
17
  }
18
- export type ChatMessage = TextChatMessage;
19
18
  export type RenderedChatMessage = GenRenderedChatPrompt["messages"][number];
20
- export type RenderedPrompt = GenRenderedPrompt;
19
+ /** Provider shape for `prompts.render()` output. Omit for the neutral result. */
20
+ export type RenderFormat = "openai" | "anthropic";
21
+ /**
22
+ * Policy for a message whose role is outside the known set
23
+ * (`system | user | assistant | developer | tool`) when converting to a
24
+ * provider shape. `"drop"` (default) omits it silently; `"warn"` omits it and
25
+ * emits a `console.warn`; `"error"` throws `UnknownRoleError`. Applies to the
26
+ * standalone converters and to `render({ format })`.
27
+ */
28
+ export type UnknownRoleMode = "drop" | "warn" | "error";
21
29
  /**
22
30
  * A provider-neutral tool definition (`{ name, description?, parameters }`),
23
31
  * sourced from authored tool-definition blocks. Surfaced on the resolved
@@ -29,7 +37,7 @@ export type ResolvedToolDefinition = GenResolvedToolDefinition;
29
37
  * on a rendered `assistant` turn (few-shot multi-tool history).
30
38
  */
31
39
  export type ResolvedToolCall = GenResolvedToolCall;
32
- export type ResolvedPrompt = Pick<GenResolvedPrompt, "promptId" | "versionId" | "version" | "labels" | "contentHash" | "rendered" | "tools" | "toolChoice">;
40
+ export type ResolvedPrompt = Pick<GenResolvedPrompt, "promptId" | "versionId" | "version" | "label" | "contentHash" | "rendered" | "tools" | "toolChoice" | "modelConfig">;
33
41
  export interface PaginationInfo {
34
42
  page: number;
35
43
  limit: number;
@@ -41,7 +49,7 @@ export interface PaginatedResult<T> {
41
49
  pagination: PaginationInfo;
42
50
  }
43
51
  export interface CreatePromptInput {
44
- projectId: string;
52
+ projectId?: string;
45
53
  name: string;
46
54
  slug: string;
47
55
  description?: string;
@@ -49,7 +57,7 @@ export interface CreatePromptInput {
49
57
  }
50
58
  export type CreatePromptResult = Prompt;
51
59
  export interface ListPromptsInput {
52
- projectId: string;
60
+ projectId?: string;
53
61
  status?: PromptStatus;
54
62
  sortBy?: "createdAt" | "updatedAt" | "name";
55
63
  tags?: string;
@@ -58,12 +66,12 @@ export interface ListPromptsInput {
58
66
  }
59
67
  export type ListPromptsResult = Prompt;
60
68
  export interface GetPromptInput {
61
- projectId: string;
69
+ projectId?: string;
62
70
  promptId: string;
63
71
  }
64
72
  export type GetPromptResult = Prompt;
65
73
  export interface UpdatePromptInput {
66
- projectId: string;
74
+ projectId?: string;
67
75
  promptId: string;
68
76
  name?: string;
69
77
  description?: string | null;
@@ -71,12 +79,12 @@ export interface UpdatePromptInput {
71
79
  }
72
80
  export type UpdatePromptResult = Prompt;
73
81
  export interface ArchivePromptInput {
74
- projectId: string;
82
+ projectId?: string;
75
83
  promptId: string;
76
84
  }
77
85
  export type ArchivePromptResult = Prompt;
78
86
  export interface CreatePromptVersionInput {
79
- projectId: string;
87
+ projectId?: string;
80
88
  promptId: string;
81
89
  format: PromptFormat;
82
90
  templateJson: unknown;
@@ -86,18 +94,18 @@ export interface CreatePromptVersionInput {
86
94
  }
87
95
  export type CreatePromptVersionResult = PromptVersion;
88
96
  export interface ListPromptVersionsInput {
89
- projectId: string;
97
+ projectId?: string;
90
98
  promptId: string;
91
99
  }
92
100
  export type ListPromptVersionsResult = PromptVersion[];
93
101
  export interface GetPromptVersionInput {
94
- projectId: string;
102
+ projectId?: string;
95
103
  promptId: string;
96
104
  versionNumber: number;
97
105
  }
98
106
  export type GetPromptVersionResult = PromptVersion;
99
107
  export interface MovePromptLabelInput {
100
- projectId: string;
108
+ projectId?: string;
101
109
  promptId: string;
102
110
  label: string;
103
111
  versionId: string;
@@ -105,24 +113,20 @@ export interface MovePromptLabelInput {
105
113
  }
106
114
  export type MovePromptLabelResult = PromptLabelPointer;
107
115
  export interface ListPromptLabelsInput {
108
- projectId: string;
116
+ projectId?: string;
109
117
  promptId: string;
110
118
  }
111
119
  export type ListPromptLabelsResult = PromptLabelPointer[];
112
- export interface ResolvePromptInput {
113
- projectId: string;
114
- slug: string;
115
- labels: string[];
116
- variables?: Record<string, unknown>;
117
- /** Set false to bypass the LRU cache for this call. Default: true */
118
- cache?: boolean;
119
- /** Fallback prompt served if the API is unreachable and cache is empty. */
120
- fallback?: ResolvedPrompt;
121
- }
122
- export type ResolvePromptResult = ResolvedPrompt;
120
+ /**
121
+ * Slug rule for a `render()` label — lowercase-kebab, 1-63 chars. Env slugs are
122
+ * a special case of a label value, so labels are held to the same strict rule
123
+ * (no uppercase, no underscores): a label is a routing key, and case-insensitive
124
+ * routing keys invite silent "production" vs "Production" mismatches. Intentionally
125
+ * strict — do not loosen.
126
+ */
123
127
  export declare const ENV_SLUG_REGEX: RegExp;
124
128
  export type BlockRenderRecord = Record<string, "rendered" | "dimmed">;
125
- export interface FetchedPrompt {
129
+ export interface RenderedPrompt {
126
130
  messages: RenderedChatMessage[];
127
131
  version: number;
128
132
  releaseId: string | null;
@@ -131,8 +135,24 @@ export interface FetchedPrompt {
131
135
  promptId: string;
132
136
  versionId: string;
133
137
  contentHash: string;
134
- labels: string[];
135
- rendered: RenderedPrompt;
138
+ /**
139
+ * The single label the prompt resolved through — the env slug today, a real
140
+ * label once labels ship. Surfaced as `x-to11-prompt-label` by
141
+ * `gatewayPromptHeaders` / `turn.headers()` (TO11-2725).
142
+ */
143
+ label: string;
144
+ /**
145
+ * The prompt's human-readable slug (the `render()` input). Surfaced as
146
+ * `x-to11-prompt-slug` by `gatewayPromptHeaders` / `turn.headers()` so traces
147
+ * carry a readable name alongside the opaque `promptId` (TO11-2727).
148
+ */
149
+ slug: string;
150
+ /**
151
+ * The served version's model config (model, temperature, max_tokens, …),
152
+ * passed through verbatim. Surfaced as `config` by `render({ format })`.
153
+ * Optional: absent when a pre-`modelConfig` API omits it.
154
+ */
155
+ modelConfig?: unknown;
136
156
  /**
137
157
  * Provider-neutral tool definitions lifted from authored tool-definition
138
158
  * blocks. Absent (rather than `[]`) when the resolved version declares no
@@ -145,47 +165,42 @@ export interface FetchedPrompt {
145
165
  * into `toOpenAIToolChoice` / `toAnthropicToolChoice`.
146
166
  *
147
167
  * `NonNullable` because `normalizeResolvedEnvelope` maps wire-`null` to absent,
148
- * so a present `FetchedPrompt.toolChoice` is never `null` — callers get the
168
+ * so a present `RenderedPrompt.toolChoice` is never `null` — callers get the
149
169
  * key or nothing, and never have to branch on `null`.
150
170
  */
151
171
  toolChoice?: NonNullable<ResolvedPrompt["toolChoice"]>;
152
172
  }
153
- export type ResolvedPromptEnvelope = GenResolvedPrompt & {
154
- /** Active release strategy. Used to decide weighted-no-subject cache bypass (D8). */
155
- strategy?: "single" | "weighted";
156
- };
157
- /**
158
- * How an authored `developer` block is rendered. The caller controls this
159
- * per-call because it knows the upstream it targets. Omitted ⇒ `"user"`
160
- * (back-compatible; safe for any upstream). `"developer"` preserves the role
161
- * (OpenAI); `"system"` folds it into a system message.
162
- */
163
- export type DeveloperRole = "user" | "developer" | "system";
164
- export interface FetchPromptOptions {
165
- env?: string;
166
- subject?: string;
173
+ export type ResolvedPromptEnvelope = GenResolvedPrompt;
174
+ export interface RenderOptions {
175
+ /**
176
+ * Label to resolve this call's prompt version; overrides the client default.
177
+ * When omitted, falls back to the client's `env` (env is a label value).
178
+ */
179
+ label?: string;
167
180
  variables?: Record<string, unknown>;
168
- cache?: boolean;
169
- fallback?: ResolvedPrompt | FetchedPrompt;
181
+ /** Prompt served if the API is unreachable on a network error. */
182
+ fallback?: RenderedPrompt;
183
+ /** Provider shape for this call's output; overrides the client default. */
184
+ format?: RenderFormat;
170
185
  /**
171
- * How authored `developer` blocks render. Default `"user"`. Forwarded on the
172
- * resolve request and folded into the cache key so two calls differing only
173
- * by `developerRole` never share a cached result.
186
+ * How to handle a message with an unrecognized role while shaping for a
187
+ * provider (`format` set). Overrides the client default; defaults to `"drop"`.
188
+ * Only meaningful with a `format` — the neutral result runs no converter.
174
189
  */
175
- developerRole?: DeveloperRole;
190
+ onUnknownRole?: UnknownRoleMode;
176
191
  }
177
192
  export type PaletteToken = ProjectPromptLabel["displayColor"];
178
193
  export type ProjectPromptLabel = GenProjectPromptLabel;
179
194
  export type ProjectPromptLabelUsage = GenProjectPromptLabelUsage;
180
195
  export type PromptLabelEvent = GenPromptLabelEvent;
181
196
  export interface ListProjectPromptLabelsInput {
182
- projectId: string;
197
+ projectId?: string;
183
198
  /** Set true to include archived (soft-deleted) entries. Default: false. */
184
199
  includeArchived?: boolean;
185
200
  }
186
201
  export type ListProjectPromptLabelsResult = ProjectPromptLabel[];
187
202
  export interface CreateProjectPromptLabelInput {
188
- projectId: string;
203
+ projectId?: string;
189
204
  label: string;
190
205
  isDefault?: boolean;
191
206
  description?: string;
@@ -193,12 +208,12 @@ export interface CreateProjectPromptLabelInput {
193
208
  }
194
209
  export type CreateProjectPromptLabelResult = ProjectPromptLabel;
195
210
  export interface GetProjectPromptLabelInput {
196
- projectId: string;
211
+ projectId?: string;
197
212
  label: string;
198
213
  }
199
214
  export type GetProjectPromptLabelResult = ProjectPromptLabel;
200
215
  export interface UpdateProjectPromptLabelInput {
201
- projectId: string;
216
+ projectId?: string;
202
217
  label: string;
203
218
  isDefault?: boolean;
204
219
  description?: string | null;
@@ -206,18 +221,18 @@ export interface UpdateProjectPromptLabelInput {
206
221
  }
207
222
  export type UpdateProjectPromptLabelResult = ProjectPromptLabel;
208
223
  export interface DeleteProjectPromptLabelInput {
209
- projectId: string;
224
+ projectId?: string;
210
225
  label: string;
211
226
  }
212
227
  export type DeleteProjectPromptLabelResult = ProjectPromptLabel;
213
228
  export interface ListProjectPromptLabelUsagesInput {
214
- projectId: string;
229
+ projectId?: string;
215
230
  label: string;
216
231
  }
217
232
  export type ListProjectPromptLabelUsagesResult = ProjectPromptLabelUsage[];
218
233
  export type ListLabelEventsInput = {
219
234
  scope: "label";
220
- projectId: string;
235
+ projectId?: string;
221
236
  promptId: string;
222
237
  label: string;
223
238
  page?: number;
@@ -226,7 +241,7 @@ export type ListLabelEventsInput = {
226
241
  until?: string;
227
242
  } | {
228
243
  scope: "prompt";
229
- projectId: string;
244
+ projectId?: string;
230
245
  promptId: string;
231
246
  label?: string;
232
247
  page?: number;
@@ -235,7 +250,7 @@ export type ListLabelEventsInput = {
235
250
  until?: string;
236
251
  } | {
237
252
  scope: "project";
238
- projectId: string;
253
+ projectId?: string;
239
254
  promptId?: string;
240
255
  label?: string;
241
256
  page?: number;