anpord 0.1.2 → 0.1.4

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.
@@ -0,0 +1,93 @@
1
+ import { Schema } from "effect";
2
+ import "@effect/platform";
3
+ //#region ../schema/src/domain/errors.d.ts
4
+ declare const NotFound_base: Schema.TaggedErrorClass<NotFound, "NotFound", {
5
+ readonly _tag: Schema.tag<"NotFound">;
6
+ } & {
7
+ message: typeof Schema.String;
8
+ }>;
9
+ declare class NotFound extends NotFound_base {}
10
+ declare const Conflict_base: Schema.TaggedErrorClass<Conflict, "Conflict", {
11
+ readonly _tag: Schema.tag<"Conflict">;
12
+ } & {
13
+ message: typeof Schema.String;
14
+ }>;
15
+ declare class Conflict extends Conflict_base {}
16
+ declare const BadRequest_base: Schema.TaggedErrorClass<BadRequest, "BadRequest", {
17
+ readonly _tag: Schema.tag<"BadRequest">;
18
+ } & {
19
+ message: typeof Schema.String;
20
+ }>;
21
+ declare class BadRequest extends BadRequest_base {}
22
+ declare const Unauthorized_base: Schema.TaggedErrorClass<Unauthorized, "Unauthorized", {
23
+ readonly _tag: Schema.tag<"Unauthorized">;
24
+ } & {
25
+ message: typeof Schema.String;
26
+ }>;
27
+ declare class Unauthorized extends Unauthorized_base {}
28
+ declare const Forbidden_base: Schema.TaggedErrorClass<Forbidden, "Forbidden", {
29
+ readonly _tag: Schema.tag<"Forbidden">;
30
+ } & {
31
+ message: typeof Schema.String;
32
+ }>;
33
+ /** Distinct from Unauthorized: the caller is who they say they are, and the
34
+ * answer is still no. Signing in again cannot help, so the client must not
35
+ * treat this as an expired session. */
36
+ declare class Forbidden extends Forbidden_base {}
37
+ //#endregion
38
+ //#region ../schema/src/public/evals-api.d.ts
39
+ declare const PublicStartEvalRequest: Schema.Struct<{
40
+ cases: Schema.filter<Schema.Array$<Schema.refine<{
41
+ readonly name: string;
42
+ readonly setup?: string | null | undefined;
43
+ readonly source?: {
44
+ readonly kind: "empty";
45
+ } | {
46
+ readonly kind: "repo";
47
+ readonly ref: string | null;
48
+ readonly url: string;
49
+ } | {
50
+ readonly kind: "files";
51
+ readonly files: {
52
+ readonly [x: string]: string;
53
+ };
54
+ } | undefined;
55
+ readonly validator?: {
56
+ readonly name: string;
57
+ readonly source: string;
58
+ } | null | undefined;
59
+ readonly variables?: {
60
+ readonly [x: string]: string;
61
+ } | undefined;
62
+ readonly verify: string | null;
63
+ }, Schema.Struct<{
64
+ name: typeof Schema.String;
65
+ setup: Schema.optional<Schema.NullOr<typeof Schema.String>>;
66
+ source: Schema.optional<Schema.Union<[Schema.Struct<{
67
+ kind: Schema.Literal<["empty"]>;
68
+ }>, Schema.Struct<{
69
+ kind: Schema.Literal<["repo"]>;
70
+ ref: Schema.NullOr<typeof Schema.String>;
71
+ url: Schema.refine<string, typeof Schema.String>;
72
+ }>, Schema.Struct<{
73
+ files: Schema.Record$<typeof Schema.String, typeof Schema.String>;
74
+ kind: Schema.Literal<["files"]>;
75
+ }>]>>;
76
+ validator: Schema.optional<Schema.NullOr<Schema.Struct<{
77
+ name: Schema.filter<Schema.filter<typeof Schema.String>>;
78
+ source: Schema.filter<Schema.filter<typeof Schema.String>>;
79
+ }>>>;
80
+ variables: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.String>>;
81
+ verify: Schema.NullOr<typeof Schema.String>;
82
+ }>>>>;
83
+ prompt: typeof Schema.String;
84
+ tasks: Schema.filter<Schema.Array$<Schema.Struct<{
85
+ harness: Schema.Literal<["codex", "opencode", "pi", "fx", "claude", "gemini", "qwen", "cursor"]>;
86
+ model: Schema.filter<typeof Schema.String>;
87
+ provider: Schema.Literal<["daytona", "e2b", "upstash", "modal", "cloudflare", "vercel"]>;
88
+ }>>>;
89
+ trials: Schema.filter<typeof Schema.Int>;
90
+ }>;
91
+ type PublicStartEvalRequest = typeof PublicStartEvalRequest.Type;
92
+ //#endregion
93
+ export { NotFound as a, Forbidden as i, BadRequest as n, Unauthorized as o, Conflict as r, PublicStartEvalRequest as t };
package/dist/index.cjs CHANGED
@@ -1,8 +1,373 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_client = require("./client-Cno4LwRq.cjs");
3
- const require_errors = require("./errors-C0E5A8fN.cjs");
2
+ const require_client = require("./client-BCZEcfVE.cjs");
3
+ const require_errors = require("./errors-Boum34f5.cjs");
4
+ const require_source = require("./source-DvlGawEw.cjs");
4
5
  let _effect_platform = require("@effect/platform");
5
6
  let effect = require("effect");
7
+ //#region ../template/src/errors.ts
8
+ /**
9
+ * A template asked for something the caller did not supply.
10
+ *
11
+ * A plain `Error` rather than a tagged one: this package has no dependencies,
12
+ * and it is thrown across the published SDK boundary where callers reach for
13
+ * `instanceof`.
14
+ */
15
+ var MissingVariables = class extends Error {
16
+ missing;
17
+ constructor(missing) {
18
+ const names = missing.map((name) => `{{${name}}}`).join(", ");
19
+ super(`No value for ${names}. Pass them, or set onMissing to "keep" or "empty".`);
20
+ this.name = "MissingVariables";
21
+ this.missing = missing;
22
+ }
23
+ };
24
+ //#endregion
25
+ //#region ../template/src/render.ts
26
+ /** Null and undefined read as absent rather than as the strings "null" and
27
+ * "undefined", because that is what `{ name: user.name }` produces when the
28
+ * field is not there. */
29
+ const suppliedValue = (values, name) => {
30
+ const value = values[name];
31
+ return value === null || value === void 0 ? void 0 : String(value);
32
+ };
33
+ /**
34
+ * Fills `{{name}}` from a flat map.
35
+ *
36
+ * Dots and hyphens are part of the name rather than a path: `{{user.name}}`
37
+ * reads the key `"user.name"`. One rule beats two, and a caller who wants
38
+ * nesting writes the flat key themselves.
39
+ */
40
+ function render(template, values, options = {}) {
41
+ const onMissing = options.onMissing ?? "throw";
42
+ const missing = [];
43
+ const content = template.replace(require_errors.tokenMatcher(), (match, open, close, name) => {
44
+ if (open !== void 0) return "{{";
45
+ if (close !== void 0) return "}}";
46
+ if (name === void 0) return match;
47
+ const value = suppliedValue(values, name);
48
+ if (value !== void 0) return value;
49
+ if (!missing.includes(name)) missing.push(name);
50
+ return onMissing === "empty" ? "" : match;
51
+ });
52
+ if (onMissing === "throw" && missing.length > 0) throw new MissingVariables(missing);
53
+ return {
54
+ content,
55
+ missing
56
+ };
57
+ }
58
+ //#endregion
59
+ //#region src/client/cache/cache-key.ts
60
+ /** Structural rather than referential, so two identical selectors are one
61
+ * entry and one in-flight request rather than two. A plain object literal
62
+ * hashes by reference and every call would miss. */
63
+ const cacheKey = (selector) => effect.Data.struct({
64
+ channel: selector.channel,
65
+ id: selector.id,
66
+ includeVersions: selector.includeVersions,
67
+ version: selector.version
68
+ });
69
+ //#endregion
70
+ //#region src/client/cache/keys.ts
71
+ const NAMESPACE = "prompt";
72
+ /**
73
+ * Which version a selector asks for.
74
+ *
75
+ * Asking for no channel is its own selector rather than a named one: the
76
+ * organisation decides which channel answers, it can rename or drop that
77
+ * channel, and naming a guess here would key the answer under a channel the
78
+ * server never resolved.
79
+ */
80
+ const selectorSegment = (selector) => {
81
+ if (selector.version !== void 0) return `v:${selector.version}`;
82
+ return selector.channel === void 0 ? "default" : `c:${selector.channel}`;
83
+ };
84
+ /**
85
+ * What makes one cached answer different from another.
86
+ *
87
+ * `includeVersions` belongs here even though the server's key omits it: this
88
+ * cache holds the response rather than the resolution, and a response asked
89
+ * for without history has no `versions` to give to a caller who wanted it.
90
+ */
91
+ const promptKey = (selector) => [
92
+ NAMESPACE,
93
+ encodeURIComponent(selector.id),
94
+ selectorSegment(selector),
95
+ selector.includeVersions === true ? "full" : "bare"
96
+ ].join(":");
97
+ /** Every key for one prompt, so a write invalidates all of them. */
98
+ const promptPrefix = (id) => `${NAMESPACE}:${encodeURIComponent(id)}:`;
99
+ //#endregion
100
+ //#region src/client/cache/prompt-cache.ts
101
+ var PromptCache = class extends effect.Context.Tag("@anpord/sdk/PromptCache")() {};
102
+ const make$1 = (settings, fetch) => effect.Effect.gen(function* () {
103
+ const scope = yield* effect.Effect.scope;
104
+ const permits = yield* effect.Effect.makeSemaphore(settings.maxConcurrentRefresh);
105
+ const cache = yield* effect.Cache.makeWith({
106
+ capacity: settings.capacity,
107
+ lookup: (selector) => fetch(selector),
108
+ /** A failure is not an answer, so it is not kept: the next call tries
109
+ * again rather than waiting out a whole window on one bad response. */
110
+ timeToLive: (exit) => effect.Exit.isFailure(exit) ? effect.Duration.zero : effect.Duration.infinity
111
+ });
112
+ /** A pinned version cannot change, so only capacity ever evicts it. A
113
+ * channel can be repointed at any moment. */
114
+ const ttlFor = (selector) => selector.version === void 0 ? settings.ttlMs : Number.POSITIVE_INFINITY;
115
+ const ageOf = (key) => effect.Effect.gen(function* () {
116
+ const stats = yield* cache.entryStats(key);
117
+ if (effect.Option.isNone(stats)) return effect.Option.none();
118
+ const now = yield* effect.Clock.currentTimeMillis;
119
+ return effect.Option.some(Math.max(0, now - stats.value.loadedMillis));
120
+ });
121
+ /** Forked into the cache's own scope rather than as a daemon, so a client
122
+ * that is disposed takes its refreshes with it. A refresh that cannot get
123
+ * a permit is dropped: the next call will ask again. */
124
+ const revalidate = (key) => permits.withPermitsIfAvailable(1)(cache.refresh(key)).pipe(effect.Effect.catchAllCause(() => effect.Effect.void), effect.Effect.forkIn(scope), effect.Effect.asVoid);
125
+ const heldWithin = (selector, limitMs) => effect.Effect.gen(function* () {
126
+ const key = cacheKey(selector);
127
+ const ttl = ttlFor(key);
128
+ const value = yield* cache.getOptionComplete(key);
129
+ const age = yield* ageOf(key);
130
+ if (effect.Option.isNone(value) || effect.Option.isNone(age)) return effect.Option.none();
131
+ if (age.value > limitMs) return effect.Option.none();
132
+ if (age.value > ttl) yield* revalidate(key);
133
+ return effect.Option.some({
134
+ ageMs: age.value,
135
+ value: value.value
136
+ });
137
+ });
138
+ return {
139
+ held: (selector) => heldWithin(selector, settings.maxStaleMs),
140
+ invalidate: (id) => effect.Effect.gen(function* () {
141
+ const prefix = promptPrefix(id);
142
+ const keys = yield* cache.keys;
143
+ yield* effect.Effect.forEach(keys.filter((key) => promptKey(key).startsWith(prefix)), (key) => cache.invalidate(key), { discard: true });
144
+ }).pipe(effect.Effect.withSpan("PromptCache.invalidate")),
145
+ load: (selector) => effect.Effect.gen(function* () {
146
+ const key = cacheKey(selector);
147
+ const value = yield* fetch(selector);
148
+ yield* cache.set(key, value);
149
+ return value;
150
+ }).pipe(effect.Effect.withSpan("PromptCache.load", { attributes: { key: promptKey(selector) } })),
151
+ stale: (selector) => heldWithin(selector, Number.POSITIVE_INFINITY)
152
+ };
153
+ });
154
+ const layer$1 = (settings, fetch) => effect.Layer.scoped(PromptCache, make$1(settings, fetch));
155
+ //#endregion
156
+ //#region src/client/cache/noop.ts
157
+ /** Disabled caching is a cache that holds nothing, so the one path through
158
+ * `resolvePrompt` still runs rather than being wrapped in a condition. */
159
+ const noopLayer = (fetch) => effect.Layer.succeed(PromptCache, {
160
+ /** Effects rather than bare values: yielding an Option would make an empty
161
+ * one a failure, and every read would end in NoSuchElementException. */
162
+ held: () => effect.Effect.succeedNone,
163
+ invalidate: () => effect.Effect.void,
164
+ load: fetch,
165
+ stale: () => effect.Effect.succeedNone
166
+ });
167
+ //#endregion
168
+ //#region src/client/cache/failure.ts
169
+ /** A status the server chose deliberately, telling the caller something true
170
+ * about their request rather than about its own health. */
171
+ const DEFINITIVE = /* @__PURE__ */ new Set([
172
+ 400,
173
+ 401,
174
+ 403,
175
+ 404,
176
+ 409,
177
+ 422
178
+ ]);
179
+ /**
180
+ * Whether a failure means the answer is unavailable rather than no.
181
+ *
182
+ * A 404 is a successful reply carrying real information: this prompt does not
183
+ * exist. Covering it with a fallback turns a typo in a prompt id into a silent
184
+ * permanent substitution that ships and is found weeks later. Serving stale
185
+ * content covers the case where a prompt someone was using is removed, and it
186
+ * sits ahead of the fallback anyway.
187
+ *
188
+ * An unrecognised failure counts as unavailable: a transport error carries no
189
+ * status at all, and guessing the other way would turn a flaky network into an
190
+ * outage.
191
+ */
192
+ const isAvailabilityFailure = (error) => error.status === void 0 || !DEFINITIVE.has(error.status);
193
+ //#endregion
194
+ //#region src/client/cache/fallback.ts
195
+ /** No version the API can return is zero, so a caller who logs it knows
196
+ * without being told that they are reading a fallback rather than a prompt. */
197
+ const FALLBACK_VERSION = 0;
198
+ /**
199
+ * The shape of a prompt, built from what the caller had to hand.
200
+ *
201
+ * The branded fields are asserted rather than decoded: this value never came
202
+ * from the API and never goes back to it, and a fallback that could fail to
203
+ * parse would defeat the reason it exists.
204
+ */
205
+ const fallbackPrompt = (selector, fallback, now) => {
206
+ const given = typeof fallback === "string" ? { content: fallback } : fallback;
207
+ return {
208
+ channel: selector.channel ?? null,
209
+ config: given.config ?? {},
210
+ content: given.content,
211
+ createdAt: effect.DateTime.unsafeMake(now),
212
+ id: selector.id,
213
+ message: null,
214
+ name: selector.id,
215
+ version: FALLBACK_VERSION
216
+ };
217
+ };
218
+ //#endregion
219
+ //#region src/client/cache/resolve.ts
220
+ /**
221
+ * Which answer the caller gets, in the order the answers are worth having.
222
+ *
223
+ * Fresh cache first, because that is the whole point. Then the API, since it
224
+ * is the only source that can be right. Then whatever is held however old,
225
+ * because a prompt someone wrote and promoted beats a string written at deploy
226
+ * time. Then the fallback, which the caller asked for. Then the failure, since
227
+ * with nothing cached and no fallback there is no honest answer to give.
228
+ */
229
+ const resolvePrompt = (options) => effect.Effect.gen(function* () {
230
+ const cache = yield* PromptCache;
231
+ const key = promptKey(options);
232
+ const held = yield* cache.held(options);
233
+ if (effect.Option.isSome(held)) return {
234
+ metadata: {
235
+ ageMs: held.value.ageMs,
236
+ /** Where the answer came from, not how old it is. An entry read in
237
+ * the same millisecond it was stored is still an entry, and calling
238
+ * it fresh made a cache hit indistinguishable from a network read. */
239
+ freshness: "cached",
240
+ key
241
+ },
242
+ value: held.value.value
243
+ };
244
+ const loaded = yield* effect.Effect.either(cache.load(options));
245
+ if (loaded._tag === "Right") return {
246
+ metadata: {
247
+ ageMs: 0,
248
+ freshness: "fresh",
249
+ key
250
+ },
251
+ value: loaded.right
252
+ };
253
+ const error = require_errors.asAnpordError(loaded.left);
254
+ if (!isAvailabilityFailure(error)) return yield* effect.Effect.fail(error);
255
+ const remembered = yield* cache.stale(options);
256
+ if (effect.Option.isSome(remembered)) return {
257
+ metadata: {
258
+ ageMs: remembered.value.ageMs,
259
+ freshness: "stale",
260
+ key,
261
+ reason: error.message
262
+ },
263
+ value: remembered.value.value
264
+ };
265
+ if (options.fallback === void 0) return yield* effect.Effect.fail(error);
266
+ const now = yield* effect.Clock.currentTimeMillis;
267
+ return {
268
+ metadata: {
269
+ ageMs: 0,
270
+ freshness: "fallback",
271
+ key,
272
+ reason: error.message
273
+ },
274
+ value: fallbackPrompt(options, options.fallback, now)
275
+ };
276
+ }).pipe(effect.Effect.withSpan("Prompts.resolve", { attributes: { key: promptKey(options) } }));
277
+ //#endregion
278
+ //#region src/client/cache/settings.ts
279
+ /**
280
+ * How long a channel's answer is trusted without asking again.
281
+ *
282
+ * This is the delay between a promotion and callers seeing it, so it is short:
283
+ * the dashboard tells whoever promotes that callers receive the new version
284
+ * immediately, and a minute of drift makes that untrue exactly when someone is
285
+ * rolling back something bad. Serving stale while refreshing means the number
286
+ * costs no latency, only freshness.
287
+ */
288
+ const TTL_MS = 15e3;
289
+ /** Long enough to cover a deploy or an incident, short enough that a value
290
+ * this old is worth saying out loud. Only reached while the API answers; when
291
+ * it cannot be reached at all there is no bound, since a day-old real prompt
292
+ * beats no prompt. */
293
+ const MAX_STALE_MS = 864e5;
294
+ /** Least recently used past this. A thousand prompts is far more than one
295
+ * process serves and still bounds the memory a long-running server holds. */
296
+ const CAPACITY = 1e3;
297
+ /** A cold cache going stale at once must not fork a refresh per prompt. */
298
+ const MAX_CONCURRENT_REFRESH = 8;
299
+ const positive = (value, fallback) => value !== void 0 && Number.isFinite(value) && value > 0 ? value : fallback;
300
+ const settingsFrom = (options) => {
301
+ const given = typeof options === "object" ? options : {};
302
+ return {
303
+ capacity: positive(given.capacity, CAPACITY),
304
+ maxConcurrentRefresh: positive(given.maxConcurrentRefresh, MAX_CONCURRENT_REFRESH),
305
+ maxStaleMs: positive(given.maxStaleMs, MAX_STALE_MS),
306
+ ttlMs: positive(given.ttlMs, TTL_MS)
307
+ };
308
+ };
309
+ const cacheEnabled = (options) => options !== false;
310
+ //#endregion
311
+ //#region src/client/promised.ts
312
+ const promised = (group) => Object.fromEntries(Object.entries(group).map(([method, run]) => [method, async (request) => {
313
+ const exit = await effect.Effect.runPromiseExit(run({ payload: request ?? {} }));
314
+ if (effect.Exit.isSuccess(exit)) return exit.value;
315
+ throw require_errors.asAnpordError(effect.Cause.failureOption(exit.cause).pipe(effect.Option.getOrElse(() => effect.Cause.squash(exit.cause))));
316
+ }]));
317
+ //#endregion
318
+ //#region src/client/wait.ts
319
+ var EvalTimeout = class extends Error {
320
+ name = "EvalTimeout";
321
+ runId;
322
+ constructor(runId, elapsedMs) {
323
+ const elapsed = elapsedMs < 1e3 ? `${elapsedMs}ms` : `${Math.round(elapsedMs / 1e3)}s`;
324
+ super(`Eval ${runId} was still running after ${elapsed}. It was not cancelled — read it later with evals.get({ id: "${runId}" }).`);
325
+ this.runId = runId;
326
+ }
327
+ };
328
+ var EvalAborted = class extends Error {
329
+ name = "EvalAborted";
330
+ runId;
331
+ constructor(runId) {
332
+ super(`Waiting on eval ${runId} was aborted. The run was not cancelled — read it later with evals.get({ id: "${runId}" }).`);
333
+ this.runId = runId;
334
+ }
335
+ };
336
+ const DEFAULT_INTERVAL = 2e3;
337
+ const DEFAULT_MAX_INTERVAL = 1e4;
338
+ const DEFAULT_TIMEOUT = 36e5;
339
+ const nextInterval = (current, max) => Math.min(Math.round(current * 1.5), max);
340
+ const sleep = (ms, signal) => new Promise((resolve, reject) => {
341
+ const timer = setTimeout(() => {
342
+ signal?.removeEventListener("abort", onAbort);
343
+ resolve();
344
+ }, ms);
345
+ function onAbort() {
346
+ clearTimeout(timer);
347
+ reject(signal?.reason);
348
+ }
349
+ signal?.addEventListener("abort", onAbort, { once: true });
350
+ });
351
+ const waitForRun = async (get, id, options = {}) => {
352
+ const { maxIntervalMs = DEFAULT_MAX_INTERVAL, onProgress, pollIntervalMs = DEFAULT_INTERVAL, signal, timeoutMs = DEFAULT_TIMEOUT } = options;
353
+ const startedAt = Date.now();
354
+ let interval = pollIntervalMs;
355
+ for (;;) {
356
+ if (signal?.aborted) throw new EvalAborted(id);
357
+ const run = await get({ id });
358
+ onProgress?.(run);
359
+ if (run.status !== "running") return run;
360
+ const elapsed = Date.now() - startedAt;
361
+ if (elapsed >= timeoutMs) throw new EvalTimeout(id, elapsed);
362
+ try {
363
+ await sleep(Math.min(interval, timeoutMs - elapsed), signal);
364
+ } catch {
365
+ throw new EvalAborted(id);
366
+ }
367
+ interval = nextInterval(interval, maxIntervalMs);
368
+ }
369
+ };
370
+ //#endregion
6
371
  //#region src/client/anpord.ts
7
372
  const resolveApiKey = (provided) => {
8
373
  const apiKey = provided ?? globalThis.process?.env?.ANPORD_API_KEY;
@@ -10,26 +375,81 @@ const resolveApiKey = (provided) => {
10
375
  return apiKey;
11
376
  };
12
377
  var Anpord = class {
378
+ evals;
13
379
  prompts;
380
+ runtime;
14
381
  constructor(options = {}) {
15
382
  const apiKey = resolveApiKey(options.apiKey);
16
383
  const client = require_client.make({
17
384
  apiKey: effect.Redacted.make(apiKey),
18
385
  baseUrl: options.baseUrl ?? "https://api.anpord.com"
19
386
  }).pipe(effect.Effect.provide(_effect_platform.FetchHttpClient.layer), effect.Effect.runSync);
20
- this.prompts = promised(client.prompts);
387
+ const fetch = (selector) => client.prompts.get({ payload: selector });
388
+ this.runtime = effect.ManagedRuntime.make(cacheEnabled(options.cache) ? layer$1(settingsFrom(options.cache), fetch) : noopLayer(fetch));
389
+ const group = promised(client.prompts);
390
+ const evals = promised(client.evals);
391
+ this.evals = {
392
+ ...evals,
393
+ startAndWait: async (options) => {
394
+ const { maxIntervalMs, onProgress, pollIntervalMs, signal, timeoutMs, ...request } = options;
395
+ const { id } = await evals.start(request);
396
+ return await waitForRun(evals.get, id, {
397
+ maxIntervalMs,
398
+ onProgress,
399
+ pollIntervalMs,
400
+ signal,
401
+ timeoutMs
402
+ });
403
+ },
404
+ wait: ({ id, ...options }) => waitForRun(evals.get, id, options)
405
+ };
406
+ const forget = (id) => this.runtime.runPromise(effect.Effect.flatMap(PromptCache, (cache) => cache.invalidate(id))).catch(() => void 0);
407
+ this.prompts = {
408
+ ...group,
409
+ get: (request) => this.resolve(request),
410
+ promote: invalidating(group.promote, forget),
411
+ update: invalidating(group.update, forget)
412
+ };
413
+ }
414
+ dispose() {
415
+ return this.runtime.dispose();
416
+ }
417
+ [Symbol.asyncDispose]() {
418
+ return this.runtime.dispose();
419
+ }
420
+ async resolve(options) {
421
+ const exit = await this.runtime.runPromiseExit(resolvePrompt(options));
422
+ if (effect.Exit.isFailure(exit)) throw require_errors.asAnpordError(effect.Cause.failureOption(exit.cause).pipe(effect.Option.getOrElse(() => effect.Cause.squash(exit.cause))));
423
+ const prompt = exit.value.value;
424
+ const value = options.variables === void 0 ? { ...prompt } : {
425
+ ...prompt,
426
+ content: render(prompt.content, options.variables).content
427
+ };
428
+ return Object.defineProperty(value, "anpord", {
429
+ enumerable: false,
430
+ value: exit.value.metadata
431
+ });
21
432
  }
22
433
  };
23
- const promised = (group) => Object.fromEntries(Object.entries(group).map(([method, run]) => [method, async (request) => {
24
- const exit = await effect.Effect.runPromiseExit(run({ payload: request ?? {} }));
25
- if (effect.Exit.isSuccess(exit)) return exit.value;
26
- throw require_errors.asAnpordError(effect.Cause.failureOption(exit.cause).pipe(effect.Option.getOrElse(() => effect.Cause.squash(exit.cause))));
27
- }]));
434
+ const invalidating = (write, forget) => async (request) => {
435
+ const result = await write(request);
436
+ await forget(request.id);
437
+ return result;
438
+ };
439
+ //#endregion
440
+ //#region src/evals/define.ts
441
+ const defineEval = (definition) => definition;
28
442
  //#endregion
29
443
  exports.Anpord = Anpord;
30
444
  exports.AnpordApi = require_client.AnpordApi;
31
445
  exports.AnpordError = require_errors.AnpordError;
32
446
  exports.DEFAULT_BASE_URL = require_client.DEFAULT_BASE_URL;
447
+ exports.EvalAborted = EvalAborted;
448
+ exports.EvalTimeout = EvalTimeout;
33
449
  exports.MissingApiKey = require_errors.MissingApiKey;
450
+ exports.defineEval = defineEval;
451
+ exports.empty = require_source.empty;
452
+ exports.files = require_source.files;
34
453
  exports.layer = require_client.layer;
35
454
  exports.make = require_client.make;
455
+ exports.repo = require_source.repo;