@zenera/neo 1.1.24 → 1.1.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/agent.js +2 -1
  2. package/dist/index.d.ts +3 -0
  3. package/dist/index.js +3 -0
  4. package/dist/inspect/client.d.ts +1 -1
  5. package/dist/inspect/client.js +82 -11
  6. package/dist/inspect/css.d.ts +1 -1
  7. package/dist/inspect/css.js +1 -0
  8. package/dist/inspect/index.d.ts +1 -1
  9. package/dist/inspect/report.d.ts +9 -0
  10. package/dist/inspect/report.js +1 -0
  11. package/dist/lock.d.ts +27 -0
  12. package/dist/lock.js +66 -0
  13. package/dist/match.d.ts +44 -0
  14. package/dist/match.js +100 -0
  15. package/dist/memory/diff.d.ts +39 -0
  16. package/dist/memory/diff.js +95 -0
  17. package/dist/memory/files.d.ts +1 -1
  18. package/dist/memory/grep.d.ts +1 -1
  19. package/dist/memory/grep.js +2 -2
  20. package/dist/memory/instructions.d.ts +15 -0
  21. package/dist/memory/instructions.js +103 -0
  22. package/dist/memory/merge.js +1 -31
  23. package/dist/memory/store.d.ts +1 -5
  24. package/dist/memory/store.js +7 -53
  25. package/dist/memory/twin.d.ts +6 -0
  26. package/dist/memory/twin.js +40 -0
  27. package/dist/memory-stores/factory.d.ts +15 -0
  28. package/dist/memory-stores/factory.js +29 -0
  29. package/dist/memory-stores/file.d.ts +37 -0
  30. package/dist/memory-stores/file.js +174 -0
  31. package/dist/memory-stores/in-memory.d.ts +17 -0
  32. package/dist/memory-stores/in-memory.js +80 -0
  33. package/dist/memory-stores/index.d.ts +4 -0
  34. package/dist/memory-stores/index.js +5 -0
  35. package/dist/memory.d.ts +115 -0
  36. package/dist/memory.js +213 -0
  37. package/dist/models/factory.d.ts +24 -0
  38. package/dist/models/factory.js +153 -14
  39. package/dist/project/config.d.ts +9 -9
  40. package/dist/runner.js +7 -0
  41. package/dist/tools/sandbox.js +40 -2
  42. package/package.json +1 -1
package/dist/runner.js CHANGED
@@ -449,6 +449,13 @@ export class AgentRunner {
449
449
  catch (e) {
450
450
  return fail(`error: arguments are not valid JSON: ${String(e)}`);
451
451
  }
452
+ if (typeof args !== 'object' || args === null || Array.isArray(args)) {
453
+ return fail(`error: arguments to ${def.name} must be a JSON object`);
454
+ }
455
+ const missing = (def.parameters.required ?? []).filter((k) => args[k] == null);
456
+ if (missing.length) {
457
+ return fail(`error: ${def.name} is missing required arguments: ${missing.join(', ')}`);
458
+ }
452
459
  try {
453
460
  const out = await def.execute(args, {
454
461
  ctx: state.context,
@@ -243,7 +243,10 @@ export class Sandbox {
243
243
  this.#created = true;
244
244
  return;
245
245
  }
246
- await this.#must(this.#createArgs(), `could not create container ${this.name}`);
246
+ const made = await this.#podman(this.#createArgs());
247
+ if (made.code !== 0) {
248
+ throw new SandboxError(`could not create container ${this.name}: ${message(made)}`, LOCKS.test(made.stderr) ? locksHint(this.spec.engine) : undefined);
249
+ }
247
250
  this.#created = true;
248
251
  }
249
252
  #createArgs() {
@@ -320,7 +323,13 @@ export class Sandbox {
320
323
  const cwd = this.inside(opts.cwd);
321
324
  const timeoutMs = this.#timeout(opts.timeout);
322
325
  const startedAt = Date.now();
323
- const res = await this.#run(this.spec.engine, ['exec', '--interactive', '--workdir', cwd, this.name, '/bin/sh', '-s'], { input: command, timeoutMs, signal: opts.signal });
326
+ const once = () => this.#run(this.spec.engine, ['exec', '--interactive', '--workdir', cwd, this.name, '/bin/sh', '-s'], { input: command, timeoutMs, signal: opts.signal });
327
+ let res = await once();
328
+ if (gone(res)) {
329
+ // podman refused before running anything, so the retry cannot run the command twice.
330
+ await this.#revive(res);
331
+ res = await once();
332
+ }
324
333
  return {
325
334
  exit_code: res.code,
326
335
  stdout: res.stdout,
@@ -527,6 +536,18 @@ export class Sandbox {
527
536
  #podman(args) {
528
537
  return this.#run(this.spec.engine, args, { timeoutMs: 120_000 });
529
538
  }
539
+ /** The container stopped or vanished under us (machine slept, restarted, or someone removed it). */
540
+ async #revive(res) {
541
+ this.#ready = undefined;
542
+ try {
543
+ await this.start();
544
+ }
545
+ catch (err) {
546
+ throw new SandboxError(`the sandbox container ${this.name} stopped (${message(res)}) and could not be restarted: ` +
547
+ (err instanceof Error ? err.message : String(err)), `the ${this.spec.engine} machine may have stopped or restarted — check \`${this.spec.engine} machine list\`, ` +
548
+ `start it with \`${this.spec.engine} machine start\`, then retry`);
549
+ }
550
+ }
530
551
  async #must(args, what) {
531
552
  const res = await this.#podman(args);
532
553
  if (res.code !== 0) {
@@ -541,6 +562,23 @@ function mount(m) {
541
562
  function message(res) {
542
563
  return (res.stderr.trim() || res.stdout.trim() || `exit ${res.code}`).split('\n')[0];
543
564
  }
565
+ /** podman's words for "every lock is taken": `allocating lock … exceeded num_locks (2048)`. */
566
+ const LOCKS = /exceeded num_locks|allocating lock/i;
567
+ /**
568
+ * A stopped container holds a lock as surely as a running one, and a
569
+ * persisted sandbox is stopped, never removed — so they pile up one per
570
+ * session until the engine can create nothing at all, for anyone.
571
+ */
572
+ function locksHint(engine) {
573
+ return (`the ${engine} engine has no locks left: every container it holds, stopped ones ` +
574
+ `included, takes one. Remove the stopped sandbox containers with ` +
575
+ `\`${engine} container prune --force --filter label=zenera=1\`, then retry`);
576
+ }
577
+ /** podman's own exit code for "could not exec at all", with the two reasons that mean the container is not there to exec in. */
578
+ function gone(res) {
579
+ return (res.code === 125 &&
580
+ /can only create exec sessions on running containers|container state improper|no such container/i.test(res.stderr));
581
+ }
544
582
  /** Only ever applied to paths this module derived, never to a model's text. */
545
583
  function quote(s) {
546
584
  return `'${s.replaceAll("'", `'\\''`)}'`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenera/neo",
3
- "version": "1.1.24",
3
+ "version": "1.1.26",
4
4
  "description": "A multi-agent runtime for Node.js: agents, models, tools, skills, memory and an append-only trajectory.",
5
5
  "keywords": [
6
6
  "agents",