Skip to content

Commit 4f396c7

Browse files
committed
feat: add prompt management SDK methods (list, versions, resolve, override, promote) and test task
1 parent 7533941 commit 4f396c7

5 files changed

Lines changed: 349 additions & 0 deletions

File tree

packages/core/src/v3/apiClient/index.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,14 @@ import {
4444
RetrieveQueueParam,
4545
ResolvePromptRequestBody,
4646
ResolvePromptResponseBody,
47+
ListPromptsResponseBody,
48+
ListPromptVersionsResponseBody,
49+
PromotePromptVersionRequestBody,
50+
CreatePromptOverrideRequestBody,
51+
UpdatePromptOverrideRequestBody,
52+
ReactivatePromptOverrideRequestBody,
53+
PromptOkResponseBody,
54+
PromptOverrideCreatedResponseBody,
4755
RetrieveRunResponse,
4856
RetrieveRunTraceResponseBody,
4957
ScheduleObject,
@@ -1587,6 +1595,69 @@ export class ApiClient {
15871595
);
15881596
}
15891597

1598+
listPrompts(requestOptions?: ZodFetchOptions) {
1599+
return zodfetch(
1600+
ListPromptsResponseBody,
1601+
`${this.baseUrl}/api/v1/prompts`,
1602+
{ method: "GET", headers: this.#getHeaders(false) },
1603+
mergeRequestOptions(this.defaultRequestOptions, requestOptions)
1604+
);
1605+
}
1606+
1607+
listPromptVersions(slug: string, requestOptions?: ZodFetchOptions) {
1608+
return zodfetch(
1609+
ListPromptVersionsResponseBody,
1610+
`${this.baseUrl}/api/v1/prompts/${slug}/versions`,
1611+
{ method: "GET", headers: this.#getHeaders(false) },
1612+
mergeRequestOptions(this.defaultRequestOptions, requestOptions)
1613+
);
1614+
}
1615+
1616+
promotePromptVersion(slug: string, body: PromotePromptVersionRequestBody, requestOptions?: ZodFetchOptions) {
1617+
return zodfetch(
1618+
PromptOkResponseBody,
1619+
`${this.baseUrl}/api/v1/prompts/${slug}/promote`,
1620+
{ method: "POST", headers: this.#getHeaders(false), body: JSON.stringify(body) },
1621+
mergeRequestOptions(this.defaultRequestOptions, requestOptions)
1622+
);
1623+
}
1624+
1625+
createPromptOverride(slug: string, body: CreatePromptOverrideRequestBody, requestOptions?: ZodFetchOptions) {
1626+
return zodfetch(
1627+
PromptOverrideCreatedResponseBody,
1628+
`${this.baseUrl}/api/v1/prompts/${slug}/override`,
1629+
{ method: "POST", headers: this.#getHeaders(false), body: JSON.stringify(body) },
1630+
mergeRequestOptions(this.defaultRequestOptions, requestOptions)
1631+
);
1632+
}
1633+
1634+
updatePromptOverride(slug: string, body: UpdatePromptOverrideRequestBody, requestOptions?: ZodFetchOptions) {
1635+
return zodfetch(
1636+
PromptOkResponseBody,
1637+
`${this.baseUrl}/api/v1/prompts/${slug}/override`,
1638+
{ method: "PUT", headers: this.#getHeaders(false), body: JSON.stringify(body) },
1639+
mergeRequestOptions(this.defaultRequestOptions, requestOptions)
1640+
);
1641+
}
1642+
1643+
removePromptOverride(slug: string, requestOptions?: ZodFetchOptions) {
1644+
return zodfetch(
1645+
PromptOkResponseBody,
1646+
`${this.baseUrl}/api/v1/prompts/${slug}/override`,
1647+
{ method: "DELETE", headers: this.#getHeaders(false) },
1648+
mergeRequestOptions(this.defaultRequestOptions, requestOptions)
1649+
);
1650+
}
1651+
1652+
reactivatePromptOverride(slug: string, body: ReactivatePromptOverrideRequestBody, requestOptions?: ZodFetchOptions) {
1653+
return zodfetch(
1654+
PromptOkResponseBody,
1655+
`${this.baseUrl}/api/v1/prompts/${slug}/override/reactivate`,
1656+
{ method: "POST", headers: this.#getHeaders(false), body: JSON.stringify(body) },
1657+
mergeRequestOptions(this.defaultRequestOptions, requestOptions)
1658+
);
1659+
}
1660+
15901661
#getRealtimeHeaders() {
15911662
let headers: Record<string, string> = {
15921663
Authorization: `Bearer ${this.accessToken}`,

packages/core/src/v3/schemas/api.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1660,3 +1660,70 @@ export const ResolvePromptResponseBody = z.object({
16601660
}),
16611661
});
16621662
export type ResolvePromptResponseBody = z.infer<typeof ResolvePromptResponseBody>;
1663+
1664+
export const ListPromptsResponseBody = z.object({
1665+
data: z.array(
1666+
z.object({
1667+
slug: z.string(),
1668+
friendlyId: z.string(),
1669+
description: z.string().nullable(),
1670+
tags: z.array(z.string()),
1671+
defaultModel: z.string().nullable(),
1672+
currentVersion: z.number().nullable(),
1673+
hasOverride: z.boolean(),
1674+
updatedAt: z.string(),
1675+
})
1676+
),
1677+
});
1678+
export type ListPromptsResponseBody = z.infer<typeof ListPromptsResponseBody>;
1679+
1680+
export const ListPromptVersionsResponseBody = z.object({
1681+
data: z.array(
1682+
z.object({
1683+
id: z.string(),
1684+
version: z.number(),
1685+
labels: z.array(z.string()),
1686+
source: z.string(),
1687+
model: z.string().nullable(),
1688+
textContent: z.string().nullable(),
1689+
commitMessage: z.string().nullable(),
1690+
contentHash: z.string(),
1691+
createdAt: z.string(),
1692+
})
1693+
),
1694+
});
1695+
export type ListPromptVersionsResponseBody = z.infer<typeof ListPromptVersionsResponseBody>;
1696+
1697+
export const PromotePromptVersionRequestBody = z.object({
1698+
version: z.number().int().positive(),
1699+
});
1700+
export type PromotePromptVersionRequestBody = z.infer<typeof PromotePromptVersionRequestBody>;
1701+
1702+
export const CreatePromptOverrideRequestBody = z.object({
1703+
textContent: z.string(),
1704+
model: z.string().optional(),
1705+
commitMessage: z.string().optional(),
1706+
source: z.string().optional(),
1707+
});
1708+
export type CreatePromptOverrideRequestBody = z.infer<typeof CreatePromptOverrideRequestBody>;
1709+
1710+
export const UpdatePromptOverrideRequestBody = z.object({
1711+
textContent: z.string().optional(),
1712+
model: z.string().optional(),
1713+
commitMessage: z.string().optional(),
1714+
});
1715+
export type UpdatePromptOverrideRequestBody = z.infer<typeof UpdatePromptOverrideRequestBody>;
1716+
1717+
export const ReactivatePromptOverrideRequestBody = z.object({
1718+
version: z.number().int().positive(),
1719+
});
1720+
export type ReactivatePromptOverrideRequestBody = z.infer<typeof ReactivatePromptOverrideRequestBody>;
1721+
1722+
export const PromptOkResponseBody = z.object({ ok: z.boolean() });
1723+
export type PromptOkResponseBody = z.infer<typeof PromptOkResponseBody>;
1724+
1725+
export const PromptOverrideCreatedResponseBody = z.object({
1726+
ok: z.boolean(),
1727+
version: z.number(),
1728+
});
1729+
export type PromptOverrideCreatedResponseBody = z.infer<typeof PromptOverrideCreatedResponseBody>;
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import {
2+
apiClientManager,
3+
type ApiRequestOptions,
4+
type CreatePromptOverrideRequestBody,
5+
type ListPromptsResponseBody,
6+
type ListPromptVersionsResponseBody,
7+
type PromptOkResponseBody,
8+
type PromptOverrideCreatedResponseBody,
9+
type ResolvePromptResponseBody,
10+
type UpdatePromptOverrideRequestBody,
11+
} from "@trigger.dev/core/v3";
12+
import type { ResolvedPrompt } from "./prompt.js";
13+
14+
function makeToAISDKTelemetry(
15+
slug: string,
16+
promptId: string,
17+
version: number,
18+
labels: string[],
19+
model?: string,
20+
input?: string
21+
) {
22+
return function toAISDKTelemetry(additionalMetadata?: Record<string, string>) {
23+
return {
24+
experimental_telemetry: {
25+
isEnabled: true as const,
26+
metadata: {
27+
"prompt.slug": slug,
28+
"prompt.id": promptId,
29+
"prompt.version": String(version),
30+
"prompt.labels": labels.join(", "),
31+
...(model ? { "prompt.model": model } : {}),
32+
...(input ? { "prompt.input": input } : {}),
33+
...additionalMetadata,
34+
},
35+
},
36+
};
37+
};
38+
}
39+
40+
/**
41+
* Resolve a prompt by slug, calling the API to get the current version's
42+
* compiled text. Works both inside and outside of a task context — requires
43+
* an API client to be configured (via `configure()` or task runtime).
44+
*/
45+
export async function resolvePrompt(
46+
slug: string,
47+
variables?: Record<string, unknown>,
48+
options?: { label?: string; version?: number; requestOptions?: ApiRequestOptions }
49+
): Promise<ResolvedPrompt> {
50+
const apiClient = apiClientManager.clientOrThrow();
51+
const vars = variables ?? {};
52+
const response = await apiClient.resolvePrompt(slug, {
53+
variables: vars,
54+
label: options?.label,
55+
version: options?.version,
56+
});
57+
58+
const data = response.data;
59+
const inputJson = Object.keys(vars).length > 0 ? JSON.stringify(vars) : undefined;
60+
61+
return {
62+
promptId: data.promptId,
63+
version: data.version,
64+
labels: data.labels,
65+
text: data.text ?? "",
66+
model: data.model ?? undefined,
67+
config: (data.config as Record<string, unknown>) ?? undefined,
68+
toAISDKTelemetry: makeToAISDKTelemetry(
69+
data.slug,
70+
data.promptId,
71+
data.version,
72+
data.labels,
73+
data.model ?? undefined,
74+
inputJson
75+
),
76+
};
77+
}
78+
79+
/** List all prompts in the current environment. */
80+
export function listPrompts(
81+
requestOptions?: ApiRequestOptions
82+
): Promise<ListPromptsResponseBody> {
83+
const apiClient = apiClientManager.clientOrThrow();
84+
return apiClient.listPrompts(requestOptions);
85+
}
86+
87+
/** List all versions for a prompt. */
88+
export function listPromptVersions(
89+
slug: string,
90+
requestOptions?: ApiRequestOptions
91+
): Promise<ListPromptVersionsResponseBody> {
92+
const apiClient = apiClientManager.clientOrThrow();
93+
return apiClient.listPromptVersions(slug, requestOptions);
94+
}
95+
96+
/** Promote a code-deployed version to be the current version. */
97+
export async function promotePromptVersion(
98+
slug: string,
99+
version: number,
100+
requestOptions?: ApiRequestOptions
101+
): Promise<PromptOkResponseBody> {
102+
const apiClient = apiClientManager.clientOrThrow();
103+
return apiClient.promotePromptVersion(slug, { version }, requestOptions);
104+
}
105+
106+
/** Create an override — a dashboard/API edit that takes priority over the deployed version. */
107+
export async function createPromptOverride(
108+
slug: string,
109+
body: CreatePromptOverrideRequestBody,
110+
requestOptions?: ApiRequestOptions
111+
): Promise<PromptOverrideCreatedResponseBody> {
112+
const apiClient = apiClientManager.clientOrThrow();
113+
return apiClient.createPromptOverride(slug, body, requestOptions);
114+
}
115+
116+
/** Update the active override's content or model. */
117+
export async function updatePromptOverride(
118+
slug: string,
119+
body: UpdatePromptOverrideRequestBody,
120+
requestOptions?: ApiRequestOptions
121+
): Promise<PromptOkResponseBody> {
122+
const apiClient = apiClientManager.clientOrThrow();
123+
return apiClient.updatePromptOverride(slug, body, requestOptions);
124+
}
125+
126+
/** Remove the active override, reverting to the current deployed version. */
127+
export async function removePromptOverride(
128+
slug: string,
129+
requestOptions?: ApiRequestOptions
130+
): Promise<PromptOkResponseBody> {
131+
const apiClient = apiClientManager.clientOrThrow();
132+
return apiClient.removePromptOverride(slug, requestOptions);
133+
}
134+
135+
/** Reactivate a previously removed override version. */
136+
export async function reactivatePromptOverride(
137+
slug: string,
138+
version: number,
139+
requestOptions?: ApiRequestOptions
140+
): Promise<PromptOkResponseBody> {
141+
const apiClient = apiClientManager.clientOrThrow();
142+
return apiClient.reactivatePromptOverride(slug, { version }, requestOptions);
143+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,13 @@
11
export { definePrompt as define } from "./prompt.js";
22
export type { PromptHandle, PromptOptions, ResolvedPrompt } from "./prompt.js";
3+
4+
export {
5+
resolvePrompt as resolve,
6+
listPrompts as list,
7+
listPromptVersions as versions,
8+
promotePromptVersion as promote,
9+
createPromptOverride as createOverride,
10+
updatePromptOverride as updateOverride,
11+
removePromptOverride as removeOverride,
12+
reactivatePromptOverride as reactivateOverride,
13+
} from "./promptManagement.js";

references/hello-world/src/trigger/prompts.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,3 +282,60 @@ export const generateObjectWithPromptTask = task({
282282
return { contact: result.object };
283283
},
284284
});
285+
286+
// ─── Prompt management SDK methods ───────────────────────
287+
288+
export const testPromptManagement = task({
289+
id: "test-prompt-management",
290+
run: async () => {
291+
// List all prompts
292+
const allPrompts = await prompts.list();
293+
logger.info("Listed prompts", { count: allPrompts.data.length, slugs: allPrompts.data.map((p) => p.slug) });
294+
295+
if (allPrompts.data.length === 0) {
296+
return { success: false, reason: "No prompts found — deploy first" };
297+
}
298+
299+
const slug = allPrompts.data[0].slug;
300+
301+
// List versions
302+
const versions = await prompts.versions(slug);
303+
logger.info("Listed versions", { slug, count: versions.data.length });
304+
305+
// Resolve the prompt (standalone, not via PromptHandle)
306+
const resolved = await prompts.resolve(slug, { customerName: "SDK Test", plan: "Enterprise", issue: "Testing management API" });
307+
logger.info("Resolved prompt standalone", { version: resolved.version, textLength: resolved.text.length });
308+
309+
// Create an override
310+
const override = await prompts.createOverride(slug, {
311+
textContent: "Override from SDK test: Hello {{customerName}} on {{plan}}!",
312+
model: "gpt-4o-mini",
313+
commitMessage: "SDK test override",
314+
});
315+
logger.info("Created override", { version: override.version });
316+
317+
// Resolve again — should get the override
318+
const resolvedOverride = await prompts.resolve(slug, { customerName: "SDK Test", plan: "Enterprise", issue: "Testing override" });
319+
logger.info("Resolved with override", { version: resolvedOverride.version, text: resolvedOverride.text });
320+
321+
// Update the override
322+
await prompts.updateOverride(slug, {
323+
textContent: "Updated override: Hi {{customerName}} ({{plan}})!",
324+
commitMessage: "SDK test update",
325+
});
326+
logger.info("Updated override");
327+
328+
// Remove the override
329+
await prompts.removeOverride(slug);
330+
logger.info("Removed override");
331+
332+
// Promote the first version to current
333+
if (versions.data.length > 0) {
334+
const v = versions.data[versions.data.length - 1].version; // oldest version
335+
await prompts.promote(slug, v);
336+
logger.info("Promoted version", { version: v });
337+
}
338+
339+
return { success: true, slug, versionsCount: versions.data.length };
340+
},
341+
});

0 commit comments

Comments
 (0)