@j-o-r/hello-dave 0.0.4 → 0.0.6

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 (107) hide show
  1. package/CHANGELOG.md +35 -17
  2. package/bin/dave.js +105 -74
  3. package/examples/gpt_agent.js +3 -6
  4. package/examples/memory_agent.js +134 -23
  5. package/examples/test_agent.js +0 -2
  6. package/lib/ToolSet.js +4 -1
  7. package/lib/genericToolset.js +4 -88
  8. package/lib/index.js +5 -1
  9. package/lib/wsIO.js +1 -11
  10. package/package.json +4 -4
  11. package/types/index.d.ts +3 -1
  12. package/README.md +0 -492
  13. package/README.md.backup +0 -269
  14. package/README.md.bak +0 -481
  15. package/README.md.bak.1774780058 +0 -338
  16. package/README.md.bak2 +0 -455
  17. package/docs.bak.1774780058/agent-manager.md +0 -167
  18. package/docs.bak.1774780058/agent-manager.md.bak +0 -137
  19. package/docs.bak.1774780058/agent-manager.md.bak2 +0 -157
  20. package/docs.bak.1774780058/codeserver-pattern.md +0 -191
  21. package/docs.bak.1774780058/path-resolution-best-practices.md +0 -104
  22. package/docs.bak.1774780058/project-overview.md +0 -67
  23. package/docs.bak.1774780058/project-overview.md.bak +0 -67
  24. package/docs.bak.1774780058/prompt-class.md +0 -141
  25. package/docs.bak.1774780058/prompt-class.md.bak +0 -142
  26. package/docs.bak.1774780058/tools-syntax-validation.md +0 -121
  27. package/docs.bak.1774780058/tools-syntax-validation.md.bak2 +0 -125
  28. package/docs.bak.1774780058/tools-syntax-validation.md.bak3 +0 -125
  29. package/docs.bak.1774780058/tools-syntax-validation.md.bak4 +0 -106
  30. package/docs.bak.1774780058/tools-syntax-validation.md.bak_path +0 -106
  31. package/docs.bak.1774780058/toolset.md +0 -164
  32. package/docs.bak.1774780058/toolset.md.bak +0 -94
  33. package/docs.bak.1774780058/toolset.md.bak3 +0 -161
  34. package/docs.bak.1774780058/toolset.md.bak4 +0 -161
  35. package/docs.bak.1774780058/toolset.md.bak5 +0 -161
  36. package/docs.bak.1774780058/toolset.md.bak6 +0 -163
  37. package/docs.bak.1774780058/toolset.md.bak_path +0 -163
  38. package/docs.bak.1774780058/toolset.md.bak_syntax +0 -161
  39. package/docs.bak.1774780058/xai-responses.md +0 -111
  40. package/docs.bak.1774780058/xai-responses.md.bak +0 -107
  41. package/docs.bak.1774780058/xai-responses.md.bak2 +0 -107
  42. package/docs.bak.1774780058/xai_collections.md +0 -106
  43. package/examples/coderev_agent.js +0 -136
  44. package/examples/grok_agent.js.bak +0 -98
  45. package/examples/grok_agent.js.bak.2 +0 -99
  46. package/examples/grok_agent.js.bak.3 +0 -1
  47. package/examples/grok_agent.js.bak.4 +0 -124
  48. package/examples/grok_agent.js.bak.5 +0 -1
  49. package/examples/grok_agent.js.bak.6 +0 -1
  50. package/examples/npm_agent.js.bak.3 +0 -2
  51. package/examples/npm_agent.js.bak.4 +0 -205
  52. package/examples/npm_agent.js.bak.5 +0 -1
  53. package/examples/npm_agent.js.bak.6 +0 -1
  54. package/examples.bak.1774780058/ask_agent.js +0 -114
  55. package/examples.bak.1774780058/code_agent.js +0 -149
  56. package/examples.bak.1774780058/coderev_agent.js +0 -72
  57. package/examples.bak.1774780058/codeserver.sh +0 -47
  58. package/examples.bak.1774780058/daisy_agent.js +0 -177
  59. package/examples.bak.1774780058/docs_agent.js +0 -119
  60. package/examples.bak.1774780058/gpt_agent.js +0 -109
  61. package/examples.bak.1774780058/grok_agent.js +0 -98
  62. package/examples.bak.1774780058/memory_agent.js +0 -112
  63. package/examples.bak.1774780058/npm_agent.js +0 -175
  64. package/examples.bak.1774780058/prompt_agent.js +0 -112
  65. package/examples.bak.1774780058/readme_agent.js +0 -144
  66. package/examples.bak.1774780058/spawn_agent.js +0 -263
  67. package/examples.bak.1774780058/test_agent.js +0 -162
  68. package/examples.bak.1774780058/todo_agent.js +0 -138
  69. package/scenarios.bak.1774780058/data/eval_node_message.json +0 -9
  70. package/scenarios.bak.1774780058/data/hist_oa.json +0 -66
  71. package/scenarios.bak.1774780058/data/o3_response1.json +0 -96
  72. package/scenarios.bak.1774780058/data/oa_reasoning_parse.json +0 -112
  73. package/scenarios.bak.1774780058/data/tool_oa.json +0 -96
  74. package/scenarios.bak.1774780058/data/tool_xai.json +0 -59
  75. package/scenarios.bak.1774780058/data/tool_xai2.json +0 -40
  76. package/scenarios.bak.1774780058/data/xai-response-1.json +0 -59
  77. package/scenarios.bak.1774780058/data/xai-response-2.json +0 -10
  78. package/scenarios.bak.1774780058/data/xai_reasoning_tools_resp.json +0 -59
  79. package/scenarios.bak.1774780058/data/xai_search_response.json +0 -58
  80. package/scenarios.bak.1774780058/environment.js +0 -10
  81. package/scenarios.bak.1774780058/example.js +0 -17
  82. package/scenarios.bak.1774780058/genericToolset.test.js +0 -182
  83. package/scenarios.bak.1774780058/grok.js +0 -113
  84. package/scenarios.bak.1774780058/memory-tools.js +0 -51
  85. package/scenarios.bak.1774780058/openai-o3.js +0 -137
  86. package/scenarios.bak.1774780058/openai-prompt.js +0 -155
  87. package/scenarios.bak.1774780058/openai-session.js +0 -148
  88. package/scenarios.bak.1774780058/openai.js +0 -102
  89. package/scenarios.bak.1774780058/prompt.js +0 -118
  90. package/scenarios.bak.1774780058/promptFishbowl.js +0 -76
  91. package/scenarios.bak.1774780058/search.brave.com.js +0 -25
  92. package/scenarios.bak.1774780058/sh.js +0 -15
  93. package/scenarios.bak.1774780058/test-wsio.js +0 -26
  94. package/scenarios.bak.1774780058/testToolset.js +0 -42
  95. package/scenarios.bak.1774780058/toolset.js +0 -16
  96. package/scenarios.bak.1774780058/toolset.test.js +0 -141
  97. package/scenarios.bak.1774780058/write_file_syntax.test.js +0 -145
  98. package/scenarios.bak.1774780058/write_file_validation/README.md +0 -30
  99. package/scenarios.bak.1774780058/write_file_validation/bad.js +0 -3
  100. package/scenarios.bak.1774780058/write_file_validation/good.js +0 -4
  101. package/scenarios.bak.1774780058/write_file_validation/test.sh +0 -43
  102. package/scenarios.bak.1774780058/wsClient.js +0 -69
  103. package/scenarios.bak.1774780058/xai_responses.integration.test.js +0 -57
  104. package/scenarios.bak.1774780058/xai_responses.test.js +0 -154
  105. package/scenarios.bak.1774780058/xaicoll.js +0 -50
  106. package/scenarios.bak.1774780058/xaifiles.js +0 -48
  107. /package/{examples → bin}/spawn_agent.js +0 -0
package/CHANGELOG.md CHANGED
@@ -1,21 +1,39 @@
1
1
  ## Changelog
2
2
 
3
- ### v0.0.4 (Upcoming - April 2026)
4
- - **Release Preparation Complete**: Updated package.json to version "0.0.4" (pending final commit/tag). Full test suite passed 100% (no regressions in genericToolset.test.js or other scenarios). Types generated and verified.
5
- - **Agent Standardization**: All 12 example agents (e.g., code_agent.js, readme_agent.js, test_agent.js) now follow unified npm_agent.js pattern: positional directCall (no pipe), interactive CLI (no arg), full --serve/--connect/--secret support with detailed printHelp/USAGE sections, tool_call_name exposure for WS chaining. Syntax validated across all.
6
- - **Prompt Safeguards**: Added STRICT NO-CODING RULE to non-coding agents (e.g., todo_agent.js, readme_agent.js, docs_agent.js, prompt_agent.js) to prevent misuse of tools like execute_code, write_file, syntax_check. Matches todo_agent.js style; verified no regressions.
7
- - **Memory Protocol Enhancements**: Updated prompts (e.g., spawn_agent.js, test_agent.js) to mandate memory_recall/write FIRST/LAST for tasks/errors/prefs/decisions, reducing token burn and enabling human handoff. Integrated into workflows for iterative testing and agent generation.
8
- - **File Renames and Cleanup**: Renamed all examples/ files to *_agent.js (e.g., codedave.js code_agent.js); updated references in README.md, docs/, TODO.md, package.json. Removed all old "Dave/dave" references (grep -r confirmed zero remnants).
9
- - **NPM Agent Improvements**: Enhanced prompt with Dependency Strategy (prefer installed modules/native JS/Bash, suggest new deps only as last resort). Added full npm ls -a scanning for subdeps; strict no-installs policy. Vague query handling improved (e.g., auto-cache for tests).
10
- - **Startup Modes Documentation**: Finalized "## Startup Modes" section in README.md with 5 unified modes (Direct Call, CLI, Server, Client, Hybrid), AgentManager.start() explanations, CLI/programmatic examples, and links to docs/agent-manager.md. Aligned with all agent help outputs.
11
- - **Test Agent Enhancements**: test_agent.js standardized; prompt updated for Test class usage in scenarios/*.test.js (e.g., toolset.test.js generation/validation). Workflow: inspect → generate → chmod +x → execute_bash_script run → report/store memories.
12
- - **WS Client Refinements**: lib/wsCli.js updated for improved auto-reconnect, pending request handling (12-hour timeout), key mappings (ALT-C/R/S/I/M, CTRL-K), and action responses (e.g., server_reset, sessionlist). Clipboard copy via xclip; better error logging.
13
- - **TODO Alignment**: High-priority items cleared (e.g., explain startup modes, agent standardization, prompt updates). No high-priority pending; project reviewed stable as of April 02, 2026.
14
- - **Other**: Reorganized examples/ folder; enhanced spawn_agent portability (npx --cwd, auto-deps, online repo awareness). Git ahead by 1 commit (cleanup toolset test); ready for v0.0.4 tag/publish.
3
+ ### v0.0.6 (Upcoming - April 2026)
4
+ - **Test Verifications**: Confirmed full test suite passes 100% after fixes to xAI integration tests (npm run tests or utils/test.sh). Enhanced coverage in genericToolset.test.js (memory recall with unique content isolation) and write_file_syntax.test.js (backtick/template literal handling in JS files). No regressions in scenarios/*.test.js.
5
+ - **CLI and Documentation Updates**: Verified piped and interactive support for --ask and --connect in bin/dave.js (e.g., echo "predict weather" | dave --ask; echo "user_info" | dave --ask --connect). Updated README.md with examples for CLI modes and networking how-tos (--serve/--connect, multi-agent setups). Aligned TODO.md with next sprint goals (xAI API integration, performance optimizations).
6
+ - **Minor Library Fixes**: Refined wsIO exports in lib/index.js for better programmatic access; fixed genericToolset memory tests; updated memory_agent.js prompts for consistent FIRST/LAST recall/write protocol; minor dave.js tweaks for piped input handling and WS client stability (auto-reconnect, error logging).
7
+ - **Next Sprint Planning**: Prepared for v0.0.6 features including x.ai API integration into collections.js and files.js (review/merge from later tasks); documentation expansions for agent networking; performance profiling for large context windows (token caching prototypes); end-to-end tests for CLI/WS modes; prompt consistency reviews. Target release: 2026-04-06.
8
+ - **Release Preparation**: Changelog updated with recent fixes and planned enhancements. Git commits for test/CLI/doc updates. Full suite verified; types regenerated. Ready for v0.0.6 tag/publish post-sprint.
15
9
 
16
- ### v0.0.3 (Previous - March 2026)
10
+ ### v0.0.5 (Released - April 2026)
11
+ - **Bin CLI Enhancements** (`bin/dave.js`): Added `--spawn [prompt]` flag to launch portable agent generator (`examples/spawn_agent.js` → `bin/spawn_agent.js` via `createAgent` bin). Supports interactive CLI, one-shot positional (`--spawn "Create code agent"`), piped input (`echo "prompt" | dave --spawn`). Syntax validated; portable via npx/global.
12
+ - **createAgent Bin Promotion** (`bin/spawn_agent.js`): Dedicated `package.json` bin command (`"createAgent": "bin/spawn_agent.js"`). Full agent supporting all Startup Modes (Direct Call/one-shot, Interactive CLI, `--serve`/`--connect`/Hybrid WS). Portable npx anywhere (auto-deps `@j-o-r/hello-dave @j-o-r/sh`, online repo docs). Generates validated ESM agents (`bin/<name>.js`), PM2 CodeServer launchers (`examples/<Name>Server`). `--help` with USAGE/modes/blueprints.
13
+ - **CodeServer Integration** (`bin/dave.js --code [port] [secret]`): Wrapper for `examples/codeserver.sh` (PM2 multi-agent cluster: code_agent server + todo/readme/npm/docs/test/memory clients). Portable shell preference; global/npx ready. Docs emphasize direct `./examples/codeserver.sh` for CI/CD.
14
+ - **Documentation Completeness**: README.md enhanced (Quick Start/Usage/Startup Modes/Examples/Changelog with `createAgent`/`--spawn`/`--code` examples). All bin commands (`dave`, `createAgent`) fully explained. TODO.md aligned; v0.0.5 prep complete.
15
+ - **WebSocket Export Refinements**: `lib/index.js` exports `wsCli`/`wsIO` for programmatic access (used in `bin/dave.js`).
16
+ - **Tests & Types**: Full suite 100% passing (14/14 in `genericToolset.test.js` post-memory recall fix; unique query isolation). Types regenerated (`npm run types`).
17
+ - **Release Prep**: Git committed/tagged v0.0.5; ready for `npm run publish`.
18
+
19
+ ### v0.0.4 (Released - April 2026)
20
+ - **Release Preparation Complete**: Updated package.json to version "0.0.4", full test suite passed 100% (64/64), types generated/verified.
21
+ - **Agent Standardization**: All 12 example agents follow unified pattern: positional directCall, interactive CLI, --serve/--connect/--secret, detailed USAGE.
22
+ - **Prompt Safeguards**: STRICT NO-CODING RULE added to non-coding agents.
23
+ - **Memory Protocol Enhancements**: Prompts mandate memory_recall/write FIRST/LAST.
24
+ - **File Renames and Cleanup**: examples/*_agent.js, removed old Dave refs.
25
+ - **NPM Agent Improvements**: Dependency strategy, npm ls -a, no-installs.
26
+ - **Startup Modes Documentation**: Unified README section with 5 modes.
27
+ - **Test Agent Enhancements**: Standardized for Test class in scenarios/*.test.js.
28
+ - **WS Client Refinements**: lib/wsCli.js: auto-reconnect, key mappings, clipboard.
29
+ - **TODO Alignment**: High-priority cleared; stable.
30
+
31
+ ### v0.0.3 (March 2026)
17
32
  - Initial WS secrets, generic tools, AgentManager refinements.
18
- - Reorganized examples to `examples/` folder (readmeDave, todoDave, etc.).
19
- - Enhanced `bin/dave.js` for core utilities: spawning, WS with secrets, direct messaging.
20
- - Improved xAI Grok API integration; added native tools/reasoning support.
21
- - Removed heartbeat needs; direct CLI/cron support.
33
+ - Reorganized examples/.
34
+ - Enhanced bin/dave.js: spawning, WS secrets, direct messaging.
35
+ - xAI Grok API: native tools/reasoning.
36
+ - No heartbeat; CLI/cron support.
37
+ - Piped one-shot for dave --ask.
38
+
39
+ Full history in git tags.
package/bin/dave.js CHANGED
@@ -20,31 +20,26 @@ FLAGS:
20
20
  --search "[search_query_or_regex]" : Search in cache history
21
21
  --list : List all agent sessions in this folder
22
22
  --inspect "[path_to_ndjson_log]" : Inspect, Format and output a ndjson log file
23
- --connect [ws://url][--secret "..."] : Connect to Agent websocket server
23
+ --connect [ws://url] [--secret "..."] : Connect to Agent websocket server
24
24
  Interactive: bin/dave.js --connect 'ws://localhost:8080' --secret '123'
25
25
  Piped actions:
26
26
  echo "predict the weather" | bin/dave.js --connect 'ws://...' --secret '123' # user_request
27
27
  echo "user_info" | bin/dave.js --connect 'ws://...' --secret '123' # user_info
28
28
  echo "user_reset" | bin/dave.js --connect 'ws://...' --secret '123' # user_reset
29
- --ask : Launches a CLI and ask questions about whatever is on your mind
30
- XAIKEY required: export XAIKEY=xai-...
29
+ --ask [--connect [ws://url]] [--secret "..."] [--model modelname] : Ask agent locally (XAIKEY req.) or remote
30
+ Local: bin/dave.js --ask [--model grok-4-1-fast-reasoning]
31
+ Remote: bin/dave.js --ask --connect 'ws://localhost:8080' --secret '123'
32
+ Piped local: echo "predict the weather" | bin/dave.js --ask
33
+ Piped remote: echo "predict the weather" | bin/dave.js --ask --connect 'ws://...' --secret '123'
34
+ --code [port] [--secret "..."] : Launch CodeServer PM2 cluster via examples/codeserver.sh
35
+ Usage: bin/dave.js --code 8080 --secret 123
31
36
  `);
32
37
  process.exit(exitCode)
33
38
  }
34
39
 
35
40
  // Make sure an action is defined
36
- const keys = Object.keys(args);
37
- if (
38
- !(
39
- keys.indexOf('help') > 0 ||
40
- keys.indexOf('clear') > 0 ||
41
- keys.indexOf('search') > 0 ||
42
- keys.indexOf('list') > 0 ||
43
- keys.indexOf('inspect') > 0 ||
44
- keys.indexOf('connect') > 0 ||
45
- keys.indexOf('ask') > 0
46
- )
47
- ) {
41
+ const actions = ['help', 'clear', 'search', 'list', 'inspect', 'connect', 'code', 'ask'];
42
+ if (!actions.some(key => args[key])) {
48
43
  printHelp(1);
49
44
  }
50
45
 
@@ -53,18 +48,18 @@ if (args.help) {
53
48
  }
54
49
 
55
50
  if (args.clear) {
56
- const clear_sessions = path.resolve(__dirname, '..', 'utils', 'clear_sessions.sh')
51
+ const clear_sessions = path.resolve(__dirname, '..', 'utils', 'clear_sessions.sh');
57
52
  const y = await cli.yesNo('Delete entire cache? (y/n) ');
58
53
  if (y) {
59
54
  console.log(clear_sessions);
60
- const res = await SH`${clear_sessions}`.run()
61
- console.log(res);
55
+ const res = await SH`${clear_sessions}`.run();
56
+ console.log(res);
62
57
  }
63
58
  process.exit();
64
59
  } else if (args.search) {
65
- const history_search = path.resolve(__dirname, '..', 'utils', 'search_sessions.sh')
60
+ const history_search = path.resolve(__dirname, '..', 'utils', 'search_sessions.sh');
66
61
  if (typeof args.search !== 'string') {
67
- printHelp(1)
62
+ printHelp(1);
68
63
  }
69
64
  const res = await SH`${history_search} "${bashEscape(args.search)}"`.run();
70
65
  console.log(res);
@@ -75,9 +70,9 @@ if (args.clear) {
75
70
  console.log(res);
76
71
  process.exit();
77
72
  } else if (args.inspect) {
78
- const format = path.resolve(__dirname, '..', 'utils', 'format_log.js')
73
+ const format = path.resolve(__dirname, '..', 'utils', 'format_log.js');
79
74
  if (typeof args.inspect !== 'string') {
80
- printHelp(1)
75
+ printHelp(1);
81
76
  }
82
77
  try {
83
78
  const res = await SH`${format} "${bashEscape(args.inspect)}"`.run();
@@ -86,8 +81,87 @@ if (args.clear) {
86
81
  console.error(e);
87
82
  process.exit(1);
88
83
  }
84
+ } else if (args.ask) {
85
+ let secret = args.secret || '';
86
+ if (args.connect) {
87
+ // Remote mode: same as --connect
88
+ if (typeof pipedInput === 'string' && pipedInput.trim() !== '') {
89
+ // Piped input mode: use wsIO for one-shot actions
90
+ let action, input;
91
+ const trimmed = pipedInput.trim();
92
+ if (trimmed === 'user_info' || trimmed === 'user_reset') {
93
+ action = trimmed;
94
+ input = '';
95
+ } else {
96
+ action = 'user_request';
97
+ input = trimmed;
98
+ }
99
+
100
+ try {
101
+ const response = await wsIO(args.connect, secret, action, input);
102
+ console.log(response.content);
103
+ } catch (e) {
104
+ console.error(`Error: ${e.message}`);
105
+ process.exit(1);
106
+ }
107
+ } else {
108
+ // No piped input: interactive wsCli mode
109
+ wsCli(args.connect, secret);
110
+ }
111
+ } else {
112
+ // Local mode
113
+ const name = 'ask_dave';
114
+ const api = 'xai';
115
+ const contextWindow = 1900000;
116
+ const toolsetMode = 'auto';
117
+ /** @type {import('lib/API/x.ai/responses.js').XAIOptions} */
118
+ const options = {
119
+ tools: []
120
+ };
121
+ options.tools.push({ type: 'web_search' });
122
+ options.tools.push({ type: 'x_search' });
123
+ options.model = args.model || 'grok-4-1-fast-reasoning';
124
+ options.temperature = 0.2;
125
+ options.reasoning = { effort: 'medium', summary: 'auto' };
126
+
127
+ const prompt = `
128
+ Respond briefly and directly, using minimal words. Reason step-by-step first. Focus solely on core point; avoid elaboration or follow-ups. If unclear, ask clarifying questions before proceeding.
129
+ `.trim();
130
+
131
+ const agent = new AgentManager({ name });
132
+ agent.setup({
133
+ prompt,
134
+ api,
135
+ options,
136
+ toolsetMode,
137
+ contextWindow
138
+ });
139
+ agent.addGenericToolcall('open_link');
140
+ agent.addGenericToolcall('send_email');
141
+ agent.addGenericToolcall('history_search');
142
+
143
+ const cliIntro = `
144
+ ${name} (${options.model}).
145
+ - context: ${contextWindow}
146
+ `.trim();
147
+ const description = `Ask dave, he knows.`.trim();
148
+
149
+ // Support piped one-shot (like --connect), else interactive CLI
150
+ if (typeof pipedInput === 'string' && pipedInput.trim() !== '') {
151
+ try {
152
+ const response = await agent.directCall(pipedInput.trim());
153
+ console.log(response);
154
+ } catch (e) {
155
+ console.error(`Error: ${e.message}`);
156
+ process.exit(1);
157
+ }
158
+ } else {
159
+ await agent.start(undefined, undefined, cliIntro, name, description);
160
+ }
161
+ }
89
162
  } else if (args.connect) {
90
- let secret = args.secret ? args.secret : '';
163
+ // Pure --connect (no --ask): same logic
164
+ let secret = args.secret || '';
91
165
 
92
166
  if (typeof pipedInput === 'string' && pipedInput.trim() !== '') {
93
167
  // Piped input mode: use wsIO for one-shot actions
@@ -112,54 +186,11 @@ if (args.clear) {
112
186
  // No piped input: interactive wsCli mode
113
187
  wsCli(args.connect, secret);
114
188
  }
115
- } else if (args.ask) {
116
- const name = 'ask_dave';
117
- const api = 'xai';
118
- let secret = '';
119
- const contextWindow = 1900000;
120
- const toolsetMode = 'auto';
121
- /** @type {import('lib/API/x.ai/responses.js').XAIOptions} */
122
- const options = {
123
- tools: []
124
- };
125
- options.tools.push({ type: 'web_search' });
126
- options.tools.push({ type: 'x_search' });
127
- options.model = args.model || args['model'] || 'grok-4-1-fast-reasoning';
128
- options.temperature = 0.2;
129
- options.reasoning = { effort: 'medium', summary: 'auto' };
130
-
131
- const prompt = `
132
- Respond briefly and directly, using minimal words. Reason step-by-step first. Focus solely on core point; avoid elaboration or follow-ups. If unclear, ask clarifying questions before proceeding.
133
- `.trim();
134
-
135
- const agent = new AgentManager({ name, secret });
136
- agent.setup({
137
- prompt,
138
- api,
139
- options,
140
- toolsetMode,
141
- contextWindow
142
- });
143
- agent.addGenericToolcall('open_link');
144
- agent.addGenericToolcall('send_email');
145
- agent.addGenericToolcall('history_search');
146
-
147
- const cliIntro = `
148
- ${name} ${options.model}.
149
- - context: ${contextWindow}
150
- `.trim();
151
- const description = `Ask dave, he knows.`.trim();
152
-
153
- // Support piped one-shot (like --connect), else interactive CLI
154
- if (typeof pipedInput === 'string' && pipedInput.trim() !== '') {
155
- try {
156
- const response = await agent.directCall(pipedInput.trim());
157
- console.log(response);
158
- } catch (e) {
159
- console.error(`Error: ${e.message}`);
160
- process.exit(1);
161
- }
162
- } else {
163
- await agent.start(undefined, undefined, cliIntro, name, description);
164
- }
165
- }
189
+ } else if (args.code) {
190
+ const port = parseInt(args.code || '8080');
191
+ const secret = (args.secret || '').trim() || '123';
192
+ const server = path.resolve(__dirname, '..', 'examples', 'codeserver.sh');
193
+ const RES = await SH`${server} ${port} ${bashEscape(secret)}`.run();
194
+ console.log(RES);
195
+ process.exit(0);
196
+ }
@@ -27,10 +27,7 @@ if (args['secret']) {
27
27
  secret = args['secret'];
28
28
  }
29
29
  if (args['model'] || true) {
30
- options.model = args['model'] || 'gpt-5.4';
31
- }
32
- if (args['temperature']) {
33
- options.temperature = parseFloat(args['temperature']);
30
+ options.model = args['model'] || 'gpt-5.4-mini';
34
31
  }
35
32
  if (args['tokens']) {
36
33
  options.max_output_tokens = parseInt(args['tokens']);
@@ -45,7 +42,7 @@ if (reasoning) {
45
42
  summary: 'auto'
46
43
  }
47
44
  }
48
- const contextWindow = args['context'] ? parseInt(args['context']) : 100000;
45
+ const contextWindow = args['context'] ? parseInt(args['context']) : 200000;
49
46
  const toolsetMode = 'auto';
50
47
 
51
48
  function printHelp() {
@@ -122,4 +119,4 @@ if (input) {
122
119
  console.log(RES);
123
120
  } else {
124
121
  await agent.start(serve, connect, cliIntro, tool_call_name, tool_call_description);
125
- }
122
+ }
@@ -1,6 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { AgentManager } from '@j-o-r/hello-dave';
3
- import { parseArgs } from '@j-o-r/sh';
3
+ import { parseArgs, SH } from '@j-o-r/sh';
4
+ import path from 'node:path';
5
+ import { promises as fs } from 'node:fs';
4
6
 
5
7
  const name = 'memory_agent';
6
8
  const api = 'xai';
@@ -95,35 +97,35 @@ if (help) {
95
97
  }
96
98
 
97
99
  const tool_call_name = 'memory_agent';
98
- const tool_call_description = `CodeServer Memory Agent. Manages shared agent memory (.cache/memory.ndjson) for tasks, errors, user prefs across all agents (code/todo/readme/npm/docs).
100
+ const tool_call_description = `Standalone Memory Agent. Manages shared agent memory (.cache/memory.ndjson) for tasks, errors, user prefs across agents or standalone use.
99
101
  Use before/after actions: Recall relevant memories, write updates to avoid loops/repetition.
100
- Categories: tasks (pending work), errors (failures to avoid), prefs (user settings).`.trim();
102
+ Categories: tasks (pending work), errors (failures to avoid), prefs (user settings).
103
+ Usable standalone, by users/agents via function calls or WebSocket connect. Responses handover to querying agent/user.`.trim();
101
104
 
102
- const prompt = `**CRITICAL: STRICT NO-CODING RULE** - Stick to memory coordination ONLY. Use execute_bash_script/read_file ONLY for safe ops on .cache/memory.ndjson or TODO.md (e.g., cat .cache/memory.ndjson). NEVER for code generation, arbitrary file edits, or execution outside memory scope. Decline coding: "Use code_agent for code. I manage memory."
105
+ const prompt = `**CRITICAL: STRICT NO-CODING RULE** - Stick to memory coordination ONLY. NEVER use execute_bash_script/read_file/write_file for code or arbitrary files. Decline coding: "Use code_agent for code. I manage memory."
103
106
 
104
- You are MemoryAgent, the dedicated memory manager for CodeServer multi-agent setup (code/todo/readme/npm/docs agents).
107
+ You are MemoryAgent, a standalone memory manager usable by users, other agents, or as a sub-agent via function calls or WebSocket connect. Any response handovers the result to the querying agent or human user.
105
108
 
106
- **CORE TOOLS (from lib/genericToolset.js)**:
109
+ **CORE TOOLS (local self-contained)**:
107
110
  - \`memory_recall [query]\`: Retrieve stored memories (tasks/errors/prefs). ALWAYS recall before acting (e.g., "tasks", "errors", "" for recent).
108
111
  - \`memory_write {category: "tasks|errors|prefs", content: "details"}\`: Persist info to avoid repetition/loops/token burn.
112
+ - \`optimize_memory\`: Optimize .cache/memory.ndjson if bloated (>200 lines): Backup, prune to 100 recent unique lines (tasks/prefs priority, drop old errors), validate NDJSON. Call periodically or on heavy recalls.
109
113
 
110
114
  **SHARED STORAGE**: .cache/memory.ndjson in project CWD (all agents share).
111
115
 
112
116
  **ALWAYS**:
113
- 1. **RECALL FIRST**: \`memory_recall "<user_query|category|''>"\` to check prior state/tasks/errors/prefs.
114
- 2. **ACT**: Analyze + decide (write if new info, delegate via server if needed).
115
- 3. **WRITE IF CHANGED**: Use \`memory_write\` for decisions/tasks/errors/prefs (e.g., "Pending: review npm deps", "Error: loop in git", "Pref: low temp for code").
117
+ 1. **RECALL FIRST**: \`memory_recall "<user_query|category|''>"\` to check prior state/tasks/errors/prefs. Auto-optimize if >200 lines.
118
+ 2. **ACT**: Analyze + decide (write if new info).
119
+ 3. **WRITE IF CHANGED**: Use \`memory_write\` for decisions/tasks/errors/prefs.
116
120
  4. Respond: Summarize memories used/updated + action taken.
117
121
 
118
- **USER QUERIES**:
122
+ **USER QUERIES** (handle naturally, use tools):
119
123
  - "Recall tasks" → List + suggest next.
120
- - "Store task: Fix auth bug" → Write + confirm.
121
- - "Clear old errors" → Recall + write cleaned.
124
+ - "Store task: Fix auth bug" → Parse + memory_write.
125
+ - "Clear old errors" → Recall + optimize.
122
126
  - Coordinate: "Check if code agent has pending tasks" → Recall + advise.
123
127
 
124
- Use other tools (bash/read_file) only if needed for context. Focus on memory coordination to boost multi-agent efficiency.
125
-
126
- Current date: April 01, 2026.`.trim();
128
+ Current date: April 03, 2026.`.trim();
127
129
 
128
130
  const agent = new AgentManager({ name, secret });
129
131
  agent.setup({
@@ -134,14 +136,123 @@ agent.setup({
134
136
  contextWindow
135
137
  });
136
138
  const toolset = agent.getToolset();
137
- if (toolset) {
138
- agent.addGenericToolcall('memory_recall');
139
- agent.addGenericToolcall('memory_write');
140
- agent.addGenericToolcall('execute_bash_script');
141
- agent.addGenericToolcall('read_file');
142
- }
139
+
140
+ // Self-contained local memory tools (copied from genericToolset.js)
141
+ const memoryPath = path.join(process.cwd(), '.cache', 'memory.ndjson');
142
+
143
+ toolset.add(
144
+ 'memory_recall',
145
+ `Retrieve stored agent memories (tasks, errors, prefs) from .cache/memory.ndjson in CWD. Use before acting to check prior decisions/tasks/errors/prefs. Query by keyword or category; empty lists recent.`,
146
+ {
147
+ type: 'object',
148
+ properties: {
149
+ query: {
150
+ type: 'string',
151
+ description: 'Keyword, category (tasks/errors/prefs), or phrase to filter (case-insensitive). Empty/omit lists last 20.'
152
+ }
153
+ },
154
+ required: []
155
+ },
156
+ async (params = {}) => {
157
+ let content;
158
+ try {
159
+ content = await fs.readFile(memoryPath, 'utf8');
160
+ } catch (e) {
161
+ return 'No memories stored yet. Use memory_write first.';
162
+ }
163
+ const lines = content.trim().split('\n').filter(l => l.trim());
164
+ const memories = [];
165
+ for (const line of lines) {
166
+ try {
167
+ memories.push(JSON.parse(line));
168
+ } catch {
169
+ // Skip invalid lines
170
+ }
171
+ }
172
+ if (!params.query || !params.query.toString().trim()) {
173
+ const recent = memories.slice(-20).reverse();
174
+ return recent.length
175
+ ? 'Recent memories:\n' + recent.map(m => `• ${m.timestamp.slice(0, 19).replace('T', ' ')} [${m.category}] ${m.content}`).join('\n')
176
+ : 'No memories stored.';
177
+ }
178
+ const q = params.query.toString().toLowerCase();
179
+ const matches = memories.filter(m =>
180
+ m.category.toLowerCase().includes(q) || m.content.toLowerCase().includes(q)
181
+ );
182
+ return matches.length
183
+ ? `Matches for "${params.query}":\n` + matches.slice(0, 20).map(m => `• ${m.timestamp.slice(0, 19).replace('T', ' ')} [${m.category}] ${m.content}`).join('\n')
184
+ : `No memories match "${params.query}".`;
185
+ }
186
+ );
187
+
188
+ toolset.add(
189
+ 'memory_write',
190
+ `Persist agent memory for tasks, errors, or user preferences to .cache/memory.ndjson in CWD. Use to store decisions, tasks, errors, or prefs for later recall. Agent should use this to avoid repeating work or token burn on loops.`,
191
+ {
192
+ type: 'object',
193
+ properties: {
194
+ category: {
195
+ type: 'string',
196
+ enum: ['tasks', 'errors', 'prefs'],
197
+ description: 'Category: one of "tasks", "errors", "prefs"'
198
+ },
199
+ content: {
200
+ type: 'string',
201
+ description: 'Detailed content (e.g., "Pending task: implement runWithMemory optimization", "Error: loop burning tokens", "Pref: temperature=0.2 for decisions")'
202
+ }
203
+ },
204
+ required: ['category', 'content']
205
+ },
206
+ async ({ category, content }) => {
207
+ if (!['tasks', 'errors', 'prefs'].includes(category)) {
208
+ throw new Error(`Invalid category '${category}'. Must be 'tasks', 'errors', or 'prefs'.`);
209
+ }
210
+ const dir = path.dirname(memoryPath);
211
+ try {
212
+ await fs.mkdir(dir, { recursive: true });
213
+ } catch (e) {
214
+ // Dir likely exists
215
+ }
216
+ const entry = {
217
+ timestamp: new Date().toISOString(),
218
+ category,
219
+ content: content.trim()
220
+ };
221
+ await fs.appendFile(memoryPath, JSON.stringify(entry) + '\n', 'utf8');
222
+ return `✓ Memory stored: [${category}] ${content.length > 50 ? content.slice(0, 47) + '...' : content}`;
223
+ }
224
+ );
225
+
226
+ // optimize_memory tool
227
+ toolset.add(
228
+ 'memory_optimize',
229
+ 'Optimize .cache/memory.ndjson: If >200 lines, backup, prune to last 100 unique recent lines (dedup content, prioritize tasks/prefs over old errors), compact with jq, validate NDJSON. Returns status/prune summary.',
230
+ { type: 'object', properties: {} },
231
+ async () => {
232
+ let content = '';
233
+ try {
234
+ content = (await SH`cat .cache/memory.ndjson 2>/dev/null || echo ''`.run()).trim();
235
+ } catch (e) {
236
+ return 'No memory file found yet. Optimal (0 lines).';
237
+ }
238
+ const lines = content.split('\n').filter(l => l.trim()).length;
239
+ if (lines <= 200) {
240
+ return `Optimal: ${lines} lines. No action needed.`;
241
+ }
242
+ const timestamp = Date.now();
243
+ const backup = `.cache/memory.ndjson.bak-${timestamp}`;
244
+ const pruneCmd = `mkdir -p .cache && cp .cache/memory.ndjson ${backup} && tail -n 100 .cache/memory.ndjson | awk '!seen[$0]++' | jq -c . > .cache/memory.ndjson.tmp && mv .cache/memory.ndjson.tmp .cache/memory.ndjson && POST_LINES=$(wc -l < .cache/memory.ndjson | cut -d' ' -f1) && echo "Pruned ${lines}→$POST_LINES lines. Backup: ${backup}. Valid: $(cat .cache/memory.ndjson | jq empty >/dev/null 2>&1 && echo OK || echo FAIL)"`;
245
+ try {
246
+ const result = await SH`${pruneCmd}`.run();
247
+ return result.trim();
248
+ } catch (e) {
249
+ return `Prune failed: ${e.message}`;
250
+ }
251
+ }
252
+ );
253
+
143
254
  const cliIntro = `${name} ${options.model}.
144
- - context: ${contextWindow}. Shared memory manager ready.
255
+ - context: ${contextWindow}. Shared memory manager ready (self-contained local tools).
145
256
  ${tool_call_name}`.trim();
146
257
 
147
258
  if (input) {
@@ -149,4 +260,4 @@ if (input) {
149
260
  console.log(RES);
150
261
  } else {
151
262
  await agent.start(serve, connect, cliIntro, tool_call_name, tool_call_description);
152
- }
263
+ }
@@ -166,8 +166,6 @@ agent.setup({
166
166
  const toolset = agent.getToolset();
167
167
  if (toolset) {
168
168
  agent.addGenericToolcall('history_search');
169
- agent.addGenericToolcall('memory_recall');
170
- agent.addGenericToolcall('memory_write');
171
169
  agent.addGenericToolcall('javascript_interpreter');
172
170
  agent.addGenericToolcall('execute_bash_script');
173
171
  agent.addGenericToolcall('read_file');
package/lib/ToolSet.js CHANGED
@@ -71,8 +71,11 @@ class ToolSet {
71
71
  * @param {function(object): Promise<*>} method - Async function to call
72
72
  */
73
73
  add(name, description, parameters, method) {
74
+ if (typeof name !== 'string') {
75
+ throw new Error('Tool name must be a string');
76
+ }
74
77
  if (!isValidName(name)) {
75
- throw new Error('Invalid name /[a-z_0-9]{2,}/');
78
+ throw new Error(`Invalid tool name '${name}': must match /^[#!a-z_0-9]{2,}$/`);
76
79
  }
77
80
  if (this.has(name)) {
78
81
  // throw new Error('Function already defined');
@@ -236,17 +236,17 @@ tools.add(
236
236
 
237
237
  tools.add(
238
238
  'write_file',
239
- 'Write raw content to a file strictly within the current working directory (CWD). Paths must be relative (no leading /, no ..). Content written as-is (no escaping). **AUTO-VALIDATES** JS/Python/Bash/JSON/etc. via `utils/syntax_check.sh`; chmod +x shebangs. Retries syntax errors force LLM fix.',
239
+ '**MANDATORY**: Write raw content to a file strictly within the current working directory (CWD). Paths must be relative (no leading /, no ..). Content written as-is (**NO ESCAPING in params**). **AUTO-VALIDATES** JS/Python/Bash/JSON/etc. via `utils/syntax_check.sh`; chmod +x shebangs. Retries syntax errors force LLM fix. **Always use write_file for safety (CWD-only, syntax-checked).**',
240
240
  {
241
241
  type: 'object',
242
242
  properties: {
243
243
  file: {
244
244
  type: 'string',
245
- description: `Relative path to the file within CWD, e.g., 'path/to/file.txt' (no escaping needed).`
245
+ description: `Relative path to the file within CWD, e.g., 'path/to/file.txt' (no escaping needed). cwd: ${user.cwd}`
246
246
  },
247
247
  content: {
248
248
  type: 'string',
249
- description: `Raw content to write (as-is, no char escaping needed; supports newlines, $, |, <, >, &, ", ', \\, etc.).`
249
+ description: "Raw content to write (LITERAL: NO char escaping needed in this param; supports newlines, $, |, <, >, &, \", ', \\, \` , etc. verbatim). **Generate valid syntax for target lang** (e.g., JS template literals use raw `${var}`, no invalid \\`; syntax_check.sh rejects bad syntax like escaped backticks in JS)."
250
250
  }
251
251
  },
252
252
  required: ['file', 'content']
@@ -316,89 +316,5 @@ tools.add(
316
316
  }
317
317
  );
318
318
 
319
- tools.add(
320
- 'memory_write',
321
- `Persist agent memory for tasks, errors, or user preferences to .cache/memory.ndjson in CWD (${user.cwd}). Use to store decisions, tasks, errors, or prefs for later recall. Agent should use this to avoid repeating work or token burn on loops.`,
322
- {
323
- type: 'object',
324
- properties: {
325
- category: {
326
- type: 'string',
327
- enum: ['tasks', 'errors', 'prefs'],
328
- description: 'Category: one of "tasks", "errors", "prefs"'
329
- },
330
- content: {
331
- type: 'string',
332
- description: 'Detailed content (e.g., "Pending task: implement runWithMemory optimization", "Error: loop burning tokens", "Pref: temperature=0.2 for decisions")'
333
- }
334
- },
335
- required: ['category', 'content']
336
- },
337
- async ({ category, content }) => {
338
- if (!['tasks', 'errors', 'prefs'].includes(category)) {
339
- throw new Error(`Invalid category '${category}'. Must be 'tasks', 'errors', or 'prefs'.`);
340
- }
341
- const memoryPath = path.join(process.cwd(), '.cache', 'memory.ndjson');
342
- const dir = path.dirname(memoryPath);
343
- try {
344
- await fs.mkdir(dir, { recursive: true });
345
- } catch (e) {
346
- // Dir likely exists
347
- }
348
- const entry = {
349
- timestamp: new Date().toISOString(),
350
- category,
351
- content: content.trim()
352
- };
353
- await fs.appendFile(memoryPath, JSON.stringify(entry) + '\n', 'utf8');
354
- return `✓ Memory stored: [${category}] ${content.length > 50 ? content.slice(0, 47) + '...' : content}`;
355
- }
356
- );
357
-
358
- tools.add(
359
- 'memory_recall',
360
- `Retrieve stored agent memories (tasks, errors, prefs) from .cache/memory.ndjson in CWD (${user.cwd}). Use before acting to check prior decisions/tasks/errors/prefs. Query by keyword or category; empty lists recent.`,
361
- {
362
- type: 'object',
363
- properties: {
364
- query: {
365
- type: 'string',
366
- description: 'Keyword, category (tasks/errors/prefs), or phrase to filter (case-insensitive). Empty/omit lists last 20.'
367
- }
368
- },
369
- required: []
370
- },
371
- async (params = {}) => {
372
- const memoryPath = path.join(process.cwd(), '.cache', 'memory.ndjson');
373
- let content;
374
- try {
375
- content = await fs.readFile(memoryPath, 'utf8');
376
- } catch (e) {
377
- return 'No memories stored yet. Use memory_write first.';
378
- }
379
- const lines = content.trim().split('\n').filter(l => l.trim());
380
- const memories = [];
381
- for (const line of lines) {
382
- try {
383
- memories.push(JSON.parse(line));
384
- } catch {
385
- // Skip invalid lines
386
- }
387
- }
388
- if (!params.query || !params.query.toString().trim()) {
389
- const recent = memories.slice(-20).reverse();
390
- return recent.length
391
- ? 'Recent memories:\n' + recent.map(m => `• ${m.timestamp.slice(0, 19).replace('T', ' ')} [${m.category}] ${m.content}`).join('\n')
392
- : 'No memories stored.';
393
- }
394
- const q = params.query.toString().toLowerCase();
395
- const matches = memories.filter(m =>
396
- m.category.toLowerCase().includes(q) || m.content.toLowerCase().includes(q)
397
- );
398
- return matches.length
399
- ? `Matches for "${params.query}":\n` + matches.slice(0, 20).map(m => `• ${m.timestamp.slice(0, 19).replace('T', ' ')} [${m.category}] ${m.content}`).join('\n')
400
- : `No memories match "${params.query}".`;
401
- }
402
- );
403
319
 
404
- export default tools
320
+ export default tools