@to11ai/sdk 0.1.1 → 0.2.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/behaviors/store.d.ts +62 -0
- package/dist/client.cjs +37 -4
- package/dist/client.d.ts +41 -2
- package/dist/client.js +45 -4
- package/dist/errors.cjs +90 -1
- package/dist/errors.d.ts +142 -0
- package/dist/errors.js +90 -1
- package/dist/gateway.cjs +12 -0
- package/dist/gateway.d.ts +26 -12
- package/dist/gateway.js +14 -0
- package/dist/generated/index.d.ts +1 -0
- package/dist/generated/types.gen.d.ts +22974 -0
- package/dist/generated/zod.gen.d.ts +13531 -0
- package/dist/projectEnvironments/resource.cjs +7 -2
- package/dist/projectEnvironments/resource.js +7 -2
- package/dist/projectEnvironments/types.d.ts +4 -75
- package/dist/prompts/cache.d.ts +24 -3
- package/dist/prompts/resource.cjs +101 -3
- package/dist/prompts/resource.d.ts +47 -3
- package/dist/prompts/resource.js +103 -5
- package/dist/prompts/types.d.ts +36 -177
- package/dist/routingRules/resource.cjs +9 -2
- package/dist/routingRules/resource.js +9 -2
- package/dist/routingRules/types.d.ts +12 -123
- package/dist/transport.d.ts +23 -0
- package/package.json +23 -12
- package/src/behaviors/store.ts +175 -0
- package/src/client.ts +115 -3
- package/src/errors.ts +261 -0
- package/src/gateway.ts +54 -12
- package/src/generated/index.ts +3 -0
- package/src/generated/types.gen.ts +24083 -0
- package/src/generated/zod.gen.ts +12648 -0
- package/src/projectEnvironments/resource.ts +10 -0
- package/src/projectEnvironments/types.ts +9 -91
- package/src/prompts/cache.ts +39 -4
- package/src/prompts/resource.ts +258 -5
- package/src/prompts/types.ts +56 -237
- package/src/routingRules/resource.ts +10 -1
- package/src/routingRules/types.ts +21 -155
- package/src/traceparent.ts +69 -4
- package/src/transport.ts +188 -3
|
@@ -42,6 +42,8 @@ __export(exports_resource, {
|
|
|
42
42
|
ProjectEnvironmentResource: () => ProjectEnvironmentResource
|
|
43
43
|
});
|
|
44
44
|
module.exports = __toCommonJS(exports_resource);
|
|
45
|
+
var import_zod = require("zod");
|
|
46
|
+
var import_zod2 = require("../generated/zod.gen");
|
|
45
47
|
function unwrap(envelope) {
|
|
46
48
|
if (envelope.data === null || envelope.data === undefined) {
|
|
47
49
|
throw new Error("API returned success but data is null");
|
|
@@ -62,12 +64,15 @@ class ProjectEnvironmentResource {
|
|
|
62
64
|
}
|
|
63
65
|
async list(input) {
|
|
64
66
|
const envelope = await this.transport.request("GET", projectEnvironmentsPath(input.projectId), {
|
|
65
|
-
query: input.includeArchived ? { includeArchived: "true" } : undefined
|
|
67
|
+
query: input.includeArchived ? { includeArchived: "true" } : undefined,
|
|
68
|
+
decode: (data) => import_zod.z.array(import_zod2.zProjectEnvironment).parse(data)
|
|
66
69
|
});
|
|
67
70
|
return unwrap(envelope);
|
|
68
71
|
}
|
|
69
72
|
async get(input) {
|
|
70
|
-
const envelope = await this.transport.request("GET", projectEnvironmentPath(input.projectId, input.slug)
|
|
73
|
+
const envelope = await this.transport.request("GET", projectEnvironmentPath(input.projectId, input.slug), {
|
|
74
|
+
decode: (data) => import_zod2.zProjectEnvironment.parse(data)
|
|
75
|
+
});
|
|
71
76
|
return unwrap(envelope);
|
|
72
77
|
}
|
|
73
78
|
async create(input) {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
// src/projectEnvironments/resource.ts
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { zProjectEnvironment } from "../generated/zod.gen";
|
|
2
4
|
function unwrap(envelope) {
|
|
3
5
|
if (envelope.data === null || envelope.data === undefined) {
|
|
4
6
|
throw new Error("API returned success but data is null");
|
|
@@ -19,12 +21,15 @@ class ProjectEnvironmentResource {
|
|
|
19
21
|
}
|
|
20
22
|
async list(input) {
|
|
21
23
|
const envelope = await this.transport.request("GET", projectEnvironmentsPath(input.projectId), {
|
|
22
|
-
query: input.includeArchived ? { includeArchived: "true" } : undefined
|
|
24
|
+
query: input.includeArchived ? { includeArchived: "true" } : undefined,
|
|
25
|
+
decode: (data) => z.array(zProjectEnvironment).parse(data)
|
|
23
26
|
});
|
|
24
27
|
return unwrap(envelope);
|
|
25
28
|
}
|
|
26
29
|
async get(input) {
|
|
27
|
-
const envelope = await this.transport.request("GET", projectEnvironmentPath(input.projectId, input.slug)
|
|
30
|
+
const envelope = await this.transport.request("GET", projectEnvironmentPath(input.projectId, input.slug), {
|
|
31
|
+
decode: (data) => zProjectEnvironment.parse(data)
|
|
32
|
+
});
|
|
28
33
|
return unwrap(envelope);
|
|
29
34
|
}
|
|
30
35
|
async create(input) {
|
|
@@ -1,62 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
* Notes:
|
|
6
|
-
* - `isSystem: true` for the seeded `prod` / `staging` rows. Those rows
|
|
7
|
-
* cannot be renamed, archived, or have their `slug`/`isSystem` mutated.
|
|
8
|
-
* - `isGatewayFallback: true` marks the env the gateway routes to when no
|
|
9
|
-
* `x-to11-env` header is supplied. At most one env per project may carry
|
|
10
|
-
* this flag; clearing the only fallback is rejected with 409
|
|
11
|
-
* `CANNOT_CLEAR_ONLY_GATEWAY_FALLBACK`.
|
|
12
|
-
* - `archivedAt` is `null` for live envs and an ISO-8601 timestamp for
|
|
13
|
-
* soft-archived ones.
|
|
14
|
-
*/
|
|
15
|
-
export interface ProjectEnvironment {
|
|
16
|
-
id: string;
|
|
17
|
-
projectId: string;
|
|
18
|
-
slug: string;
|
|
19
|
-
name: string;
|
|
20
|
-
color: string | null;
|
|
21
|
-
description: string | null;
|
|
22
|
-
isPointer: boolean;
|
|
23
|
-
requiresApproval: boolean;
|
|
24
|
-
isDefault: boolean;
|
|
25
|
-
isGatewayFallback: boolean;
|
|
26
|
-
sortOrder: number;
|
|
27
|
-
isSystem: boolean;
|
|
28
|
-
archivedAt: string | null;
|
|
29
|
-
createdBy: string;
|
|
30
|
-
updatedBy: string;
|
|
31
|
-
createdAt: string;
|
|
32
|
-
updatedAt: string;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Pointer-count payload attached to archive responses. `prompts` is real
|
|
36
|
-
* today; `rules` / `providers` are 0 in v1 (reserved for Wave 6+ specs to
|
|
37
|
-
* keep the response shape stable when those domains land).
|
|
38
|
-
*/
|
|
39
|
-
export interface LivePointerCounts {
|
|
40
|
-
prompts: number;
|
|
41
|
-
rules: number;
|
|
42
|
-
providers: number;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Response body for `POST /v1/projects/:projectId/environments/:slug/archive`.
|
|
46
|
-
* Carries the soft-archived environment plus the count of live pointers
|
|
47
|
-
* cascade-cleared by the archive operation (informational, for the
|
|
48
|
-
* confirmation modal in the web UI).
|
|
49
|
-
*/
|
|
50
|
-
export interface ArchiveProjectEnvironmentResult {
|
|
51
|
-
environment: ProjectEnvironment;
|
|
52
|
-
livePointerCounts: LivePointerCounts;
|
|
53
|
-
}
|
|
1
|
+
import type { ArchiveProjectEnvironmentResult as GenArchiveProjectEnvironmentResult, LivePointerCounts as GenLivePointerCounts, ProjectEnvironment as GenProjectEnvironment } from "../generated/types.gen";
|
|
2
|
+
export type ProjectEnvironment = GenProjectEnvironment;
|
|
3
|
+
export type LivePointerCounts = GenLivePointerCounts;
|
|
4
|
+
export type ArchiveProjectEnvironmentResult = GenArchiveProjectEnvironmentResult;
|
|
54
5
|
export interface ListProjectEnvironmentsInput {
|
|
55
6
|
projectId: string;
|
|
56
|
-
/**
|
|
57
|
-
* When `true`, the response includes archived envs (those with a
|
|
58
|
-
* non-null `archivedAt`). Default behavior excludes them.
|
|
59
|
-
*/
|
|
60
7
|
includeArchived?: boolean;
|
|
61
8
|
}
|
|
62
9
|
export type ListProjectEnvironmentsResult = ProjectEnvironment[];
|
|
@@ -65,15 +12,6 @@ export interface GetProjectEnvironmentInput {
|
|
|
65
12
|
slug: string;
|
|
66
13
|
}
|
|
67
14
|
export type GetProjectEnvironmentResult = ProjectEnvironment;
|
|
68
|
-
/**
|
|
69
|
-
* Create input — must specify a unique `slug` matching lowercase-kebab
|
|
70
|
-
* (a-z, 0-9, hyphen, 1..63 chars). Reserved system slugs (`prod`,
|
|
71
|
-
* `staging`) are rejected by the API with `ENVIRONMENT_SLUG_TAKEN`.
|
|
72
|
-
*
|
|
73
|
-
* Setting `isGatewayFallback: true` here additionally requires the
|
|
74
|
-
* `project:manage_default_environment` capability; the create use case
|
|
75
|
-
* atomically clears the flag on any other env in the same project.
|
|
76
|
-
*/
|
|
77
15
|
export interface CreateProjectEnvironmentInput {
|
|
78
16
|
projectId: string;
|
|
79
17
|
slug: string;
|
|
@@ -87,15 +25,6 @@ export interface CreateProjectEnvironmentInput {
|
|
|
87
25
|
sortOrder?: number;
|
|
88
26
|
}
|
|
89
27
|
export type CreateProjectEnvironmentResult = ProjectEnvironment;
|
|
90
|
-
/**
|
|
91
|
-
* PATCH input — every field is optional. `slug` rename triggers a 7-day
|
|
92
|
-
* alias row server-side. System envs (`isSystem: true`) reject `slug`,
|
|
93
|
-
* `isSystem`, and other immutable-field mutations with
|
|
94
|
-
* `SYSTEM_ENV_IMMUTABLE`.
|
|
95
|
-
*
|
|
96
|
-
* As with `create`, mutating `isGatewayFallback` requires the additional
|
|
97
|
-
* `project:manage_default_environment` capability.
|
|
98
|
-
*/
|
|
99
28
|
export interface UpdateProjectEnvironmentInput {
|
|
100
29
|
projectId: string;
|
|
101
30
|
slug: string;
|
package/dist/prompts/cache.d.ts
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
import type { ResolvedPrompt } from "./types";
|
|
1
|
+
import type { FetchedPrompt, PromptContext, ResolvedPrompt } from "./types";
|
|
2
2
|
export interface CacheConfig {
|
|
3
3
|
/** Time-to-live in seconds. Default: 300 (5 minutes) */
|
|
4
4
|
ttlSeconds?: number;
|
|
5
5
|
/** Maximum number of entries. Default: 100 */
|
|
6
6
|
maxEntries?: number;
|
|
7
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* The cache stores either a legacy `resolve()` result or an enriched
|
|
10
|
+
* `fetch()` result. Both are JSON-cloneable; the cache is shape-agnostic.
|
|
11
|
+
*/
|
|
12
|
+
export type CacheableResolved = ResolvedPrompt | FetchedPrompt;
|
|
8
13
|
/**
|
|
9
14
|
* Build a canonical cache key for a resolve() call.
|
|
10
15
|
*
|
|
@@ -18,6 +23,22 @@ export interface CacheConfig {
|
|
|
18
23
|
* values cannot cause key collisions (e.g. a slug containing "|" or ",").
|
|
19
24
|
*/
|
|
20
25
|
export declare function buildCacheKey(projectId: string, slug: string, labels: string[], variables?: Record<string, unknown>): string;
|
|
26
|
+
/**
|
|
27
|
+
* Build a cache key for an env-aware `fetch()` call.
|
|
28
|
+
*
|
|
29
|
+
* Folds in `env`, `context`, and `subject` ON TOP of the base
|
|
30
|
+
* project/slug/labels/variables key so two calls that differ only by
|
|
31
|
+
* env/context/subject do not return a stale cross-env / cross-cohort hit
|
|
32
|
+
* (spec §3 "Caching key changes"). The env slug is also forwarded as the
|
|
33
|
+
* single resolution label (env→label mapping, correction #3), so it appears
|
|
34
|
+
* in the `labels` segment too; including it explicitly here keeps the key
|
|
35
|
+
* unambiguous and self-documenting.
|
|
36
|
+
*
|
|
37
|
+
* `subject` participates in the key so a `subject`-keyed weighted assignment
|
|
38
|
+
* caches as the same deterministic variant on repeat (D8); the
|
|
39
|
+
* weighted-no-subject bypass is handled in the resource, not here.
|
|
40
|
+
*/
|
|
41
|
+
export declare function buildFetchCacheKey(projectId: string, slug: string, env: string, context?: PromptContext, subject?: string, variables?: Record<string, unknown>): string;
|
|
21
42
|
/**
|
|
22
43
|
* In-memory LRU cache for ResolvedPrompt objects.
|
|
23
44
|
*
|
|
@@ -30,8 +51,8 @@ export declare class PromptCache {
|
|
|
30
51
|
private readonly maxEntries;
|
|
31
52
|
private readonly store;
|
|
32
53
|
constructor(config?: CacheConfig);
|
|
33
|
-
get(key: string):
|
|
34
|
-
set(key: string, value:
|
|
54
|
+
get(key: string): CacheableResolved | undefined;
|
|
55
|
+
set(key: string, value: CacheableResolved): void;
|
|
35
56
|
delete(key: string): void;
|
|
36
57
|
clear(): void;
|
|
37
58
|
get size(): number;
|
|
@@ -42,8 +42,20 @@ __export(exports_resource, {
|
|
|
42
42
|
PromptResource: () => PromptResource
|
|
43
43
|
});
|
|
44
44
|
module.exports = __toCommonJS(exports_resource);
|
|
45
|
+
var import_zod = require("zod");
|
|
45
46
|
var import_errors = require("../errors");
|
|
47
|
+
var import_zod2 = require("../generated/zod.gen");
|
|
46
48
|
var import_cache = require("./cache");
|
|
49
|
+
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
|
+
});
|
|
58
|
+
var zResolvedPromptEnvelope = import_zod2.zResolvedPrompt.partial({ releaseId: true }).extend({ strategy: import_zod.z.enum(["single", "weighted"]).optional() });
|
|
47
59
|
function unwrap(envelope) {
|
|
48
60
|
if (envelope.data === null || envelope.data === undefined) {
|
|
49
61
|
throw new Error("API returned success but data is null");
|
|
@@ -53,6 +65,36 @@ function unwrap(envelope) {
|
|
|
53
65
|
function getProjectPromptsPath(projectId) {
|
|
54
66
|
return `/v1/projects/${encodeURIComponent(projectId)}/prompts`;
|
|
55
67
|
}
|
|
68
|
+
function renderedToMessages(rendered) {
|
|
69
|
+
if (rendered.format === "chat") {
|
|
70
|
+
return rendered.messages;
|
|
71
|
+
}
|
|
72
|
+
return [{ role: "user", content: rendered.text }];
|
|
73
|
+
}
|
|
74
|
+
function normalizeResolvedEnvelope(raw) {
|
|
75
|
+
const provenance = raw;
|
|
76
|
+
const result = {
|
|
77
|
+
messages: renderedToMessages(raw.rendered),
|
|
78
|
+
version: raw.version,
|
|
79
|
+
releaseId: provenance.releaseId ?? null,
|
|
80
|
+
blockRenderRecord: provenance.blockRenderRecord ?? {},
|
|
81
|
+
promptId: raw.promptId,
|
|
82
|
+
versionId: raw.versionId,
|
|
83
|
+
contentHash: raw.contentHash,
|
|
84
|
+
labels: raw.labels,
|
|
85
|
+
rendered: raw.rendered
|
|
86
|
+
};
|
|
87
|
+
if (typeof provenance.variantName === "string" && provenance.variantName.length > 0) {
|
|
88
|
+
result.variantName = provenance.variantName;
|
|
89
|
+
}
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
function liftFallbackToFetched(fallback) {
|
|
93
|
+
if ("messages" in fallback) {
|
|
94
|
+
return structuredClone(fallback);
|
|
95
|
+
}
|
|
96
|
+
return normalizeResolvedEnvelope(fallback);
|
|
97
|
+
}
|
|
56
98
|
function getProjectPromptPath(projectId, promptId) {
|
|
57
99
|
return `${getProjectPromptsPath(projectId)}/${encodeURIComponent(promptId)}`;
|
|
58
100
|
}
|
|
@@ -87,9 +129,13 @@ function buildLabelEventsQuery(input) {
|
|
|
87
129
|
class PromptResource {
|
|
88
130
|
transport;
|
|
89
131
|
cache;
|
|
90
|
-
|
|
132
|
+
projectId;
|
|
133
|
+
env;
|
|
134
|
+
constructor(transport, cacheConfig, config) {
|
|
91
135
|
this.transport = transport;
|
|
92
136
|
this.cache = new import_cache.PromptCache(cacheConfig);
|
|
137
|
+
this.projectId = config?.projectId;
|
|
138
|
+
this.env = config?.env;
|
|
93
139
|
}
|
|
94
140
|
async create(input) {
|
|
95
141
|
const { projectId, ...body } = input;
|
|
@@ -153,6 +199,57 @@ class PromptResource {
|
|
|
153
199
|
const envelope = await this.transport.request("GET", `${getProjectPromptPath(projectId, promptId)}/labels`);
|
|
154
200
|
return unwrap(envelope);
|
|
155
201
|
}
|
|
202
|
+
async fetch(slug, options = {}) {
|
|
203
|
+
if (this.projectId === undefined || this.projectId.trim() === "") {
|
|
204
|
+
throw new Error("[to11ai/sdk] `prompts.fetch()` requires a `projectId` on the client — pass it to createClient({ projectId, ... }).");
|
|
205
|
+
}
|
|
206
|
+
const env = options.env ?? this.env;
|
|
207
|
+
if (env === undefined) {
|
|
208
|
+
throw import_errors.EnvNotFoundError.missing();
|
|
209
|
+
}
|
|
210
|
+
if (!import_types.ENV_SLUG_REGEX.test(env)) {
|
|
211
|
+
throw new Error(`[to11ai/sdk] \`env\` must match ${import_types.ENV_SLUG_REGEX} (lowercase-kebab, 1-63 chars). Received: ${JSON.stringify(env)}`);
|
|
212
|
+
}
|
|
213
|
+
const {
|
|
214
|
+
context,
|
|
215
|
+
subject,
|
|
216
|
+
variables,
|
|
217
|
+
cache: useCache = true,
|
|
218
|
+
fallback
|
|
219
|
+
} = options;
|
|
220
|
+
const cacheKey = import_cache.buildFetchCacheKey(this.projectId, slug, env, context, subject, variables);
|
|
221
|
+
if (useCache) {
|
|
222
|
+
const cached = this.cache.get(cacheKey);
|
|
223
|
+
if (cached && "messages" in cached)
|
|
224
|
+
return structuredClone(cached);
|
|
225
|
+
}
|
|
226
|
+
const body = { slug, labels: [env] };
|
|
227
|
+
if (context !== undefined)
|
|
228
|
+
body.context = context;
|
|
229
|
+
if (subject !== undefined)
|
|
230
|
+
body.subject = subject;
|
|
231
|
+
if (variables !== undefined)
|
|
232
|
+
body.variables = variables;
|
|
233
|
+
try {
|
|
234
|
+
const envelope = await this.transport.request("POST", `${getProjectPromptsPath(this.projectId)}:resolve`, {
|
|
235
|
+
body,
|
|
236
|
+
decode: (data) => zResolvedPromptEnvelope.parse(data)
|
|
237
|
+
});
|
|
238
|
+
const raw = unwrap(envelope);
|
|
239
|
+
const result = normalizeResolvedEnvelope(raw);
|
|
240
|
+
const isWeighted = raw.strategy === "weighted" || result.variantName !== undefined;
|
|
241
|
+
const cacheable = !(isWeighted && subject === undefined);
|
|
242
|
+
if (useCache && cacheable) {
|
|
243
|
+
this.cache.set(cacheKey, structuredClone(result));
|
|
244
|
+
}
|
|
245
|
+
return result;
|
|
246
|
+
} catch (err) {
|
|
247
|
+
if (err instanceof import_errors.To11aiNetworkError && fallback !== undefined) {
|
|
248
|
+
return liftFallbackToFetched(fallback);
|
|
249
|
+
}
|
|
250
|
+
throw err;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
156
253
|
async resolve(input) {
|
|
157
254
|
const {
|
|
158
255
|
projectId,
|
|
@@ -165,12 +262,13 @@ class PromptResource {
|
|
|
165
262
|
const cacheKey = import_cache.buildCacheKey(projectId, slug, labels, variables);
|
|
166
263
|
if (useCache) {
|
|
167
264
|
const cached = this.cache.get(cacheKey);
|
|
168
|
-
if (cached)
|
|
265
|
+
if (cached && !("messages" in cached))
|
|
169
266
|
return structuredClone(cached);
|
|
170
267
|
}
|
|
171
268
|
try {
|
|
172
269
|
const envelope = await this.transport.request("POST", `${getProjectPromptsPath(projectId)}:resolve`, {
|
|
173
|
-
body: { slug, labels, variables }
|
|
270
|
+
body: { slug, labels, variables },
|
|
271
|
+
decode: (data) => zResolvedPromptLegacy.parse(data)
|
|
174
272
|
});
|
|
175
273
|
const result = unwrap(envelope);
|
|
176
274
|
if (useCache) {
|
|
@@ -1,12 +1,27 @@
|
|
|
1
1
|
import type { Transport } from "../transport";
|
|
2
2
|
import type { CacheConfig } from "./cache";
|
|
3
|
-
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, ResolvePromptInput, ResolvePromptResult, UpdateProjectPromptLabelInput, UpdateProjectPromptLabelResult, UpdatePromptInput, UpdatePromptResult } from "./types";
|
|
3
|
+
import type { ArchivePromptInput, ArchivePromptResult, CreateProjectPromptLabelInput, CreateProjectPromptLabelResult, CreatePromptInput, CreatePromptResult, CreatePromptVersionInput, CreatePromptVersionResult, DeleteProjectPromptLabelInput, DeleteProjectPromptLabelResult, FetchedPrompt, FetchPromptOptions, GetProjectPromptLabelInput, GetProjectPromptLabelResult, GetPromptInput, GetPromptResult, GetPromptVersionInput, GetPromptVersionResult, ListLabelEventsInput, ListLabelEventsResult, ListProjectPromptLabelsInput, ListProjectPromptLabelsResult, ListProjectPromptLabelUsagesInput, ListProjectPromptLabelUsagesResult, ListPromptLabelsInput, ListPromptLabelsResult, ListPromptsInput, ListPromptsResult, ListPromptVersionsInput, ListPromptVersionsResult, MovePromptLabelInput, MovePromptLabelResult, PaginatedResult, ResolvePromptInput, ResolvePromptResult, UpdateProjectPromptLabelInput, UpdateProjectPromptLabelResult, UpdatePromptInput, UpdatePromptResult } from "./types";
|
|
4
4
|
export type { CacheConfig } from "./cache";
|
|
5
|
-
export type { ArchivePromptInput, ArchivePromptResult, 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, ResolvedPrompt, ResolvePromptInput, ResolvePromptResult, RowError, TextChatMessage, TextChatRole, ToolChatMessage, UpdateProjectPromptLabelInput, UpdateProjectPromptLabelResult, UpdatePromptInput, UpdatePromptResult, } from "./types";
|
|
5
|
+
export type { ArchivePromptInput, ArchivePromptResult, BlockRenderRecord, ChatMessage, CreateProjectPromptLabelInput, CreateProjectPromptLabelResult, CreatePromptInput, CreatePromptResult, CreatePromptVersionInput, CreatePromptVersionResult, DeleteProjectPromptLabelInput, DeleteProjectPromptLabelResult, FetchedPrompt, FetchPromptOptions, 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, PromptContext, PromptFormat, PromptLabelEvent, PromptLabelPointer, PromptStatus, PromptVersion, RenderedChatMessage, RenderedPrompt, ResolvedPrompt, ResolvedPromptEnvelope, ResolvePromptInput, ResolvePromptResult, RowError, TextChatMessage, TextChatRole, ToolChatMessage, UpdateProjectPromptLabelInput, UpdateProjectPromptLabelResult, UpdatePromptInput, UpdatePromptResult, } from "./types";
|
|
6
|
+
/**
|
|
7
|
+
* Init-time config for the env-aware `fetch()` surface (TO11-980 / S9).
|
|
8
|
+
*
|
|
9
|
+
* `projectId` and `env` come from `createClient`. `projectId` is required for
|
|
10
|
+
* `fetch()` (it builds the project-scoped resolve path); `env` is the default
|
|
11
|
+
* serving environment inherited by every `fetch(slug)` call.
|
|
12
|
+
*/
|
|
13
|
+
export interface PromptResourceConfig {
|
|
14
|
+
/** Project the client is bound to. Required for `fetch()`; validated at createClient. */
|
|
15
|
+
projectId?: string;
|
|
16
|
+
/** Default serving env for `fetch()`. Validated against ENV_SLUG_REGEX at createClient. */
|
|
17
|
+
env?: string;
|
|
18
|
+
}
|
|
6
19
|
export declare class PromptResource {
|
|
7
20
|
private readonly transport;
|
|
8
21
|
private readonly cache;
|
|
9
|
-
|
|
22
|
+
private readonly projectId;
|
|
23
|
+
private readonly env;
|
|
24
|
+
constructor(transport: Transport, cacheConfig?: CacheConfig, config?: PromptResourceConfig);
|
|
10
25
|
create(input: CreatePromptInput): Promise<CreatePromptResult>;
|
|
11
26
|
list(input: ListPromptsInput): Promise<PaginatedResult<ListPromptsResult>>;
|
|
12
27
|
get(input: GetPromptInput): Promise<GetPromptResult>;
|
|
@@ -17,6 +32,35 @@ export declare class PromptResource {
|
|
|
17
32
|
getVersion(input: GetPromptVersionInput): Promise<GetPromptVersionResult>;
|
|
18
33
|
moveLabel(input: MovePromptLabelInput): Promise<MovePromptLabelResult>;
|
|
19
34
|
listLabels(input: ListPromptLabelsInput): Promise<ListPromptLabelsResult>;
|
|
35
|
+
/**
|
|
36
|
+
* Resolve a prompt for the client's configured `projectId` + `env`
|
|
37
|
+
* (Style-A). The ergonomic slug-first surface: env is configured once at
|
|
38
|
+
* `createClient` and inherited here, with an optional per-call override.
|
|
39
|
+
*
|
|
40
|
+
* - **env→label wire mapping (correction #3):** the resolve route is
|
|
41
|
+
* label-based (`/v1/projects/:projectId/prompts:resolve`, body
|
|
42
|
+
* `labels[]`); it does NOT accept a top-level `env` field. The resolved
|
|
43
|
+
* env slug (lowercase-kebab — a valid label name) is therefore sent as
|
|
44
|
+
* the single resolution label: body `{ slug, labels: [env], context?,
|
|
45
|
+
* subject?, variables? }`.
|
|
46
|
+
* - **No silent fallback (R4):** if no env is resolvable (none at init AND
|
|
47
|
+
* none per call) this throws `EnvNotFoundError` (`reason.source =
|
|
48
|
+
* "missing"`) CLIENT-side, eagerly, before any transport call.
|
|
49
|
+
* - **Cache (D8):** caches `single`-strategy releases and weighted releases
|
|
50
|
+
* WITH a `subject`; BYPASSES the cache for weighted releases with NO
|
|
51
|
+
* `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` / `context` /
|
|
59
|
+
* `subject`, 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
|
+
*/
|
|
20
64
|
resolve(input: ResolvePromptInput): Promise<ResolvePromptResult>;
|
|
21
65
|
/**
|
|
22
66
|
* List the project-level label registry.
|
package/dist/prompts/resource.js
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
// src/prompts/resource.ts
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { EnvNotFoundError, To11aiNetworkError } from "../errors";
|
|
4
|
+
import { zResolvedPrompt } from "../generated/zod.gen";
|
|
5
|
+
import { buildCacheKey, buildFetchCacheKey, PromptCache } from "./cache";
|
|
6
|
+
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
|
+
});
|
|
15
|
+
var zResolvedPromptEnvelope = zResolvedPrompt.partial({ releaseId: true }).extend({ strategy: z.enum(["single", "weighted"]).optional() });
|
|
4
16
|
function unwrap(envelope) {
|
|
5
17
|
if (envelope.data === null || envelope.data === undefined) {
|
|
6
18
|
throw new Error("API returned success but data is null");
|
|
@@ -10,6 +22,36 @@ function unwrap(envelope) {
|
|
|
10
22
|
function getProjectPromptsPath(projectId) {
|
|
11
23
|
return `/v1/projects/${encodeURIComponent(projectId)}/prompts`;
|
|
12
24
|
}
|
|
25
|
+
function renderedToMessages(rendered) {
|
|
26
|
+
if (rendered.format === "chat") {
|
|
27
|
+
return rendered.messages;
|
|
28
|
+
}
|
|
29
|
+
return [{ role: "user", content: rendered.text }];
|
|
30
|
+
}
|
|
31
|
+
function normalizeResolvedEnvelope(raw) {
|
|
32
|
+
const provenance = raw;
|
|
33
|
+
const result = {
|
|
34
|
+
messages: renderedToMessages(raw.rendered),
|
|
35
|
+
version: raw.version,
|
|
36
|
+
releaseId: provenance.releaseId ?? null,
|
|
37
|
+
blockRenderRecord: provenance.blockRenderRecord ?? {},
|
|
38
|
+
promptId: raw.promptId,
|
|
39
|
+
versionId: raw.versionId,
|
|
40
|
+
contentHash: raw.contentHash,
|
|
41
|
+
labels: raw.labels,
|
|
42
|
+
rendered: raw.rendered
|
|
43
|
+
};
|
|
44
|
+
if (typeof provenance.variantName === "string" && provenance.variantName.length > 0) {
|
|
45
|
+
result.variantName = provenance.variantName;
|
|
46
|
+
}
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
function liftFallbackToFetched(fallback) {
|
|
50
|
+
if ("messages" in fallback) {
|
|
51
|
+
return structuredClone(fallback);
|
|
52
|
+
}
|
|
53
|
+
return normalizeResolvedEnvelope(fallback);
|
|
54
|
+
}
|
|
13
55
|
function getProjectPromptPath(projectId, promptId) {
|
|
14
56
|
return `${getProjectPromptsPath(projectId)}/${encodeURIComponent(promptId)}`;
|
|
15
57
|
}
|
|
@@ -44,9 +86,13 @@ function buildLabelEventsQuery(input) {
|
|
|
44
86
|
class PromptResource {
|
|
45
87
|
transport;
|
|
46
88
|
cache;
|
|
47
|
-
|
|
89
|
+
projectId;
|
|
90
|
+
env;
|
|
91
|
+
constructor(transport, cacheConfig, config) {
|
|
48
92
|
this.transport = transport;
|
|
49
93
|
this.cache = new PromptCache(cacheConfig);
|
|
94
|
+
this.projectId = config?.projectId;
|
|
95
|
+
this.env = config?.env;
|
|
50
96
|
}
|
|
51
97
|
async create(input) {
|
|
52
98
|
const { projectId, ...body } = input;
|
|
@@ -110,6 +156,57 @@ class PromptResource {
|
|
|
110
156
|
const envelope = await this.transport.request("GET", `${getProjectPromptPath(projectId, promptId)}/labels`);
|
|
111
157
|
return unwrap(envelope);
|
|
112
158
|
}
|
|
159
|
+
async fetch(slug, options = {}) {
|
|
160
|
+
if (this.projectId === undefined || this.projectId.trim() === "") {
|
|
161
|
+
throw new Error("[to11ai/sdk] `prompts.fetch()` requires a `projectId` on the client — pass it to createClient({ projectId, ... }).");
|
|
162
|
+
}
|
|
163
|
+
const env = options.env ?? this.env;
|
|
164
|
+
if (env === undefined) {
|
|
165
|
+
throw EnvNotFoundError.missing();
|
|
166
|
+
}
|
|
167
|
+
if (!ENV_SLUG_REGEX.test(env)) {
|
|
168
|
+
throw new Error(`[to11ai/sdk] \`env\` must match ${ENV_SLUG_REGEX} (lowercase-kebab, 1-63 chars). Received: ${JSON.stringify(env)}`);
|
|
169
|
+
}
|
|
170
|
+
const {
|
|
171
|
+
context,
|
|
172
|
+
subject,
|
|
173
|
+
variables,
|
|
174
|
+
cache: useCache = true,
|
|
175
|
+
fallback
|
|
176
|
+
} = options;
|
|
177
|
+
const cacheKey = buildFetchCacheKey(this.projectId, slug, env, context, subject, variables);
|
|
178
|
+
if (useCache) {
|
|
179
|
+
const cached = this.cache.get(cacheKey);
|
|
180
|
+
if (cached && "messages" in cached)
|
|
181
|
+
return structuredClone(cached);
|
|
182
|
+
}
|
|
183
|
+
const body = { slug, labels: [env] };
|
|
184
|
+
if (context !== undefined)
|
|
185
|
+
body.context = context;
|
|
186
|
+
if (subject !== undefined)
|
|
187
|
+
body.subject = subject;
|
|
188
|
+
if (variables !== undefined)
|
|
189
|
+
body.variables = variables;
|
|
190
|
+
try {
|
|
191
|
+
const envelope = await this.transport.request("POST", `${getProjectPromptsPath(this.projectId)}:resolve`, {
|
|
192
|
+
body,
|
|
193
|
+
decode: (data) => zResolvedPromptEnvelope.parse(data)
|
|
194
|
+
});
|
|
195
|
+
const raw = unwrap(envelope);
|
|
196
|
+
const result = normalizeResolvedEnvelope(raw);
|
|
197
|
+
const isWeighted = raw.strategy === "weighted" || result.variantName !== undefined;
|
|
198
|
+
const cacheable = !(isWeighted && subject === undefined);
|
|
199
|
+
if (useCache && cacheable) {
|
|
200
|
+
this.cache.set(cacheKey, structuredClone(result));
|
|
201
|
+
}
|
|
202
|
+
return result;
|
|
203
|
+
} catch (err) {
|
|
204
|
+
if (err instanceof To11aiNetworkError && fallback !== undefined) {
|
|
205
|
+
return liftFallbackToFetched(fallback);
|
|
206
|
+
}
|
|
207
|
+
throw err;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
113
210
|
async resolve(input) {
|
|
114
211
|
const {
|
|
115
212
|
projectId,
|
|
@@ -122,12 +219,13 @@ class PromptResource {
|
|
|
122
219
|
const cacheKey = buildCacheKey(projectId, slug, labels, variables);
|
|
123
220
|
if (useCache) {
|
|
124
221
|
const cached = this.cache.get(cacheKey);
|
|
125
|
-
if (cached)
|
|
222
|
+
if (cached && !("messages" in cached))
|
|
126
223
|
return structuredClone(cached);
|
|
127
224
|
}
|
|
128
225
|
try {
|
|
129
226
|
const envelope = await this.transport.request("POST", `${getProjectPromptsPath(projectId)}:resolve`, {
|
|
130
|
-
body: { slug, labels, variables }
|
|
227
|
+
body: { slug, labels, variables },
|
|
228
|
+
decode: (data) => zResolvedPromptLegacy.parse(data)
|
|
131
229
|
});
|
|
132
230
|
const result = unwrap(envelope);
|
|
133
231
|
if (useCache) {
|