axiom 0.25.0 → 0.27.0
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/bin.cjs +831 -408
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +460 -372
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-BSZFDG3O.js → chunk-3YNZM3A7.js} +21 -9
- package/dist/chunk-3YNZM3A7.js.map +1 -0
- package/dist/chunk-CZJEEQDG.js +32 -0
- package/dist/chunk-CZJEEQDG.js.map +1 -0
- package/dist/chunk-GPMG4NO7.js +301 -0
- package/dist/chunk-GPMG4NO7.js.map +1 -0
- package/dist/chunk-NV3Y4T4G.js +22 -0
- package/dist/chunk-NV3Y4T4G.js.map +1 -0
- package/dist/{chunk-JGAXOVPZ.js → chunk-YCOR62XR.js} +35 -44
- package/dist/chunk-YCOR62XR.js.map +1 -0
- package/dist/chunk-ZLRPS5IN.js +400 -0
- package/dist/chunk-ZLRPS5IN.js.map +1 -0
- package/dist/{config-DT-xvV7w.d.cts → config-BsY1WraV.d.cts} +6 -0
- package/dist/{config-DT-xvV7w.d.ts → config-BsY1WraV.d.ts} +6 -0
- package/dist/config.cjs.map +1 -1
- package/dist/config.d.cts +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +2 -1
- package/dist/evals/custom-runner.cjs +102 -0
- package/dist/evals/custom-runner.cjs.map +1 -0
- package/dist/evals/custom-runner.d.cts +17 -0
- package/dist/evals/custom-runner.d.ts +17 -0
- package/dist/evals/custom-runner.js +63 -0
- package/dist/evals/custom-runner.js.map +1 -0
- package/dist/evals.cjs +137 -86
- package/dist/evals.cjs.map +1 -1
- package/dist/evals.d.cts +85 -12
- package/dist/evals.d.ts +85 -12
- package/dist/evals.js +60 -42
- package/dist/evals.js.map +1 -1
- package/dist/index.cjs +20 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/token-5SBK3AVU.js +63 -0
- package/dist/token-5SBK3AVU.js.map +1 -0
- package/dist/token-util-KUW2O75G.js +6 -0
- package/dist/token-util-KUW2O75G.js.map +1 -0
- package/package.json +9 -7
- package/dist/chunk-BSZFDG3O.js.map +0 -1
- package/dist/chunk-JGAXOVPZ.js.map +0 -1
- package/dist/chunk-N7MOZLNM.js +0 -73
- package/dist/chunk-N7MOZLNM.js.map +0 -1
package/dist/bin.cjs
CHANGED
|
@@ -36,360 +36,10 @@ __export(bin_exports, {
|
|
|
36
36
|
program: () => program
|
|
37
37
|
});
|
|
38
38
|
module.exports = __toCommonJS(bin_exports);
|
|
39
|
-
var
|
|
40
|
-
|
|
41
|
-
// src/cli/commands/push.command.ts
|
|
42
|
-
var import_commander = require("commander");
|
|
43
|
-
|
|
44
|
-
// src/transpiler.ts
|
|
45
|
-
var import_esbuild = require("esbuild");
|
|
46
|
-
var import_node_os = __toESM(require("os"), 1);
|
|
47
|
-
var import_promises = __toESM(require("fs/promises"), 1);
|
|
48
|
-
var import_node_path = __toESM(require("path"), 1);
|
|
49
|
-
var import_node_path2 = require("path");
|
|
50
|
-
async function loadPromptModule(filePath) {
|
|
51
|
-
const result = await (0, import_esbuild.build)({
|
|
52
|
-
entryPoints: [filePath],
|
|
53
|
-
bundle: true,
|
|
54
|
-
write: false,
|
|
55
|
-
platform: "node",
|
|
56
|
-
format: "esm",
|
|
57
|
-
target: ["node18"],
|
|
58
|
-
sourcemap: false,
|
|
59
|
-
external: [
|
|
60
|
-
// Only Node.js built-ins should be external
|
|
61
|
-
"fs",
|
|
62
|
-
"fs/promises",
|
|
63
|
-
"node:fs",
|
|
64
|
-
"node:fs/promises",
|
|
65
|
-
"readline",
|
|
66
|
-
"node:readline",
|
|
67
|
-
"path",
|
|
68
|
-
"node:path",
|
|
69
|
-
"os",
|
|
70
|
-
"node:os",
|
|
71
|
-
"url",
|
|
72
|
-
"node:url",
|
|
73
|
-
"util",
|
|
74
|
-
"node:util",
|
|
75
|
-
"crypto",
|
|
76
|
-
"node:crypto",
|
|
77
|
-
"events",
|
|
78
|
-
"node:events",
|
|
79
|
-
"stream",
|
|
80
|
-
"node:stream",
|
|
81
|
-
"buffer",
|
|
82
|
-
"node:buffer",
|
|
83
|
-
"process",
|
|
84
|
-
"node:process"
|
|
85
|
-
]
|
|
86
|
-
});
|
|
87
|
-
const code = result.outputFiles[0].text;
|
|
88
|
-
const tempDir = import_node_os.default.tmpdir();
|
|
89
|
-
const tempFileName = `axiom-ai-prompt-${Date.now()}-${Math.random().toString(36).substring(2)}.mjs`;
|
|
90
|
-
const tempFilePath = import_node_path.default.join(tempDir, tempFileName);
|
|
91
|
-
try {
|
|
92
|
-
await import_promises.default.writeFile(tempFilePath, code, "utf-8");
|
|
93
|
-
const moduleUrl = `file://${tempFilePath}`;
|
|
94
|
-
const module2 = await import(moduleUrl);
|
|
95
|
-
return module2.default || module2;
|
|
96
|
-
} finally {
|
|
97
|
-
try {
|
|
98
|
-
await import_promises.default.unlink(tempFilePath);
|
|
99
|
-
} catch (error) {
|
|
100
|
-
console.warn(`Failed to clean up temporary file ${tempFilePath}:`, error);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
function convertTypeBoxArgumentsToJsonSchema(arguments_) {
|
|
105
|
-
if (!arguments_ || typeof arguments_ !== "object") {
|
|
106
|
-
return {
|
|
107
|
-
type: "object",
|
|
108
|
-
properties: {},
|
|
109
|
-
required: [],
|
|
110
|
-
additionalProperties: false
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
const properties = {};
|
|
114
|
-
const required = [];
|
|
115
|
-
for (const [key, value] of Object.entries(arguments_)) {
|
|
116
|
-
if (value && typeof value === "object" && value.type) {
|
|
117
|
-
properties[key] = {
|
|
118
|
-
type: value.type,
|
|
119
|
-
...value.description && { description: value.description },
|
|
120
|
-
...value.enum && { enum: value.enum },
|
|
121
|
-
...value.items && { items: value.items },
|
|
122
|
-
...value.properties && { properties: value.properties },
|
|
123
|
-
...value.required && { required: value.required }
|
|
124
|
-
};
|
|
125
|
-
required.push(key);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
return {
|
|
129
|
-
type: "object",
|
|
130
|
-
properties,
|
|
131
|
-
required,
|
|
132
|
-
additionalProperties: false
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
function extractPromptFromModule(moduleContent, filePath) {
|
|
136
|
-
const fileBaseName = (0, import_node_path2.basename)(filePath, ".ts");
|
|
137
|
-
const defaultId = fileBaseName.toLowerCase().replace(/[^a-z0-9]/g, "-");
|
|
138
|
-
const convertedArguments = convertTypeBoxArgumentsToJsonSchema(moduleContent.arguments);
|
|
139
|
-
const prompt = {
|
|
140
|
-
name: moduleContent.name || "Untitled Prompt",
|
|
141
|
-
slug: moduleContent.slug || defaultId,
|
|
142
|
-
messages: moduleContent.messages || [],
|
|
143
|
-
model: moduleContent.model,
|
|
144
|
-
options: moduleContent.options,
|
|
145
|
-
arguments: convertedArguments,
|
|
146
|
-
id: moduleContent.id || defaultId,
|
|
147
|
-
version: moduleContent.version || "1.0.0",
|
|
148
|
-
// Optional fields from API response
|
|
149
|
-
...moduleContent.promptId && { promptId: moduleContent.promptId },
|
|
150
|
-
...moduleContent.description && { description: moduleContent.description }
|
|
151
|
-
};
|
|
152
|
-
if (!prompt.name) {
|
|
153
|
-
throw new Error("Prompt must have a name");
|
|
154
|
-
}
|
|
155
|
-
if (!prompt.slug) {
|
|
156
|
-
throw new Error("Prompt must have a slug");
|
|
157
|
-
}
|
|
158
|
-
if (!Array.isArray(prompt.messages)) {
|
|
159
|
-
throw new Error("Prompt messages must be an array");
|
|
160
|
-
}
|
|
161
|
-
if (!prompt.model) {
|
|
162
|
-
throw new Error("Prompt must have a model");
|
|
163
|
-
}
|
|
164
|
-
return prompt;
|
|
165
|
-
}
|
|
166
|
-
function transformJsonSchemaToTypeBox(schema) {
|
|
167
|
-
if (schema.type === "string") {
|
|
168
|
-
if (schema.enum && Array.isArray(schema.enum)) {
|
|
169
|
-
const literals = schema.enum.map((value) => `Type.Literal('${value}')`).join(", ");
|
|
170
|
-
const options = schema.description ? `, { description: '${schema.description}' }` : "";
|
|
171
|
-
return `Type.Union([${literals}]${options})`;
|
|
172
|
-
} else {
|
|
173
|
-
const options = schema.description ? `{ description: '${schema.description}' }` : "";
|
|
174
|
-
return `Type.String(${options})`;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
if (schema.type === "number" || schema.type === "integer") {
|
|
178
|
-
const typeMethod = schema.type === "integer" ? "Integer" : "Number";
|
|
179
|
-
const options = schema.description ? `{ description: '${schema.description}' }` : "";
|
|
180
|
-
return `Type.${typeMethod}(${options})`;
|
|
181
|
-
}
|
|
182
|
-
if (schema.type === "boolean") {
|
|
183
|
-
const options = schema.description ? `{ description: '${schema.description}' }` : "";
|
|
184
|
-
return `Type.Boolean(${options})`;
|
|
185
|
-
}
|
|
186
|
-
if (schema.type === "array") {
|
|
187
|
-
const itemsType = schema.items ? transformJsonSchemaToTypeBox(schema.items) : "Type.String()";
|
|
188
|
-
const options = schema.description ? `, { description: '${schema.description}' }` : "";
|
|
189
|
-
return `Type.Array(${itemsType}${options})`;
|
|
190
|
-
}
|
|
191
|
-
if (schema.type === "object") {
|
|
192
|
-
if (schema.properties) {
|
|
193
|
-
const props = Object.entries(schema.properties).map(([key, value]) => {
|
|
194
|
-
const isRequired = schema.required && schema.required.includes(key);
|
|
195
|
-
const propType = transformJsonSchemaToTypeBox(value);
|
|
196
|
-
return ` ${key}: ${isRequired ? propType : `Type.Optional(${propType})`}`;
|
|
197
|
-
}).join(",\n");
|
|
198
|
-
const options = schema.description ? `, { description: '${schema.description}' }` : "";
|
|
199
|
-
return `Type.Object({
|
|
200
|
-
${props}
|
|
201
|
-
}${options})`;
|
|
202
|
-
} else {
|
|
203
|
-
const options = schema.description ? `{ description: '${schema.description}' }` : "";
|
|
204
|
-
return `Type.Object({}${options ? `, ${options}` : ""})`;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
return "Type.String()";
|
|
208
|
-
}
|
|
209
|
-
function generatePromptFileFromApiResponse(apiResponse) {
|
|
210
|
-
const { prompt, version } = apiResponse;
|
|
211
|
-
const { data, options } = version;
|
|
212
|
-
let argumentsCode = "{}";
|
|
213
|
-
if (data.arguments && data.arguments.properties) {
|
|
214
|
-
const argEntries = Object.entries(data.arguments.properties).map(([key, schema]) => {
|
|
215
|
-
const isRequired = data.arguments.required && data.arguments.required.includes(key);
|
|
216
|
-
const typeCode = transformJsonSchemaToTypeBox(schema);
|
|
217
|
-
return ` ${key}: ${isRequired ? typeCode : `Type.Optional(${typeCode})`}`;
|
|
218
|
-
}).join(",\n");
|
|
219
|
-
if (argEntries) {
|
|
220
|
-
argumentsCode = `{
|
|
221
|
-
${argEntries}
|
|
222
|
-
}`;
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
return `import { Type } from 'axiom/ai';
|
|
226
|
-
|
|
227
|
-
export default {
|
|
228
|
-
name: '${prompt.name}',
|
|
229
|
-
slug: '${prompt.slug}',
|
|
230
|
-
description: '${prompt.description || ""}',
|
|
231
|
-
messages: [${data.messages.map(
|
|
232
|
-
(msg) => `
|
|
233
|
-
{
|
|
234
|
-
role: '${msg.role}',
|
|
235
|
-
content: '${msg.content.replace(/'/g, "\\'")}',
|
|
236
|
-
}`
|
|
237
|
-
).join(",")}
|
|
238
|
-
],
|
|
239
|
-
model: '${data.model || "gpt-4"}',
|
|
240
|
-
options: {
|
|
241
|
-
${options ? Object.entries(options).map(([key, value]) => ` ${key}: ${value}`).join(",\n") : ""}
|
|
242
|
-
},
|
|
243
|
-
arguments: ${argumentsCode},
|
|
244
|
-
version: '${version.version}',
|
|
245
|
-
promptId: '${prompt.promptId}',
|
|
246
|
-
};
|
|
247
|
-
`;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// src/cli/commands/push.command.ts
|
|
251
|
-
var import_promises2 = __toESM(require("fs/promises"), 1);
|
|
252
|
-
var import_node_readline = __toESM(require("readline"), 1);
|
|
253
|
-
async function askConfirmation(message) {
|
|
254
|
-
const rl = import_node_readline.default.createInterface({
|
|
255
|
-
input: process.stdin,
|
|
256
|
-
output: process.stdout
|
|
257
|
-
});
|
|
258
|
-
return new Promise((resolve3) => {
|
|
259
|
-
rl.question(`${message} (y/N): `, (answer) => {
|
|
260
|
-
rl.close();
|
|
261
|
-
resolve3(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
|
|
262
|
-
});
|
|
263
|
-
});
|
|
264
|
-
}
|
|
265
|
-
var loadPushCommand = (program2) => {
|
|
266
|
-
const push = new import_commander.Command("push").description("Push a new version of an object").argument(
|
|
267
|
-
"<object>",
|
|
268
|
-
"The object to push, could be a prompt, en eval, a monitor, a dashboard, etc."
|
|
269
|
-
).option("--prod", "Adds the production tag to the prompt").option("--yes", "Automatically confirm overwriting the file with server response").action(async (filePath, options) => {
|
|
270
|
-
let content = null;
|
|
271
|
-
if (!filePath.endsWith(".prompt.ts")) {
|
|
272
|
-
console.error("Prompt files must end with .prompt.ts");
|
|
273
|
-
process.exit(1);
|
|
274
|
-
}
|
|
275
|
-
try {
|
|
276
|
-
const moduleContent = await loadPromptModule(filePath);
|
|
277
|
-
const promptData = extractPromptFromModule(moduleContent, filePath);
|
|
278
|
-
content = promptData;
|
|
279
|
-
console.log(`Transpiled prompt: ${promptData.name} (${promptData.slug})`);
|
|
280
|
-
} catch (error) {
|
|
281
|
-
console.error("Failed to transpile prompt file:", error);
|
|
282
|
-
process.exit(1);
|
|
283
|
-
}
|
|
284
|
-
if (!content) {
|
|
285
|
-
console.error("No content found");
|
|
286
|
-
process.exit(1);
|
|
287
|
-
}
|
|
288
|
-
let shouldProceed = options.yes;
|
|
289
|
-
if (!shouldProceed) {
|
|
290
|
-
shouldProceed = await askConfirmation(
|
|
291
|
-
`This will push "${content.name}" to Axiom and overwrite ${filePath}, are you sure you want to continue?`
|
|
292
|
-
);
|
|
293
|
-
}
|
|
294
|
-
if (!shouldProceed) {
|
|
295
|
-
console.log("Push operation cancelled.");
|
|
296
|
-
process.exit(0);
|
|
297
|
-
}
|
|
298
|
-
try {
|
|
299
|
-
const response = await fetch(`${process.env.AXIOM_URL}/v1/prompts`, {
|
|
300
|
-
method: "POST",
|
|
301
|
-
headers: {
|
|
302
|
-
Authorization: `Bearer ${process.env.AXIOM_TOKEN}`,
|
|
303
|
-
"Content-Type": "application/json",
|
|
304
|
-
"x-axiom-client": "axiom-ai-cli",
|
|
305
|
-
"x-axiom-check": "good"
|
|
306
|
-
},
|
|
307
|
-
body: JSON.stringify({
|
|
308
|
-
...content,
|
|
309
|
-
tags: options.yes ? ["production"] : []
|
|
310
|
-
})
|
|
311
|
-
});
|
|
312
|
-
if (!response.ok) {
|
|
313
|
-
try {
|
|
314
|
-
const errorText = await response.clone().json();
|
|
315
|
-
console.error(`Failed to fetch prompt: ${response.status} ${response.statusText}`);
|
|
316
|
-
console.error(JSON.stringify(errorText, null, 2));
|
|
317
|
-
process.exit(1);
|
|
318
|
-
} catch (_error) {
|
|
319
|
-
const errorText = await response.clone().text();
|
|
320
|
-
console.error(`Failed to fetch prompt: ${response.status} ${response.statusText}`);
|
|
321
|
-
console.error(errorText);
|
|
322
|
-
process.exit(1);
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
const apiResponse = await response.json();
|
|
326
|
-
console.log(
|
|
327
|
-
`Successfully pushed prompt: ${apiResponse.prompt.name} (${apiResponse.prompt.slug})`
|
|
328
|
-
);
|
|
329
|
-
console.log(`Version: ${apiResponse.version.version}`);
|
|
330
|
-
const updatedTsContent = generatePromptFileFromApiResponse(apiResponse);
|
|
331
|
-
await import_promises2.default.writeFile(filePath, updatedTsContent, "utf-8");
|
|
332
|
-
console.log(`Successfully updated ${filePath}`);
|
|
333
|
-
} catch (error) {
|
|
334
|
-
console.error("Failed to push prompt:", error);
|
|
335
|
-
process.exit(1);
|
|
336
|
-
}
|
|
337
|
-
});
|
|
338
|
-
program2.addCommand(push);
|
|
339
|
-
};
|
|
340
|
-
|
|
341
|
-
// src/cli/commands/pull.command.ts
|
|
342
|
-
var import_commander2 = require("commander");
|
|
343
|
-
var fs3 = __toESM(require("fs/promises"), 1);
|
|
344
|
-
var path2 = __toESM(require("path"), 1);
|
|
345
|
-
var loadPullCommand = (program2) => {
|
|
346
|
-
const pull = new import_commander2.Command("pull").description("Pull a version of an object").argument(
|
|
347
|
-
"<slug>",
|
|
348
|
-
"The object to pull, could be a prompt, en eval, a monitor, a dashboard, etc."
|
|
349
|
-
).option("--version <version>", "The version to pull, default: latest", "latest").option("--output <path>", "Output file path (optional, defaults to <slug>.prompt.ts)").action(async (slug, options) => {
|
|
350
|
-
try {
|
|
351
|
-
console.log(`Pulling prompt: ${slug} (version: ${options.version})`);
|
|
352
|
-
const url = `${process.env.AXIOM_URL}/v1/prompts/${slug}`;
|
|
353
|
-
const response = await fetch(url, {
|
|
354
|
-
method: "GET",
|
|
355
|
-
headers: {
|
|
356
|
-
Authorization: `Bearer ${process.env.AXIOM_TOKEN}`,
|
|
357
|
-
"Content-Type": "application/json",
|
|
358
|
-
"x-axiom-client": "axiom-ai-cli",
|
|
359
|
-
"x-axiom-check": "good"
|
|
360
|
-
}
|
|
361
|
-
});
|
|
362
|
-
if (!response.ok) {
|
|
363
|
-
try {
|
|
364
|
-
const errorText = await response.clone().json();
|
|
365
|
-
console.error(`Failed to fetch prompt: ${response.status} ${response.statusText}`);
|
|
366
|
-
console.error(JSON.stringify(errorText, null, 2));
|
|
367
|
-
process.exit(1);
|
|
368
|
-
} catch (_error) {
|
|
369
|
-
const errorText = await response.clone().text();
|
|
370
|
-
console.error(`Failed to fetch prompt: ${response.status} ${response.statusText}`);
|
|
371
|
-
console.error(errorText);
|
|
372
|
-
process.exit(1);
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
const apiResponse = await response.json();
|
|
376
|
-
const tsContent = generatePromptFileFromApiResponse(apiResponse);
|
|
377
|
-
const outputPath = options.output || `${slug}.prompt.ts`;
|
|
378
|
-
const fullPath = path2.resolve(outputPath);
|
|
379
|
-
await fs3.writeFile(fullPath, tsContent, "utf-8");
|
|
380
|
-
console.log(`Successfully generated prompt file: ${fullPath}`);
|
|
381
|
-
console.log(`Prompt: ${apiResponse.prompt.name} (${apiResponse.prompt.slug})`);
|
|
382
|
-
console.log(`Version: ${apiResponse.version.version}`);
|
|
383
|
-
} catch (error) {
|
|
384
|
-
console.error("Failed to pull prompt:", error);
|
|
385
|
-
process.exit(1);
|
|
386
|
-
}
|
|
387
|
-
});
|
|
388
|
-
program2.addCommand(pull);
|
|
389
|
-
};
|
|
39
|
+
var import_commander3 = require("commander");
|
|
390
40
|
|
|
391
41
|
// src/cli/commands/eval.command.ts
|
|
392
|
-
var
|
|
42
|
+
var import_commander = require("commander");
|
|
393
43
|
var import_nanoid = require("nanoid");
|
|
394
44
|
|
|
395
45
|
// ../../node_modules/.pnpm/tinyrainbow@2.0.0/node_modules/tinyrainbow/dist/chunk-BVHSVHOK.js
|
|
@@ -477,7 +127,11 @@ var r = process.env.FORCE_TTY !== void 0 || (0, import_tty.isatty)(1);
|
|
|
477
127
|
var u = p(r);
|
|
478
128
|
|
|
479
129
|
// src/evals/run-vitest.ts
|
|
480
|
-
var
|
|
130
|
+
var import_node_url = require("url");
|
|
131
|
+
var import_node_path = require("path");
|
|
132
|
+
var import_node_fs = require("fs");
|
|
133
|
+
var import_node_os = require("os");
|
|
134
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
481
135
|
var import_node = require("vitest/node");
|
|
482
136
|
|
|
483
137
|
// src/evals/context/storage.ts
|
|
@@ -604,7 +258,10 @@ var ATTR_EVAL_TYPE = "eval.type";
|
|
|
604
258
|
var ATTR_EVAL_TAGS = "eval.tags";
|
|
605
259
|
var ATTR_EVAL_BASELINE_ID = "eval.baseline.id";
|
|
606
260
|
var ATTR_EVAL_BASELINE_NAME = "eval.baseline.name";
|
|
261
|
+
var ATTR_EVAL_BASELINE_VERSION = "eval.baseline.version";
|
|
607
262
|
var ATTR_EVAL_METADATA = "eval.metadata";
|
|
263
|
+
var ATTR_EVAL_CAPABILITY_NAME = "eval.capability.name";
|
|
264
|
+
var ATTR_EVAL_STEP_NAME = "eval.step.name";
|
|
608
265
|
var ATTR_EVAL_COLLECTION_ID = "eval.collection.id";
|
|
609
266
|
var ATTR_EVAL_COLLECTION_SIZE = "eval.collection.size";
|
|
610
267
|
var ATTR_EVAL_COLLECTION_NAME = "eval.collection.name";
|
|
@@ -819,7 +476,14 @@ var Attr = {
|
|
|
819
476
|
Type: ATTR_EVAL_TYPE,
|
|
820
477
|
Baseline: {
|
|
821
478
|
ID: ATTR_EVAL_BASELINE_ID,
|
|
822
|
-
Name: ATTR_EVAL_BASELINE_NAME
|
|
479
|
+
Name: ATTR_EVAL_BASELINE_NAME,
|
|
480
|
+
Version: ATTR_EVAL_BASELINE_VERSION
|
|
481
|
+
},
|
|
482
|
+
Capability: {
|
|
483
|
+
Name: ATTR_EVAL_CAPABILITY_NAME
|
|
484
|
+
},
|
|
485
|
+
Step: {
|
|
486
|
+
Name: ATTR_EVAL_STEP_NAME
|
|
823
487
|
},
|
|
824
488
|
Tags: ATTR_EVAL_TAGS,
|
|
825
489
|
Metadata: ATTR_EVAL_METADATA,
|
|
@@ -879,7 +543,7 @@ var import_api4 = require("@opentelemetry/api");
|
|
|
879
543
|
// package.json
|
|
880
544
|
var package_default = {
|
|
881
545
|
name: "axiom",
|
|
882
|
-
version: "0.
|
|
546
|
+
version: "0.27.0",
|
|
883
547
|
type: "module",
|
|
884
548
|
author: "Axiom, Inc.",
|
|
885
549
|
contributors: [
|
|
@@ -962,7 +626,8 @@ var package_default = {
|
|
|
962
626
|
commander: "^14.0.0",
|
|
963
627
|
defu: "^6.1.4",
|
|
964
628
|
handlebars: "^4.7.8",
|
|
965
|
-
nanoid: "^5.1.5"
|
|
629
|
+
nanoid: "^5.1.5",
|
|
630
|
+
open: "^10.1.0"
|
|
966
631
|
},
|
|
967
632
|
peerDependencies: {
|
|
968
633
|
"@opentelemetry/api": "^1.9.0",
|
|
@@ -970,11 +635,11 @@ var package_default = {
|
|
|
970
635
|
},
|
|
971
636
|
devDependencies: {
|
|
972
637
|
"@ai-sdk/anthropicv1": "npm:@ai-sdk/anthropic@^1.2.12",
|
|
973
|
-
"@ai-sdk/anthropicv2": "npm:@ai-sdk/anthropic
|
|
974
|
-
"@ai-sdk/openaiv1": "npm:@ai-sdk/openai@^1.3.
|
|
975
|
-
"@ai-sdk/openaiv2": "npm:@ai-sdk/openai
|
|
638
|
+
"@ai-sdk/anthropicv2": "npm:@ai-sdk/anthropic@^2.0.44",
|
|
639
|
+
"@ai-sdk/openaiv1": "npm:@ai-sdk/openai@^1.3.24",
|
|
640
|
+
"@ai-sdk/openaiv2": "npm:@ai-sdk/openai@^2.0.67",
|
|
976
641
|
"@ai-sdk/providerv1": "npm:@ai-sdk/provider@^1.1.3",
|
|
977
|
-
"@ai-sdk/providerv2": "npm:@ai-sdk/provider
|
|
642
|
+
"@ai-sdk/providerv2": "npm:@ai-sdk/provider@^2.0.0",
|
|
978
643
|
"@opentelemetry/api": "^1.9.0",
|
|
979
644
|
"@opentelemetry/core": "^2.0.1",
|
|
980
645
|
"@opentelemetry/sdk-trace-base": "^2.0.1",
|
|
@@ -983,9 +648,10 @@ var package_default = {
|
|
|
983
648
|
"@types/node": "^22.15.29",
|
|
984
649
|
"@vitest/coverage-v8": "^3.2.4",
|
|
985
650
|
aiv4: "npm:ai@^4.3.19",
|
|
986
|
-
aiv5: "npm:ai@^5.0.
|
|
651
|
+
aiv5: "npm:ai@^5.0.93",
|
|
987
652
|
esbuild: "^0.25.8",
|
|
988
653
|
eslint: "catalog:",
|
|
654
|
+
msw: "^2.12.2",
|
|
989
655
|
prettier: "catalog:",
|
|
990
656
|
tinyrainbow: "^2.0.0",
|
|
991
657
|
tsup: "catalog:",
|
|
@@ -1095,17 +761,36 @@ function resolveAxiomConnection(config) {
|
|
|
1095
761
|
url: config.eval.url,
|
|
1096
762
|
consoleEndpointUrl,
|
|
1097
763
|
token: config.eval.token,
|
|
1098
|
-
dataset: config.eval.dataset
|
|
764
|
+
dataset: config.eval.dataset,
|
|
765
|
+
orgId: config.eval.orgId
|
|
1099
766
|
};
|
|
1100
767
|
}
|
|
1101
768
|
|
|
769
|
+
// src/cli/errors.ts
|
|
770
|
+
var AxiomCLIError = class extends Error {
|
|
771
|
+
constructor(message) {
|
|
772
|
+
super(message);
|
|
773
|
+
this.name = "AxiomCLIError";
|
|
774
|
+
}
|
|
775
|
+
};
|
|
776
|
+
function errorToString(error) {
|
|
777
|
+
if (typeof error === "string") {
|
|
778
|
+
return error;
|
|
779
|
+
}
|
|
780
|
+
if (error instanceof Error) {
|
|
781
|
+
return error.message;
|
|
782
|
+
}
|
|
783
|
+
return JSON.stringify(error);
|
|
784
|
+
}
|
|
785
|
+
|
|
1102
786
|
// src/evals/eval.service.ts
|
|
1103
787
|
var findEvaluationCases = async (evalId, config) => {
|
|
1104
|
-
const { dataset, url, token } = resolveAxiomConnection(config);
|
|
788
|
+
const { dataset, url, token, orgId } = resolveAxiomConnection(config);
|
|
1105
789
|
const apl = `['${dataset}'] | where trace_id == "${evalId}" | order by _time`;
|
|
1106
790
|
const headers = new Headers({
|
|
1107
791
|
Authorization: `Bearer ${token}`,
|
|
1108
|
-
"Content-Type": "application/json"
|
|
792
|
+
"Content-Type": "application/json",
|
|
793
|
+
...orgId ? { "X-AXIOM-ORG-ID": orgId } : {}
|
|
1109
794
|
});
|
|
1110
795
|
const resp = await fetch(`${url}/v1/datasets/_apl?format=legacy`, {
|
|
1111
796
|
headers,
|
|
@@ -1698,23 +1383,6 @@ function printFinalReport({
|
|
|
1698
1383
|
}
|
|
1699
1384
|
}
|
|
1700
1385
|
|
|
1701
|
-
// src/cli/errors.ts
|
|
1702
|
-
var AxiomCLIError = class extends Error {
|
|
1703
|
-
constructor(message) {
|
|
1704
|
-
super(message);
|
|
1705
|
-
this.name = "AxiomCLIError";
|
|
1706
|
-
}
|
|
1707
|
-
};
|
|
1708
|
-
function errorToString(error) {
|
|
1709
|
-
if (typeof error === "string") {
|
|
1710
|
-
return error;
|
|
1711
|
-
}
|
|
1712
|
-
if (error instanceof Error) {
|
|
1713
|
-
return error.message;
|
|
1714
|
-
}
|
|
1715
|
-
return JSON.stringify(error);
|
|
1716
|
-
}
|
|
1717
|
-
|
|
1718
1386
|
// src/evals/reporter.ts
|
|
1719
1387
|
var AxiomReporter = class {
|
|
1720
1388
|
constructor() {
|
|
@@ -1869,13 +1537,344 @@ var import_api10 = require("@opentelemetry/api");
|
|
|
1869
1537
|
var import_c12 = require("c12");
|
|
1870
1538
|
var import_defu = require("defu");
|
|
1871
1539
|
|
|
1540
|
+
// src/cli/auth/config.ts
|
|
1541
|
+
var import_fs = require("fs");
|
|
1542
|
+
var import_path = __toESM(require("path"), 1);
|
|
1543
|
+
var import_os = __toESM(require("os"), 1);
|
|
1544
|
+
var CONFIG_FILENAME = "config.json";
|
|
1545
|
+
var CONFIG_DIR_NAME = "axiom";
|
|
1546
|
+
function getConfigDir() {
|
|
1547
|
+
const platform = process.platform;
|
|
1548
|
+
const homeDir = import_os.default.homedir();
|
|
1549
|
+
const xdgConfigHome = process.env.XDG_CONFIG_HOME;
|
|
1550
|
+
if (xdgConfigHome) {
|
|
1551
|
+
return import_path.default.join(xdgConfigHome, CONFIG_DIR_NAME);
|
|
1552
|
+
}
|
|
1553
|
+
if (platform === "win32") {
|
|
1554
|
+
const appData = process.env.APPDATA;
|
|
1555
|
+
if (appData) {
|
|
1556
|
+
return import_path.default.join(appData, CONFIG_DIR_NAME);
|
|
1557
|
+
}
|
|
1558
|
+
return import_path.default.join(homeDir, "AppData", "Roaming", CONFIG_DIR_NAME);
|
|
1559
|
+
}
|
|
1560
|
+
return import_path.default.join(homeDir, ".config", CONFIG_DIR_NAME);
|
|
1561
|
+
}
|
|
1562
|
+
function getGlobalConfigPath() {
|
|
1563
|
+
return import_path.default.join(getConfigDir(), CONFIG_FILENAME);
|
|
1564
|
+
}
|
|
1565
|
+
async function loadGlobalConfig() {
|
|
1566
|
+
const configPath = getGlobalConfigPath();
|
|
1567
|
+
try {
|
|
1568
|
+
const content = await import_fs.promises.readFile(configPath, "utf-8");
|
|
1569
|
+
return JSON.parse(content);
|
|
1570
|
+
} catch (error) {
|
|
1571
|
+
if (error.code === "ENOENT") {
|
|
1572
|
+
return { profiles: {} };
|
|
1573
|
+
}
|
|
1574
|
+
throw error;
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1577
|
+
async function saveGlobalConfig(config) {
|
|
1578
|
+
const configPath = getGlobalConfigPath();
|
|
1579
|
+
const configDir = import_path.default.dirname(configPath);
|
|
1580
|
+
const content = JSON.stringify(config, null, 2);
|
|
1581
|
+
await import_fs.promises.mkdir(configDir, { recursive: true, mode: 448 });
|
|
1582
|
+
await import_fs.promises.writeFile(configPath, content, "utf-8");
|
|
1583
|
+
await import_fs.promises.chmod(configPath, 384);
|
|
1584
|
+
}
|
|
1585
|
+
function getActiveProfile(config) {
|
|
1586
|
+
const profileName = config.active_profile;
|
|
1587
|
+
if (!profileName) return null;
|
|
1588
|
+
const profile = config.profiles[profileName];
|
|
1589
|
+
if (!profile) return null;
|
|
1590
|
+
return profile;
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
// src/cli/auth/oauth.ts
|
|
1594
|
+
var import_crypto = require("crypto");
|
|
1595
|
+
var OAUTH_CLIENT_ID = "264d906a404efc209b027f6595e6b616";
|
|
1596
|
+
var OAUTH_AUTH_PATH = "/oauth/authorize";
|
|
1597
|
+
var OAUTH_TOKEN_PATH = "/oauth/token";
|
|
1598
|
+
var OAuth = class {
|
|
1599
|
+
constructor(oauthBaseUrl) {
|
|
1600
|
+
this.oauthBaseUrl = oauthBaseUrl;
|
|
1601
|
+
}
|
|
1602
|
+
static generateCodeVerifier() {
|
|
1603
|
+
return (0, import_crypto.randomBytes)(32).toString("base64url");
|
|
1604
|
+
}
|
|
1605
|
+
static generateCodeChallenge(verifier) {
|
|
1606
|
+
return (0, import_crypto.createHash)("sha256").update(verifier).digest("base64url");
|
|
1607
|
+
}
|
|
1608
|
+
static generateState() {
|
|
1609
|
+
return (0, import_crypto.randomBytes)(16).toString("hex");
|
|
1610
|
+
}
|
|
1611
|
+
buildAuthUrl(params) {
|
|
1612
|
+
const url = new URL(OAUTH_AUTH_PATH, this.oauthBaseUrl);
|
|
1613
|
+
url.searchParams.set("client_id", OAUTH_CLIENT_ID);
|
|
1614
|
+
url.searchParams.set("redirect_uri", params.redirectUri);
|
|
1615
|
+
url.searchParams.set("response_type", "code");
|
|
1616
|
+
url.searchParams.set("state", params.state);
|
|
1617
|
+
url.searchParams.set("code_challenge", params.codeChallenge);
|
|
1618
|
+
url.searchParams.set("code_challenge_method", "S256");
|
|
1619
|
+
url.searchParams.set("scope", "*");
|
|
1620
|
+
return url.toString();
|
|
1621
|
+
}
|
|
1622
|
+
async exchangeCodeForToken(params) {
|
|
1623
|
+
const tokenUrl = new URL(OAUTH_TOKEN_PATH, this.oauthBaseUrl);
|
|
1624
|
+
const body = new URLSearchParams({
|
|
1625
|
+
grant_type: "authorization_code",
|
|
1626
|
+
client_id: OAUTH_CLIENT_ID,
|
|
1627
|
+
code: params.code,
|
|
1628
|
+
redirect_uri: params.redirectUri,
|
|
1629
|
+
code_verifier: params.codeVerifier
|
|
1630
|
+
});
|
|
1631
|
+
const response = await fetch(tokenUrl.toString(), {
|
|
1632
|
+
method: "POST",
|
|
1633
|
+
headers: {
|
|
1634
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
1635
|
+
},
|
|
1636
|
+
body: body.toString()
|
|
1637
|
+
});
|
|
1638
|
+
if (!response.ok) {
|
|
1639
|
+
const errorText = await response.text();
|
|
1640
|
+
throw new Error(`Token exchange failed: ${response.status} ${errorText}`);
|
|
1641
|
+
}
|
|
1642
|
+
const data = await response.json();
|
|
1643
|
+
return data.access_token;
|
|
1644
|
+
}
|
|
1645
|
+
};
|
|
1646
|
+
|
|
1647
|
+
// src/cli/auth/api.ts
|
|
1648
|
+
async function fetchOrganizations(token, apiBaseUrl) {
|
|
1649
|
+
const response = await fetch(`${apiBaseUrl}/v2/orgs`, {
|
|
1650
|
+
headers: {
|
|
1651
|
+
Authorization: `Bearer ${token}`,
|
|
1652
|
+
"Content-Type": "application/json"
|
|
1653
|
+
}
|
|
1654
|
+
});
|
|
1655
|
+
if (!response.ok) {
|
|
1656
|
+
throw new AxiomCLIError(
|
|
1657
|
+
`Failed to fetch organizations: ${response.status} ${response.statusText}`
|
|
1658
|
+
);
|
|
1659
|
+
}
|
|
1660
|
+
const data = await response.json();
|
|
1661
|
+
return data;
|
|
1662
|
+
}
|
|
1663
|
+
async function verifyToken(token, orgId, apiBaseUrl) {
|
|
1664
|
+
const response = await fetch(`${apiBaseUrl}/v2/user`, {
|
|
1665
|
+
headers: {
|
|
1666
|
+
Authorization: `Bearer ${token}`,
|
|
1667
|
+
"X-Axiom-Org-Id": orgId,
|
|
1668
|
+
"Content-Type": "application/json"
|
|
1669
|
+
}
|
|
1670
|
+
});
|
|
1671
|
+
return response.ok;
|
|
1672
|
+
}
|
|
1673
|
+
|
|
1674
|
+
// src/cli/auth/callback-server.ts
|
|
1675
|
+
var import_http = __toESM(require("http"), 1);
|
|
1676
|
+
function escapeHtml(text) {
|
|
1677
|
+
const map = {
|
|
1678
|
+
"&": "&",
|
|
1679
|
+
"<": "<",
|
|
1680
|
+
">": ">",
|
|
1681
|
+
'"': """,
|
|
1682
|
+
"'": "'",
|
|
1683
|
+
"`": "`"
|
|
1684
|
+
};
|
|
1685
|
+
return text.replace(/[&<>"']/g, (m2) => map[m2] || m2);
|
|
1686
|
+
}
|
|
1687
|
+
var SVG_LOGO = `<svg width="124" height="24" viewBox="0 0 124 24" fill="none" xmlns="http://www.w3.org/2000/svg" class="logo">
|
|
1688
|
+
<path d="M42.9919 16.8116H36.3696L35.5537 19.1572C35.4209 19.539 34.9714 19.8513 34.5548 19.8513H30.9779C30.5614 19.8513 30.3459 19.5449 30.499 19.1703L36.9816 3.31644C37.1346 2.9419 37.6009 2.63546 38.0174 2.63546H41.3718C41.7883 2.63546 42.2541 2.94207 42.4067 3.3168L48.8634 19.17C49.016 19.5447 48.8 19.8513 48.3835 19.8513H44.8067C44.3901 19.8513 43.9406 19.539 43.8078 19.1572L42.9919 16.8116ZM41.8232 13.4223L39.6807 7.18148L37.5383 13.4223H41.8232ZM64.1105 19.8513C63.694 19.8513 63.1767 19.5694 62.9611 19.2247L59.9029 14.3369L56.8447 19.2247C56.6291 19.5694 56.1119 19.8513 55.6953 19.8513H51.3392C50.9227 19.8513 50.7754 19.5801 51.0119 19.2486L56.8978 11.0013L51.5315 3.24414C51.2999 2.90937 51.4513 2.63546 51.8679 2.63546H55.89C56.3066 2.63546 56.8268 2.91563 57.0461 3.25807L59.9029 7.71959L62.7343 3.25955C62.9522 2.9163 63.4713 2.63546 63.8879 2.63546H67.938C68.3545 2.63546 68.5048 2.90868 68.272 3.24261L62.8801 10.9743L68.7935 19.2489C69.0303 19.5802 68.8832 19.8513 68.4666 19.8513H64.1105ZM76.525 19.119C76.525 19.5218 76.1841 19.8513 75.7675 19.8513H72.5522C72.1356 19.8513 71.7947 19.5218 71.7947 19.119V3.36771C71.7947 2.96498 72.1356 2.63546 72.5522 2.63546H75.7675C76.1841 2.63546 76.525 2.96498 76.525 3.36771V19.119ZM79.3736 11.1896C79.3736 6.18625 83.2688 2.15134 89.2511 2.15134C95.2334 2.15134 99.1289 6.18625 99.1289 11.1896C99.1289 16.2199 95.2334 20.2548 89.2511 20.2548C83.2688 20.2548 79.3736 16.2199 79.3736 11.1896ZM94.2873 11.1896C94.2873 8.58038 92.3953 6.21307 89.2511 6.21307C86.1349 6.21307 84.2149 8.58038 84.2149 11.1896C84.2149 13.7989 86.1349 16.2199 89.2511 16.2199C92.3675 16.2199 94.2873 13.7989 94.2873 11.1896ZM119.318 19.8513C118.902 19.8513 118.517 19.5245 118.463 19.1251L117.225 9.89847L113.65 19.1652C113.505 19.5426 113.045 19.8513 112.628 19.8513H111.055C110.638 19.8513 110.179 19.5423 110.034 19.1645L106.457 9.81766L105.218 19.125C105.165 19.5245 104.781 19.8513 104.364 19.8513H101.344C100.927 19.8513 100.633 19.5249 100.69 19.1259L102.932 3.3609C102.988 2.96191 103.376 2.63546 103.792 2.63546H106.59C107.007 2.63546 107.469 2.94351 107.617 3.32002L111.827 14.041L116.064 3.31949C116.213 2.94327 116.676 2.63546 117.092 2.63546H119.89C120.307 2.63546 120.694 2.96191 120.751 3.3609L122.993 19.1259C123.05 19.5249 122.755 19.8513 122.339 19.8513H119.318ZM23.9616 15.6531L18.8054 6.97021C18.5689 6.57115 17.9863 6.24465 17.5106 6.24465H14.2915C13.5433 6.24465 13.2365 5.73171 13.6097 5.1048L15.375 2.13986C15.5151 1.90455 15.5148 1.61487 15.3743 1.37981C15.2337 1.14476 14.9741 1 14.6933 1H10.2025C9.72681 1 9.14291 1.32577 8.90491 1.72395L0.17865 16.3217C-0.0594434 16.7199 -0.0595348 17.3715 0.178285 17.7698L2.42362 21.5297C2.79777 22.1561 3.41129 22.1569 3.78699 21.5313L5.54143 18.6103C5.91722 17.9847 6.53065 17.9854 6.9048 18.6119L8.49538 21.2754C8.7332 21.6737 9.317 21.9995 9.79273 21.9995H20.1698C20.6455 21.9995 21.2293 21.6737 21.4672 21.2754L23.959 17.1028C24.1968 16.7045 24.198 16.0521 23.9616 15.6531ZM16.9981 15.2352C17.3699 15.8629 17.0619 16.3765 16.3136 16.3765H8.24192C7.49372 16.3765 7.1876 15.864 7.56175 15.2375L11.6007 8.47417C11.9748 7.84772 12.5869 7.84774 12.9611 8.47421L16.9981 15.2352Z" fill="#121224"/>
|
|
1689
|
+
</svg>`;
|
|
1690
|
+
function renderCallbackPage(error) {
|
|
1691
|
+
const errorClass = error ? ' class="error"' : "";
|
|
1692
|
+
const errorMessage = error ? escapeHtml(error) : "";
|
|
1693
|
+
return `<!doctype html>
|
|
1694
|
+
<html lang="en">
|
|
1695
|
+
<head>
|
|
1696
|
+
<meta charset="utf-8">
|
|
1697
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
1698
|
+
<title>Axiom</title>
|
|
1699
|
+
<link rel="icon" href="https://app.axiom.co/static/favicon.ico">
|
|
1700
|
+
<meta name="description" content="Axiom CLI">
|
|
1701
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
1702
|
+
<style>
|
|
1703
|
+
html,
|
|
1704
|
+
body,
|
|
1705
|
+
.root {
|
|
1706
|
+
width: 100%;
|
|
1707
|
+
height: 100%;
|
|
1708
|
+
text-rendering: optimizeLegibility;
|
|
1709
|
+
-webkit-font-smoothing: antialiased;
|
|
1710
|
+
}
|
|
1711
|
+
body {
|
|
1712
|
+
color: #334155;
|
|
1713
|
+
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji;
|
|
1714
|
+
font-size: 14px;
|
|
1715
|
+
font-weight: 500;
|
|
1716
|
+
font-variant: tabular-nums;
|
|
1717
|
+
line-height: 1.5;
|
|
1718
|
+
background-color: #fff;
|
|
1719
|
+
font-feature-settings: "tnum";
|
|
1720
|
+
margin: 0;
|
|
1721
|
+
}
|
|
1722
|
+
h1,
|
|
1723
|
+
h2,
|
|
1724
|
+
h3,
|
|
1725
|
+
h4,
|
|
1726
|
+
h5,
|
|
1727
|
+
h6 {
|
|
1728
|
+
margin-top: 0;
|
|
1729
|
+
margin-bottom: .5em;
|
|
1730
|
+
font-weight: 500;
|
|
1731
|
+
}
|
|
1732
|
+
p {
|
|
1733
|
+
margin-top: 0;
|
|
1734
|
+
margin-bottom: 1em;
|
|
1735
|
+
}
|
|
1736
|
+
h2 {
|
|
1737
|
+
font-size: 16px;
|
|
1738
|
+
font-weight: 600;
|
|
1739
|
+
}
|
|
1740
|
+
.root {
|
|
1741
|
+
display: flex;
|
|
1742
|
+
align-items: center;
|
|
1743
|
+
justify-content: center;
|
|
1744
|
+
}
|
|
1745
|
+
.logo {
|
|
1746
|
+
width: 92px;
|
|
1747
|
+
float: left;
|
|
1748
|
+
position: absolute;
|
|
1749
|
+
top: 16px;
|
|
1750
|
+
left: 16px;
|
|
1751
|
+
}
|
|
1752
|
+
.center p {
|
|
1753
|
+
padding: 8px 0;
|
|
1754
|
+
}
|
|
1755
|
+
.error .center {
|
|
1756
|
+
color: #bf0e08;
|
|
1757
|
+
}
|
|
1758
|
+
</style>
|
|
1759
|
+
</head>
|
|
1760
|
+
<body${errorClass}>
|
|
1761
|
+
<div class="root">
|
|
1762
|
+
<a class="" target="_blank" rel="noopener noreferrer" href="https://axiom.co">
|
|
1763
|
+
${SVG_LOGO}
|
|
1764
|
+
</svg>
|
|
1765
|
+
</a>
|
|
1766
|
+
<div class="center">
|
|
1767
|
+
${error ? `<h2 id="msg">Login failed</h2>
|
|
1768
|
+
<p id="details">${errorMessage}</p>` : `<h2 id="msg">Login successful</h2>
|
|
1769
|
+
<p id="details">You can close this page and return to your CLI.</p>`}
|
|
1770
|
+
</div>
|
|
1771
|
+
</div>
|
|
1772
|
+
<script>
|
|
1773
|
+
window.history.replaceState({}, '', \`\${window.location.pathname}\`);
|
|
1774
|
+
</script>
|
|
1775
|
+
</body>
|
|
1776
|
+
</html>`;
|
|
1777
|
+
}
|
|
1778
|
+
async function startCallbackServer() {
|
|
1779
|
+
return new Promise((resolve3) => {
|
|
1780
|
+
const server = import_http.default.createServer();
|
|
1781
|
+
server.listen(0, "127.0.0.1", () => {
|
|
1782
|
+
const address = server.address();
|
|
1783
|
+
resolve3({
|
|
1784
|
+
server,
|
|
1785
|
+
port: address.port,
|
|
1786
|
+
url: `http://127.0.0.1:${address.port}`
|
|
1787
|
+
});
|
|
1788
|
+
});
|
|
1789
|
+
});
|
|
1790
|
+
}
|
|
1791
|
+
async function waitForCallback(server, expectedState) {
|
|
1792
|
+
return new Promise((resolve3, reject) => {
|
|
1793
|
+
const timeout = setTimeout(
|
|
1794
|
+
() => {
|
|
1795
|
+
server.close();
|
|
1796
|
+
reject(new Error("Authentication timeout after 5 minutes"));
|
|
1797
|
+
},
|
|
1798
|
+
5 * 60 * 1e3
|
|
1799
|
+
);
|
|
1800
|
+
server.on("request", (req, res) => {
|
|
1801
|
+
const url = new URL(req.url || "", `http://${req.headers.host}`);
|
|
1802
|
+
const code = url.searchParams.get("code");
|
|
1803
|
+
const state = url.searchParams.get("state");
|
|
1804
|
+
const error = url.searchParams.get("error");
|
|
1805
|
+
const errorDescription = url.searchParams.get("error_description");
|
|
1806
|
+
if (error) {
|
|
1807
|
+
const errorMsg = errorDescription || error;
|
|
1808
|
+
res.writeHead(400, { "Content-Type": "text/html" });
|
|
1809
|
+
res.end(renderCallbackPage(errorMsg));
|
|
1810
|
+
clearTimeout(timeout);
|
|
1811
|
+
server.close();
|
|
1812
|
+
reject(new Error(`OAuth error: ${errorMsg}`));
|
|
1813
|
+
return;
|
|
1814
|
+
}
|
|
1815
|
+
if (!code || !state) {
|
|
1816
|
+
res.writeHead(400, { "Content-Type": "text/html" });
|
|
1817
|
+
res.end(renderCallbackPage("Missing code or state parameter"));
|
|
1818
|
+
return;
|
|
1819
|
+
}
|
|
1820
|
+
if (state !== expectedState) {
|
|
1821
|
+
res.writeHead(400, { "Content-Type": "text/html" });
|
|
1822
|
+
res.end(renderCallbackPage("Invalid state parameter (CSRF protection)"));
|
|
1823
|
+
clearTimeout(timeout);
|
|
1824
|
+
server.close();
|
|
1825
|
+
reject(new Error("Invalid state parameter"));
|
|
1826
|
+
return;
|
|
1827
|
+
}
|
|
1828
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
1829
|
+
res.end(renderCallbackPage());
|
|
1830
|
+
clearTimeout(timeout);
|
|
1831
|
+
server.close();
|
|
1832
|
+
resolve3({ code });
|
|
1833
|
+
});
|
|
1834
|
+
});
|
|
1835
|
+
}
|
|
1836
|
+
|
|
1837
|
+
// src/cli/auth/global-auth.ts
|
|
1838
|
+
var authContext = null;
|
|
1839
|
+
function getAuthContext() {
|
|
1840
|
+
return authContext;
|
|
1841
|
+
}
|
|
1842
|
+
async function setupGlobalAuth() {
|
|
1843
|
+
const config = await loadGlobalConfig();
|
|
1844
|
+
const profile = getActiveProfile(config);
|
|
1845
|
+
if (profile) {
|
|
1846
|
+
authContext = {
|
|
1847
|
+
token: profile.token,
|
|
1848
|
+
url: profile.url,
|
|
1849
|
+
orgId: profile.org_id
|
|
1850
|
+
};
|
|
1851
|
+
}
|
|
1852
|
+
return authContext;
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1872
1855
|
// src/config/index.ts
|
|
1873
1856
|
var DEFAULT_EVAL_INCLUDE = ["**/*.eval.{ts,js,mts,mjs,cts,cjs}"];
|
|
1874
1857
|
function createPartialDefaults() {
|
|
1858
|
+
let token;
|
|
1859
|
+
let url;
|
|
1860
|
+
let orgId;
|
|
1861
|
+
try {
|
|
1862
|
+
const authContext2 = getAuthContext();
|
|
1863
|
+
if (authContext2) {
|
|
1864
|
+
token = authContext2.token;
|
|
1865
|
+
url = authContext2.url;
|
|
1866
|
+
orgId = authContext2.orgId;
|
|
1867
|
+
}
|
|
1868
|
+
} catch {
|
|
1869
|
+
}
|
|
1870
|
+
token = token || process.env.AXIOM_TOKEN;
|
|
1871
|
+
url = url || process.env.AXIOM_URL;
|
|
1872
|
+
orgId = orgId || process.env.AXIOM_ORG_ID;
|
|
1875
1873
|
return {
|
|
1876
1874
|
eval: {
|
|
1877
|
-
url:
|
|
1878
|
-
|
|
1875
|
+
url: url || "https://api.axiom.co",
|
|
1876
|
+
orgId,
|
|
1877
|
+
token,
|
|
1879
1878
|
dataset: process.env.AXIOM_DATASET,
|
|
1880
1879
|
instrumentation: null,
|
|
1881
1880
|
include: [...DEFAULT_EVAL_INCLUDE],
|
|
@@ -1978,7 +1977,8 @@ async function runInstrumentationHook(hook, options) {
|
|
|
1978
1977
|
}
|
|
1979
1978
|
function setupEvalProvider(connection) {
|
|
1980
1979
|
const headers = {
|
|
1981
|
-
"X-Axiom-Dataset": connection.dataset
|
|
1980
|
+
"X-Axiom-Dataset": connection.dataset,
|
|
1981
|
+
...connection.orgId ? { "X-AXIOM-ORG-ID": connection.orgId } : {}
|
|
1982
1982
|
};
|
|
1983
1983
|
if (connection.token) {
|
|
1984
1984
|
headers.Authorization = `Bearer ${connection.token}`;
|
|
@@ -1998,11 +1998,11 @@ function setupEvalProvider(connection) {
|
|
|
1998
1998
|
axiomProvider = new import_sdk_trace_node.NodeTracerProvider({
|
|
1999
1999
|
resource: (0, import_resources.resourceFromAttributes)({
|
|
2000
2000
|
["service.name"]: "axiom",
|
|
2001
|
-
["service.version"]: "0.
|
|
2001
|
+
["service.version"]: "0.27.0"
|
|
2002
2002
|
}),
|
|
2003
2003
|
spanProcessors: [processor]
|
|
2004
2004
|
});
|
|
2005
|
-
axiomTracer = axiomProvider.getTracer("axiom", "0.
|
|
2005
|
+
axiomTracer = axiomProvider.getTracer("axiom", "0.27.0");
|
|
2006
2006
|
}
|
|
2007
2007
|
async function initInstrumentation(config) {
|
|
2008
2008
|
if (initialized) {
|
|
@@ -2014,7 +2014,7 @@ async function initInstrumentation(config) {
|
|
|
2014
2014
|
}
|
|
2015
2015
|
initializationPromise = (async () => {
|
|
2016
2016
|
if (!config.enabled) {
|
|
2017
|
-
axiomTracer = import_api10.trace.getTracer("axiom", "0.
|
|
2017
|
+
axiomTracer = import_api10.trace.getTracer("axiom", "0.27.0");
|
|
2018
2018
|
initialized = true;
|
|
2019
2019
|
return;
|
|
2020
2020
|
}
|
|
@@ -2026,7 +2026,8 @@ async function initInstrumentation(config) {
|
|
|
2026
2026
|
hookResult = await runInstrumentationHook(hook, {
|
|
2027
2027
|
dataset: connection.dataset,
|
|
2028
2028
|
token: connection.token,
|
|
2029
|
-
url: connection.url
|
|
2029
|
+
url: connection.url,
|
|
2030
|
+
orgId: connection.orgId
|
|
2030
2031
|
});
|
|
2031
2032
|
userProvider = hookResult?.provider ?? userProvider;
|
|
2032
2033
|
}
|
|
@@ -2077,6 +2078,9 @@ var flush = async () => {
|
|
|
2077
2078
|
};
|
|
2078
2079
|
|
|
2079
2080
|
// src/evals/run-vitest.ts
|
|
2081
|
+
var import_meta2 = {};
|
|
2082
|
+
var __filename = (0, import_node_url.fileURLToPath)(import_meta2.url);
|
|
2083
|
+
var __dirname = (0, import_node_path.dirname)(__filename);
|
|
2080
2084
|
var printCollectedEvals = (result, rootDir) => {
|
|
2081
2085
|
if (!result.testModules || result.testModules.length === 0) {
|
|
2082
2086
|
console.log(u.yellow("\nNo evaluations found\n"));
|
|
@@ -2086,7 +2090,7 @@ var printCollectedEvals = (result, rootDir) => {
|
|
|
2086
2090
|
let totalEvals = 0;
|
|
2087
2091
|
let totalCases = 0;
|
|
2088
2092
|
for (const module2 of result.testModules) {
|
|
2089
|
-
const relativePath =
|
|
2093
|
+
const relativePath = import_node_path2.default.relative(rootDir, module2.moduleId);
|
|
2090
2094
|
for (const suite of module2.children.suites()) {
|
|
2091
2095
|
totalEvals++;
|
|
2092
2096
|
const caseCount = suite.children.size;
|
|
@@ -2116,6 +2120,16 @@ var runVitest = async (dir, opts) => {
|
|
|
2116
2120
|
if (opts.debug) {
|
|
2117
2121
|
console.log(u.bgWhite(u.blackBright(" Debug mode enabled ")));
|
|
2118
2122
|
}
|
|
2123
|
+
const tmpDir = (0, import_node_path.join)((0, import_node_os.tmpdir)(), "axiom-eval", opts.runId);
|
|
2124
|
+
(0, import_node_fs.mkdirSync)(tmpDir, { recursive: true });
|
|
2125
|
+
const nameRegistryFile = (0, import_node_path.join)(tmpDir, "names.jsonl");
|
|
2126
|
+
const abortFile = (0, import_node_path.join)(tmpDir, "abort.txt");
|
|
2127
|
+
(0, import_node_fs.writeFileSync)(nameRegistryFile, "", "utf8");
|
|
2128
|
+
if ((0, import_node_fs.existsSync)(abortFile)) {
|
|
2129
|
+
(0, import_node_fs.unlinkSync)(abortFile);
|
|
2130
|
+
}
|
|
2131
|
+
process.env.AXIOM_NAME_REGISTRY_FILE = nameRegistryFile;
|
|
2132
|
+
process.env.AXIOM_ABORT_FILE = abortFile;
|
|
2119
2133
|
if (opts.list) {
|
|
2120
2134
|
console.log(u.bgWhite(u.blackBright(" List mode ")));
|
|
2121
2135
|
}
|
|
@@ -2135,6 +2149,7 @@ var runVitest = async (dir, opts) => {
|
|
|
2135
2149
|
disableConsoleIntercept: true,
|
|
2136
2150
|
testTimeout: opts.config?.eval?.timeoutMs || 6e4,
|
|
2137
2151
|
globals: true,
|
|
2152
|
+
runner: (0, import_node_path.resolve)(__dirname, "evals", "custom-runner.js"),
|
|
2138
2153
|
provide: {
|
|
2139
2154
|
baseline: opts.baseline,
|
|
2140
2155
|
debug: opts.debug,
|
|
@@ -2151,6 +2166,12 @@ var runVitest = async (dir, opts) => {
|
|
|
2151
2166
|
process.exit(0);
|
|
2152
2167
|
}
|
|
2153
2168
|
await vi.start();
|
|
2169
|
+
if ((0, import_node_fs.existsSync)(abortFile)) {
|
|
2170
|
+
const message = (0, import_node_fs.readFileSync)(abortFile, "utf8");
|
|
2171
|
+
console.error("\n" + message);
|
|
2172
|
+
await vi.close();
|
|
2173
|
+
process.exit(1);
|
|
2174
|
+
}
|
|
2154
2175
|
const dispose = (0, import_node.registerConsoleShortcuts)(vi, process.stdin, process.stdout);
|
|
2155
2176
|
if (!vi.shouldKeepServer()) {
|
|
2156
2177
|
dispose();
|
|
@@ -2162,7 +2183,7 @@ var runVitest = async (dir, opts) => {
|
|
|
2162
2183
|
};
|
|
2163
2184
|
|
|
2164
2185
|
// src/cli/commands/eval.command.ts
|
|
2165
|
-
var
|
|
2186
|
+
var import_node_fs2 = require("fs");
|
|
2166
2187
|
|
|
2167
2188
|
// src/context.ts
|
|
2168
2189
|
function overrideFlags(partial) {
|
|
@@ -2207,14 +2228,35 @@ function isGlob(str) {
|
|
|
2207
2228
|
|
|
2208
2229
|
// src/cli/commands/eval.command.ts
|
|
2209
2230
|
var createRunId = (0, import_nanoid.customAlphabet)("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", 10);
|
|
2231
|
+
function getDefaultToken(value) {
|
|
2232
|
+
if (typeof value === "string") {
|
|
2233
|
+
return value;
|
|
2234
|
+
}
|
|
2235
|
+
const authContext2 = getAuthContext();
|
|
2236
|
+
return authContext2?.token || process.env.AXIOM_TOKEN;
|
|
2237
|
+
}
|
|
2238
|
+
function getDefaultUrl(value) {
|
|
2239
|
+
if (typeof value === "string") {
|
|
2240
|
+
return value;
|
|
2241
|
+
}
|
|
2242
|
+
const authContext2 = getAuthContext();
|
|
2243
|
+
return authContext2?.url || process.env.AXIOM_URL || "https://api.axiom.co";
|
|
2244
|
+
}
|
|
2245
|
+
function getDefaultOrgId(value) {
|
|
2246
|
+
if (typeof value === "string") {
|
|
2247
|
+
return value;
|
|
2248
|
+
}
|
|
2249
|
+
const authContext2 = getAuthContext();
|
|
2250
|
+
return authContext2?.orgId ?? process.env.AXIOM_ORG_ID;
|
|
2251
|
+
}
|
|
2210
2252
|
var loadEvalCommand = (program2, flagOverrides = {}) => {
|
|
2211
2253
|
return program2.addCommand(
|
|
2212
|
-
new
|
|
2213
|
-
new
|
|
2254
|
+
new import_commander.Command("eval").description("run evals locally").addArgument(
|
|
2255
|
+
new import_commander.Argument("[target]", "file, directory, glob pattern, or eval name").default(
|
|
2214
2256
|
".",
|
|
2215
2257
|
"any *.eval.ts file in current directory"
|
|
2216
2258
|
)
|
|
2217
|
-
).option("-w, --watch true", "keep server running and watch for changes", false).option("-t, --token <TOKEN>", "axiom token",
|
|
2259
|
+
).option("-w, --watch true", "keep server running and watch for changes", false).option("-t, --token <TOKEN>", "axiom token", getDefaultToken).option("-d, --dataset <DATASET>", "axiom dataset name", process.env.AXIOM_DATASET).option("-u, --url <AXIOM URL>", "axiom url", getDefaultUrl).option("-o, --org-id <ORG ID>", "axiom organization id", getDefaultOrgId).option("-b, --baseline <BASELINE ID>", "id of baseline evaluation to compare against").option("--debug", "run locally without sending to Axiom or loading baselines", false).option("--list", "list evaluations and test cases without running them", false).action(async (target, options) => {
|
|
2218
2260
|
try {
|
|
2219
2261
|
if (options.debug) {
|
|
2220
2262
|
process.env.AXIOM_DEBUG = "true";
|
|
@@ -2223,12 +2265,22 @@ var loadEvalCommand = (program2, flagOverrides = {}) => {
|
|
|
2223
2265
|
let exclude;
|
|
2224
2266
|
let testNamePattern;
|
|
2225
2267
|
const isGlobPattern = isGlob(target);
|
|
2226
|
-
const { config } = await loadConfig(".");
|
|
2268
|
+
const { config: loadedConfig } = await loadConfig(".");
|
|
2269
|
+
const config = {
|
|
2270
|
+
...loadedConfig,
|
|
2271
|
+
eval: {
|
|
2272
|
+
...loadedConfig.eval,
|
|
2273
|
+
...options.token && { token: options.token },
|
|
2274
|
+
...options.url && { url: options.url },
|
|
2275
|
+
...options.dataset && { dataset: options.dataset },
|
|
2276
|
+
...options.orgId && { orgId: options.orgId }
|
|
2277
|
+
}
|
|
2278
|
+
};
|
|
2227
2279
|
if (isGlobPattern) {
|
|
2228
2280
|
include = [target];
|
|
2229
2281
|
} else {
|
|
2230
2282
|
try {
|
|
2231
|
-
const stat = (0,
|
|
2283
|
+
const stat = (0, import_node_fs2.lstatSync)(target);
|
|
2232
2284
|
if (stat.isDirectory()) {
|
|
2233
2285
|
include = config?.eval?.include || [];
|
|
2234
2286
|
} else {
|
|
@@ -2276,10 +2328,360 @@ var loadEvalCommand = (program2, flagOverrides = {}) => {
|
|
|
2276
2328
|
);
|
|
2277
2329
|
};
|
|
2278
2330
|
|
|
2331
|
+
// src/cli/commands/auth-login.command.ts
|
|
2332
|
+
var BASE_HOSTNAME = "axiom.co";
|
|
2333
|
+
var getApiUrl = (hostname) => {
|
|
2334
|
+
return `https://api.${hostname}`;
|
|
2335
|
+
};
|
|
2336
|
+
var getOauthUrl = (hostname) => {
|
|
2337
|
+
return `https://login.${hostname}`;
|
|
2338
|
+
};
|
|
2339
|
+
async function promptSelect(message, choices) {
|
|
2340
|
+
console.log(`
|
|
2341
|
+
${message}`);
|
|
2342
|
+
choices.forEach((choice, index) => {
|
|
2343
|
+
console.log(` ${index + 1}. ${choice.name}`);
|
|
2344
|
+
});
|
|
2345
|
+
const readline = await import("readline");
|
|
2346
|
+
const rl = readline.createInterface({
|
|
2347
|
+
input: process.stdin,
|
|
2348
|
+
output: process.stdout
|
|
2349
|
+
});
|
|
2350
|
+
return new Promise((resolve3) => {
|
|
2351
|
+
const askQuestion = () => {
|
|
2352
|
+
rl.question(`
|
|
2353
|
+
Select (1-${choices.length}): `, (answer) => {
|
|
2354
|
+
const index = parseInt(answer.trim(), 10) - 1;
|
|
2355
|
+
if (index >= 0 && index < choices.length) {
|
|
2356
|
+
rl.close();
|
|
2357
|
+
resolve3(choices[index].value);
|
|
2358
|
+
} else {
|
|
2359
|
+
console.log("Invalid selection. Please try again.");
|
|
2360
|
+
askQuestion();
|
|
2361
|
+
}
|
|
2362
|
+
});
|
|
2363
|
+
};
|
|
2364
|
+
askQuestion();
|
|
2365
|
+
});
|
|
2366
|
+
}
|
|
2367
|
+
async function promptInput(message, defaultValue) {
|
|
2368
|
+
const readline = await import("readline");
|
|
2369
|
+
const rl = readline.createInterface({
|
|
2370
|
+
input: process.stdin,
|
|
2371
|
+
output: process.stdout
|
|
2372
|
+
});
|
|
2373
|
+
return new Promise((resolve3) => {
|
|
2374
|
+
const prompt = defaultValue ? `${message} (${defaultValue}): ` : `${message}: `;
|
|
2375
|
+
rl.question(prompt, (answer) => {
|
|
2376
|
+
rl.close();
|
|
2377
|
+
resolve3(answer.trim() || defaultValue || "");
|
|
2378
|
+
});
|
|
2379
|
+
});
|
|
2380
|
+
}
|
|
2381
|
+
async function openBrowser(url) {
|
|
2382
|
+
const { default: open } = await import("open");
|
|
2383
|
+
await open(url);
|
|
2384
|
+
}
|
|
2385
|
+
async function loginCommand(hostname) {
|
|
2386
|
+
try {
|
|
2387
|
+
console.log("\u{1F510} Starting authentication flow...\n");
|
|
2388
|
+
const codeVerifier = OAuth.generateCodeVerifier();
|
|
2389
|
+
const codeChallenge = OAuth.generateCodeChallenge(codeVerifier);
|
|
2390
|
+
const state = OAuth.generateState();
|
|
2391
|
+
const oauth = new OAuth(getOauthUrl(hostname));
|
|
2392
|
+
const { server, url: redirectUri } = await startCallbackServer();
|
|
2393
|
+
console.log(`\u2713 Started local callback server on ${redirectUri}
|
|
2394
|
+
`);
|
|
2395
|
+
const authUrl = oauth.buildAuthUrl({
|
|
2396
|
+
redirectUri,
|
|
2397
|
+
state,
|
|
2398
|
+
codeChallenge
|
|
2399
|
+
});
|
|
2400
|
+
console.log("Opening browser for authentication...");
|
|
2401
|
+
console.log(`If the browser doesn't open, visit: ${authUrl}
|
|
2402
|
+
`);
|
|
2403
|
+
try {
|
|
2404
|
+
await openBrowser(authUrl);
|
|
2405
|
+
} catch {
|
|
2406
|
+
console.log("Could not open browser automatically.\n");
|
|
2407
|
+
}
|
|
2408
|
+
console.log("Waiting for authentication...");
|
|
2409
|
+
const { code } = await waitForCallback(server, state);
|
|
2410
|
+
console.log("\u2713 Authentication successful, exchanging code for token...\n");
|
|
2411
|
+
const accessToken = await oauth.exchangeCodeForToken({
|
|
2412
|
+
code,
|
|
2413
|
+
redirectUri,
|
|
2414
|
+
codeVerifier
|
|
2415
|
+
});
|
|
2416
|
+
console.log("\u2713 Token received, fetching organizations...\n");
|
|
2417
|
+
const organizations = await fetchOrganizations(accessToken, getApiUrl(hostname));
|
|
2418
|
+
if (organizations.length === 0) {
|
|
2419
|
+
throw new AxiomCLIError("No organizations found for this account");
|
|
2420
|
+
}
|
|
2421
|
+
let selectedOrgId;
|
|
2422
|
+
if (organizations.length === 1) {
|
|
2423
|
+
selectedOrgId = organizations[0].id;
|
|
2424
|
+
console.log(`\u2713 Using organization: ${organizations[0].name}
|
|
2425
|
+
`);
|
|
2426
|
+
} else {
|
|
2427
|
+
selectedOrgId = await promptSelect(
|
|
2428
|
+
"Select an organization:",
|
|
2429
|
+
organizations.map((org) => ({
|
|
2430
|
+
name: `${org.name} (${org.id})`,
|
|
2431
|
+
value: org.id
|
|
2432
|
+
}))
|
|
2433
|
+
);
|
|
2434
|
+
}
|
|
2435
|
+
const selectedOrg = organizations.find((org) => org.id === selectedOrgId);
|
|
2436
|
+
const defaultAlias = selectedOrg.slug || selectedOrg.name.toLowerCase().replace(/\s+/g, "-");
|
|
2437
|
+
const alias = await promptInput("Enter profile alias", defaultAlias);
|
|
2438
|
+
console.log("\n\u2713 Verifying credentials...\n");
|
|
2439
|
+
const isValid = await verifyToken(accessToken, selectedOrgId, getApiUrl(hostname));
|
|
2440
|
+
if (!isValid) {
|
|
2441
|
+
throw new AxiomCLIError("Token verification failed");
|
|
2442
|
+
}
|
|
2443
|
+
const config = await loadGlobalConfig();
|
|
2444
|
+
config.active_profile = alias;
|
|
2445
|
+
config.profiles[alias] = {
|
|
2446
|
+
url: getApiUrl(hostname),
|
|
2447
|
+
token: accessToken,
|
|
2448
|
+
org_id: selectedOrgId
|
|
2449
|
+
};
|
|
2450
|
+
await saveGlobalConfig(config);
|
|
2451
|
+
console.log(`\u2713 Successfully logged in as ${alias}`);
|
|
2452
|
+
console.log(`\u2713 Configuration saved to ${getGlobalConfigPath()}
|
|
2453
|
+
`);
|
|
2454
|
+
} catch (error) {
|
|
2455
|
+
if (error instanceof AxiomCLIError) {
|
|
2456
|
+
throw error;
|
|
2457
|
+
}
|
|
2458
|
+
throw new AxiomCLIError(`Login failed: ${error.message}`);
|
|
2459
|
+
}
|
|
2460
|
+
}
|
|
2461
|
+
function loadAuthLoginCommand(auth, root) {
|
|
2462
|
+
[auth, root].forEach((program2) => {
|
|
2463
|
+
program2.command("login").description("Authenticate with Axiom").option("--hostname <hostname>", "Axiom hostname (default: axiom.co)").action(async (options) => {
|
|
2464
|
+
try {
|
|
2465
|
+
await loginCommand(options.hostname ?? BASE_HOSTNAME);
|
|
2466
|
+
} catch (error) {
|
|
2467
|
+
if (error instanceof AxiomCLIError) {
|
|
2468
|
+
console.error(`
|
|
2469
|
+
\u274C Error: ${error.message}
|
|
2470
|
+
`);
|
|
2471
|
+
} else {
|
|
2472
|
+
console.error(`
|
|
2473
|
+
\u274C Unexpected error: ${error.message}
|
|
2474
|
+
`);
|
|
2475
|
+
}
|
|
2476
|
+
process.exit(1);
|
|
2477
|
+
}
|
|
2478
|
+
});
|
|
2479
|
+
});
|
|
2480
|
+
}
|
|
2481
|
+
|
|
2482
|
+
// src/cli/commands/auth-logout.command.ts
|
|
2483
|
+
async function logoutCommand(alias) {
|
|
2484
|
+
const config = await loadGlobalConfig();
|
|
2485
|
+
const profileToRemove = alias || config.active_profile;
|
|
2486
|
+
if (!profileToRemove) {
|
|
2487
|
+
throw new AxiomCLIError("No active profile. Use --alias to specify which profile to remove.");
|
|
2488
|
+
}
|
|
2489
|
+
if (!config.profiles[profileToRemove]) {
|
|
2490
|
+
throw new AxiomCLIError(`Profile "${profileToRemove}" not found`);
|
|
2491
|
+
}
|
|
2492
|
+
delete config.profiles[profileToRemove];
|
|
2493
|
+
if (config.active_profile === profileToRemove) {
|
|
2494
|
+
const remainingProfiles = Object.keys(config.profiles);
|
|
2495
|
+
config.active_profile = remainingProfiles.length > 0 ? remainingProfiles[0] : void 0;
|
|
2496
|
+
}
|
|
2497
|
+
await saveGlobalConfig(config);
|
|
2498
|
+
console.log(`\u2713 Logged out from ${profileToRemove}`);
|
|
2499
|
+
if (config.active_profile) {
|
|
2500
|
+
console.log(`\u2713 Active profile is now: ${config.active_profile}`);
|
|
2501
|
+
} else {
|
|
2502
|
+
console.log('No active profiles remaining. Run "axiom auth login" to authenticate.');
|
|
2503
|
+
}
|
|
2504
|
+
}
|
|
2505
|
+
function loadAuthLogoutCommand(auth, root) {
|
|
2506
|
+
[auth, root].forEach((program2) => {
|
|
2507
|
+
program2.command("logout").description("Remove authentication credentials").option("-a, --alias <alias>", "Profile alias to remove").action(async (options) => {
|
|
2508
|
+
try {
|
|
2509
|
+
await logoutCommand(options.alias);
|
|
2510
|
+
} catch (error) {
|
|
2511
|
+
if (error instanceof AxiomCLIError) {
|
|
2512
|
+
console.error(`
|
|
2513
|
+
\u274C Error: ${error.message}
|
|
2514
|
+
`);
|
|
2515
|
+
} else {
|
|
2516
|
+
console.error(`
|
|
2517
|
+
\u274C Unexpected error: ${error.message}
|
|
2518
|
+
`);
|
|
2519
|
+
}
|
|
2520
|
+
process.exit(1);
|
|
2521
|
+
}
|
|
2522
|
+
});
|
|
2523
|
+
});
|
|
2524
|
+
}
|
|
2525
|
+
|
|
2526
|
+
// src/cli/commands/auth-status.command.ts
|
|
2527
|
+
async function statusCommand() {
|
|
2528
|
+
const config = await loadGlobalConfig();
|
|
2529
|
+
if (Object.keys(config.profiles).length === 0) {
|
|
2530
|
+
console.log("No authenticated profiles found.");
|
|
2531
|
+
console.log('Run "axiom auth login" to authenticate.');
|
|
2532
|
+
return;
|
|
2533
|
+
}
|
|
2534
|
+
console.log("\nAuthentication Status:\n");
|
|
2535
|
+
for (const [alias, profile] of Object.entries(config.profiles)) {
|
|
2536
|
+
const isActive = config.active_profile === alias;
|
|
2537
|
+
const marker = isActive ? "\u2192" : " ";
|
|
2538
|
+
try {
|
|
2539
|
+
const isValid = await verifyToken(profile.token, profile.org_id, profile.url);
|
|
2540
|
+
const status = isValid ? "\u2713" : "\u2717";
|
|
2541
|
+
const statusText = isValid ? "Valid" : "Invalid";
|
|
2542
|
+
console.log(`${marker} ${status} ${alias}`);
|
|
2543
|
+
console.log(` URL: ${profile.url}`);
|
|
2544
|
+
console.log(` Org ID: ${profile.org_id}`);
|
|
2545
|
+
console.log(` Status: ${statusText}`);
|
|
2546
|
+
if (isActive) {
|
|
2547
|
+
console.log(` (Active)`);
|
|
2548
|
+
}
|
|
2549
|
+
console.log();
|
|
2550
|
+
} catch (error) {
|
|
2551
|
+
console.log(`${marker} \u2717 ${alias}`);
|
|
2552
|
+
console.log(` URL: ${profile.url}`);
|
|
2553
|
+
console.log(` Org ID: ${profile.org_id}`);
|
|
2554
|
+
console.log(` Status: Error - ${error.message}`);
|
|
2555
|
+
if (isActive) {
|
|
2556
|
+
console.log(` (Active)`);
|
|
2557
|
+
}
|
|
2558
|
+
console.log();
|
|
2559
|
+
}
|
|
2560
|
+
}
|
|
2561
|
+
const activeProfile = getActiveProfile(config);
|
|
2562
|
+
if (process.env.AXIOM_TOKEN) {
|
|
2563
|
+
console.log("Note: Using AXIOM_TOKEN environment variable (overrides config file)\n");
|
|
2564
|
+
} else if (activeProfile && config.active_profile) {
|
|
2565
|
+
console.log(`Active profile: ${config.active_profile}
|
|
2566
|
+
`);
|
|
2567
|
+
}
|
|
2568
|
+
}
|
|
2569
|
+
function loadAuthStatusCommand(program2) {
|
|
2570
|
+
program2.command("status").description("Check authentication status for all profiles").action(async () => {
|
|
2571
|
+
try {
|
|
2572
|
+
await statusCommand();
|
|
2573
|
+
} catch (error) {
|
|
2574
|
+
if (error instanceof AxiomCLIError) {
|
|
2575
|
+
console.error(`
|
|
2576
|
+
\u274C Error: ${error.message}
|
|
2577
|
+
`);
|
|
2578
|
+
} else {
|
|
2579
|
+
console.error(`
|
|
2580
|
+
\u274C Unexpected error: ${error.message}
|
|
2581
|
+
`);
|
|
2582
|
+
}
|
|
2583
|
+
process.exit(1);
|
|
2584
|
+
}
|
|
2585
|
+
});
|
|
2586
|
+
}
|
|
2587
|
+
|
|
2588
|
+
// src/cli/commands/auth-switch.command.ts
|
|
2589
|
+
async function promptSelect2(message, choices) {
|
|
2590
|
+
console.log(`
|
|
2591
|
+
${message}`);
|
|
2592
|
+
choices.forEach((choice, index) => {
|
|
2593
|
+
console.log(` ${index + 1}. ${choice.name}`);
|
|
2594
|
+
});
|
|
2595
|
+
const readline = await import("readline");
|
|
2596
|
+
const rl = readline.createInterface({
|
|
2597
|
+
input: process.stdin,
|
|
2598
|
+
output: process.stdout
|
|
2599
|
+
});
|
|
2600
|
+
return new Promise((resolve3) => {
|
|
2601
|
+
const askQuestion = () => {
|
|
2602
|
+
rl.question(`
|
|
2603
|
+
Select (1-${choices.length}): `, (answer) => {
|
|
2604
|
+
const index = parseInt(answer.trim(), 10) - 1;
|
|
2605
|
+
if (index >= 0 && index < choices.length) {
|
|
2606
|
+
rl.close();
|
|
2607
|
+
resolve3(choices[index].value);
|
|
2608
|
+
} else {
|
|
2609
|
+
console.log("Invalid selection. Please try again.");
|
|
2610
|
+
askQuestion();
|
|
2611
|
+
}
|
|
2612
|
+
});
|
|
2613
|
+
};
|
|
2614
|
+
askQuestion();
|
|
2615
|
+
});
|
|
2616
|
+
}
|
|
2617
|
+
async function switchCommand(alias) {
|
|
2618
|
+
const config = await loadGlobalConfig();
|
|
2619
|
+
if (Object.keys(config.profiles).length === 0) {
|
|
2620
|
+
throw new AxiomCLIError(
|
|
2621
|
+
'No authenticated profiles found. Run "axiom auth login" to authenticate.'
|
|
2622
|
+
);
|
|
2623
|
+
}
|
|
2624
|
+
let selectedAlias;
|
|
2625
|
+
if (alias) {
|
|
2626
|
+
if (!config.profiles[alias]) {
|
|
2627
|
+
throw new AxiomCLIError(`Profile "${alias}" not found`);
|
|
2628
|
+
}
|
|
2629
|
+
selectedAlias = alias;
|
|
2630
|
+
} else {
|
|
2631
|
+
const profiles = Object.entries(config.profiles).map(([alias2, profile]) => ({
|
|
2632
|
+
name: `${alias2} (${profile.url})`,
|
|
2633
|
+
value: alias2
|
|
2634
|
+
}));
|
|
2635
|
+
if (profiles.length === 1) {
|
|
2636
|
+
selectedAlias = profiles[0].value;
|
|
2637
|
+
console.log(`\u2713 Using profile: ${selectedAlias}
|
|
2638
|
+
`);
|
|
2639
|
+
} else {
|
|
2640
|
+
selectedAlias = await promptSelect2("Select a profile to switch to:", profiles);
|
|
2641
|
+
}
|
|
2642
|
+
}
|
|
2643
|
+
if (config.active_profile === selectedAlias) {
|
|
2644
|
+
console.log(`\u2713 Profile "${selectedAlias}" is already active
|
|
2645
|
+
`);
|
|
2646
|
+
return;
|
|
2647
|
+
}
|
|
2648
|
+
config.active_profile = selectedAlias;
|
|
2649
|
+
await saveGlobalConfig(config);
|
|
2650
|
+
console.log(`\u2713 Switched to profile: ${selectedAlias}
|
|
2651
|
+
`);
|
|
2652
|
+
}
|
|
2653
|
+
function loadAuthSwitchCommand(program2) {
|
|
2654
|
+
program2.command("switch").description("Switch to a different profile").argument("[alias]", "Profile alias to switch to").action(async (alias) => {
|
|
2655
|
+
try {
|
|
2656
|
+
await switchCommand(alias);
|
|
2657
|
+
} catch (error) {
|
|
2658
|
+
if (error instanceof AxiomCLIError) {
|
|
2659
|
+
console.error(`
|
|
2660
|
+
\u274C Error: ${error.message}
|
|
2661
|
+
`);
|
|
2662
|
+
} else {
|
|
2663
|
+
console.error(`
|
|
2664
|
+
\u274C Unexpected error: ${error.message}
|
|
2665
|
+
`);
|
|
2666
|
+
}
|
|
2667
|
+
process.exit(1);
|
|
2668
|
+
}
|
|
2669
|
+
});
|
|
2670
|
+
}
|
|
2671
|
+
|
|
2672
|
+
// src/cli/commands/auth.command.ts
|
|
2673
|
+
function loadAuthCommand(program2) {
|
|
2674
|
+
const auth = program2.command("auth").description("Manage authentication with Axiom");
|
|
2675
|
+
loadAuthLoginCommand(auth, program2);
|
|
2676
|
+
loadAuthLogoutCommand(auth, program2);
|
|
2677
|
+
loadAuthStatusCommand(auth);
|
|
2678
|
+
loadAuthSwitchCommand(auth);
|
|
2679
|
+
}
|
|
2680
|
+
|
|
2279
2681
|
// src/cli/utils/parse-flag-overrides.ts
|
|
2280
2682
|
var import_zod5 = require("zod");
|
|
2281
|
-
var
|
|
2282
|
-
var
|
|
2683
|
+
var import_node_fs3 = require("fs");
|
|
2684
|
+
var import_node_path3 = require("path");
|
|
2283
2685
|
var FLAG_RE = /^--flag\.([^=]+)(?:=(.*))?$/;
|
|
2284
2686
|
var CONFIG_RE = /^--flags-config(?:=(.*))?$/;
|
|
2285
2687
|
function ensureNoSpaceSeparatedSyntax(flagName, value, nextToken, flagType) {
|
|
@@ -2308,10 +2710,10 @@ function coerceValue(raw) {
|
|
|
2308
2710
|
return raw;
|
|
2309
2711
|
}
|
|
2310
2712
|
}
|
|
2311
|
-
function loadConfigFile(
|
|
2312
|
-
const abs = (0,
|
|
2713
|
+
function loadConfigFile(path3) {
|
|
2714
|
+
const abs = (0, import_node_path3.resolve)(process.cwd(), path3);
|
|
2313
2715
|
try {
|
|
2314
|
-
const contents = (0,
|
|
2716
|
+
const contents = (0, import_node_fs3.readFileSync)(abs, "utf8");
|
|
2315
2717
|
const parsed = JSON.parse(contents);
|
|
2316
2718
|
if (typeof parsed !== "object" || Array.isArray(parsed) || parsed === null) {
|
|
2317
2719
|
console.error(
|
|
@@ -2321,7 +2723,7 @@ function loadConfigFile(path4) {
|
|
|
2321
2723
|
}
|
|
2322
2724
|
return parsed;
|
|
2323
2725
|
} catch (err) {
|
|
2324
|
-
console.error(`\u274C Could not read or parse flags config "${
|
|
2726
|
+
console.error(`\u274C Could not read or parse flags config "${path3}": ${err.message}`);
|
|
2325
2727
|
process.exit(1);
|
|
2326
2728
|
}
|
|
2327
2729
|
}
|
|
@@ -2380,11 +2782,11 @@ function extractOverrides(argv) {
|
|
|
2380
2782
|
var import_env = __toESM(require("@next/env"), 1);
|
|
2381
2783
|
|
|
2382
2784
|
// src/cli/commands/version.command.ts
|
|
2383
|
-
var
|
|
2785
|
+
var import_commander2 = require("commander");
|
|
2384
2786
|
var loadVersionCommand = (program2) => {
|
|
2385
2787
|
return program2.addCommand(
|
|
2386
|
-
new
|
|
2387
|
-
console.log("0.
|
|
2788
|
+
new import_commander2.Command("version").description("cli version").action(() => {
|
|
2789
|
+
console.log("0.27.0");
|
|
2388
2790
|
})
|
|
2389
2791
|
);
|
|
2390
2792
|
};
|
|
@@ -2393,10 +2795,31 @@ var loadVersionCommand = (program2) => {
|
|
|
2393
2795
|
var { loadEnvConfig } = import_env.default;
|
|
2394
2796
|
loadEnvConfig(process.cwd());
|
|
2395
2797
|
var { cleanedArgv, overrides } = extractOverrides(process.argv.slice(2));
|
|
2396
|
-
var program = new
|
|
2397
|
-
program.name("axiom").description("Axiom's CLI to manage your objects and run evals").version("0.
|
|
2398
|
-
|
|
2399
|
-
|
|
2798
|
+
var program = new import_commander3.Command();
|
|
2799
|
+
program.name("axiom").description("Axiom's CLI to manage your objects and run evals").version("0.27.0");
|
|
2800
|
+
program.hook("preAction", async (_, actionCommand) => {
|
|
2801
|
+
const commandName = actionCommand.name();
|
|
2802
|
+
const parentCommand = actionCommand.parent;
|
|
2803
|
+
const parentName = parentCommand?.name();
|
|
2804
|
+
if (commandName === "auth" || parentName === "auth" || commandName === "version") {
|
|
2805
|
+
return;
|
|
2806
|
+
}
|
|
2807
|
+
try {
|
|
2808
|
+
await setupGlobalAuth();
|
|
2809
|
+
} catch (error) {
|
|
2810
|
+
if (error instanceof Error) {
|
|
2811
|
+
console.error(`
|
|
2812
|
+
\u274C ${error.message}
|
|
2813
|
+
`);
|
|
2814
|
+
} else {
|
|
2815
|
+
console.error(`
|
|
2816
|
+
\u274C Unexpected error: ${String(error)}
|
|
2817
|
+
`);
|
|
2818
|
+
}
|
|
2819
|
+
process.exit(1);
|
|
2820
|
+
}
|
|
2821
|
+
});
|
|
2822
|
+
loadAuthCommand(program);
|
|
2400
2823
|
loadEvalCommand(program, overrides);
|
|
2401
2824
|
loadVersionCommand(program);
|
|
2402
2825
|
program.parse(["node", "axiom", ...cleanedArgv]);
|