@j-o-r/hello-dave 0.0.5 → 0.0.7

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 (127) hide show
  1. package/CHANGELOG.md +13 -26
  2. package/README.md +161 -522
  3. package/README.md.bak +144 -449
  4. package/{examples → agents}/ask_agent.js +5 -5
  5. package/{examples → agents}/codeserver.sh +14 -14
  6. package/{examples → agents}/daisy_agent.js +5 -5
  7. package/{examples → agents}/docs_agent.js +5 -5
  8. package/{examples → agents}/gpt_agent.js +5 -5
  9. package/{examples → agents}/grok_agent.js +5 -5
  10. package/agents/memory_agent.js +263 -0
  11. package/{examples → agents}/npm_agent.js +5 -5
  12. package/{examples → agents}/prompt_agent.js +5 -5
  13. package/agents/spawn_agent.js +137 -0
  14. package/{examples → agents}/test_agent.js +6 -8
  15. package/{examples → agents}/todo_agent.js +5 -5
  16. package/bin/codeDave +58 -0
  17. package/bin/dave.js +114 -96
  18. package/lib/AgentClient.js +111 -67
  19. package/lib/AgentManager.js +111 -80
  20. package/lib/AgentServer.js +144 -104
  21. package/lib/Cli.js +126 -93
  22. package/lib/Prompt.js +38 -5
  23. package/lib/Session.js +102 -79
  24. package/lib/ToolSet.js +79 -60
  25. package/lib/fafs.js +54 -19
  26. package/lib/genericToolset.js +109 -213
  27. package/lib/wsCli.js +50 -19
  28. package/lib/wsIO.js +11 -17
  29. package/package.json +2 -2
  30. package/types/AgentClient.d.ts +69 -35
  31. package/types/AgentManager.d.ts +50 -56
  32. package/types/AgentServer.d.ts +63 -16
  33. package/types/Cli.d.ts +56 -10
  34. package/types/Prompt.d.ts +36 -4
  35. package/types/Session.d.ts +23 -9
  36. package/types/ToolSet.d.ts +49 -32
  37. package/types/fafs.d.ts +68 -25
  38. package/types/wsCli.d.ts +14 -0
  39. package/types/wsIO.d.ts +9 -5
  40. package/utils/search_sessions.sh +100 -53
  41. package/README.md.backup +0 -269
  42. package/README.md.bak.1774780058 +0 -338
  43. package/README.md.bak2 +0 -531
  44. package/bin/spawn_agent.js +0 -293
  45. package/docs.bak.1774780058/agent-manager.md +0 -167
  46. package/docs.bak.1774780058/agent-manager.md.bak +0 -137
  47. package/docs.bak.1774780058/agent-manager.md.bak2 +0 -157
  48. package/docs.bak.1774780058/codeserver-pattern.md +0 -191
  49. package/docs.bak.1774780058/path-resolution-best-practices.md +0 -104
  50. package/docs.bak.1774780058/project-overview.md +0 -67
  51. package/docs.bak.1774780058/project-overview.md.bak +0 -67
  52. package/docs.bak.1774780058/prompt-class.md +0 -141
  53. package/docs.bak.1774780058/prompt-class.md.bak +0 -142
  54. package/docs.bak.1774780058/tools-syntax-validation.md +0 -121
  55. package/docs.bak.1774780058/tools-syntax-validation.md.bak2 +0 -125
  56. package/docs.bak.1774780058/tools-syntax-validation.md.bak3 +0 -125
  57. package/docs.bak.1774780058/tools-syntax-validation.md.bak4 +0 -106
  58. package/docs.bak.1774780058/tools-syntax-validation.md.bak_path +0 -106
  59. package/docs.bak.1774780058/toolset.md +0 -164
  60. package/docs.bak.1774780058/toolset.md.bak +0 -94
  61. package/docs.bak.1774780058/toolset.md.bak3 +0 -161
  62. package/docs.bak.1774780058/toolset.md.bak4 +0 -161
  63. package/docs.bak.1774780058/toolset.md.bak5 +0 -161
  64. package/docs.bak.1774780058/toolset.md.bak6 +0 -163
  65. package/docs.bak.1774780058/toolset.md.bak_path +0 -163
  66. package/docs.bak.1774780058/toolset.md.bak_syntax +0 -161
  67. package/docs.bak.1774780058/xai-responses.md +0 -111
  68. package/docs.bak.1774780058/xai-responses.md.bak +0 -107
  69. package/docs.bak.1774780058/xai-responses.md.bak2 +0 -107
  70. package/docs.bak.1774780058/xai_collections.md +0 -106
  71. package/examples/memory_agent.js +0 -152
  72. package/examples.bak.1774780058/ask_agent.js +0 -114
  73. package/examples.bak.1774780058/code_agent.js +0 -149
  74. package/examples.bak.1774780058/coderev_agent.js +0 -72
  75. package/examples.bak.1774780058/codeserver.sh +0 -47
  76. package/examples.bak.1774780058/daisy_agent.js +0 -177
  77. package/examples.bak.1774780058/docs_agent.js +0 -119
  78. package/examples.bak.1774780058/gpt_agent.js +0 -109
  79. package/examples.bak.1774780058/grok_agent.js +0 -98
  80. package/examples.bak.1774780058/memory_agent.js +0 -112
  81. package/examples.bak.1774780058/npm_agent.js +0 -175
  82. package/examples.bak.1774780058/prompt_agent.js +0 -112
  83. package/examples.bak.1774780058/readme_agent.js +0 -144
  84. package/examples.bak.1774780058/spawn_agent.js +0 -263
  85. package/examples.bak.1774780058/test_agent.js +0 -162
  86. package/examples.bak.1774780058/todo_agent.js +0 -138
  87. package/lib/genericToolset.js.bak_syntax +0 -402
  88. package/scenarios.bak.1774780058/data/eval_node_message.json +0 -9
  89. package/scenarios.bak.1774780058/data/hist_oa.json +0 -66
  90. package/scenarios.bak.1774780058/data/o3_response1.json +0 -96
  91. package/scenarios.bak.1774780058/data/oa_reasoning_parse.json +0 -112
  92. package/scenarios.bak.1774780058/data/tool_oa.json +0 -96
  93. package/scenarios.bak.1774780058/data/tool_xai.json +0 -59
  94. package/scenarios.bak.1774780058/data/tool_xai2.json +0 -40
  95. package/scenarios.bak.1774780058/data/xai-response-1.json +0 -59
  96. package/scenarios.bak.1774780058/data/xai-response-2.json +0 -10
  97. package/scenarios.bak.1774780058/data/xai_reasoning_tools_resp.json +0 -59
  98. package/scenarios.bak.1774780058/data/xai_search_response.json +0 -58
  99. package/scenarios.bak.1774780058/environment.js +0 -10
  100. package/scenarios.bak.1774780058/example.js +0 -17
  101. package/scenarios.bak.1774780058/genericToolset.test.js +0 -182
  102. package/scenarios.bak.1774780058/grok.js +0 -113
  103. package/scenarios.bak.1774780058/memory-tools.js +0 -51
  104. package/scenarios.bak.1774780058/openai-o3.js +0 -137
  105. package/scenarios.bak.1774780058/openai-prompt.js +0 -155
  106. package/scenarios.bak.1774780058/openai-session.js +0 -148
  107. package/scenarios.bak.1774780058/openai.js +0 -102
  108. package/scenarios.bak.1774780058/prompt.js +0 -118
  109. package/scenarios.bak.1774780058/promptFishbowl.js +0 -76
  110. package/scenarios.bak.1774780058/search.brave.com.js +0 -25
  111. package/scenarios.bak.1774780058/sh.js +0 -15
  112. package/scenarios.bak.1774780058/test-wsio.js +0 -26
  113. package/scenarios.bak.1774780058/testToolset.js +0 -42
  114. package/scenarios.bak.1774780058/toolset.js +0 -16
  115. package/scenarios.bak.1774780058/toolset.test.js +0 -141
  116. package/scenarios.bak.1774780058/write_file_syntax.test.js +0 -145
  117. package/scenarios.bak.1774780058/write_file_validation/README.md +0 -30
  118. package/scenarios.bak.1774780058/write_file_validation/bad.js +0 -3
  119. package/scenarios.bak.1774780058/write_file_validation/good.js +0 -4
  120. package/scenarios.bak.1774780058/write_file_validation/test.sh +0 -43
  121. package/scenarios.bak.1774780058/wsClient.js +0 -69
  122. package/scenarios.bak.1774780058/xai_responses.integration.test.js +0 -57
  123. package/scenarios.bak.1774780058/xai_responses.test.js +0 -154
  124. package/scenarios.bak.1774780058/xaicoll.js +0 -50
  125. package/scenarios.bak.1774780058/xaifiles.js +0 -48
  126. /package/{examples → agents}/code_agent.js +0 -0
  127. /package/{examples → agents}/readme_agent.js +0 -0
@@ -1,58 +1,82 @@
1
- /*
2
- Websocket client for AI sessions
3
- */
4
- import { WebSocketClient } from "@j-o-r/apiserver";
1
+ import { WebSocketClient } from '@j-o-r/apiserver';
2
+ /**
3
+ * @module lib/AgentClient
4
+ * @exports default AgentClient
5
+ * Websocket client for AI agent sessions, wrapping a Prompt/ToolSet instance with robust queue-based message handling, auto-reconnect, and epoch-based resets.
6
+ */
5
7
 
6
8
  /**
7
- * @typedef {import('./API/openai.com/reponses/text.js').request} OARequest
8
- * @typedef {import('./API/x.ai/text.js').request} XRequest
9
- * @typedef {import('./API/anthropic.com/text.js').request} ANTHRequest
10
- *
11
- * @typedef {import('./API/x.ai/text.js').XOptions} XOptions
12
- * @typedef {import('./API/openai.com/reponses/text.js').OAOptions} OAOptions
13
- * @typedef {import('./API/anthropic.com/text.js').ANTHOptions} ANTHOptions
14
- *
15
- * @typedef {import('./Prompt.js').default} Prompt
16
- * @typedef {import('./ToolSet.js').default} ToolSet
17
- */
9
+ * @typedef {import('./API/openai.com/reponses/text.js').request} OARequest
10
+ * @typedef {import('./API/x.ai/text.js').request} XRequest
11
+ * @typedef {import('./API/anthropic.com/text.js').request} ANTHRequest
12
+ *
13
+ * @typedef {import('./API/x.ai/text.js').XOptions} XOptions
14
+ * @typedef {import('./API/openai.com/reponses/text.js').OAOptions} OAOptions
15
+ * @typedef {import('./API/anthropic.com/text.js').ANTHOptions} ANTHOptions
16
+ *
17
+ * @typedef {import('./Prompt.js').default} Prompt
18
+ * @typedef {import('./ToolSet.js').default} ToolSet
19
+ */
18
20
  /**
19
- * @typedef {Object} WSOptions
20
- * @property {Prompt} prompt - The prompt session
21
- * @property {ToolSet} [toolset] - The toolset
22
- * @property {string} description - Custom introduction message.
23
- * @property {string} name - Logical name: e.g. search, code, os, support.
24
- * @property {string} secret - Websocket server access secret.
25
- * @property {string} [url='ws://127.0.0.1:8000/ws?params=1234']
26
- * @property {number} [intervalMs=250] - How often to pull one message from the queue.
27
- */
21
+ * @typedef {Object} WSOptions
22
+ * @property {Prompt} prompt - The prompt session instance.
23
+ * @property {ToolSet} [toolset] - Optional toolset for the prompt.
24
+ * @property {string} description - Custom introduction message for the agent.
25
+ * @property {string} name - Logical name (e.g., 'search', 'code', 'os').
26
+ * @property {string} secret - Websocket server access secret (must match server).
27
+ * @property {string} [url='ws://127.0.0.1:8000/ws'] - WebSocket URL.
28
+ * @property {number} [intervalMs=2000] - Polling interval for queue processing (ms).
29
+ * @example { prompt, name: 'code-agent', secret: 'abc123', url: 'ws://localhost:8001/ws' }
30
+ */
31
+
28
32
  /**
29
- * Websocket Client
30
- * Wrapper combining a session and a websocket
31
- */
33
+ * AgentClient: WebSocket client wrapper for AI agent sessions.
34
+ * Combines Prompt/ToolSet with WS communication for bidirectional queries, responses, tool calls, and resets.
35
+ * Features: Sequential message queue (one-at-a-time processing), auto-reconnect on close, epoch invalidation for resets.
36
+ * Logs events via console; emits via underlying Prompt (tool_request, tool_error, etc.).
37
+ * @emits tool_request - When tools are requested (via #prompt).
38
+ * @emits tool_error - When tools fail (via #prompt).
39
+ * @example
40
+ * const client = new AgentClient({
41
+ * prompt: myPrompt,
42
+ * name: 'code',
43
+ * description: 'Code execution agent',
44
+ * secret: 'mysecret',
45
+ * intervalMs: 1000
46
+ * });
47
+ */
32
48
  class AgentClient {
33
- /** @type {Prompt} */
49
+ /** @private @type {Prompt} */
34
50
  #prompt;
51
+ /** @private @type {string} */
35
52
  #description = '';
53
+ /** @private @type {string} */
36
54
  #name;
55
+ /** @private @type {string} */
37
56
  #secret = '';
38
- /** @type {WebSocketClient} */
57
+ /** @private @type {import('@j-o-r/apiserver').WebSocketClient} */
39
58
  #ws;
59
+ /** @private @type {string} */
40
60
  #url = 'ws://127.0.0.1:8000/ws';
41
61
 
42
- // Message queue and processing flag to ensure one-at-a-time handling
43
- /** @type {Array<any>} */
62
+ /** @private @type {Array&lt;Object&gt;} Message queue for sequential processing. */
44
63
  #queue = [];
64
+ /** @private @type {boolean} Flag to prevent reentrant processing. */
45
65
  #processing = false;
46
- // Bump this to invalidate in-flight work (hard reset)
66
+ /** @private @type {number} Epoch counter; increments on reset to invalidate in-flight work. */
47
67
  #epoch = 0;
48
68
 
49
- // Interval-based scheduler (no tight while-loop)
69
+ /** @private @type {NodeJS.Timeout|null} Interval ID for scheduler. */
50
70
  #intervalId = null;
71
+ /** @private @type {number} Queue polling interval (ms). */
51
72
  #intervalMs = 2000;
52
73
 
53
74
  /**
54
- * Creates an instance of CLILoader.
55
- * @param {WSOptions} options - The options to configure the CLILoader.
75
+ * Initializes the AgentClient with configuration options.
76
+ * Registers Prompt events for logging and starts the WebSocket connection.
77
+ * @param {WSOptions} options - Configuration object.
78
+ * @throws {TypeError} If required options (e.g., prompt, secret) are invalid/missing.
79
+ * @example See WSOptions.
56
80
  */
57
81
  constructor(options) {
58
82
  if (options.url) this.#url = options.url;
@@ -64,11 +88,13 @@ class AgentClient {
64
88
  this.#registerPromptEvents();
65
89
  this._start();
66
90
  }
67
- /**
68
- * Informative.
69
- * See what is happening
70
- */
71
- #registerPromptEvents () {
91
+
92
+ /**
93
+ * @private
94
+ * Registers Prompt events for logging tool requests/errors.
95
+ * @returns {void}
96
+ */
97
+ #registerPromptEvents() {
72
98
  const events = Object.keys(this.#prompt.EVENTS);
73
99
  events.forEach((evt) => {
74
100
  this.#prompt.on(evt, (_msg) => {
@@ -82,72 +108,85 @@ class AgentClient {
82
108
  });
83
109
  });
84
110
  }
111
+
112
+ /**
113
+ * @private
114
+ * Starts the WebSocket connection, sends introduction, sets up handlers.
115
+ * Auto-retries on close after 5s.
116
+ * @returns {void}
117
+ */
85
118
  _start() {
86
119
  const url = this.#url + '?wssrc_id=' + this.#secret;
87
- this.#ws = new WebSocketClient(url); // Match server port/path
120
+ this.#ws = new WebSocketClient(url);
88
121
  this.#ws.onopen = () => {
89
- // Send my introduction to the server
90
122
  this.#ws.send(JSON.stringify({
91
123
  action: 'agent_introduction',
92
124
  name: this.#name,
93
125
  content: this.#description,
94
126
  id: new Date().getTime()
95
127
  }));
96
- console.log('introduction_send:>>')
128
+ console.log('introduction_send:>>');
97
129
  console.log(this.#name);
98
130
  console.log(this.#description);
99
131
  };
100
132
  this.#ws.onmessage = (m) => {
101
- // Enqueue messages; processing happens sequentially
102
133
  this.incoming(m);
103
134
  };
104
135
  this.#ws.onclose = () => {
105
136
  console.error('CLOSE: Lost Connection, retry in 5 seconds');
106
- // Stop ticking while disconnected
107
137
  this.#stopInterval();
108
138
  setTimeout(() => {
109
139
  this._start();
110
- }, 5000)
140
+ }, 5000);
111
141
  };
112
- this.#ws.onerror = (e) => {
113
-
114
- }
142
+ this.#ws.onerror = (e) => {};
115
143
  }
144
+
116
145
  /**
117
- * Enqueue an incoming websocket message and trigger the processor.
118
- */
146
+ * Enqueues an incoming WebSocket message and starts interval processing if needed.
147
+ * Immediately handles 'reset' actions (clears queue, resets prompt, increments epoch).
148
+ * @param {MessageEvent} e - Raw WebSocket message event.
149
+ * @returns {void}
150
+ * @throws {SyntaxError} If JSON parse fails.
151
+ */
119
152
  incoming(e) {
120
- const message = JSON.parse(e.data);
121
- // Handle resets immediately: do not enqueue, just clear the queue and reset the prompt
153
+ let message;
154
+ try {
155
+ message = JSON.parse(e.data);
156
+ } catch (err) {
157
+ console.error('Invalid JSON in incoming message');
158
+ return;
159
+ }
122
160
  if (message?.action === "reset") {
123
161
  console.log("<RESET:incoming>");
124
- // Invalidate in-flight work
125
162
  this.#epoch++;
126
- // Empty the queue immediately
127
163
  this.#queue = [];
128
- // Stop the scheduler; any in-flight handler will finish, but no further items will run
129
164
  this.#stopInterval();
130
- // Reset the prompt/session state
131
165
  this.#prompt.reset();
132
- return; // Do not enqueue this message
166
+ return;
133
167
  }
134
168
  this.#queue.push(message);
135
- // Start interval-based processing (no while-loop)
136
169
  this.#startInterval();
137
170
  }
138
171
 
139
172
  /**
140
- * Start the interval that pulls one message at each tick.
173
+ * @private
174
+ * Starts the interval ticker to process one queued message per tick.
175
+ * Idempotent; skips if already running.
176
+ * @returns {void}
141
177
  */
142
178
  #startInterval() {
143
179
  if (this.#intervalId) return;
144
180
  this.#intervalId = setInterval(() => {
145
- // We intentionally do not await here; #processOne guards reentrancy
146
181
  void this.#processOne();
147
182
  }, this.#intervalMs);
148
183
  }
149
184
 
150
- /** Stop the interval if it is running. */
185
+ /**
186
+ * @private
187
+ * Stops the processing interval.
188
+ * @returns {void}
189
+ */
151
190
  #stopInterval() {
152
191
  if (this.#intervalId) {
153
192
  clearInterval(this.#intervalId);
@@ -156,13 +195,15 @@ class AgentClient {
156
195
  }
157
196
 
158
197
  /**
159
- * Internal: process at most ONE message. Called on an interval tick.
198
+ * @private
199
+ * Processes exactly one queued message (guards reentrancy).
200
+ * Stops interval if queue empty post-process.
201
+ * @returns {Promise&lt;void&gt;}
160
202
  */
161
203
  async #processOne() {
162
204
  if (this.#processing) return;
163
205
  const message = this.#queue.shift();
164
206
  if (!message) {
165
- // Nothing to do; stop ticking until a new message arrives
166
207
  this.#stopInterval();
167
208
  return;
168
209
  }
@@ -172,13 +213,17 @@ class AgentClient {
172
213
  await this.#handleMessage(message, epochAtStart);
173
214
  } finally {
174
215
  this.#processing = false;
175
- // If the queue drained, we can stop; else the next tick will pick the next one
176
216
  if (this.#queue.length === 0) this.#stopInterval();
177
217
  }
178
218
  }
179
219
 
180
220
  /**
181
- * Internal: handle a single message
221
+ * @private
222
+ * Handles a single enqueued message (query/response/reset).
223
+ * Sends responses/errors back via WS.
224
+ * @param {Object} message - Parsed message.
225
+ * @param {number} epochAtStart - Epoch at start; aborts if changed.
226
+ * @returns {Promise&lt;void&gt;}
182
227
  */
183
228
  async #handleMessage(message, epochAtStart) {
184
229
  if (message.action === 'agent_query') {
@@ -193,7 +238,6 @@ class AgentClient {
193
238
  }
194
239
  } else if (message.action === 'reset') {
195
240
  console.log('<RESET>');
196
- // Empty the que;
197
241
  this.#queue = [];
198
242
  this.#epoch++;
199
243
  this.#prompt.reset();
@@ -1,56 +1,83 @@
1
1
  import { Prompt, Cli, AgentClient, AgentServer, API, ToolSet, Session, env } from './index.js';
2
2
  import toolsPool from './genericToolset.js'
3
3
  /**
4
- * @typedef {import('./API/x.ai/text.js').XOptions} XOptions
5
- * @typedef {import('./API/x.ai/responses.js').XAIOptions} XAIOptions
6
- * @typedef {import('./API/openai.com/reponses/text.js').OAOptions} OAOptions
7
- * @typedef {import('./API/anthropic.com/text.js').ANTHOptions} ANTHOptions
8
- */
4
+ * @module lib/AgentManager
5
+ * @exports default AgentManager
6
+ * High-level orchestrator for AI agent lifecycle: configures Prompt/Session/ToolSet, launches CLI/Server/Client modes.
7
+ * Supports chaining setup() → start(); adds generic tools; direct calls.
8
+ */
9
+
10
+ /**
11
+ * @typedef {import('./API/x.ai/text.js').XOptions} XOptions
12
+ * @typedef {import('./API/x.ai/responses.js').XAIOptions} XAIOptions
13
+ * @typedef {import('./API/openai.com/reponses/text.js').OAOptions} OAOptions
14
+ * @typedef {import('./API/anthropic.com/text.js').ANTHOptions} ANTHOptions
15
+ */
9
16
  /**
10
- * @typedef {Object} Setup
11
- * @property {string} prompt - Initial system prompt
12
- * @property {XAIOptions|OAOptions|XOptions|ANTHOptions} options - Model options
13
- * @property {'gpt'|'xai'|'claude'} api - AI endpoint to use
14
- * @property {number} [contextWindow] - The size in tokens for the context/session
15
- * @property {'auto'|'required'|void} [toolsetMode] -
16
- * @property {boolean} [debug] - verbose output
17
- */
17
+ * @typedef {Object} Setup
18
+ * @property {string} prompt - Initial system prompt.
19
+ * @property {XAIOptions|OAOptions|XOptions|ANTHOptions} options - API model options.
20
+ * @property {'gpt'|'xai'|'claude'} api - AI provider.
21
+ * @property {number} [contextWindow=300000] - Token limit for context.
22
+ * @property {'auto'|'required'|null} [toolsetMode] - Toolset activation mode.
23
+ * @property {boolean} [debug] - Enable verbose output.
24
+ */
18
25
  /**
19
- * @typedef {Object} Options
20
- * @property {string} name - Agent name
21
- * @property {string} secret - Secret string for WS access authorisation (server and client secrets should match)
22
- * @property {string} [cachePath] - path to session/record storage
23
- */
26
+ * @typedef {Object} Options
27
+ * @property {string} name - Agent name (validated /^[a-z_0-9]{2,}$/).
28
+ * @property {string} secret - WS auth secret (base64-encoded).
29
+ * @property {string} [cachePath='.cache/hello-dave'] - Session cache directory.
30
+ * @example { name: 'code-agent', secret: 'mysecret' }
31
+ */
32
+ /** @const {RegExp} Validates agent/tool names (lowercase a-z0-9_, min 2 chars). */
33
+ const validNameRegex = /^[a-z_0-9]{2,}$/;
34
+
24
35
  class AgentManager {
25
- /** @type {Prompt} */
36
+ /** @private @type {Prompt} */
26
37
  #prompt;
27
- /** @type {Session} */
38
+ /** @private @type {Session} */
28
39
  #sessionStorage;
40
+ /** @private @type {string} */
29
41
  #name = 'agent';
42
+ /** @private @type {string} */
30
43
  #secret = '';
44
+ /** @private @type {string} */
31
45
  #cachePath = '.cache/hello-dave';
46
+ /** @private @type {boolean} */
32
47
  #debug = false;
48
+ /** @private @type {string} */
33
49
  #model = '';
50
+ /** @private @type {number} */
34
51
  #contextWindow = 0;
52
+ /** @private @type {string} */
35
53
  #sysPrompt = '';
54
+
36
55
  /**
37
- * @param {Options} options
38
- */
56
+ * Initializes AgentManager with base options.
57
+ * Validates name regex; encodes secret.
58
+ * @param {Options} options - Base configuration.
59
+ * @throws {Error} Invalid name (regex) or options.
60
+ * @chainable
61
+ */
39
62
  constructor(options) {
40
63
  this.#name = options.name || this.#name;
41
64
  if (options.secret && typeof options.secret === 'string') {
42
65
  this.#secret = Buffer.from(options.secret).toString('base64');
43
66
  }
44
- const validNameRegex = /^[a-z_0-9]{2,}$/;
45
67
  if (!validNameRegex.test(this.#name)) {
46
- throw new Error(`Invalid agent 'name' in options: '${this.#name}'. Must match /^[a-z_0-9]{2,}$/ (lowercase a-z, digits, underscores; min 2 chars).`);
68
+ throw new Error(`Invalid agent 'name': '${this.#name}'. Must match /^[a-z_0-9]{2,}$/`);
47
69
  }
48
70
  this.#cachePath = options.cachePath || this.#cachePath;
49
71
  }
50
72
 
51
73
  /**
52
- * @param {Setup} setup
53
- */
74
+ * Configures the Prompt/Session/ToolSet with API adaptor.
75
+ * Adds system prompt; chains to start().
76
+ * @param {Setup} setup - AI setup details.
77
+ * @returns {AgentManager} This instance (chainable).
78
+ * @throws {Error} Invalid setup.
79
+ * @example mgr.setup({ prompt: 'You are a coder...', api: 'gpt', options: { model: 'gpt-4o' } });
80
+ */
54
81
  setup(setup) {
55
82
  const {
56
83
  prompt,
@@ -63,9 +90,6 @@ class AgentManager {
63
90
  this.#sysPrompt = prompt;
64
91
  this.#contextWindow = contextWindow;
65
92
  if (options?.model) this.#model = options.model;
66
- this.#sysPrompt = prompt;
67
- this.#contextWindow = contextWindow;
68
- if (options?.model) this.#model = options.model;
69
93
  let toolset;
70
94
  if (toolsetMode) {
71
95
  toolset = new ToolSet(toolsetMode);
@@ -77,43 +101,48 @@ class AgentManager {
77
101
  this.#sessionStorage = new Session(this.#name, this.#prompt, this.#cachePath);
78
102
  this.#prompt.add('system', prompt, true);
79
103
  this.#prompt.setAdaptor(API.text[api], toolset, options);
80
- return this; // For chaining
104
+ return this;
81
105
  }
82
106
 
83
107
  /**
84
- * Start a CLI for local usage
85
- * @param {string} description - introduction message for the CLI user
86
- */
108
+ * @private
109
+ * Launches interactive CLI mode.
110
+ * @param {string} description - CLI intro message.
111
+ * @returns {void}
112
+ * @throws {Error} No setup() called.
113
+ */
87
114
  #startCli(description) {
88
115
  if (!this.#prompt) throw new Error('Run setup first');
89
116
  const cli = new Cli({ prompt: this.#prompt, session: this.#sessionStorage, description });
90
117
  setTimeout(() => {
91
- // This resolves issues with log output after the console has been started
92
118
  cli.start();
93
119
  }, 1000);
94
120
  }
95
121
 
96
122
  /**
97
- * Attach a session to an AgentServer
98
- * DO NOT ATTACH TO SELF, however, when in server mode
99
- * An AgentServer can attach as client to another server
100
- * @param {string} name - function_call name
101
- * @param {string} description - function_call description
102
- * @param {string} [url='ws://127.0.0.1:8000/ws'] - ws URL
103
- */
123
+ * @private
124
+ * Attaches this agent as a WS client to another server (for chaining agents).
125
+ * @param {string} name - Tool name.
126
+ * @param {string} description - Tool desc.
127
+ * @param {string} [url='ws://127.0.0.1:8000/ws'] - Target WS URL.
128
+ * @returns {AgentClient} New client instance.
129
+ * @throws {Error} No setup().
130
+ */
104
131
  #attach(name, description, url = 'ws://127.0.0.1:8000/ws') {
105
132
  if (!this.#prompt) throw new Error('Run setup first');
106
133
  return new AgentClient({ prompt: this.#prompt, name, description, url, secret: this.#secret });
107
134
  }
108
135
 
109
136
  /**
110
- * Start the Agent in server mode.
111
- * A server is always started on localhost
112
- * Clients can attach now and are accesible as via function_calls (toolset)
113
- * @param {string} name - function_call name
114
- * @param {string} description - function_call description
115
- * @param {number} [port=8000] - Start the dynamic toolset server on this port
116
- */
137
+ * @private
138
+ * Enables server mode: Registers this agent for remote tool calls.
139
+ * Optionally attaches as client too.
140
+ * @param {string} name - Server/tool name.
141
+ * @param {string} [description=''] - Desc (auto from sysPrompt).
142
+ * @param {number} [port=8000] - Port.
143
+ * @returns {void}
144
+ * @throws {Error} No setup/toolset.
145
+ */
117
146
  #enableServer(name, description = '', port = 8000) {
118
147
  if (!this.#prompt) throw new Error('Run setup first');
119
148
  if (!this.#prompt.toolset) throw new Error('No toolset defined');
@@ -125,64 +154,68 @@ class AgentManager {
125
154
  prompt: this.#prompt,
126
155
  session: this.#sessionStorage,
127
156
  debug: this.#debug
128
-
129
157
  });
130
- // trigger reset on all Agents
131
158
  this.#prompt.on('reset', () => {
132
- // Generate new context for all Agents
133
159
  server.resetAll();
134
- })
160
+ });
135
161
  }
162
+
136
163
  /**
137
- * Direct call to the prompt
138
- * @param {string} input
139
- * @returns {Promise<string>}
140
- */
164
+ * Direct synchronous call to the underlying Prompt.
165
+ * @param {string} input - User input.
166
+ * @returns {Promise&lt;string&gt;} Response.
167
+ * @throws {Error} No setup.
168
+ */
141
169
  async directCall(input) {
142
170
  const res = await this.#prompt.call(input);
143
171
  return res;
144
172
  }
145
- /** @returns {Prompt} */
173
+
174
+ /** @returns {Prompt} Underlying Prompt instance. */
146
175
  getPrompt() { return this.#prompt; }
147
- /** @returns {ToolSet|void} */
176
+
177
+ /** @returns {ToolSet|null} Toolset if configured. */
148
178
  getToolset() { return this.#prompt.toolset; }
149
- /** @returns {Promise<import('./fafs.js').EnvironmentInfo>} */
179
+
180
+ /** @returns {Promise&lt;import('./fafs.js').EnvironmentInfo&gt;} System env info. */
150
181
  async environment() {
151
182
  return env();
152
183
  }
184
+
153
185
  /**
154
- * Adds a pre-defined generic tool from lib/genericToolset.js to this agent's ToolSet.
155
- * @param {'execute_bash_script'|'execute_remote_script'|'get_user_env'|'history_search'|'javascript_interpreter'|'memory_recall'|'memory_write'|'open_link'|'read_file'|'send_email'|'syntax_check'|'write_file'} name - Valid generic tool name (validated /^[a-z_0-9]{2,}$/).
156
- * @throws {Error} If toolset not initialized or tool not found in pool.
186
+ * Adds a pre-defined generic tool from toolsPool to this agent's ToolSet.
187
+ * @param {'execute_bash_script'|'execute_remote_script'|'get_user_env'|'history_search'|'javascript_interpreter'|'memory_recall'|'memory_write'|'open_link'|'read_file'|'send_email'|'syntax_check'|'write_file'} name - Tool name.
188
+ * @throws {Error} Invalid name, no toolset, or tool missing.
189
+ * @example mgr.addGenericToolcall('read_file');
157
190
  */
158
191
  addGenericToolcall(name) {
159
- const validNameRegex = /^[a-z_0-9]{2,}$/;
160
192
  if (!validNameRegex.test(name)) {
161
- throw new Error(`Invalid 'name': '${name}'. Must match /^[a-z_0-9]{2,}$/ (lowercase a-z, digits, underscores; min 2 chars).`);
193
+ throw new Error(`Invalid 'name': '${name}'. Must match /^[a-z_0-9]{2,}$/`);
162
194
  }
163
- if (!this.#prompt.toolset) throw new Error('No ToolSet defined')
195
+ if (!this.#prompt.toolset) throw new Error('No ToolSet defined');
164
196
  let tool = toolsPool.get(name);
165
- if (!tool) throw new Error('Tool not defined')
197
+ if (!tool) throw new Error(`Tool '${name}' not found in pool`);
166
198
  this.#prompt.toolset.add(name, tool.description, tool.parameters, tool.method);
167
199
  }
168
200
 
169
201
  /**
170
- * Smart launcher: Dispatches to CLI/server/attach/direct. Auto-gens cliIntro/desc if empty.
171
- * @param {number} [servePort] - Server port (if no input).
172
- * @param {string} [connectUrl] - WS to attach. e.g. ws://127.0.0.1:8091/ws
173
- * @param {string} [cliIntro=""] - CLI intro (auto-gen if falsy).
174
- * @param {string} [toolName=""] - name /^[a-z_0-9]{2,}$/ Tool name for server/attach (defaults to agent.name).
175
- * @param {string} [toolDescription=""] - Tool desc (auto-gen if falsy).
202
+ * Smart launcher: CLI (default), server (servePort), or client (connectUrl).
203
+ * Auto-generates intros/descriptions if empty.
204
+ * @param {number} [servePort] - Launch server on port.
205
+ * @param {string} [connectUrl] - Connect as client to WS.
206
+ * @param {string} [cliIntro=""] - CLI intro text.
207
+ * @param {string} [toolName=""] - Tool/server name (falls back to #name).
208
+ * @param {string} [toolDescription=""] - Tool desc.
209
+ * @returns {Promise&lt;void&gt;}
210
+ * @throws {Error} No setup; invalid names/ports.
211
+ * @example mgr.start(8000); // Server\nmgr.start(undefined, 'ws://other:8001/ws'); // Client\nmgr.start(); // CLI
176
212
  */
177
213
  async start(servePort, connectUrl, cliIntro = "", toolName = "", toolDescription = "") {
178
214
  if (!this.#prompt) throw new Error("Run setup first");
179
215
 
180
- const validNameRegex = /^[a-z_0-9]{2,}$/;
181
-
182
216
  toolName = toolName || this.#name;
183
- // Validate 'toolName' (or fallback agent name)
184
217
  if (!validNameRegex.test(toolName)) {
185
- throw new Error(`Invalid 'toolName' (or agent #name): '${toolName}'. Must match /^[a-z_0-9]{2,}$/ (lowercase a-z, digits, underscores; min 2 chars).`);
218
+ throw new Error(`Invalid 'toolName': '${toolName}'. Must match /^[a-z_0-9]{2,}$/`);
186
219
  }
187
220
 
188
221
  if (!toolDescription && this.#sysPrompt) {
@@ -190,22 +223,20 @@ class AgentManager {
190
223
  }
191
224
 
192
225
  if (!cliIntro) {
193
- const introStr = this.#name + " " + (this.#model || "unknown-model") + " - context: " + this.#contextWindow;
226
+ const introStr = `${this.#name} ${this.#model || "unknown-model"} - context: ${this.#contextWindow}`;
194
227
  cliIntro = introStr.trim();
195
228
  }
229
+
196
230
  if (servePort) {
197
231
  console.log(toolName);
198
232
  console.log(toolDescription);
199
233
  this.#enableServer(toolName, toolDescription, servePort);
200
- // A server can also be a client
201
234
  if (connectUrl) {
202
235
  this.#attach(toolName, toolDescription, connectUrl);
203
236
  }
204
237
  } else if (connectUrl) {
205
- // Connect to a agent 'server' and enable via websocket / toolcalls
206
238
  this.#attach(toolName, toolDescription, connectUrl);
207
239
  } else {
208
- // Terminal user CLI
209
240
  this.#startCli(cliIntro);
210
241
  }
211
242
  }