@axiom-lattice/core 3.0.3 → 3.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -12878,6 +12878,10 @@ Always set metadata on agent creation. At minimum:
12878
12878
  - verified: "unverified" (upgraded after eval passes)
12879
12879
  - version: "1.0" (bump on each update_agent)
12880
12880
  - source: the material name or "user-description"
12881
+ - role: "orchestrator" | "sub-agent" \u2014 set when the agent is part of a
12882
+ parent+subAgents structure (role clarity, User Interaction Rules).
12883
+ The eval project is NOT recorded \u2014 it is derived by naming convention
12884
+ (eval-{agent-id}, see [[eval-verify]] Setup).
12881
12885
  When trust upgrades, update both the skill's verified frontmatter and
12882
12886
  the agent's metadata.verified \u2014 they must stay in sync.
12883
12887
 
@@ -12999,8 +13003,14 @@ verified: unverified
12999
13003
  ## Setup
13000
13004
 
13001
13005
  0. Load [[eval-design-tests]] for case design guidance
13002
- 1. \`read_eval list_projects\` \u2192 find "eval-{domain}"
13003
- Exists \u2192 reuse projectId. New \u2192 create_project(name: "eval-{domain}")
13006
+ 1. **One eval project per agent**, named \`eval-{agent-id}\`:
13007
+ \`read_eval list_projects\` \u2192 find "eval-{agent-id}"
13008
+ Exists \u2192 reuse projectId. New \u2192 create_project(name: "eval-{agent-id}")
13009
+ - The agent-id is the eval project's subject. Observability: from an
13010
+ agent's id you can find its eval project by naming convention.
13011
+ - Orchestrator + subAgents \u2192 one eval project per sub-agent
13012
+ (eval-{sub-agent-id}) PLUS one integration eval project for the
13013
+ parent (eval-{parent-id}) \u2014 see Layered verification below.
13004
13014
  2. \`manage_eval create_case(suiteId, ...)\` per sample or scenario
13005
13015
  Required: inputMessage, steps=[{agent_id}], outputType, contentAssertion
13006
13016
 
@@ -23470,6 +23480,7 @@ Your sub-skills (accessible via the MOC or direct loading):
23470
23480
  - [[learn-capability]] \u2014 Learn from any source material \u2192 skills + agents
23471
23481
  - [[agent-build]] \u2014 Design and build single agents (REACT/DEEP_AGENT)
23472
23482
  - [[design-workflow]] \u2014 Design workflow agents
23483
+ - [[eval-verify]] \u2014 Run evaluations with fix loop, hold-out, trust upgrade
23473
23484
  - [[task-tracking]] \u2014 Manage persistent tasks (manage_task)
23474
23485
  - [[completion-gate]] \u2014 THE rule: no agent is "done" without eval
23475
23486
  - [[domain-moc]] \u2014 Create the domain MOC (mandatory per learning run)
@@ -30104,7 +30115,26 @@ Use read_eval get_run_results for multiple runs and present comparison.
30104
30115
  `
30105
30116
  };
30106
30117
 
30118
+ // src/tool_lattice/withToolTimeout.ts
30119
+ function withToolTimeout(executor, timeoutMs = 18e4) {
30120
+ return async (input, exeConfig) => {
30121
+ return new Promise((resolve4, reject) => {
30122
+ const timer = setTimeout(() => {
30123
+ reject(new Error(`Tool execution timed out after ${timeoutMs}ms`));
30124
+ }, timeoutMs);
30125
+ executor(input, exeConfig).then((result) => {
30126
+ clearTimeout(timer);
30127
+ resolve4(result);
30128
+ }).catch((err) => {
30129
+ clearTimeout(timer);
30130
+ reject(err);
30131
+ });
30132
+ });
30133
+ };
30134
+ }
30135
+
30107
30136
  // src/middlewares/evalMiddleware.ts
30137
+ var RUN_EVAL_SYNC_WAIT_MS = 15e4;
30108
30138
  function getStore() {
30109
30139
  return getStoreLattice("default", "eval").store;
30110
30140
  }
@@ -30131,6 +30161,23 @@ function sanitize(obj) {
30131
30161
  }
30132
30162
  return out;
30133
30163
  }
30164
+ function aggregateHoldoutResults(results) {
30165
+ const passed = results.filter((r) => r.pass).length;
30166
+ return {
30167
+ holdout: true,
30168
+ passedCases: passed,
30169
+ failedCases: results.length - passed,
30170
+ passRate: results.length > 0 ? passed / results.length : 0,
30171
+ totalCases: results.length
30172
+ };
30173
+ }
30174
+ async function runWithResults(tid, store, svc, run, runnerAlive) {
30175
+ const results = run.status === "completed" ? await store.getResultsByRun(tid, run.id) : void 0;
30176
+ if (run.holdout && results) {
30177
+ return { ...run, runnerAlive, results: aggregateHoldoutResults(results) };
30178
+ }
30179
+ return { ...run, runnerAlive, results };
30180
+ }
30134
30181
  function createReadEvalTool() {
30135
30182
  const schema6 = import_zod64.z.object({
30136
30183
  action: import_zod64.z.enum([
@@ -30365,100 +30412,119 @@ function createRunEvalTool() {
30365
30412
  projectId: import_zod64.z.string().optional().describe("Required for start"),
30366
30413
  suiteIds: import_zod64.z.array(import_zod64.z.string()).optional().describe("Optional for start \u2014 only run these suites (e.g. dev set only). Omit to run all."),
30367
30414
  caseIds: import_zod64.z.array(import_zod64.z.string()).optional().describe("Optional for start \u2014 only run these cases across the selected suites. Omit to run all cases in those suites."),
30368
- runId: import_zod64.z.string().optional().describe("Required for status, resume, abort")
30415
+ runId: import_zod64.z.string().optional().describe("Required for status, resume, abort"),
30416
+ sleepMs: import_zod64.z.number().int().min(0).max(12e4).optional().describe("Optional for status \u2014 sleep this many ms BEFORE checking the run, to pace polling (e.g. 15000 \u2192 30000 \u2192 60000 \u2192 120000). Omit to check immediately."),
30417
+ wait: import_zod64.z.boolean().optional().describe("Optional for start \u2014 defaults to true: block synchronously (up to ~150s) and return final results in one call. Set false to return the runId immediately and poll.")
30369
30418
  });
30370
30419
  return (0, import_langchain78.tool)(
30371
- async (input, exeConfig) => {
30372
- const tid = tenantId(exeConfig);
30373
- if (!tid) {
30374
- return JSON.stringify({ success: false, error: "No tenant context. Agent must be invoked through gateway." });
30375
- }
30376
- try {
30377
- const store = getStore();
30378
- const svc = getEvalRunService();
30379
- let data;
30380
- switch (input.action) {
30381
- case "start": {
30382
- const ctx = workspaceContext(exeConfig);
30383
- const runId = await svc.startRun(tid, input.projectId, input.suiteIds, input.caseIds, {
30384
- workspaceId: ctx.workspaceId,
30385
- projectId: ctx.projectId
30386
- });
30387
- data = sanitize({ runId, message: "Run started. Poll with run_eval status (backoff: 15s\u219230s\u219260s\u2192max 120s)." });
30388
- break;
30389
- }
30390
- case "status": {
30391
- const run = await store.getRunById(tid, input.runId);
30392
- if (!run) return JSON.stringify({ success: false, error: "Run not found" });
30393
- data = sanitize({ ...run, runnerAlive: svc.isRunning(input.runId) });
30394
- break;
30395
- }
30396
- case "resume": {
30397
- const run = await store.getRunById(tid, input.runId);
30398
- if (!run) return JSON.stringify({ success: false, error: "Run not found" });
30399
- const runnerAlive = svc.isRunning(input.runId);
30400
- if (run.status === "running" && !runnerAlive) {
30401
- await store.updateRunStatus(tid, run.id, {
30402
- status: "failed",
30403
- error: "Gateway restarted \u2014 run orphaned",
30404
- completedAt: /* @__PURE__ */ new Date()
30405
- });
30406
- data = sanitize({
30407
- ...run,
30408
- status: "failed",
30409
- runnerAlive: false,
30410
- message: "Run was orphaned \u2014 marked failed. Start a new run."
30411
- });
30420
+ withToolTimeout(
30421
+ async (input, exeConfig) => {
30422
+ const tid = tenantId(exeConfig);
30423
+ if (!tid) {
30424
+ return JSON.stringify({ success: false, error: "No tenant context. Agent must be invoked through gateway." });
30425
+ }
30426
+ try {
30427
+ const store = getStore();
30428
+ const svc = getEvalRunService();
30429
+ let data;
30430
+ switch (input.action) {
30431
+ case "start": {
30432
+ const ctx = workspaceContext(exeConfig);
30433
+ const runId = await svc.startRun(tid, input.projectId, input.suiteIds, input.caseIds, ctx);
30434
+ if (input.wait === false) {
30435
+ data = sanitize({ runId, message: "Run started. Poll with run_eval status (backoff: 15s\u219230s\u219260s\u2192max 120s)." });
30436
+ break;
30437
+ }
30438
+ let timer;
30439
+ try {
30440
+ await Promise.race([
30441
+ svc.waitForRun(runId).catch(() => {
30442
+ }),
30443
+ new Promise((resolve4) => {
30444
+ timer = setTimeout(resolve4, RUN_EVAL_SYNC_WAIT_MS);
30445
+ })
30446
+ ]);
30447
+ } finally {
30448
+ if (timer) clearTimeout(timer);
30449
+ }
30450
+ const run = await store.getRunById(tid, runId);
30451
+ if (!run) return JSON.stringify({ success: false, error: "Run not found" });
30452
+ if (run.status === "running") {
30453
+ data = sanitize({
30454
+ runId,
30455
+ status: "running",
30456
+ runnerAlive: svc.isRunning(runId),
30457
+ message: `Run not finished within ${RUN_EVAL_SYNC_WAIT_MS / 1e3}s \u2014 poll with run_eval status(runId, sleepMs) (e.g. 15000, doubling up to 120000), or abort with run_eval abort.`
30458
+ });
30459
+ break;
30460
+ }
30461
+ data = sanitize({ synced: true, ...await runWithResults(tid, store, svc, run, svc.isRunning(runId)) });
30412
30462
  break;
30413
30463
  }
30414
- const results = run.status === "completed" ? await store.getResultsByRun(tid, run.id) : void 0;
30415
- if (run.holdout && results) {
30416
- const passed = results.filter((r) => r.pass).length;
30417
- data = sanitize({
30418
- ...run,
30419
- runnerAlive,
30420
- results: {
30421
- holdout: true,
30422
- passedCases: passed,
30423
- failedCases: results.length - passed,
30424
- passRate: results.length > 0 ? passed / results.length : 0,
30425
- totalCases: results.length
30426
- }
30427
- });
30464
+ case "status": {
30465
+ if (input.sleepMs && input.sleepMs > 0) {
30466
+ await new Promise((resolve4) => setTimeout(resolve4, input.sleepMs));
30467
+ }
30468
+ const run = await store.getRunById(tid, input.runId);
30469
+ if (!run) return JSON.stringify({ success: false, error: "Run not found" });
30470
+ data = sanitize({ ...run, runnerAlive: svc.isRunning(input.runId) });
30428
30471
  break;
30429
30472
  }
30430
- data = sanitize({ ...run, runnerAlive, results });
30431
- break;
30432
- }
30433
- case "abort": {
30434
- const run = await store.getRunById(tid, input.runId);
30435
- if (!run) return JSON.stringify({ success: false, error: "Run not found" });
30436
- const ok = await svc.abortRun(input.runId);
30437
- data = sanitize({ aborted: ok });
30438
- break;
30473
+ case "resume": {
30474
+ const run = await store.getRunById(tid, input.runId);
30475
+ if (!run) return JSON.stringify({ success: false, error: "Run not found" });
30476
+ const runnerAlive = svc.isRunning(input.runId);
30477
+ if (run.status === "running" && !runnerAlive) {
30478
+ await store.updateRunStatus(tid, run.id, {
30479
+ status: "failed",
30480
+ error: "Gateway restarted \u2014 run orphaned",
30481
+ completedAt: /* @__PURE__ */ new Date()
30482
+ });
30483
+ data = sanitize({
30484
+ ...run,
30485
+ status: "failed",
30486
+ runnerAlive: false,
30487
+ message: "Run was orphaned \u2014 marked failed. Start a new run."
30488
+ });
30489
+ break;
30490
+ }
30491
+ data = sanitize(await runWithResults(tid, store, svc, run, runnerAlive));
30492
+ break;
30493
+ }
30494
+ case "abort": {
30495
+ const run = await store.getRunById(tid, input.runId);
30496
+ if (!run) return JSON.stringify({ success: false, error: "Run not found" });
30497
+ const ok = await svc.abortRun(input.runId);
30498
+ data = sanitize({ aborted: ok });
30499
+ break;
30500
+ }
30501
+ default:
30502
+ return JSON.stringify({ success: false, error: `Unknown action: ${input.action}` });
30439
30503
  }
30440
- default:
30441
- return JSON.stringify({ success: false, error: `Unknown action: ${input.action}` });
30504
+ return JSON.stringify({ success: true, data });
30505
+ } catch (e) {
30506
+ return JSON.stringify({ success: false, error: e.message });
30442
30507
  }
30443
- return JSON.stringify({ success: true, data });
30444
- } catch (e) {
30445
- return JSON.stringify({ success: false, error: e.message });
30446
30508
  }
30447
- },
30509
+ ),
30448
30510
  {
30449
30511
  name: "run_eval",
30450
- description: `Execute and manage evaluation runs. ASYNCHRONOUS \u2014 may take minutes.
30512
+ description: `Execute and manage evaluation runs.
30451
30513
 
30452
30514
  ACTIONS:
30453
- - start(projectId, suiteIds?, caseIds?) \u2014 begin evaluation (optionally only the listed suites, and/or only the listed cases). Returns runId.
30454
- - status(runId) \u2014 current status + runnerAlive flag:
30455
- \u2022 runnerAlive=true, status=running: keep polling
30515
+ - start(projectId, suiteIds?, caseIds?, wait?) \u2014 begin evaluation (optionally only the listed suites, and/or only the listed cases).
30516
+ wait=true (DEFAULT): SYNCHRONOUS \u2014 blocks up to ~150s and returns the FINAL RESULTS in one call:
30517
+ { status, results } with per-case pass/score (hold-out/validation runs: aggregates only \u2014 per-case details withheld by design).
30518
+ If the run exceeds 150s: returns { runId, status: "running" } \u2014 NOT an error \u2014 then poll with status/resume until completed.
30519
+ wait=false: fire-and-forget \u2014 returns { runId } immediately; poll with status.
30520
+ - status(runId, sleepMs?) \u2014 sleep sleepMs first (to pace polling), then return current status + runnerAlive flag:
30521
+ \u2022 runnerAlive=true, status=running: keep polling \u2014 call status(runId, sleepMs) with backoff 15s\u219230s\u219260s\u2192max 120s
30456
30522
  \u2022 runnerAlive=false, status=running: ORPHANED \u2014 resume marks it failed automatically; then start a new run
30457
30523
  \u2022 status=completed: get results with read_eval get_run_results or run_eval resume
30458
30524
  - resume(runId) \u2014 reconnect from new conversation. Returns status + results if completed.
30459
30525
  - abort(runId) \u2014 cancel running evaluation.
30460
30526
 
30461
- Polling: start at 15s, double each time, max 120s between polls. Batch reports.`,
30527
+ Polling (only needed with wait=false or after a sync timeout): call status(runId, sleepMs) so the tool sleeps before checking; start at 15s, double each time, max 120s between polls. Batch reports.`,
30462
30528
  schema: schema6
30463
30529
  }
30464
30530
  );
@@ -31138,7 +31204,8 @@ Both modes use the same agent type \u2014 skill only, no domain tools:
31138
31204
  verified: "unverified", # upgraded after eval passes
31139
31205
  version: "1.0", # bump on each update_agent
31140
31206
  source: "{material name}", # provenance
31141
- skill: "skill-name"
31207
+ skill: "skill-name",
31208
+ role: "orchestrator" | "sub-agent" # only for parent+subAgents structure
31142
31209
  }
31143
31210
  )
31144
31211
 
@@ -31234,6 +31301,11 @@ Run evaluation, fix loop, hold-out validation, trust upgrade. See
31234
31301
  [[eval-verify]] for the full workflow. The eval-design-tests and
31235
31302
  eval-run-and-govern skills cover case design and run governance.
31236
31303
 
31304
+ **One eval project per agent**, named \`eval-{agent-id}\` \u2014 every agent
31305
+ built by this workflow gets its own eval project (see eval-verify
31306
+ Setup). Orchestrator + subAgents \u2192 one eval project per sub-agent plus
31307
+ one integration eval for the parent.
31308
+
31237
31309
  Learning-specific suite guidance:
31238
31310
  - 0.2 \u2461 \u2192 {skill}-user-sample; samples \u22658 \u2192 also {skill}-validation
31239
31311
  - 0.2 \u2460 \u2192 {skill}-api-verified (single step, \xA74.1)
@@ -31272,11 +31344,12 @@ base is wanted (it is extra work beyond the skill).
31272
31344
  ## Fallback
31273
31345
 
31274
31346
  - All engines fail \u2192 suggest text version or different format.
31275
- - No eval agent \u2192 judge-only scoring, or build a production agent via \xA75
31276
- (generic or API-verified variant, thin prompt) \u2014 never reuse an agent
31277
- whose knowledge derives from the learning material.
31278
- Judge-only scoring does NOT unlock machine-confirmed \u2014 trust caps at
31279
- human-reviewed; say so explicitly.
31347
+ - Eval runtime unavailable (no eval agent / service down) \u2192 still
31348
+ DESIGN and CREATE the eval project with test cases (every agent MUST
31349
+ have an eval \u2014 no skip). If the eval cannot RUN now, deliver with
31350
+ trust capped at human-reviewed and state: "Test framework created;
31351
+ run the evaluation once the eval service is available." Judge-only
31352
+ scoring (when run) does NOT unlock machine-confirmed.
31280
31353
  - No test files \u2192 user-described scenarios as contentAssertion.
31281
31354
  - run_eval orphaned (resume shows runnerAlive=false) \u2192 \`run_eval resume(runId)\`
31282
31355
  marks it failed automatically; then \`run_eval start(projectId)\` to restart.