evalution 1.0.2 → 1.0.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.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as MemoryTraceProvider, c as PROMPT_PROVIDER_ID_ATTRIBUTE, d as isEditable, i as setupStepCommand, l as SPAN_KIND_ATTRIBUTE, n as findPackageDts, o as PROMPT_ID_ATTRIBUTE, s as PROMPT_NAME_ATTRIBUTE, t as VercelAISDK, u as createTracerForPrompt } from "./vercel-ai-sdk-CareWPDM.js";
1
+ import { a as MemoryTraceProvider, c as PROMPT_NAME_ATTRIBUTE, d as createTracerForPrompt, f as getPromptSpanAttributes, l as PROMPT_PROVIDER_ID_ATTRIBUTE, n as findPackageDts, o as PROMPT_ID_ATTRIBUTE, p as isEditable, s as PROMPT_INPUTS_ATTRIBUTE, t as VercelAISDK, u as SPAN_KIND_ATTRIBUTE } from "./vercel-ai-sdk-B8ivuOzP.js";
2
2
  import fs, { glob } from "node:fs/promises";
3
3
  import path from "node:path";
4
4
  import { pathToFileURL } from "node:url";
@@ -8,13 +8,79 @@ import ts from "typescript";
8
8
  import chokidar from "chokidar";
9
9
  import { makeRe, minimatch } from "minimatch";
10
10
  import { GoogleGenAI } from "@google/genai";
11
- //#region src/file-provider.ts
11
+ //#region src/file-provider-local.ts
12
+ /**
13
+ * A {@link FileProvider} backed by the local file system.
14
+ *
15
+ * Uses `fs/promises` for I/O, `fs/promises.glob` (Node.js ≥ 22) for pattern
16
+ * matching, and [chokidar](https://github.com/paulmillr/chokidar) for file
17
+ * watching.
18
+ *
19
+ * This is the default implementation used by {@link FilePromptProvider} and
20
+ * {@link TSPromptFileType} when no custom provider is supplied.
21
+ */
22
+ var LocalFileProvider = class {
23
+ async readFile(filePath) {
24
+ return fs.readFile(filePath, "utf-8");
25
+ }
26
+ async writeFile(filePath, content) {
27
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
28
+ await fs.writeFile(filePath, content, "utf-8");
29
+ }
30
+ async deleteFile(filePath) {
31
+ await fs.unlink(filePath);
32
+ }
33
+ async import(filePath) {
34
+ return import(pathToFileURL(filePath).href);
35
+ }
36
+ async *glob(pattern, options = {}) {
37
+ const { cwd, ignore = [], absolute = false } = options;
38
+ const baseCwd = cwd ?? process.cwd();
39
+ for await (const file of glob(pattern, { cwd: baseCwd })) {
40
+ const relativePath = file.replace(/\\/g, "/");
41
+ if (ignore.some((p) => minimatch(relativePath, p))) continue;
42
+ yield absolute ? path.resolve(baseCwd, file) : file;
43
+ }
44
+ }
45
+ watch(patterns, options, callback) {
46
+ const cwd = options.cwd ?? process.cwd();
47
+ const ignored = options.ignored ?? [];
48
+ const includeMatchers = patterns.map((p) => makeRe(p)).filter((re) => re !== false);
49
+ const matches = (fp) => includeMatchers.some((re) => re.test(fp));
50
+ const watcher = chokidar.watch(".", {
51
+ cwd,
52
+ ignored: (absPath) => {
53
+ const rel = path.relative(cwd, absPath).replace(/\\/g, "/");
54
+ return ignored.some((p) => minimatch(rel, p, { dot: true }));
55
+ },
56
+ persistent: true,
57
+ ignoreInitial: options.ignoreInitial ?? true
58
+ });
59
+ watcher.on("change", (fp) => {
60
+ if (matches(fp)) callback("change", fp);
61
+ });
62
+ watcher.on("add", (fp) => {
63
+ if (matches(fp)) callback("add", fp);
64
+ });
65
+ watcher.on("unlink", (fp) => {
66
+ if (matches(fp)) callback("remove", fp);
67
+ });
68
+ return () => {
69
+ watcher.close();
70
+ };
71
+ }
72
+ };
73
+ //#endregion
74
+ //#region src/file-provider-memory.ts
12
75
  /**
13
76
  * An in-memory {@link FileProvider} backed by a `Map<string, string>`.
14
77
  *
15
- * Intended for unit tests all file I/O stays in-process with no disk access.
16
- * Calling {@link writeFile} triggers any active {@link watch} callbacks
17
- * synchronously, making it easy to test reactive code paths.
78
+ * Intended for unit tests and non-local environments (e.g. a browser or
79
+ * service-worker bundle) all file I/O stays in-process with no disk access.
80
+ * It depends only on `node:path` and `minimatch`, so it carries no Node-only
81
+ * runtime dependencies (no `node:fs`, `chokidar`, etc.). Calling
82
+ * {@link writeFile} triggers any active {@link watch} callbacks synchronously,
83
+ * making it easy to test reactive code paths.
18
84
  *
19
85
  * @example
20
86
  * ```ts
@@ -85,67 +151,6 @@ var MemoryFileProvider = class {
85
151
  }
86
152
  }
87
153
  };
88
- /**
89
- * A {@link FileProvider} backed by the local file system.
90
- *
91
- * Uses `fs/promises` for I/O, `fs/promises.glob` (Node.js ≥ 22) for pattern
92
- * matching, and [chokidar](https://github.com/paulmillr/chokidar) for file
93
- * watching.
94
- *
95
- * This is the default implementation used by {@link FilePromptProvider} and
96
- * {@link TSPromptFileType} when no custom provider is supplied.
97
- */
98
- var LocalFileProvider = class {
99
- async readFile(filePath) {
100
- return fs.readFile(filePath, "utf-8");
101
- }
102
- async writeFile(filePath, content) {
103
- await fs.mkdir(path.dirname(filePath), { recursive: true });
104
- await fs.writeFile(filePath, content, "utf-8");
105
- }
106
- async deleteFile(filePath) {
107
- await fs.unlink(filePath);
108
- }
109
- async import(filePath) {
110
- return import(pathToFileURL(filePath).href);
111
- }
112
- async *glob(pattern, options = {}) {
113
- const { cwd, ignore = [], absolute = false } = options;
114
- const baseCwd = cwd ?? process.cwd();
115
- for await (const file of glob(pattern, { cwd: baseCwd })) {
116
- const relativePath = file.replace(/\\/g, "/");
117
- if (ignore.some((p) => minimatch(relativePath, p))) continue;
118
- yield absolute ? path.resolve(baseCwd, file) : file;
119
- }
120
- }
121
- watch(patterns, options, callback) {
122
- const cwd = options.cwd ?? process.cwd();
123
- const ignored = options.ignored ?? [];
124
- const includeMatchers = patterns.map((p) => makeRe(p)).filter((re) => re !== false);
125
- const matches = (fp) => includeMatchers.some((re) => re.test(fp));
126
- const watcher = chokidar.watch(".", {
127
- cwd,
128
- ignored: (absPath) => {
129
- const rel = path.relative(cwd, absPath).replace(/\\/g, "/");
130
- return ignored.some((p) => minimatch(rel, p, { dot: true }));
131
- },
132
- persistent: true,
133
- ignoreInitial: options.ignoreInitial ?? true
134
- });
135
- watcher.on("change", (fp) => {
136
- if (matches(fp)) callback("change", fp);
137
- });
138
- watcher.on("add", (fp) => {
139
- if (matches(fp)) callback("add", fp);
140
- });
141
- watcher.on("unlink", (fp) => {
142
- if (matches(fp)) callback("remove", fp);
143
- });
144
- return () => {
145
- watcher.close();
146
- };
147
- }
148
- };
149
154
  //#endregion
150
155
  //#region src/prompt/file/ts/ts-prompt-file-type.ts
151
156
  /**
@@ -183,7 +188,7 @@ var TSPromptFileType = class {
183
188
  return `import { prompts } from ${JSON.stringify(importPath)};
184
189
 
185
190
  export default prompts(
186
- ${JSON.stringify(promptsId)},
191
+ { id: ${JSON.stringify(promptsId)} },
187
192
  () => ({
188
193
  ${key}: () => ({
189
194
  })
@@ -382,10 +387,9 @@ export default prompts(
382
387
  }
383
388
  };
384
389
  /**
385
- * If `expr` is a call like `prompts(id, factory)` (or the legacy `prompts(factory)`)
386
- * whose factory immediately returns an object literal, return that object literal
387
- * together with the module ID — the first string-literal argument, when present.
388
- * Otherwise null.
390
+ * If `expr` is a call like `prompts({ id }, factory)` whose factory immediately
391
+ * returns an object literal, return that object literal together with the module
392
+ * ID extracted from the options object. Otherwise null.
389
393
  */
390
394
  function findPromptsHelperCall(expr) {
391
395
  if (!ts.isCallExpression(expr)) return null;
@@ -397,9 +401,12 @@ function findPromptsHelperCall(expr) {
397
401
  const first = expr.arguments[0];
398
402
  return {
399
403
  object,
400
- moduleId: first && ts.isStringLiteralLike(first) ? first.text : void 0
404
+ moduleId: first && ts.isObjectLiteralExpression(first) ? extractStringProperty(first, "id") : void 0
401
405
  };
402
406
  }
407
+ function extractStringProperty(obj, key) {
408
+ for (const prop of obj.properties) if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && prop.name.text === key && ts.isStringLiteralLike(prop.initializer)) return prop.initializer.text;
409
+ }
403
410
  function getPropertyName(prop) {
404
411
  if (ts.isMethodDeclaration(prop) || ts.isPropertyAssignment(prop)) {
405
412
  const name = prop.name;
@@ -600,7 +607,6 @@ var FilePromptProvider = class {
600
607
  includePatterns;
601
608
  ignorePatterns;
602
609
  sdkAdapter;
603
- suppressedWatchEvents = /* @__PURE__ */ new Map();
604
610
  constructor({ id = "fs" + (defaultIDCounter++ ? defaultIDCounter : ""), rootDir = process.cwd(), fileProvider = new LocalFileProvider(), fileType, includePatterns, ignorePatterns = DEFAULT_IGNORE_PATTERNS, sdk }) {
605
611
  fileType ??= new TSPromptFileType(fileProvider);
606
612
  this.id = id;
@@ -626,7 +632,6 @@ var FilePromptProvider = class {
626
632
  const { definitions, values } = parsed.extractedProps;
627
633
  const rawUpdates = this.sdkAdapter.denormalizeUpdates(updates, values);
628
634
  for (const [propertyName, value] of Object.entries(rawUpdates)) {
629
- this.suppressNextWatchEvent(filePath, "change");
630
635
  const propDef = definitions.find((d) => d.name === propertyName);
631
636
  const currentValue = values?.[propertyName];
632
637
  if (value === null) {
@@ -663,14 +668,13 @@ var FilePromptProvider = class {
663
668
  getModelParameters() {
664
669
  return this.sdkAdapter.getModelParameters(this.rootDir);
665
670
  }
666
- async execute(promptId, params, stream) {
671
+ async execute(promptId, params) {
667
672
  const [filePath, promptName] = this.parsePromptId(promptId);
668
673
  const config = await this.fileType.loadConfig(filePath, promptName, params);
669
- return this.sdkAdapter.executeConfig(config, stream);
674
+ await this.sdkAdapter.executeConfig(config);
670
675
  }
671
676
  async renamePrompt(promptId, newName) {
672
677
  const [filePath, oldName] = this.parsePromptId(promptId);
673
- this.suppressNextWatchEvent(filePath, "change");
674
678
  await this.fileType.renamePrompt(filePath, oldName, newName);
675
679
  const relFilePath = path.relative(this.rootDir, filePath);
676
680
  const prompt = await this.getPrompt(`${relFilePath}#${newName}`);
@@ -687,7 +691,6 @@ var FilePromptProvider = class {
687
691
  const promptsId = firstDot >= 0 ? baseName.slice(0, firstDot) : baseName;
688
692
  const name = partial.name ?? promptsId;
689
693
  const content = this.fileType.newPromptSkeleton(promptsId, name, this.sdkAdapter.promptsHelperImport);
690
- this.suppressNextWatchEvent(absPath, "add");
691
694
  await this.fileProvider.writeFile(absPath, content);
692
695
  if (this.files && !this.files.includes(absPath)) this.files.push(absPath);
693
696
  const prompt = await this.getPrompt(`${normalizedRelFilePath}#${name}`);
@@ -741,7 +744,6 @@ var FilePromptProvider = class {
741
744
  ignored: this.ignorePatterns
742
745
  }, async (eventType, filePath) => {
743
746
  const absolutePath = this.resolveFilePath(filePath);
744
- if (this.consumeSuppressedWatchEvent(absolutePath, eventType)) return;
745
747
  if (eventType === "change" || eventType === "add") {
746
748
  if (this.files && !this.files.includes(absolutePath)) this.files.push(absolutePath);
747
749
  (await this.fileType.parsePrompts([absolutePath], this.rootDir)).forEach((prompt) => {
@@ -762,30 +764,6 @@ var FilePromptProvider = class {
762
764
  async ensureFiles() {
763
765
  if (!this.files) this.files = await Array.fromAsync(this.findPromptFiles());
764
766
  }
765
- suppressNextWatchEvent(filePath, eventType) {
766
- if (eventType !== "change" && eventType !== "add") return;
767
- const key = `${eventType}:${filePath}`;
768
- const entry = this.suppressedWatchEvents.get(key);
769
- this.suppressedWatchEvents.set(key, {
770
- remaining: (entry?.remaining ?? 0) + 1,
771
- expiresAt: Date.now() + 2e3
772
- });
773
- }
774
- consumeSuppressedWatchEvent(filePath, eventType) {
775
- const key = `${eventType}:${filePath}`;
776
- const entry = this.suppressedWatchEvents.get(key);
777
- if (!entry) return false;
778
- if (entry.expiresAt < Date.now()) {
779
- this.suppressedWatchEvents.delete(key);
780
- return false;
781
- }
782
- if (entry.remaining <= 1) this.suppressedWatchEvents.delete(key);
783
- else this.suppressedWatchEvents.set(key, {
784
- remaining: entry.remaining - 1,
785
- expiresAt: entry.expiresAt
786
- });
787
- return true;
788
- }
789
767
  async *findPromptFiles() {
790
768
  const uniqueFiles = /* @__PURE__ */ new Set();
791
769
  for (const pattern of this.includePatterns) {
@@ -1116,26 +1094,22 @@ var GeminiInteractionsSDK = class {
1116
1094
  });
1117
1095
  }
1118
1096
  getModelParameters(rootDir) {
1119
- const dtsPath = findPackageDts("@google/genai", "dist/genai.d.ts", rootDir);
1120
- if (dtsPath) try {
1121
- const sourceText = fs$1.readFileSync(dtsPath, "utf-8");
1122
- const sourceFile = ts.createSourceFile(dtsPath, sourceText, ts.ScriptTarget.Latest, true);
1123
- const decl = findTypeDeclaration(sourceFile, "GenerationConfig_2");
1124
- if (decl) return extractPropertiesFromDeclaration(decl, sourceFile).definitions;
1097
+ try {
1098
+ const dtsPath = findPackageDts("@google/genai", "dist/genai.d.ts", rootDir);
1099
+ if (dtsPath) {
1100
+ const sourceText = fs$1.readFileSync(dtsPath, "utf-8");
1101
+ const sourceFile = ts.createSourceFile(dtsPath, sourceText, ts.ScriptTarget.Latest, true);
1102
+ const decl = findTypeDeclaration(sourceFile, "GenerationConfig_2");
1103
+ if (decl) return extractPropertiesFromDeclaration(decl, sourceFile).definitions;
1104
+ }
1125
1105
  } catch {}
1126
1106
  return FALLBACK_GENERATION_CONFIG_PARAMS;
1127
1107
  }
1128
- async executeConfig(config, stream) {
1129
- const result = await new GoogleGenAI({}).interactions.create({
1108
+ async executeConfig(config) {
1109
+ await new GoogleGenAI({}).interactions.create({
1130
1110
  ...config,
1131
- stream,
1132
1111
  store: false
1133
1112
  });
1134
- if ("id" in result) return {
1135
- text: (result.outputs ?? []).find((o) => o.type === "text")?.text ?? "",
1136
- usage: result.usage
1137
- };
1138
- else return streamTextFromSSE(result);
1139
1113
  }
1140
1114
  normalizePrompt(prompt) {
1141
1115
  const { definitions, values } = prompt.extractedProps;
@@ -1313,13 +1287,5 @@ function extractMessages(value) {
1313
1287
  }
1314
1288
  return results;
1315
1289
  }
1316
- /**
1317
- * Yields text chunks from the Interactions API SSE stream.
1318
- */
1319
- async function* streamTextFromSSE(stream) {
1320
- for await (const chunk of stream) if (chunk.event_type === "content.delta") {
1321
- if (chunk.delta?.type === "text" && chunk.delta.text) yield chunk.delta.text;
1322
- }
1323
- }
1324
1290
  //#endregion
1325
- export { FilePromptProvider, GeminiInteractionsSDK, LocalFileProvider, MemoryFileProvider, MemoryTraceProvider, PROMPT_ID_ATTRIBUTE, PROMPT_NAME_ATTRIBUTE, PROMPT_PROVIDER_ID_ATTRIBUTE, SPAN_KIND_ATTRIBUTE, TSPromptFileType, VercelAISDK, createTracerForPrompt, setupStepCommand };
1291
+ export { FilePromptProvider, GeminiInteractionsSDK, LocalFileProvider, MemoryFileProvider, MemoryTraceProvider, PROMPT_ID_ATTRIBUTE, PROMPT_INPUTS_ATTRIBUTE, PROMPT_NAME_ATTRIBUTE, PROMPT_PROVIDER_ID_ATTRIBUTE, SPAN_KIND_ATTRIBUTE, TSPromptFileType, VercelAISDK, createTracerForPrompt, getPromptSpanAttributes };
@@ -1,7 +1,7 @@
1
1
  import path from "node:path";
2
2
  import { SpanStatusCode, trace } from "@opentelemetry/api";
3
3
  import fs from "node:fs";
4
- import { generateText, streamText } from "ai";
4
+ import { generateText } from "ai";
5
5
  import { extractPropertiesFromDeclaration, findTypeDeclaration } from "ts-proppy";
6
6
  import ts from "typescript";
7
7
  //#region src/shared/helpers.ts
@@ -31,10 +31,9 @@ function isEditable(value) {
31
31
  */
32
32
  const SPAN_KIND_ATTRIBUTE = "evalution.span.type";
33
33
  /**
34
- * Attribute name a span can set to scope its {@link PROMPT_ID_ATTRIBUTE} to a
35
- * specific prompt provider. When absent, the prompt ID is treated as global.
34
+ * Attribute name a span can set to give a human-readable name to the prompt.
36
35
  */
37
- const PROMPT_PROVIDER_ID_ATTRIBUTE = "evalution.prompt.provider.id";
36
+ const PROMPT_NAME_ATTRIBUTE = "gen_ai.prompt.name";
38
37
  /**
39
38
  * Attribute name a span can set to link itself to a specific prompt. The value
40
39
  * is a globally-unique prompt ID unless {@link PROMPT_PROVIDER_ID_ATTRIBUTE} is
@@ -42,9 +41,24 @@ const PROMPT_PROVIDER_ID_ATTRIBUTE = "evalution.prompt.provider.id";
42
41
  */
43
42
  const PROMPT_ID_ATTRIBUTE = "evalution.prompt.id";
44
43
  /**
45
- * Attribute name a span can set to give a human-readable name to the prompt.
44
+ * Attribute name a span can set to scope its {@link PROMPT_ID_ATTRIBUTE} to a
45
+ * specific prompt provider. When absent, the prompt ID is treated as global.
46
46
  */
47
- const PROMPT_NAME_ATTRIBUTE = "gen_ai.prompt.name";
47
+ const PROMPT_PROVIDER_ID_ATTRIBUTE = "evalution.prompt.provider.id";
48
+ /**
49
+ * Attribute name a span can set to include an array of input parameters used
50
+ * to construct the final prompt.
51
+ */
52
+ const PROMPT_INPUTS_ATTRIBUTE = "evalution.prompt.inputs";
53
+ function getPromptSpanAttributes(prompt, attributes = {}) {
54
+ return Object.fromEntries([
55
+ [SPAN_KIND_ATTRIBUTE, "LLM"],
56
+ [PROMPT_NAME_ATTRIBUTE, prompt.name],
57
+ [PROMPT_ID_ATTRIBUTE, prompt.id],
58
+ [PROMPT_INPUTS_ATTRIBUTE, prompt.functionParameters],
59
+ ...Object.entries(attributes)
60
+ ].filter(([, v]) => v !== void 0 && v !== null));
61
+ }
48
62
  /**
49
63
  * Wraps a {@link Tracer} so that every span it produces is tagged with the
50
64
  * attributes that associate it with a prompt — the prompt's name
@@ -69,12 +83,7 @@ function createTracerForPrompt(prompt, tracer) {
69
83
  const inner = tracer ?? trace.getTracer("evalution");
70
84
  const withPromptAttributes = (options) => ({
71
85
  ...options,
72
- attributes: {
73
- [SPAN_KIND_ATTRIBUTE]: "LLM",
74
- [PROMPT_NAME_ATTRIBUTE]: prompt.name,
75
- ...prompt.id !== void 0 && { ["evalution.prompt.id"]: prompt.id },
76
- ...options?.attributes
77
- }
86
+ attributes: getPromptSpanAttributes(prompt, options?.attributes)
78
87
  });
79
88
  return {
80
89
  startSpan(name, options, context) {
@@ -171,9 +180,9 @@ function readLLM(attributes) {
171
180
  const messages = parseMessages(attributes["gen_ai.input.messages"] ?? attributes["ai.prompt.messages"]);
172
181
  const output = parseOutput(attributes["gen_ai.output.messages"]) ?? str(attributes["ai.response.text"]);
173
182
  const paramEntries = PARAM_ATTRIBUTES.map((key) => [key.replace("gen_ai.request.", ""), attributes[key]]).filter(([, v]) => v !== void 0);
174
- const parameters = paramEntries.length > 0 ? Object.fromEntries(paramEntries) : void 0;
183
+ const modelParameters = paramEntries.length > 0 ? Object.fromEntries(paramEntries) : void 0;
175
184
  const totalTokens = promptTokens !== void 0 && completionTokens !== void 0 ? promptTokens + completionTokens : void 0;
176
- if (!provider && !model && !promptTokens && !completionTokens && !messages && !output && !parameters) return;
185
+ if (!provider && !model && !promptTokens && !completionTokens && !messages && !output && !modelParameters) return;
177
186
  return {
178
187
  ...provider && { provider },
179
188
  ...model && { model },
@@ -182,7 +191,7 @@ function readLLM(attributes) {
182
191
  ...promptTokens !== void 0 && { promptTokens },
183
192
  ...completionTokens !== void 0 && { completionTokens },
184
193
  ...totalTokens !== void 0 && { totalTokens },
185
- ...parameters && { parameters }
194
+ ...modelParameters && { modelParameters }
186
195
  };
187
196
  }
188
197
  function llmAndPrompt(attributes) {
@@ -502,6 +511,93 @@ const RESERVED_KEYS = new Set([
502
511
  SYSTEM_KEY,
503
512
  MESSAGES_KEY
504
513
  ]);
514
+ const FALLBACK_CALL_SETTINGS_PARAMS = [
515
+ {
516
+ name: "maxOutputTokens",
517
+ description: "Maximum number of tokens to generate.",
518
+ type: {
519
+ kind: "primitive",
520
+ syntax: "number"
521
+ },
522
+ optional: true
523
+ },
524
+ {
525
+ name: "temperature",
526
+ description: "Temperature setting. The value is passed through to the provider. The range depends on the provider and model.",
527
+ type: {
528
+ kind: "primitive",
529
+ syntax: "number"
530
+ },
531
+ optional: true
532
+ },
533
+ {
534
+ name: "topP",
535
+ description: "Nucleus sampling. The value is passed through to the provider. The range depends on the provider and model.",
536
+ type: {
537
+ kind: "primitive",
538
+ syntax: "number"
539
+ },
540
+ optional: true
541
+ },
542
+ {
543
+ name: "topK",
544
+ description: "Only sample from the top K options for each subsequent token.",
545
+ type: {
546
+ kind: "primitive",
547
+ syntax: "number"
548
+ },
549
+ optional: true
550
+ },
551
+ {
552
+ name: "presencePenalty",
553
+ description: "Presence penalty setting. It affects the likelihood of the model to repeat information that is already in the prompt.",
554
+ type: {
555
+ kind: "primitive",
556
+ syntax: "number"
557
+ },
558
+ optional: true
559
+ },
560
+ {
561
+ name: "frequencyPenalty",
562
+ description: "Frequency penalty setting. It affects the likelihood of the model to repeatedly use the same words or phrases.",
563
+ type: {
564
+ kind: "primitive",
565
+ syntax: "number"
566
+ },
567
+ optional: true
568
+ },
569
+ {
570
+ name: "stopSequences",
571
+ description: "Stop sequences. If set, the model will stop generating text.",
572
+ type: {
573
+ kind: "array",
574
+ syntax: "string[]",
575
+ elementType: {
576
+ kind: "primitive",
577
+ syntax: "string"
578
+ }
579
+ },
580
+ optional: true
581
+ },
582
+ {
583
+ name: "seed",
584
+ description: "The seed (integer) to use for random sampling.",
585
+ type: {
586
+ kind: "primitive",
587
+ syntax: "number"
588
+ },
589
+ optional: true
590
+ },
591
+ {
592
+ name: "maxRetries",
593
+ description: "Maximum number of retries. Set to 0 to disable retries.",
594
+ type: {
595
+ kind: "primitive",
596
+ syntax: "number"
597
+ },
598
+ optional: true
599
+ }
600
+ ];
505
601
  /** The `prompts()` factory from `@evalution/vercel-ai-sdk`. */
506
602
  const PROMPTS_HELPER_CALL = {
507
603
  callee: "prompts",
@@ -581,7 +677,10 @@ export default {
581
677
  */
582
678
  var VercelAISDK = class {
583
679
  promptsHelperImport = PROMPTS_HELPER_CALL.import.from;
584
- /** Onboarding task: install the SDK package, then drop a starter config. */
680
+ /**
681
+ * Onboarding task: install the SDK package, then drop a starter config.
682
+ * @internal
683
+ */
585
684
  static setupTask = {
586
685
  id: "vercel-ai-sdk",
587
686
  label: "AI SDK",
@@ -639,24 +738,19 @@ var VercelAISDK = class {
639
738
  });
640
739
  }
641
740
  getModelParameters(rootDir) {
642
- const dtsPath = findPackageDts("ai", "dist/index.d.ts", rootDir);
643
- if (!dtsPath) return [];
644
- const sourceText = fs.readFileSync(dtsPath, "utf-8");
645
- const sourceFile = ts.createSourceFile(dtsPath, sourceText, ts.ScriptTarget.Latest, true);
646
- const decl = findTypeDeclaration(sourceFile, "CallSettings");
647
- if (!decl) return [];
648
- return extractPropertiesFromDeclaration(decl, sourceFile).definitions;
741
+ try {
742
+ const dtsPath = findPackageDts("ai", "dist/index.d.ts", rootDir);
743
+ if (dtsPath) {
744
+ const sourceText = fs.readFileSync(dtsPath, "utf-8");
745
+ const sourceFile = ts.createSourceFile(dtsPath, sourceText, ts.ScriptTarget.Latest, true);
746
+ const decl = findTypeDeclaration(sourceFile, "CallSettings");
747
+ if (decl) return extractPropertiesFromDeclaration(decl, sourceFile).definitions;
748
+ }
749
+ } catch {}
750
+ return FALLBACK_CALL_SETTINGS_PARAMS;
649
751
  }
650
- async executeConfig(config, stream) {
651
- if (stream) return (await streamText(config)).textStream;
652
- else {
653
- const result = await generateText(config);
654
- return {
655
- text: result.text,
656
- usage: result.usage,
657
- finishReason: result.finishReason
658
- };
659
- }
752
+ async executeConfig(config) {
753
+ await generateText(config);
660
754
  }
661
755
  normalizePrompt(prompt) {
662
756
  const { definitions, values } = prompt.extractedProps;
@@ -742,7 +836,7 @@ function extractMessages(value) {
742
836
  });
743
837
  }
744
838
  function extractToolCalls(value) {
745
- if (!value || value.kind !== "array") return void 0;
839
+ if (value?.kind !== "array") return void 0;
746
840
  const out = [];
747
841
  for (const el of value.elements) {
748
842
  if (el.kind !== "object") continue;
@@ -756,4 +850,4 @@ function extractToolCalls(value) {
756
850
  return out.length > 0 ? out : void 0;
757
851
  }
758
852
  //#endregion
759
- export { MemoryTraceProvider as a, PROMPT_PROVIDER_ID_ATTRIBUTE as c, isEditable as d, setupStepCommand as i, SPAN_KIND_ATTRIBUTE as l, findPackageDts as n, PROMPT_ID_ATTRIBUTE as o, CONFIG_FILE_RELATIVE_PATH as r, PROMPT_NAME_ATTRIBUTE as s, VercelAISDK as t, createTracerForPrompt as u };
853
+ export { MemoryTraceProvider as a, PROMPT_NAME_ATTRIBUTE as c, createTracerForPrompt as d, getPromptSpanAttributes as f, setupStepCommand as i, PROMPT_PROVIDER_ID_ATTRIBUTE as l, findPackageDts as n, PROMPT_ID_ATTRIBUTE as o, isEditable as p, CONFIG_FILE_RELATIVE_PATH as r, PROMPT_INPUTS_ATTRIBUTE as s, VercelAISDK as t, SPAN_KIND_ATTRIBUTE as u };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "evalution",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "TypeScript AI Prompt Playground - Edit and execute AI prompts with live preview",
5
5
  "type": "module",
6
6
  "exports": {
@@ -58,12 +58,12 @@
58
58
  "minimatch": "^10.2.4",
59
59
  "react": ">=18.2.0",
60
60
  "react-dom": ">=18.2.0",
61
- "ts-proppy": "0.2.1",
61
+ "ts-proppy": "0.2.3",
62
62
  "typescript": ">=5.3.3",
63
63
  "ws": "^8.21.0"
64
64
  },
65
65
  "devDependencies": {
66
- "@biomejs/biome": "^2.4.14",
66
+ "@biomejs/biome": "^2.5.0",
67
67
  "@playwright/experimental-ct-react": "^1.58.2",
68
68
  "@playwright/test": "^1.58.2",
69
69
  "@types/node": ">=22.18.0",