prompts.resolve()
Resolves the version of a prompt deployed in your key's environment and binds its variables. Performs no inference.
The first call fetches every prompt deployed in that environment, in one request; after that they are kept in memory and variables are filled in your process, so most calls make no request and your values are never sent.
client.prompts.resolve(
promptId: string,
options?: { vars?: Record<string, string>; signal?: AbortSignal },
): Promise<{ prompt: string; promptVersionId: string; version: string }>Parameters
| Name | Type | |
|---|---|---|
promptId | string | The prompt's id — not its name. Any version's page in the app shows it beside the prompt's name, as Prompt ID |
options.vars | Record<string, string> | Values for the {{variables}} in the body |
options.signal | AbortSignal | Stops this call waiting on a fetch |
Returns
| Field | Type | |
|---|---|---|
prompt | string | The ready-to-run text, as the version's benchmark ran it — see below |
promptVersionId | string | Id of the exact version resolved — worth logging beside the model's output |
version | string | Label of the version deployed in the key's environment, e.g. "v7" |
What prompt is
The text the version's benchmark gave its model, with your values:
- A classic prompt has the values written where its
{{placeholders}}are. - A BRAID graph comes with one sentence in front saying the flowchart is the procedure to follow, then the values listed in
<value>blocks, then the flowchart exactly as drawn. The values are not written into its labels: a value carrying]would close the label it landed in and change the graph.
Run it the way the benchmark did: prompt as the system message, your user's message as the user turn.
Which version you get
The one deployed in the key's environment. A key belongs to one environment of one project, and there is no way to ask it for another, so deploying a version is the single action that moves callers. A rollback is deploying the previous version again.
const { prompt, version } = await client.prompts.resolve(INTENT_CLASSIFIER_ID, {
vars,
});Letting a caller name a version would let any key reach drafts, and would make production's approval policy advisory. A prompt with nothing deployed in the key's environment fails with 404.
Caching
| Age of the cached environment | What resolve() does |
|---|---|
| Under 30 seconds | Answers from memory |
| 30 seconds to 5 minutes | Answers from memory at once, and fetches a fresh copy behind the call |
| Over 5 minutes | Waits for a fresh copy |
A refresh sends the ETag of what it holds, so an unchanged environment answers 304 with no body. A deploy therefore reaches an active caller within about 30 seconds. A prompt missing from the cache triggers one refresh before 404, so a prompt deployed a moment ago is found without waiting. Change the window with cache: { ttlMs } when constructing the client, or drop the cache immediately — say, from your own deploy hook:
client.prompts.invalidate();Realtime
Pass realtime: true and the client keeps a stream open to hear about deploys the moment they happen, refreshing the cache at once — within a few seconds — instead of when its TTL runs out:
const client = new EvalwrightClient({ apiKey, baseUrl, realtime: true });
process.on("SIGTERM", () => client.close());It is off by default because an open stream keeps a Node process alive: a long-running server wants it, a script or a serverless function does not. Call close() on shutdown. The stream is only a signal — every change triggers the same ETag-checked fetch — so if it drops, or the server has no realtime configured, the cache TTL keeps working underneath.
If a refresh is refused (401, 403) the cache is dropped: a revoked key stops being served. Its realtime stream is closed when the key is revoked, and the client logs a warning and stops listening. If it fails for any other reason — the network, a 5xx, a timeout — the last copy keeps serving, a warning is logged, and the next attempt waits another 30 seconds.
A request that gets no answer within 10 seconds fails with a TimeoutError; set timeoutMs on the client to change that.
The cache lives in the process. A serverless function that starts cold starts with it empty.
Parallel calls
Concurrent calls share one fetch, so batches are just Promise.all:
const resolved = await Promise.all(
customers.map((c) =>
client.prompts.resolve(WELCOME_EMAIL_ID, { vars: { name: c.name, plan: c.plan } }),
),
);Cancellation
Aborting stops that call waiting. A fetch it started keeps going for any other caller, and fills the cache when it lands.
const controller = new AbortController();
const promise = client.prompts.resolve(SLOW_PROMPT_ID, {
vars: {},
signal: controller.signal,
});
setTimeout(() => controller.abort(), 5_000);