@axiom-lattice/core 3.1.0 → 3.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -17030,6 +17030,51 @@ var FilesystemBackend = class {
17030
17030
  throw new Error(`Path: ${resolvedPath} outside root directory: ${this.cwd}`);
17031
17031
  }
17032
17032
  }
17033
+ async assertVirtualOpenedFileContained(resolvedPath, openedStat) {
17034
+ if (!this.virtualMode) {
17035
+ return;
17036
+ }
17037
+ const [rootPath, realFilePath] = await Promise.all([
17038
+ fs2.realpath(this.cwd),
17039
+ fs2.realpath(resolvedPath)
17040
+ ]);
17041
+ const relative4 = path4.relative(rootPath, realFilePath);
17042
+ if (relative4 === ".." || relative4.startsWith(`..${path4.sep}`) || path4.isAbsolute(relative4)) {
17043
+ throw new Error(`Path: ${resolvedPath} outside root directory: ${this.cwd}`);
17044
+ }
17045
+ const realPathStat = await fs2.stat(realFilePath);
17046
+ if (realPathStat.dev !== openedStat.dev || realPathStat.ino !== openedStat.ino) {
17047
+ throw new Error(`File changed during secure read: ${resolvedPath}`);
17048
+ }
17049
+ }
17050
+ async readFileBuffer(filePath) {
17051
+ const resolvedPath = this.resolvePath(filePath);
17052
+ await this.assertVirtualParentContained(resolvedPath);
17053
+ if (!SUPPORTS_NOFOLLOW) {
17054
+ const initialStat = await fs2.lstat(resolvedPath);
17055
+ if (initialStat.isSymbolicLink()) {
17056
+ throw new Error(`Symlinks are not allowed: ${filePath}`);
17057
+ }
17058
+ }
17059
+ const flags = SUPPORTS_NOFOLLOW ? fsSync.constants.O_RDONLY | fsSync.constants.O_NOFOLLOW : fsSync.constants.O_RDONLY;
17060
+ const fd = await fs2.open(resolvedPath, flags);
17061
+ try {
17062
+ const stat4 = await fd.stat();
17063
+ if (!stat4.isFile()) {
17064
+ throw new Error(`File '${filePath}' not found`);
17065
+ }
17066
+ await this.assertVirtualOpenedFileContained(resolvedPath, stat4);
17067
+ if (!SUPPORTS_NOFOLLOW) {
17068
+ const finalStat = await fs2.lstat(resolvedPath);
17069
+ if (finalStat.isSymbolicLink() || finalStat.dev !== stat4.dev || finalStat.ino !== stat4.ino) {
17070
+ throw new Error(`File changed during secure read: ${resolvedPath}`);
17071
+ }
17072
+ }
17073
+ return { content: await fd.readFile(), stat: stat4 };
17074
+ } finally {
17075
+ await fd.close();
17076
+ }
17077
+ }
17033
17078
  validateDeleteTarget(filePath, stat4) {
17034
17079
  if (stat4.isSymbolicLink()) {
17035
17080
  return `Error: Cannot delete '${filePath}': symlinks are not allowed`;
@@ -17129,32 +17174,8 @@ var FilesystemBackend = class {
17129
17174
  */
17130
17175
  async read(filePath, offset = 0, limit = 2e3) {
17131
17176
  try {
17132
- const resolvedPath = this.resolvePath(filePath);
17133
- let content;
17134
- if (SUPPORTS_NOFOLLOW) {
17135
- const stat4 = await fs2.stat(resolvedPath);
17136
- if (!stat4.isFile()) {
17137
- return `Error: File '${filePath}' not found`;
17138
- }
17139
- const fd = await fs2.open(
17140
- resolvedPath,
17141
- fsSync.constants.O_RDONLY | fsSync.constants.O_NOFOLLOW
17142
- );
17143
- try {
17144
- content = await fd.readFile({ encoding: "utf-8" });
17145
- } finally {
17146
- await fd.close();
17147
- }
17148
- } else {
17149
- const stat4 = await fs2.lstat(resolvedPath);
17150
- if (stat4.isSymbolicLink()) {
17151
- return `Error: Symlinks are not allowed: ${filePath}`;
17152
- }
17153
- if (!stat4.isFile()) {
17154
- return `Error: File '${filePath}' not found`;
17155
- }
17156
- content = await fs2.readFile(resolvedPath, "utf-8");
17157
- }
17177
+ const { content: buffer2 } = await this.readFileBuffer(filePath);
17178
+ const content = buffer2.toString("utf-8");
17158
17179
  const emptyMsg = checkEmptyContent(content);
17159
17180
  if (emptyMsg) {
17160
17181
  return emptyMsg;
@@ -17178,35 +17199,19 @@ var FilesystemBackend = class {
17178
17199
  * @returns Raw file content as FileData
17179
17200
  */
17180
17201
  async readRaw(filePath) {
17181
- const resolvedPath = this.resolvePath(filePath);
17182
- let content;
17183
- let stat4;
17184
- if (SUPPORTS_NOFOLLOW) {
17185
- stat4 = await fs2.stat(resolvedPath);
17186
- if (!stat4.isFile()) throw new Error(`File '${filePath}' not found`);
17187
- const fd = await fs2.open(
17188
- resolvedPath,
17189
- fsSync.constants.O_RDONLY | fsSync.constants.O_NOFOLLOW
17190
- );
17191
- try {
17192
- content = await fd.readFile({ encoding: "utf-8" });
17193
- } finally {
17194
- await fd.close();
17195
- }
17196
- } else {
17197
- stat4 = await fs2.lstat(resolvedPath);
17198
- if (stat4.isSymbolicLink()) {
17199
- throw new Error(`Symlinks are not allowed: ${filePath}`);
17200
- }
17201
- if (!stat4.isFile()) throw new Error(`File '${filePath}' not found`);
17202
- content = await fs2.readFile(resolvedPath, "utf-8");
17203
- }
17202
+ const { content: buffer2, stat: stat4 } = await this.readFileBuffer(filePath);
17203
+ const content = buffer2.toString("utf-8");
17204
17204
  return {
17205
17205
  content: content.split("\n"),
17206
17206
  created_at: stat4.ctime.toISOString(),
17207
17207
  modified_at: stat4.mtime.toISOString()
17208
17208
  };
17209
17209
  }
17210
+ /** Read file content as raw bytes without following symbolic links. */
17211
+ async readBinary(filePath) {
17212
+ const { content } = await this.readFileBuffer(filePath);
17213
+ return content;
17214
+ }
17210
17215
  /**
17211
17216
  * Create a new file with content.
17212
17217
  * Returns WriteResult. External storage sets filesUpdate=null.
@@ -21798,7 +21803,7 @@ registerToolLattice(
21798
21803
  "update_agent",
21799
21804
  {
21800
21805
  name: "update_agent",
21801
- description: "Update an existing agent's configuration. Provide the agent ID and the fields to change. Returns the updated agent's ID and name. NOTE: For user approval/confirmation scenarios, add middleware with type: 'ask_user_to_clarify'.",
21806
+ description: "Update an existing agent's configuration. Provide the agent ID and the fields to change. Returns the updated agent's ID and name. NOTE: For user approval/confirmation scenarios, add middleware with type: 'ask_user_to_clarify'. IMPORTANT: do NOT set 'modelKey' unless the user explicitly specified a model \u2014 leaving it unset makes the runtime use the 'default' model.",
21802
21807
  schema: updateAgentSchema
21803
21808
  },
21804
21809
  async (input, exeConfig) => {
@@ -22036,6 +22041,8 @@ OVERRIDES the defaults above:
22036
22041
  (parentId); NEVER create a new parent task for the round.
22037
22042
  - The round is pre-approved \u2014 skip the DESIGN\u2192CONFIRM gates: show the
22038
22043
  design in your reply, then build directly.
22044
+ - Do NOT set modelKey in update_agent unless the user explicitly named a
22045
+ model \u2014 leaving it unset makes the runtime use the 'default' model.
22039
22046
  - Every update_agent call must be mirrored by a manage_task work item
22040
22047
  whose summary names the changed keys (e.g. "update_agent: prompt,
22041
22048
  modelKey") \u2014 the round feed highlights these so the user can see what
@@ -26625,14 +26632,22 @@ var DEFAULT_CALIBRATION_PROBES = [
26625
26632
  expectedPass: false
26626
26633
  }
26627
26634
  ];
26635
+ function resolveJudgeModelKey(explicitKey, manager) {
26636
+ if (explicitKey) return explicitKey;
26637
+ const models = manager.getAllLattices();
26638
+ const defaultModel = models.find((m) => m.key === "default");
26639
+ if (defaultModel) return defaultModel.key;
26640
+ const first = models[0];
26641
+ if (!first) {
26642
+ throw new Error("No model registered \u2014 register a model or provide a judgeModelKey");
26643
+ }
26644
+ return first.key;
26645
+ }
26628
26646
  var LatticeEvalProject = class {
26629
26647
  constructor(project, onCaseComplete) {
26630
26648
  this.suites = /* @__PURE__ */ new Map();
26631
26649
  this.project = project;
26632
- const judgeModelKey = this.project.judge_agent_config.modelKey;
26633
- if (!judgeModelKey) {
26634
- throw new Error("judge_agent_config.modelKey is required \u2014 only pre-registered models are allowed");
26635
- }
26650
+ const judgeModelKey = resolveJudgeModelKey(this.project.judge_agent_config.modelKey, modelLatticeManager);
26636
26651
  if (!modelLatticeManager.hasLattice(judgeModelKey)) {
26637
26652
  throw new Error(
26638
26653
  `Judge model "${judgeModelKey}" not found. Register it first or provide a valid modelKey.`
@@ -29063,7 +29078,9 @@ function createManageEvalTool() {
29063
29078
  data = await store.createProject(tid, uuidv48(), {
29064
29079
  name: input.name,
29065
29080
  description: input.description,
29066
- judgeModelConfig: { modelKey: input.judgeModelKey },
29081
+ // No judge key given → default to the 'default' model key (the same
29082
+ // convention the UI model selector uses); never an empty modelKey.
29083
+ judgeModelConfig: { modelKey: input.judgeModelKey ?? "default" },
29067
29084
  targetServerConfig: {
29068
29085
  workspace_id: ctx.workspaceId,
29069
29086
  project_id: ctx.projectId,
@@ -29138,7 +29155,7 @@ function createManageEvalTool() {
29138
29155
  description: `Create, update, delete evaluation projects, suites, and test cases.
29139
29156
 
29140
29157
  Project: create_project(name, description?, judgeModelKey?, concurrency?, targetAgentId?) | update_project | delete_project
29141
- judgeModelKey defaults to first available model. concurrency defaults to 3.
29158
+ judgeModelKey defaults to the "default" model. concurrency defaults to 3.
29142
29159
  delete_project rejected if active runs exist.
29143
29160
  **When creating a project from within a workspace, the workspace/project context is
29144
29161
  automatically bound \u2014 eval runs will execute in the same workspace.**
@@ -31416,6 +31433,7 @@ export {
31416
31433
  registerWorkflowRun,
31417
31434
  removeCollectionVectorStore,
31418
31435
  renderTemplate,
31436
+ resolveJudgeModelKey,
31419
31437
  resolvePath,
31420
31438
  sandboxLatticeManager,
31421
31439
  sanitizeToolCallId,