vskill 0.5.11 → 0.5.13

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.
Files changed (89) hide show
  1. package/dist/commands/eval/credentials.d.ts +12 -0
  2. package/dist/commands/eval/credentials.js +140 -0
  3. package/dist/commands/eval/credentials.js.map +1 -0
  4. package/dist/commands/eval/generate-all.d.ts +1 -1
  5. package/dist/commands/eval/generate-all.js +57 -12
  6. package/dist/commands/eval/generate-all.js.map +1 -1
  7. package/dist/commands/eval/init.d.ts +2 -1
  8. package/dist/commands/eval/init.js +76 -10
  9. package/dist/commands/eval/init.js.map +1 -1
  10. package/dist/commands/eval/run.d.ts +7 -1
  11. package/dist/commands/eval/run.js +207 -26
  12. package/dist/commands/eval/run.js.map +1 -1
  13. package/dist/commands/eval/sweep.d.ts +7 -0
  14. package/dist/commands/eval/sweep.js +99 -0
  15. package/dist/commands/eval/sweep.js.map +1 -0
  16. package/dist/commands/eval.d.ts +10 -0
  17. package/dist/commands/eval.js +62 -4
  18. package/dist/commands/eval.js.map +1 -1
  19. package/dist/eval/batch-judge.d.ts +27 -0
  20. package/dist/eval/batch-judge.js +242 -0
  21. package/dist/eval/batch-judge.js.map +1 -0
  22. package/dist/eval/chrome-profile.d.ts +16 -0
  23. package/dist/eval/chrome-profile.js +65 -0
  24. package/dist/eval/chrome-profile.js.map +1 -0
  25. package/dist/eval/comparator.d.ts +3 -1
  26. package/dist/eval/comparator.js +19 -3
  27. package/dist/eval/comparator.js.map +1 -1
  28. package/dist/eval/concurrency.d.ts +13 -0
  29. package/dist/eval/concurrency.js +53 -0
  30. package/dist/eval/concurrency.js.map +1 -0
  31. package/dist/eval/credential-resolver.d.ts +31 -0
  32. package/dist/eval/credential-resolver.js +111 -0
  33. package/dist/eval/credential-resolver.js.map +1 -0
  34. package/dist/eval/integration-runner.d.ts +12 -0
  35. package/dist/eval/integration-runner.js +303 -0
  36. package/dist/eval/integration-runner.js.map +1 -0
  37. package/dist/eval/integration-types.d.ts +65 -0
  38. package/dist/eval/integration-types.js +18 -0
  39. package/dist/eval/integration-types.js.map +1 -0
  40. package/dist/eval/judge-cache.d.ts +29 -0
  41. package/dist/eval/judge-cache.js +109 -0
  42. package/dist/eval/judge-cache.js.map +1 -0
  43. package/dist/eval/judge.d.ts +1 -1
  44. package/dist/eval/judge.js +20 -3
  45. package/dist/eval/judge.js.map +1 -1
  46. package/dist/eval/llm.d.ts +2 -1
  47. package/dist/eval/llm.js +54 -2
  48. package/dist/eval/llm.js.map +1 -1
  49. package/dist/eval/prompt-builder.d.ts +10 -0
  50. package/dist/eval/prompt-builder.js +167 -0
  51. package/dist/eval/prompt-builder.js.map +1 -1
  52. package/dist/eval/rate-limiter.d.ts +20 -0
  53. package/dist/eval/rate-limiter.js +62 -0
  54. package/dist/eval/rate-limiter.js.map +1 -0
  55. package/dist/eval/schema.d.ts +16 -0
  56. package/dist/eval/schema.js +58 -6
  57. package/dist/eval/schema.js.map +1 -1
  58. package/dist/eval/verdict.d.ts +9 -0
  59. package/dist/eval/verdict.js +50 -0
  60. package/dist/eval/verdict.js.map +1 -1
  61. package/dist/eval-server/api-routes.js +99 -3
  62. package/dist/eval-server/api-routes.js.map +1 -1
  63. package/dist/eval-server/benchmark-runner.d.ts +7 -0
  64. package/dist/eval-server/benchmark-runner.js +158 -42
  65. package/dist/eval-server/benchmark-runner.js.map +1 -1
  66. package/dist/eval-server/concurrency.d.ts +1 -13
  67. package/dist/eval-server/concurrency.js +3 -49
  68. package/dist/eval-server/concurrency.js.map +1 -1
  69. package/dist/eval-server/eval-server.js +4 -0
  70. package/dist/eval-server/eval-server.js.map +1 -1
  71. package/dist/eval-server/integration-routes.d.ts +2 -0
  72. package/dist/eval-server/integration-routes.js +100 -0
  73. package/dist/eval-server/integration-routes.js.map +1 -0
  74. package/dist/eval-server/skill-create-routes.js +151 -22
  75. package/dist/eval-server/skill-create-routes.js.map +1 -1
  76. package/dist/eval-server/sweep-routes.d.ts +2 -0
  77. package/dist/eval-server/sweep-routes.js +93 -0
  78. package/dist/eval-server/sweep-routes.js.map +1 -0
  79. package/dist/eval-server/sweep-runner.d.ts +93 -0
  80. package/dist/eval-server/sweep-runner.js +275 -0
  81. package/dist/eval-server/sweep-runner.js.map +1 -0
  82. package/dist/eval-ui/assets/index-C9_Pey9T.css +1 -0
  83. package/dist/eval-ui/assets/index-KfkLPyh3.js +74 -0
  84. package/dist/eval-ui/index.html +2 -2
  85. package/dist/index.js +8 -0
  86. package/dist/index.js.map +1 -1
  87. package/package.json +1 -1
  88. package/dist/eval-ui/assets/index-CxHCKEhf.js +0 -74
  89. package/dist/eval-ui/assets/index-D2UkOol1.css +0 -1
@@ -0,0 +1,242 @@
1
+ // ---------------------------------------------------------------------------
2
+ // batch-judge.ts -- Anthropic Message Batches API for eval judge calls
3
+ //
4
+ // Collects all judge prompts into a single batch request, polls for completion
5
+ // with escalating intervals, maps results back to AssertionResult[].
6
+ // Falls back to sequential judgeAssertion() on any failure.
7
+ // ---------------------------------------------------------------------------
8
+ import { buildJudgeSystemPrompt, judgeAssertion } from "./judge.js";
9
+ // ---------------------------------------------------------------------------
10
+ // Polling configuration
11
+ // ---------------------------------------------------------------------------
12
+ const POLL_INTERVAL_INITIAL_MS = 5_000; // 0-60s: every 5s
13
+ const POLL_INTERVAL_MEDIUM_MS = 15_000; // 60s-5min: every 15s
14
+ const POLL_INTERVAL_SLOW_MS = 30_000; // 5min+: every 30s
15
+ const POLL_ESCALATE_1_MS = 60_000; // escalate from 5s to 15s after 60s
16
+ const POLL_ESCALATE_2_MS = 300_000; // escalate from 15s to 30s after 5min
17
+ const POLL_TIMEOUT_MS = 600_000; // 10 minutes total timeout
18
+ /** Minimum batch size — below this, sequential is faster than batch overhead */
19
+ const DEFAULT_MIN_BATCH_SIZE = 5;
20
+ // ---------------------------------------------------------------------------
21
+ // Build judge user prompt (mirrors judge.ts format)
22
+ // ---------------------------------------------------------------------------
23
+ function buildJudgeUserPrompt(output, assertionText) {
24
+ return `## LLM Output
25
+ ${output}
26
+
27
+ ## Assertion to Verify
28
+ ${assertionText}
29
+
30
+ Does the LLM output satisfy this assertion? Respond with JSON only: { "pass": boolean, "reasoning": "..." }`;
31
+ }
32
+ // ---------------------------------------------------------------------------
33
+ // Parse a single judge response from batch result
34
+ // ---------------------------------------------------------------------------
35
+ function parseJudgeResponse(raw) {
36
+ const fenceMatch = raw.match(/```(?:json)?\s*\n([\s\S]*?)\n```/);
37
+ const jsonStr = fenceMatch ? fenceMatch[1] : raw;
38
+ try {
39
+ const parsed = JSON.parse(jsonStr);
40
+ if (typeof parsed.pass !== "boolean") {
41
+ throw new Error("missing pass field");
42
+ }
43
+ return {
44
+ pass: parsed.pass,
45
+ reasoning: typeof parsed.reasoning === "string" ? parsed.reasoning : "",
46
+ };
47
+ }
48
+ catch {
49
+ throw new Error(`Invalid judge output: expected JSON with { pass, reasoning }, got: ${raw.slice(0, 100)}`);
50
+ }
51
+ }
52
+ // ---------------------------------------------------------------------------
53
+ // Get polling interval based on elapsed time
54
+ // ---------------------------------------------------------------------------
55
+ export function getPollInterval(elapsedMs) {
56
+ if (elapsedMs < POLL_ESCALATE_1_MS)
57
+ return POLL_INTERVAL_INITIAL_MS;
58
+ if (elapsedMs < POLL_ESCALATE_2_MS)
59
+ return POLL_INTERVAL_MEDIUM_MS;
60
+ return POLL_INTERVAL_SLOW_MS;
61
+ }
62
+ // ---------------------------------------------------------------------------
63
+ // Build batch request items from judge requests
64
+ // ---------------------------------------------------------------------------
65
+ function buildBatchItems(requests, model) {
66
+ return requests.map((req) => {
67
+ const customId = `${req.evalId}_${req.assertionIdx}`;
68
+ const systemPrompt = buildJudgeSystemPrompt(req.mcpDeps);
69
+ const userPrompt = buildJudgeUserPrompt(req.output, req.assertion.text);
70
+ return {
71
+ custom_id: customId,
72
+ params: {
73
+ model,
74
+ max_tokens: 256,
75
+ system: systemPrompt,
76
+ messages: [{ role: "user", content: userPrompt }],
77
+ },
78
+ };
79
+ });
80
+ }
81
+ // ---------------------------------------------------------------------------
82
+ // Map batch results back to AssertionResult[]
83
+ // ---------------------------------------------------------------------------
84
+ function mapBatchResults(results, requests) {
85
+ return requests.map((req) => {
86
+ const customId = `${req.evalId}_${req.assertionIdx}`;
87
+ const parsed = results.get(customId);
88
+ if (!parsed) {
89
+ return {
90
+ id: req.assertion.id,
91
+ text: req.assertion.text,
92
+ pass: false,
93
+ reasoning: `No batch result found for custom_id: ${customId}`,
94
+ };
95
+ }
96
+ return {
97
+ id: req.assertion.id,
98
+ text: req.assertion.text,
99
+ pass: parsed.pass,
100
+ reasoning: parsed.reasoning,
101
+ };
102
+ });
103
+ }
104
+ // ---------------------------------------------------------------------------
105
+ // Sequential fallback — uses existing judgeAssertion() one at a time
106
+ // ---------------------------------------------------------------------------
107
+ async function sequentialFallback(requests, client, judgeClient) {
108
+ const results = [];
109
+ for (const req of requests) {
110
+ const result = await judgeAssertion(req.output, req.assertion, client, judgeClient, req.mcpDeps);
111
+ results.push(result);
112
+ }
113
+ return results;
114
+ }
115
+ // ---------------------------------------------------------------------------
116
+ // Poll batch status with escalating intervals
117
+ // ---------------------------------------------------------------------------
118
+ async function pollBatchCompletion(anthropicClient, batchId) {
119
+ const startTime = Date.now();
120
+ while (true) {
121
+ const elapsed = Date.now() - startTime;
122
+ if (elapsed >= POLL_TIMEOUT_MS) {
123
+ // Timeout — attempt to cancel the batch
124
+ try {
125
+ await anthropicClient.messages.batches.cancel(batchId);
126
+ }
127
+ catch {
128
+ // Ignore cancel errors — we're throwing timeout anyway
129
+ }
130
+ throw new Error(`Batch ${batchId} timed out after ${POLL_TIMEOUT_MS / 1000}s. Batch was cancelled.`);
131
+ }
132
+ const interval = getPollInterval(elapsed);
133
+ await new Promise((resolve) => setTimeout(resolve, interval));
134
+ const status = await anthropicClient.messages.batches.retrieve(batchId);
135
+ if (status.processing_status === "ended") {
136
+ return;
137
+ }
138
+ if (status.processing_status === "canceling") {
139
+ throw new Error(`Batch ${batchId} is being cancelled.`);
140
+ }
141
+ }
142
+ }
143
+ // ---------------------------------------------------------------------------
144
+ // Retrieve and parse batch results
145
+ // ---------------------------------------------------------------------------
146
+ async function retrieveBatchResults(anthropicClient, batchId) {
147
+ const resultMap = new Map();
148
+ for await (const entry of anthropicClient.messages.batches.results(batchId)) {
149
+ const customId = entry.custom_id;
150
+ if (entry.result?.type === "succeeded") {
151
+ const message = entry.result.message;
152
+ const textBlock = message?.content?.find((b) => b.type === "text");
153
+ const raw = textBlock?.text || "";
154
+ try {
155
+ const parsed = parseJudgeResponse(raw);
156
+ resultMap.set(customId, parsed);
157
+ }
158
+ catch {
159
+ resultMap.set(customId, {
160
+ pass: false,
161
+ reasoning: `Failed to parse judge response: ${raw.slice(0, 100)}`,
162
+ });
163
+ }
164
+ }
165
+ else {
166
+ const errorType = entry.result?.type || "unknown";
167
+ const errorMsg = entry.result?.error?.message || "No error details";
168
+ resultMap.set(customId, {
169
+ pass: false,
170
+ reasoning: `Batch item ${errorType}: ${errorMsg}`,
171
+ });
172
+ }
173
+ }
174
+ return resultMap;
175
+ }
176
+ export function calculateBatchCost(inputTokens, outputTokens, model) {
177
+ // Per-token pricing (per 1M tokens) for common Anthropic models
178
+ const pricing = {
179
+ "claude-sonnet-4-6": { input: 3.0, output: 15.0 },
180
+ "claude-sonnet-4-20250514": { input: 3.0, output: 15.0 },
181
+ "claude-haiku-4-5-20251001": { input: 0.80, output: 4.0 },
182
+ "claude-opus-4-6": { input: 15.0, output: 75.0 },
183
+ };
184
+ // Default to sonnet pricing if model not found
185
+ const modelPricing = pricing[model] || pricing["claude-sonnet-4-6"];
186
+ const sequentialCost = (inputTokens / 1_000_000) * modelPricing.input +
187
+ (outputTokens / 1_000_000) * modelPricing.output;
188
+ const batchCost = sequentialCost * 0.5; // 50% batch discount
189
+ const savings = sequentialCost - batchCost;
190
+ return { batchCost, sequentialCost, savings };
191
+ }
192
+ // ---------------------------------------------------------------------------
193
+ // Main entry point: batchJudgeAssertions()
194
+ // ---------------------------------------------------------------------------
195
+ export async function batchJudgeAssertions(requests, client, judgeClient, options) {
196
+ const minBatchSize = options.minBatchSize ?? DEFAULT_MIN_BATCH_SIZE;
197
+ // Below minimum batch size, sequential is faster
198
+ if (requests.length < minBatchSize) {
199
+ const results = await sequentialFallback(requests, client, judgeClient);
200
+ return { results, costInfo: null };
201
+ }
202
+ const model = options.model || "claude-sonnet-4-6";
203
+ const batchItems = buildBatchItems(requests, model);
204
+ let anthropicClient;
205
+ try {
206
+ const { default: Anthropic } = await import("@anthropic-ai/sdk");
207
+ anthropicClient = new Anthropic({ apiKey: options.apiKey });
208
+ }
209
+ catch (err) {
210
+ console.warn(`Warning: Failed to initialize Anthropic client for batch: ${err.message}. Falling back to sequential.`);
211
+ const results = await sequentialFallback(requests, client, judgeClient);
212
+ return { results, costInfo: null };
213
+ }
214
+ try {
215
+ // T-021: Submit batch request
216
+ const batch = await anthropicClient.messages.batches.create({
217
+ requests: batchItems,
218
+ });
219
+ // T-022: Poll for completion
220
+ await pollBatchCompletion(anthropicClient, batch.id);
221
+ // T-023: Retrieve and map results
222
+ const rawResults = await retrieveBatchResults(anthropicClient, batch.id);
223
+ const results = mapBatchResults(rawResults, requests);
224
+ // T-027: Calculate cost from batch response counts
225
+ const totalInputTokens = batch.request_counts?.succeeded
226
+ ? requests.length * 500 // Estimate ~500 input tokens per judge call
227
+ : 0;
228
+ const totalOutputTokens = batch.request_counts?.succeeded
229
+ ? batch.request_counts.succeeded * 50 // Estimate ~50 output tokens per judge response
230
+ : 0;
231
+ const costInfo = calculateBatchCost(totalInputTokens, totalOutputTokens, model);
232
+ return { results, costInfo };
233
+ }
234
+ catch (err) {
235
+ // T-024: Sequential fallback on any batch failure
236
+ const errMsg = err instanceof Error ? err.message : String(err);
237
+ console.warn(`Warning: Batch judge failed: ${errMsg}. Falling back to sequential judge calls.`);
238
+ const results = await sequentialFallback(requests, client, judgeClient);
239
+ return { results, costInfo: null };
240
+ }
241
+ }
242
+ //# sourceMappingURL=batch-judge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch-judge.js","sourceRoot":"","sources":["../../src/eval/batch-judge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ export declare class UnsupportedPlatformError extends Error {
2
+ constructor(currentPlatform: string);
3
+ }
4
+ /**
5
+ * Resolve a Chrome profile name to its absolute directory path.
6
+ *
7
+ * @param profileName - e.g. "Profile 3", "Default"
8
+ * @returns Absolute path to the profile directory
9
+ * @throws UnsupportedPlatformError on non-macOS
10
+ * @throws Error if profile directory does not exist
11
+ */
12
+ export declare function resolveProfile(profileName: string): string;
13
+ /**
14
+ * List available Chrome profile names.
15
+ */
16
+ export declare function listProfiles(): string[];
@@ -0,0 +1,65 @@
1
+ // ---------------------------------------------------------------------------
2
+ // chrome-profile.ts -- macOS Chrome profile path resolver
3
+ // ---------------------------------------------------------------------------
4
+ import { existsSync, readdirSync } from "node:fs";
5
+ import { join } from "node:path";
6
+ import { homedir, platform } from "node:os";
7
+ export class UnsupportedPlatformError extends Error {
8
+ constructor(currentPlatform) {
9
+ super(`Chrome profile resolution is only supported on macOS. ` +
10
+ `Current platform: ${currentPlatform}. ` +
11
+ `Linux and Windows support is planned for a future release.`);
12
+ this.name = "UnsupportedPlatformError";
13
+ }
14
+ }
15
+ /**
16
+ * Get the base Chrome user data directory on macOS.
17
+ */
18
+ function getChromeBaseDir() {
19
+ return join(homedir(), "Library", "Application Support", "Google", "Chrome");
20
+ }
21
+ /**
22
+ * Resolve a Chrome profile name to its absolute directory path.
23
+ *
24
+ * @param profileName - e.g. "Profile 3", "Default"
25
+ * @returns Absolute path to the profile directory
26
+ * @throws UnsupportedPlatformError on non-macOS
27
+ * @throws Error if profile directory does not exist
28
+ */
29
+ export function resolveProfile(profileName) {
30
+ if (platform() !== "darwin") {
31
+ throw new UnsupportedPlatformError(platform());
32
+ }
33
+ const baseDir = getChromeBaseDir();
34
+ const profilePath = join(baseDir, profileName);
35
+ if (!existsSync(profilePath)) {
36
+ const available = listProfiles();
37
+ const profileList = available.length > 0
38
+ ? `Available profiles:\n ${available.join("\n ")}`
39
+ : "No Chrome profiles found. Is Chrome installed?";
40
+ throw new Error(`Chrome profile "${profileName}" not found at ${profilePath}\n${profileList}`);
41
+ }
42
+ return profilePath;
43
+ }
44
+ /**
45
+ * List available Chrome profile names.
46
+ */
47
+ export function listProfiles() {
48
+ const baseDir = getChromeBaseDir();
49
+ if (!existsSync(baseDir))
50
+ return [];
51
+ try {
52
+ return readdirSync(baseDir, { withFileTypes: true })
53
+ .filter((entry) => {
54
+ if (!entry.isDirectory())
55
+ return false;
56
+ // Chrome profiles are "Default", "Profile 1", "Profile 2", etc.
57
+ return entry.name === "Default" || entry.name.startsWith("Profile ");
58
+ })
59
+ .map((entry) => entry.name);
60
+ }
61
+ catch {
62
+ return [];
63
+ }
64
+ }
65
+ //# sourceMappingURL=chrome-profile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chrome-profile.js","sourceRoot":"","sources":["../../src/eval/chrome-profile.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,0DAA0D;AAC1D,8EAA8E;AAE9E,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE5C,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IACjD,YAAY,eAAuB;QACjC,KAAK,CACH,wDAAwD;YACxD,qBAAqB,eAAe,IAAI;YACxC,4DAA4D,CAC7D,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF;AAED;;GAEG;AACH,SAAS,gBAAgB;IACvB,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,qBAAqB,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAC/E,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,WAAmB;IAChD,IAAI,QAAQ,EAAE,KAAK,QAAQ,EAAE,CAAC;QAC5B,MAAM,IAAI,wBAAwB,CAAC,QAAQ,EAAE,CAAC,CAAC;IACjD,CAAC;IAED,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC;IACnC,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IAE/C,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7B,MAAM,SAAS,GAAG,YAAY,EAAE,CAAC;QACjC,MAAM,WAAW,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC;YACtC,CAAC,CAAC,0BAA0B,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;YACpD,CAAC,CAAC,gDAAgD,CAAC;QACrD,MAAM,IAAI,KAAK,CACb,mBAAmB,WAAW,kBAAkB,WAAW,KAAK,WAAW,EAAE,CAC9E,CAAC;IACJ,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY;IAC1B,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC;IACnC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,EAAE,CAAC;IAEpC,IAAI,CAAC;QACH,OAAO,WAAW,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;aACjD,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;YAChB,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;gBAAE,OAAO,KAAK,CAAC;YACvC,gEAAgE;YAChE,OAAO,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;QACvE,CAAC,CAAC;aACD,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
@@ -30,6 +30,8 @@ export interface ComparisonResult {
30
30
  baselineStructureScore: number;
31
31
  winner: "skill" | "baseline" | "tie";
32
32
  }
33
- export declare function generateComparisonOutputs(prompt: string, skillContent: string, client: LlmClient, onProgress?: ComparisonProgressCallback): Promise<ComparisonOutput>;
33
+ export declare function generateComparisonOutputs(prompt: string, skillContent: string, client: LlmClient, onProgress?: ComparisonProgressCallback, options?: {
34
+ parallel?: boolean;
35
+ }): Promise<ComparisonOutput>;
34
36
  export declare function scoreComparison(outputA: string, outputB: string, prompt: string, client: LlmClient, mcpDeps?: McpDependency[]): Promise<ComparisonScore>;
35
37
  export declare function runComparison(prompt: string, skillContent: string, client: LlmClient, onProgress?: ComparisonProgressCallback): Promise<ComparisonResult>;
@@ -20,15 +20,31 @@ Respond with ONLY valid JSON:
20
20
  "winner": "first" | "second" | "tie",
21
21
  "reasoning": "<brief explanation>"
22
22
  }`;
23
- export async function generateComparisonOutputs(prompt, skillContent, client, onProgress) {
23
+ export async function generateComparisonOutputs(prompt, skillContent, client, onProgress, options) {
24
24
  const skillSystemPrompt = buildEvalSystemPrompt(skillContent);
25
25
  const baselineSystemPrompt = buildBaselineSystemPrompt();
26
- // Run sequentially (claude-cli can only handle one at a time)
26
+ const totalTokens = (r) => r.inputTokens != null && r.outputTokens != null ? r.inputTokens + r.outputTokens : null;
27
+ // T-004: Parallelize skill+baseline generation for API providers
28
+ if (options?.parallel) {
29
+ onProgress?.("generating", "Generating skill and baseline outputs concurrently...");
30
+ const [skillResult, baselineResult] = await Promise.all([
31
+ client.generate(skillSystemPrompt, prompt),
32
+ client.generate(baselineSystemPrompt, prompt),
33
+ ]);
34
+ return {
35
+ skillOutput: skillResult.text,
36
+ skillDurationMs: skillResult.durationMs,
37
+ skillTokens: totalTokens(skillResult),
38
+ baselineOutput: baselineResult.text,
39
+ baselineDurationMs: baselineResult.durationMs,
40
+ baselineTokens: totalTokens(baselineResult),
41
+ };
42
+ }
43
+ // Sequential fallback for CLI providers
27
44
  onProgress?.("generating_skill", "Generating skill output...");
28
45
  const skillResult = await client.generate(skillSystemPrompt, prompt);
29
46
  onProgress?.("generating_baseline", "Generating baseline output...");
30
47
  const baselineResult = await client.generate(baselineSystemPrompt, prompt);
31
- const totalTokens = (r) => r.inputTokens != null && r.outputTokens != null ? r.inputTokens + r.outputTokens : null;
32
48
  return {
33
49
  skillOutput: skillResult.text,
34
50
  skillDurationMs: skillResult.durationMs,
@@ -1 +1 @@
1
- {"version":3,"file":"comparator.js","sourceRoot":"","sources":["../../src/eval/comparator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"comparator.js","sourceRoot":"","sources":["../../src/eval/comparator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export declare const DEFAULT_CONCURRENCY = 3;
2
+ export declare class Semaphore {
3
+ private readonly limit;
4
+ private running;
5
+ private queue;
6
+ constructor(limit?: number);
7
+ acquire(): Promise<void>;
8
+ release(): void;
9
+ get available(): number;
10
+ get pending(): number;
11
+ get active(): number;
12
+ }
13
+ export declare function getSkillSemaphore(skillKey: string, limit?: number): Semaphore;
@@ -0,0 +1,53 @@
1
+ // ---------------------------------------------------------------------------
2
+ // concurrency.ts -- cooperative semaphore for limiting concurrent LLM calls
3
+ // Shared module: imported by both eval-server/ and commands/eval/
4
+ // ---------------------------------------------------------------------------
5
+ export const DEFAULT_CONCURRENCY = 3;
6
+ export class Semaphore {
7
+ limit;
8
+ running = 0;
9
+ queue = [];
10
+ constructor(limit = DEFAULT_CONCURRENCY) {
11
+ this.limit = limit;
12
+ if (limit < 1)
13
+ throw new Error("Semaphore limit must be >= 1");
14
+ }
15
+ async acquire() {
16
+ if (this.running < this.limit) {
17
+ this.running++;
18
+ return;
19
+ }
20
+ return new Promise((resolve) => this.queue.push(() => {
21
+ this.running++;
22
+ resolve();
23
+ }));
24
+ }
25
+ release() {
26
+ if (this.running <= 0)
27
+ return; // idempotent — no underflow
28
+ this.running--;
29
+ const next = this.queue.shift();
30
+ if (next)
31
+ next();
32
+ }
33
+ get available() {
34
+ return Math.max(0, this.limit - this.running);
35
+ }
36
+ get pending() {
37
+ return this.queue.length;
38
+ }
39
+ get active() {
40
+ return this.running;
41
+ }
42
+ }
43
+ // Per-skill semaphore registry — ensures one semaphore per skill
44
+ const registry = new Map();
45
+ export function getSkillSemaphore(skillKey, limit = DEFAULT_CONCURRENCY) {
46
+ let sem = registry.get(skillKey);
47
+ if (!sem) {
48
+ sem = new Semaphore(limit);
49
+ registry.set(skillKey, sem);
50
+ }
51
+ return sem;
52
+ }
53
+ //# sourceMappingURL=concurrency.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"concurrency.js","sourceRoot":"","sources":["../../src/eval/concurrency.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,4EAA4E;AAC5E,kEAAkE;AAClE,8EAA8E;AAE9E,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAErC,MAAM,OAAO,SAAS;IAIS;IAHrB,OAAO,GAAG,CAAC,CAAC;IACZ,KAAK,GAAsB,EAAE,CAAC;IAEtC,YAA6B,QAAgB,mBAAmB;QAAnC,UAAK,GAAL,KAAK,CAA8B;QAC9D,IAAI,KAAK,GAAG,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IACjE,CAAC;IAED,KAAK,CAAC,OAAO;QACX,IAAI,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;YAC9B,IAAI,CAAC,OAAO,EAAE,CAAC;YACf,OAAO;QACT,CAAC;QACD,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE;YACzD,IAAI,CAAC,OAAO,EAAE,CAAC;YACf,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC,CAAC;IACN,CAAC;IAED,OAAO;QACL,IAAI,IAAI,CAAC,OAAO,IAAI,CAAC;YAAE,OAAO,CAAC,4BAA4B;QAC3D,IAAI,CAAC,OAAO,EAAE,CAAC;QACf,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QAChC,IAAI,IAAI;YAAE,IAAI,EAAE,CAAC;IACnB,CAAC;IAED,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;IAChD,CAAC;IAED,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;IAC3B,CAAC;IAED,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;CACF;AAED,iEAAiE;AACjE,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAqB,CAAC;AAE9C,MAAM,UAAU,iBAAiB,CAAC,QAAgB,EAAE,KAAK,GAAG,mBAAmB;IAC7E,IAAI,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACjC,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,GAAG,GAAG,IAAI,SAAS,CAAC,KAAK,CAAC,CAAC;QAC3B,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC9B,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,31 @@
1
+ export interface CredentialResult {
2
+ value: string;
3
+ source: "env" | "dotenv";
4
+ }
5
+ export interface CredentialStatus {
6
+ name: string;
7
+ status: "ready" | "missing" | "untested";
8
+ source?: "env" | "dotenv";
9
+ }
10
+ /**
11
+ * Resolve a single credential by name through the chain:
12
+ * 1. process.env[name]
13
+ * 2. .env.local in skillDir (parsed via dotenv-style parsing, not config())
14
+ *
15
+ * Returns null if not found in any source.
16
+ */
17
+ export declare function resolveCredential(name: string, skillDir: string): CredentialResult | null;
18
+ /**
19
+ * Resolve multiple credentials and return their statuses.
20
+ */
21
+ export declare function resolveAllCredentials(names: string[], skillDir: string): CredentialStatus[];
22
+ /**
23
+ * Write a credential to .env.local, creating the file if needed.
24
+ * Also ensures .env.local is in .gitignore.
25
+ */
26
+ export declare function writeCredential(skillDir: string, key: string, value: string): void;
27
+ /**
28
+ * Ensure .env.local is listed in .gitignore.
29
+ */
30
+ export declare function ensureGitignore(skillDir: string): void;
31
+ export declare function parseDotenv(content: string): Record<string, string>;
@@ -0,0 +1,111 @@
1
+ // ---------------------------------------------------------------------------
2
+ // credential-resolver.ts -- resolve credentials from env -> .env.local chain
3
+ // ---------------------------------------------------------------------------
4
+ import { readFileSync, existsSync, writeFileSync, appendFileSync } from "node:fs";
5
+ import { join } from "node:path";
6
+ /**
7
+ * Resolve a single credential by name through the chain:
8
+ * 1. process.env[name]
9
+ * 2. .env.local in skillDir (parsed via dotenv-style parsing, not config())
10
+ *
11
+ * Returns null if not found in any source.
12
+ */
13
+ export function resolveCredential(name, skillDir) {
14
+ // 1. Check process.env
15
+ const envVal = process.env[name];
16
+ if (envVal !== undefined && envVal !== "") {
17
+ return { value: envVal, source: "env" };
18
+ }
19
+ // 2. Check .env.local
20
+ const dotenvPath = join(skillDir, ".env.local");
21
+ if (existsSync(dotenvPath)) {
22
+ const parsed = parseDotenv(readFileSync(dotenvPath, "utf-8"));
23
+ const dotenvVal = parsed[name];
24
+ if (dotenvVal !== undefined && dotenvVal !== "") {
25
+ return { value: dotenvVal, source: "dotenv" };
26
+ }
27
+ }
28
+ return null;
29
+ }
30
+ /**
31
+ * Resolve multiple credentials and return their statuses.
32
+ */
33
+ export function resolveAllCredentials(names, skillDir) {
34
+ return names.map((name) => {
35
+ const result = resolveCredential(name, skillDir);
36
+ if (result) {
37
+ return { name, status: "ready", source: result.source };
38
+ }
39
+ return { name, status: "missing" };
40
+ });
41
+ }
42
+ /**
43
+ * Write a credential to .env.local, creating the file if needed.
44
+ * Also ensures .env.local is in .gitignore.
45
+ */
46
+ export function writeCredential(skillDir, key, value) {
47
+ const dotenvPath = join(skillDir, ".env.local");
48
+ // Read existing content or start fresh
49
+ let content = "";
50
+ if (existsSync(dotenvPath)) {
51
+ content = readFileSync(dotenvPath, "utf-8");
52
+ }
53
+ // Check if key already exists — replace it
54
+ const lines = content.split("\n");
55
+ const keyPattern = new RegExp(`^${escapeRegex(key)}=`);
56
+ const existingIndex = lines.findIndex((line) => keyPattern.test(line));
57
+ if (existingIndex >= 0) {
58
+ lines[existingIndex] = `${key}=${value}`;
59
+ writeFileSync(dotenvPath, lines.join("\n"), "utf-8");
60
+ }
61
+ else {
62
+ // Append new entry
63
+ const suffix = content.endsWith("\n") || content === "" ? "" : "\n";
64
+ appendFileSync(dotenvPath, `${suffix}${key}=${value}\n`, "utf-8");
65
+ }
66
+ // Ensure .env.local is in .gitignore
67
+ ensureGitignore(skillDir);
68
+ }
69
+ /**
70
+ * Ensure .env.local is listed in .gitignore.
71
+ */
72
+ export function ensureGitignore(skillDir) {
73
+ const gitignorePath = join(skillDir, ".gitignore");
74
+ if (existsSync(gitignorePath)) {
75
+ const content = readFileSync(gitignorePath, "utf-8");
76
+ if (content.split("\n").some((line) => line.trim() === ".env.local")) {
77
+ return; // already present
78
+ }
79
+ const suffix = content.endsWith("\n") ? "" : "\n";
80
+ appendFileSync(gitignorePath, `${suffix}.env.local\n`, "utf-8");
81
+ }
82
+ else {
83
+ writeFileSync(gitignorePath, ".env.local\n", "utf-8");
84
+ }
85
+ }
86
+ // ---------------------------------------------------------------------------
87
+ // Simple .env parser (does NOT mutate process.env)
88
+ // ---------------------------------------------------------------------------
89
+ export function parseDotenv(content) {
90
+ const result = {};
91
+ for (const line of content.split("\n")) {
92
+ const trimmed = line.trim();
93
+ if (!trimmed || trimmed.startsWith("#"))
94
+ continue;
95
+ const eqIndex = trimmed.indexOf("=");
96
+ if (eqIndex < 0)
97
+ continue;
98
+ const key = trimmed.slice(0, eqIndex).trim();
99
+ let val = trimmed.slice(eqIndex + 1).trim();
100
+ // Strip surrounding quotes
101
+ if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'"))) {
102
+ val = val.slice(1, -1);
103
+ }
104
+ result[key] = val;
105
+ }
106
+ return result;
107
+ }
108
+ function escapeRegex(str) {
109
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
110
+ }
111
+ //# sourceMappingURL=credential-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential-resolver.js","sourceRoot":"","sources":["../../src/eval/credential-resolver.ts"],"names":[],"mappings":"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"}