@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.
- package/CHANGELOG.md +13 -26
- package/README.md +161 -522
- package/README.md.bak +144 -449
- package/{examples → agents}/ask_agent.js +5 -5
- package/{examples → agents}/codeserver.sh +14 -14
- package/{examples → agents}/daisy_agent.js +5 -5
- package/{examples → agents}/docs_agent.js +5 -5
- package/{examples → agents}/gpt_agent.js +5 -5
- package/{examples → agents}/grok_agent.js +5 -5
- package/agents/memory_agent.js +263 -0
- package/{examples → agents}/npm_agent.js +5 -5
- package/{examples → agents}/prompt_agent.js +5 -5
- package/agents/spawn_agent.js +137 -0
- package/{examples → agents}/test_agent.js +6 -8
- package/{examples → agents}/todo_agent.js +5 -5
- package/bin/codeDave +58 -0
- package/bin/dave.js +114 -96
- package/lib/AgentClient.js +111 -67
- package/lib/AgentManager.js +111 -80
- package/lib/AgentServer.js +144 -104
- package/lib/Cli.js +126 -93
- package/lib/Prompt.js +38 -5
- package/lib/Session.js +102 -79
- package/lib/ToolSet.js +79 -60
- package/lib/fafs.js +54 -19
- package/lib/genericToolset.js +109 -213
- package/lib/wsCli.js +50 -19
- package/lib/wsIO.js +11 -17
- package/package.json +2 -2
- package/types/AgentClient.d.ts +69 -35
- package/types/AgentManager.d.ts +50 -56
- package/types/AgentServer.d.ts +63 -16
- package/types/Cli.d.ts +56 -10
- package/types/Prompt.d.ts +36 -4
- package/types/Session.d.ts +23 -9
- package/types/ToolSet.d.ts +49 -32
- package/types/fafs.d.ts +68 -25
- package/types/wsCli.d.ts +14 -0
- package/types/wsIO.d.ts +9 -5
- package/utils/search_sessions.sh +100 -53
- package/README.md.backup +0 -269
- package/README.md.bak.1774780058 +0 -338
- package/README.md.bak2 +0 -531
- package/bin/spawn_agent.js +0 -293
- package/docs.bak.1774780058/agent-manager.md +0 -167
- package/docs.bak.1774780058/agent-manager.md.bak +0 -137
- package/docs.bak.1774780058/agent-manager.md.bak2 +0 -157
- package/docs.bak.1774780058/codeserver-pattern.md +0 -191
- package/docs.bak.1774780058/path-resolution-best-practices.md +0 -104
- package/docs.bak.1774780058/project-overview.md +0 -67
- package/docs.bak.1774780058/project-overview.md.bak +0 -67
- package/docs.bak.1774780058/prompt-class.md +0 -141
- package/docs.bak.1774780058/prompt-class.md.bak +0 -142
- package/docs.bak.1774780058/tools-syntax-validation.md +0 -121
- package/docs.bak.1774780058/tools-syntax-validation.md.bak2 +0 -125
- package/docs.bak.1774780058/tools-syntax-validation.md.bak3 +0 -125
- package/docs.bak.1774780058/tools-syntax-validation.md.bak4 +0 -106
- package/docs.bak.1774780058/tools-syntax-validation.md.bak_path +0 -106
- package/docs.bak.1774780058/toolset.md +0 -164
- package/docs.bak.1774780058/toolset.md.bak +0 -94
- package/docs.bak.1774780058/toolset.md.bak3 +0 -161
- package/docs.bak.1774780058/toolset.md.bak4 +0 -161
- package/docs.bak.1774780058/toolset.md.bak5 +0 -161
- package/docs.bak.1774780058/toolset.md.bak6 +0 -163
- package/docs.bak.1774780058/toolset.md.bak_path +0 -163
- package/docs.bak.1774780058/toolset.md.bak_syntax +0 -161
- package/docs.bak.1774780058/xai-responses.md +0 -111
- package/docs.bak.1774780058/xai-responses.md.bak +0 -107
- package/docs.bak.1774780058/xai-responses.md.bak2 +0 -107
- package/docs.bak.1774780058/xai_collections.md +0 -106
- package/examples/memory_agent.js +0 -152
- package/examples.bak.1774780058/ask_agent.js +0 -114
- package/examples.bak.1774780058/code_agent.js +0 -149
- package/examples.bak.1774780058/coderev_agent.js +0 -72
- package/examples.bak.1774780058/codeserver.sh +0 -47
- package/examples.bak.1774780058/daisy_agent.js +0 -177
- package/examples.bak.1774780058/docs_agent.js +0 -119
- package/examples.bak.1774780058/gpt_agent.js +0 -109
- package/examples.bak.1774780058/grok_agent.js +0 -98
- package/examples.bak.1774780058/memory_agent.js +0 -112
- package/examples.bak.1774780058/npm_agent.js +0 -175
- package/examples.bak.1774780058/prompt_agent.js +0 -112
- package/examples.bak.1774780058/readme_agent.js +0 -144
- package/examples.bak.1774780058/spawn_agent.js +0 -263
- package/examples.bak.1774780058/test_agent.js +0 -162
- package/examples.bak.1774780058/todo_agent.js +0 -138
- package/lib/genericToolset.js.bak_syntax +0 -402
- package/scenarios.bak.1774780058/data/eval_node_message.json +0 -9
- package/scenarios.bak.1774780058/data/hist_oa.json +0 -66
- package/scenarios.bak.1774780058/data/o3_response1.json +0 -96
- package/scenarios.bak.1774780058/data/oa_reasoning_parse.json +0 -112
- package/scenarios.bak.1774780058/data/tool_oa.json +0 -96
- package/scenarios.bak.1774780058/data/tool_xai.json +0 -59
- package/scenarios.bak.1774780058/data/tool_xai2.json +0 -40
- package/scenarios.bak.1774780058/data/xai-response-1.json +0 -59
- package/scenarios.bak.1774780058/data/xai-response-2.json +0 -10
- package/scenarios.bak.1774780058/data/xai_reasoning_tools_resp.json +0 -59
- package/scenarios.bak.1774780058/data/xai_search_response.json +0 -58
- package/scenarios.bak.1774780058/environment.js +0 -10
- package/scenarios.bak.1774780058/example.js +0 -17
- package/scenarios.bak.1774780058/genericToolset.test.js +0 -182
- package/scenarios.bak.1774780058/grok.js +0 -113
- package/scenarios.bak.1774780058/memory-tools.js +0 -51
- package/scenarios.bak.1774780058/openai-o3.js +0 -137
- package/scenarios.bak.1774780058/openai-prompt.js +0 -155
- package/scenarios.bak.1774780058/openai-session.js +0 -148
- package/scenarios.bak.1774780058/openai.js +0 -102
- package/scenarios.bak.1774780058/prompt.js +0 -118
- package/scenarios.bak.1774780058/promptFishbowl.js +0 -76
- package/scenarios.bak.1774780058/search.brave.com.js +0 -25
- package/scenarios.bak.1774780058/sh.js +0 -15
- package/scenarios.bak.1774780058/test-wsio.js +0 -26
- package/scenarios.bak.1774780058/testToolset.js +0 -42
- package/scenarios.bak.1774780058/toolset.js +0 -16
- package/scenarios.bak.1774780058/toolset.test.js +0 -141
- package/scenarios.bak.1774780058/write_file_syntax.test.js +0 -145
- package/scenarios.bak.1774780058/write_file_validation/README.md +0 -30
- package/scenarios.bak.1774780058/write_file_validation/bad.js +0 -3
- package/scenarios.bak.1774780058/write_file_validation/good.js +0 -4
- package/scenarios.bak.1774780058/write_file_validation/test.sh +0 -43
- package/scenarios.bak.1774780058/wsClient.js +0 -69
- package/scenarios.bak.1774780058/xai_responses.integration.test.js +0 -57
- package/scenarios.bak.1774780058/xai_responses.test.js +0 -154
- package/scenarios.bak.1774780058/xaicoll.js +0 -50
- package/scenarios.bak.1774780058/xaifiles.js +0 -48
- /package/{examples → agents}/code_agent.js +0 -0
- /package/{examples → agents}/readme_agent.js +0 -0
package/lib/AgentClient.js
CHANGED
|
@@ -1,58 +1,82 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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] -
|
|
22
|
-
* @property {string} description - Custom introduction message.
|
|
23
|
-
* @property {string} name - Logical name
|
|
24
|
-
* @property {string} secret - Websocket server access secret.
|
|
25
|
-
* @property {string} [url='ws://127.0.0.1:8000/ws
|
|
26
|
-
* @property {number} [intervalMs=
|
|
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
|
-
*
|
|
30
|
-
*
|
|
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
|
-
|
|
43
|
-
/** @type {Array<any>} */
|
|
62
|
+
/** @private @type {Array<Object>} Message queue for sequential processing. */
|
|
44
63
|
#queue = [];
|
|
64
|
+
/** @private @type {boolean} Flag to prevent reentrant processing. */
|
|
45
65
|
#processing = false;
|
|
46
|
-
|
|
66
|
+
/** @private @type {number} Epoch counter; increments on reset to invalidate in-flight work. */
|
|
47
67
|
#epoch = 0;
|
|
48
68
|
|
|
49
|
-
|
|
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
|
-
*
|
|
55
|
-
*
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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);
|
|
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
|
-
|
|
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
|
-
|
|
121
|
-
|
|
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;
|
|
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
|
-
*
|
|
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
|
-
/**
|
|
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
|
-
*
|
|
198
|
+
* @private
|
|
199
|
+
* Processes exactly one queued message (guards reentrancy).
|
|
200
|
+
* Stops interval if queue empty post-process.
|
|
201
|
+
* @returns {Promise<void>}
|
|
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
|
-
*
|
|
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<void>}
|
|
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();
|
package/lib/AgentManager.js
CHANGED
|
@@ -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
|
-
* @
|
|
5
|
-
* @
|
|
6
|
-
*
|
|
7
|
-
*
|
|
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 -
|
|
13
|
-
* @property {'gpt'|'xai'|'claude'} api - AI
|
|
14
|
-
* @property {number} [contextWindow] -
|
|
15
|
-
* @property {'auto'|'required'|
|
|
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 -
|
|
22
|
-
* @property {string} [cachePath] -
|
|
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
|
-
|
|
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'
|
|
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
|
-
|
|
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;
|
|
104
|
+
return this;
|
|
81
105
|
}
|
|
82
106
|
|
|
83
107
|
/**
|
|
84
|
-
|
|
85
|
-
|
|
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
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
164
|
+
* Direct synchronous call to the underlying Prompt.
|
|
165
|
+
* @param {string} input - User input.
|
|
166
|
+
* @returns {Promise<string>} 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
|
-
|
|
173
|
+
|
|
174
|
+
/** @returns {Prompt} Underlying Prompt instance. */
|
|
146
175
|
getPrompt() { return this.#prompt; }
|
|
147
|
-
|
|
176
|
+
|
|
177
|
+
/** @returns {ToolSet|null} Toolset if configured. */
|
|
148
178
|
getToolset() { return this.#prompt.toolset; }
|
|
149
|
-
|
|
179
|
+
|
|
180
|
+
/** @returns {Promise<import('./fafs.js').EnvironmentInfo>} System env info. */
|
|
150
181
|
async environment() {
|
|
151
182
|
return env();
|
|
152
183
|
}
|
|
184
|
+
|
|
153
185
|
/**
|
|
154
|
-
* Adds a pre-defined generic tool from
|
|
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 -
|
|
156
|
-
* @throws {Error}
|
|
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,}
|
|
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(
|
|
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:
|
|
171
|
-
*
|
|
172
|
-
* @param {
|
|
173
|
-
* @param {string} [
|
|
174
|
-
* @param {string} [
|
|
175
|
-
* @param {string} [
|
|
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<void>}
|
|
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'
|
|
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
|
|
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
|
}
|