0agent 1.0.39 → 1.0.40

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 (2) hide show
  1. package/dist/daemon.mjs +130 -25
  2. package/package.json +1 -1
package/dist/daemon.mjs CHANGED
@@ -2406,14 +2406,14 @@ var init_FileCapability = __esm({
2406
2406
  "use strict";
2407
2407
  FileCapability = class {
2408
2408
  name = "file_op";
2409
- description = "Read, write, or list files. Scoped to working directory.";
2409
+ description = "Read, write, list files, or create directories. Scoped to working directory.";
2410
2410
  toolDefinition = {
2411
2411
  name: "file_op",
2412
- description: "Read, write, or list files in the working directory.",
2412
+ description: "Read, write, list files, or create directories in the working directory.",
2413
2413
  input_schema: {
2414
2414
  type: "object",
2415
2415
  properties: {
2416
- op: { type: "string", description: '"read", "write", or "list"' },
2416
+ op: { type: "string", description: '"read", "write", "list", or "mkdir"' },
2417
2417
  path: { type: "string", description: "File or directory path (relative to cwd)" },
2418
2418
  content: { type: "string", description: "Content for write operation" }
2419
2419
  },
@@ -2448,7 +2448,11 @@ var init_FileCapability = __esm({
2448
2448
  const entries = readdirSync(safe, { withFileTypes: true }).filter((e) => !e.name.startsWith(".") && e.name !== "node_modules").map((e) => `${e.isDirectory() ? "d" : "f"} ${e.name}`).join("\n");
2449
2449
  return { success: true, output: entries || "(empty)", duration_ms: Date.now() - start };
2450
2450
  }
2451
- return { success: false, output: `Unknown op: ${op}`, duration_ms: Date.now() - start };
2451
+ if (op === "mkdir") {
2452
+ mkdirSync(safe, { recursive: true });
2453
+ return { success: true, output: `Directory created: ${rel}`, duration_ms: Date.now() - start };
2454
+ }
2455
+ return { success: false, output: `Unknown op: ${op}. Use "read", "write", "list", or "mkdir"`, duration_ms: Date.now() - start };
2452
2456
  } catch (err) {
2453
2457
  return { success: false, output: `Error: ${err instanceof Error ? err.message : String(err)}`, duration_ms: Date.now() - start };
2454
2458
  }
@@ -2457,6 +2461,74 @@ var init_FileCapability = __esm({
2457
2461
  }
2458
2462
  });
2459
2463
 
2464
+ // packages/daemon/src/capabilities/MemoryCapability.ts
2465
+ var MemoryCapability;
2466
+ var init_MemoryCapability = __esm({
2467
+ "packages/daemon/src/capabilities/MemoryCapability.ts"() {
2468
+ "use strict";
2469
+ init_src();
2470
+ MemoryCapability = class {
2471
+ constructor(graph) {
2472
+ this.graph = graph;
2473
+ }
2474
+ name = "memory_write";
2475
+ description = "Persist a discovered fact to long-term memory so it survives across sessions.";
2476
+ toolDefinition = {
2477
+ name: "memory_write",
2478
+ description: 'Write an important fact to long-term memory. Call this whenever you discover something worth remembering: URLs (ngrok, live servers), file paths, port numbers, API endpoints, configuration values, decisions made, or task outcomes. Examples: memory_write({label:"ngrok_url", content:"https://abc.ngrok.io", type:"url"}) or memory_write({label:"project_port", content:"3000", type:"config"})',
2479
+ input_schema: {
2480
+ type: "object",
2481
+ properties: {
2482
+ label: { type: "string", description: 'Short name for this fact (e.g. "ngrok_url", "project_port")' },
2483
+ content: { type: "string", description: "The value to remember" },
2484
+ type: { type: "string", description: 'Category: "url", "path", "config", "note", "outcome"' }
2485
+ },
2486
+ required: ["label", "content"]
2487
+ }
2488
+ };
2489
+ async execute(input, _cwd) {
2490
+ const label = String(input.label ?? "").trim();
2491
+ const content = String(input.content ?? "").trim();
2492
+ const type = String(input.type ?? "note").trim();
2493
+ const start = Date.now();
2494
+ if (!label || !content) {
2495
+ return { success: false, output: "label and content are required", duration_ms: 0 };
2496
+ }
2497
+ try {
2498
+ const nodeId = `memory:${label.toLowerCase().replace(/[^a-z0-9_]/g, "_")}`;
2499
+ const existing = this.graph.getNode(nodeId);
2500
+ if (existing) {
2501
+ this.graph.updateNode(nodeId, {
2502
+ label,
2503
+ metadata: { ...existing.metadata, content, type, updated_at: (/* @__PURE__ */ new Date()).toISOString() }
2504
+ });
2505
+ } else {
2506
+ const node = createNode({
2507
+ id: nodeId,
2508
+ graph_id: "root",
2509
+ label,
2510
+ type: "context" /* CONTEXT */,
2511
+ metadata: { content, type, saved_at: (/* @__PURE__ */ new Date()).toISOString() }
2512
+ });
2513
+ this.graph.addNode(node);
2514
+ }
2515
+ return {
2516
+ success: true,
2517
+ output: `Remembered: "${label}" = ${content.slice(0, 120)}${content.length > 120 ? "\u2026" : ""}`,
2518
+ duration_ms: Date.now() - start
2519
+ };
2520
+ } catch (err) {
2521
+ return {
2522
+ success: false,
2523
+ output: `Memory write failed: ${err instanceof Error ? err.message : String(err)}`,
2524
+ duration_ms: Date.now() - start
2525
+ };
2526
+ }
2527
+ }
2528
+ };
2529
+ }
2530
+ });
2531
+
2460
2532
  // packages/daemon/src/capabilities/CodespaceBrowserCapability.ts
2461
2533
  var CodespaceBrowserCapability_exports = {};
2462
2534
  __export(CodespaceBrowserCapability_exports, {
@@ -2541,6 +2613,7 @@ var init_CapabilityRegistry = __esm({
2541
2613
  init_ScraperCapability();
2542
2614
  init_ShellCapability();
2543
2615
  init_FileCapability();
2616
+ init_MemoryCapability();
2544
2617
  CapabilityRegistry = class {
2545
2618
  capabilities = /* @__PURE__ */ new Map();
2546
2619
  /**
@@ -2553,7 +2626,7 @@ var init_CapabilityRegistry = __esm({
2553
2626
  * task_type: browser_task). The main agent does NOT have direct access
2554
2627
  * to browser_open without going through a subagent spawn.
2555
2628
  */
2556
- constructor(codespaceManager) {
2629
+ constructor(codespaceManager, graph) {
2557
2630
  this.register(new WebSearchCapability());
2558
2631
  if (codespaceManager) {
2559
2632
  try {
@@ -2568,6 +2641,9 @@ var init_CapabilityRegistry = __esm({
2568
2641
  this.register(new ScraperCapability());
2569
2642
  this.register(new ShellCapability());
2570
2643
  this.register(new FileCapability());
2644
+ if (graph) {
2645
+ this.register(new MemoryCapability(graph));
2646
+ }
2571
2647
  }
2572
2648
  register(cap) {
2573
2649
  this.capabilities.set(cap.name, cap);
@@ -2633,7 +2709,7 @@ var init_AgentExecutor = __esm({
2633
2709
  this.maxIterations = config.max_iterations ?? 20;
2634
2710
  this.maxCommandMs = config.max_command_ms ?? 3e4;
2635
2711
  this.agentRoot = config.agent_root;
2636
- this.registry = new CapabilityRegistry();
2712
+ this.registry = new CapabilityRegistry(void 0, config.graph);
2637
2713
  }
2638
2714
  cwd;
2639
2715
  maxIterations;
@@ -2658,23 +2734,39 @@ var init_AgentExecutor = __esm({
2658
2734
  for (let i = 0; i < this.maxIterations; i++) {
2659
2735
  this.onStep(i === 0 ? "Thinking\u2026" : "Continuing\u2026");
2660
2736
  let response;
2661
- try {
2662
- response = await this.llm.completeWithTools(
2663
- messages,
2664
- this.registry.getToolDefinitions(),
2665
- systemPrompt,
2666
- // Only stream tokens on the final (non-tool) turn
2667
- (token) => {
2668
- this.onToken(token);
2669
- finalOutput += token;
2737
+ let llmFailed = false;
2738
+ {
2739
+ let llmRetry = 0;
2740
+ while (true) {
2741
+ try {
2742
+ response = await this.llm.completeWithTools(
2743
+ messages,
2744
+ this.registry.getToolDefinitions(),
2745
+ systemPrompt,
2746
+ // Only stream tokens on the final (non-tool) turn
2747
+ (token) => {
2748
+ this.onToken(token);
2749
+ finalOutput += token;
2750
+ }
2751
+ );
2752
+ break;
2753
+ } catch (err) {
2754
+ const msg = err instanceof Error ? err.message : String(err);
2755
+ const isTimeout = /timeout|AbortError|aborted/i.test(msg);
2756
+ if (isTimeout && llmRetry < 2) {
2757
+ llmRetry++;
2758
+ this.onStep(`LLM timeout \u2014 retrying (${llmRetry}/2)\u2026`);
2759
+ await new Promise((r) => setTimeout(r, 2e3 * llmRetry));
2760
+ continue;
2761
+ }
2762
+ this.onStep(`LLM error: ${msg}`);
2763
+ finalOutput = `Error: ${msg}`;
2764
+ llmFailed = true;
2765
+ break;
2670
2766
  }
2671
- );
2672
- } catch (err) {
2673
- const msg = err instanceof Error ? err.message : String(err);
2674
- this.onStep(`LLM error: ${msg}`);
2675
- finalOutput = `Error: ${msg}`;
2676
- break;
2767
+ }
2677
2768
  }
2769
+ if (llmFailed) break;
2678
2770
  totalTokens += response.tokens_used;
2679
2771
  modelName = response.model;
2680
2772
  if (response.stop_reason === "end_turn" || !response.tool_calls?.length) {
@@ -2889,6 +2981,7 @@ content = element.text if element else page.get_all_text()` : `content = page.ge
2889
2981
  }
2890
2982
  buildSystemPrompt(extra, task) {
2891
2983
  const isSelfMod = !!(task && SELF_MOD_PATTERN.test(task));
2984
+ const hasMemory = !!this.config.graph;
2892
2985
  const lines = [
2893
2986
  `You are 0agent, an AI software engineer. You can execute shell commands and manage files.`,
2894
2987
  `Working directory: ${this.cwd}`,
@@ -2899,12 +2992,24 @@ content = element.text if element else page.get_all_text()` : `content = page.ge
2899
2992
  ` cmd > /tmp/0agent-server.log 2>&1 &`,
2900
2993
  ` Example: python3 -m http.server 3000 > /tmp/0agent-server.log 2>&1 &`,
2901
2994
  ` NEVER run background commands without redirecting output.`,
2902
- `- For npm/node projects: check package.json first with read_file or list_dir`,
2903
- `- After write_file, verify with read_file if needed`,
2995
+ `- To create a folder: use file_op with op="mkdir" and path="folder/name"`,
2996
+ `- To create a file (and its parent folders): use file_op with op="write" \u2014 parent dirs are created automatically`,
2997
+ `- For npm/node projects: check package.json first with file_op op="list"`,
2998
+ `- After writing files, verify with file_op op="read" if needed`,
2904
2999
  `- After shell_exec, check output for errors and retry if needed`,
2905
3000
  `- For research tasks: use web_search first, then scrape_url for full page content`,
2906
3001
  `- Use relative paths from the working directory`,
2907
- `- Be concise in your final response: state what was done and where to find it`
3002
+ `- Be concise in your final response: state what was done and where to find it`,
3003
+ ...hasMemory ? [
3004
+ ``,
3005
+ `Memory (IMPORTANT):`,
3006
+ `- ALWAYS call memory_write after discovering important facts:`,
3007
+ ` \xB7 Live URLs (ngrok, deployed apps, APIs): memory_write({label:"ngrok_url", content:"https://...", type:"url"})`,
3008
+ ` \xB7 Server ports: memory_write({label:"dev_server_port", content:"3000", type:"config"})`,
3009
+ ` \xB7 File paths of created projects: memory_write({label:"project_path", content:"/path/to/project", type:"path"})`,
3010
+ ` \xB7 Task outcomes: memory_write({label:"last_task_result", content:"...", type:"outcome"})`,
3011
+ `- Call memory_write immediately when you find the value, not just at the end`
3012
+ ] : []
2908
3013
  ];
2909
3014
  if (isSelfMod && this.agentRoot) {
2910
3015
  lines.push(
@@ -4597,7 +4702,7 @@ var SessionManager = class {
4597
4702
  if (activeLLM?.isConfigured) {
4598
4703
  const executor = new AgentExecutor(
4599
4704
  activeLLM,
4600
- { cwd: this.cwd, agent_root: this.agentRoot },
4705
+ { cwd: this.cwd, agent_root: this.agentRoot, graph: this.graph },
4601
4706
  // step callback → emit session.step events
4602
4707
  (step) => this.addStep(sessionId, step),
4603
4708
  // token callback → emit session.token events
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "0agent",
3
- "version": "1.0.39",
3
+ "version": "1.0.40",
4
4
  "description": "A persistent, learning AI agent that runs on your machine. An agent that learns.",
5
5
  "private": false,
6
6
  "license": "Apache-2.0",