@j-o-r/hello-dave 0.1.0 → 0.1.4
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 +42 -25
- package/README.md +81 -221
- package/TODO.md +173 -35
- package/agents/agent_creator.js +105 -0
- package/agents/agent_creator.prompt.md +371 -0
- package/agents/ask_agent.js +64 -127
- package/agents/claude_agent.js +68 -0
- package/agents/code_agent.js +55 -135
- package/agents/code_agent.prompt.md +50 -0
- package/agents/echo_agent.js +76 -0
- package/agents/financial_expert.js +75 -0
- package/agents/gpt_agent.js +52 -103
- package/agents/gpt_code.js +81 -0
- package/agents/grok_agent.js +58 -114
- package/agents/minimax_agent.js +92 -0
- package/agents/mureka_agent.js +77 -0
- package/agents/planner_agent.js +172 -0
- package/agents/stability_agent.js +87 -0
- package/agents/test_agent.js +75 -157
- package/agents/weather_agent.js +73 -0
- package/agents/workflow_agent.js +189 -0
- package/bin/dave.js +436 -184
- package/docs/bin-dave.md +85 -35
- package/docs/cdn-ssh.md +100 -0
- package/docs/creating-agents.md +301 -0
- package/docs/creating-toolsets.md +336 -0
- package/docs/docs-organization.md +48 -0
- package/docs/project-overview.md +86 -51
- package/lib/API/elevenlabs.io/music.compose.md +441 -0
- package/lib/API/elevenlabs.io/music.create-composition-plan.md +370 -0
- package/lib/API/elevenlabs.io/music.stream.md +425 -0
- package/lib/API/lalal.ai/lalal.js +445 -0
- package/lib/API/lalal.ai/openapi.json +2614 -0
- package/lib/API/minimax/ImageToolset.js +82 -37
- package/lib/API/minimax/MusicToolset.js +125 -79
- package/lib/API/minimax/VideoToolset.js +170 -167
- package/lib/API/minimax/image.js +5 -1
- package/lib/API/minimax/music.js +210 -23
- package/lib/API/minimax/video.js +242 -53
- package/lib/API/mureka/MusicToolset.js +646 -0
- package/lib/API/mureka/README.md +41 -0
- package/lib/API/mureka/index.js +7 -0
- package/lib/API/mureka/music.js +658 -0
- package/lib/API/openai.com/index.js +7 -0
- package/lib/API/openai.com/{reponses/text.js → responses.js} +64 -18
- package/lib/API/openai.com/video.create.character.md +40 -0
- package/lib/API/openai.com/video.create.md +219 -0
- package/lib/API/openai.com/video.delete.md +44 -0
- package/lib/API/openai.com/video.download.md +31 -0
- package/lib/API/openai.com/video.edit.md +155 -0
- package/lib/API/openai.com/video.extend.md +166 -0
- package/lib/API/openai.com/video.fetch.character.md +43 -0
- package/lib/API/openai.com/video.js +784 -0
- package/lib/API/openai.com/video.list.md +201 -0
- package/lib/API/openai.com/video.remix.md +175 -0
- package/lib/API/openai.com/video.retrieve.md +139 -0
- package/lib/API/openai.com/videoToolset.js +616 -0
- package/lib/API/stability.ai/ImageToolset.js +131 -40
- package/lib/API/stability.ai/MusicToolset.js +79 -47
- package/lib/API/stability.ai/audio.js +63 -131
- package/lib/API/x.ai/chat.responses.md +1040 -0
- package/lib/API/x.ai/image.js +229 -59
- package/lib/API/x.ai/imageToolset.js +376 -0
- package/lib/API/x.ai/index.js +1 -3
- package/lib/API/x.ai/responses.js +9 -18
- package/lib/Agent.js +271 -0
- package/lib/Agent.js.old +284 -0
- package/lib/AgentLauncher.js +562 -0
- package/lib/Cli.js +87 -13
- package/lib/Prompt.js +23 -1
- package/lib/Session.js +5 -4
- package/lib/ToolSet.js +102 -6
- package/lib/agentLoader.js +369 -0
- package/lib/cdn.js +67 -231
- package/lib/{CdnToolset.js → cdnToolset.js} +47 -64
- package/lib/defaultToolsets.js +43 -0
- package/lib/fafs.js +1 -1
- package/lib/genericToolset.js +442 -119
- package/lib/handOffToolset.js +179 -0
- package/lib/index.js +34 -27
- package/lib/toolsetLoader.js +248 -0
- package/package.json +11 -5
- package/types/API/lalal.ai/lalal.d.ts +116 -0
- package/types/API/minimax/image.d.ts +2 -1
- package/types/API/minimax/music.d.ts +189 -26
- package/types/API/minimax/video.d.ts +100 -31
- package/types/API/mureka/index.d.ts +7 -0
- package/types/API/mureka/music.d.ts +472 -0
- package/types/API/openai.com/index.d.ts +7 -0
- package/types/API/openai.com/{reponses/text.d.ts → responses.d.ts} +11 -11
- package/types/API/openai.com/video.d.ts +409 -0
- package/types/API/openai.com/videoToolset.d.ts +24 -0
- package/types/API/stability.ai/audio.d.ts +14 -103
- package/types/API/stability.ai/image.d.ts +2 -2
- package/types/API/x.ai/image.d.ts +138 -26
- package/types/API/x.ai/imageToolset.d.ts +3 -0
- package/types/API/x.ai/index.d.ts +1 -3
- package/types/API/x.ai/responses.d.ts +4 -4
- package/types/Agent.d.ts +123 -0
- package/types/AgentLauncher.d.ts +222 -0
- package/types/Cli.d.ts +28 -8
- package/types/Prompt.d.ts +23 -5
- package/types/Session.d.ts +1 -1
- package/types/ToolSet.d.ts +10 -0
- package/types/agentLoader.d.ts +78 -0
- package/types/cdn.d.ts +15 -90
- package/types/defaultToolsets.d.ts +9 -0
- package/types/fafs.d.ts +1 -1
- package/types/genericToolset.d.ts +1 -1
- package/types/handOffToolset.d.ts +28 -0
- package/types/index.d.ts +19 -16
- package/types/toolsetLoader.d.ts +114 -0
- package/utils/format_log.js +101 -23
- package/utils/launch_agent.js +18 -0
- package/utils/list_sessions.sh +13 -5
- package/utils/search_sessions.sh +65 -29
- package/utils/toolsets.js +33 -0
- package/README.md.bak.1779452127 +0 -240
- package/agents/codeserver.sh +0 -47
- package/agents/daisy_agent.js +0 -173
- package/agents/docs_agent.js +0 -148
- package/agents/memory_agent.js +0 -263
- package/agents/minimax.js +0 -173
- package/agents/npm_agent.js +0 -202
- package/agents/prompt_agent.js +0 -133
- package/agents/readme_agent.js +0 -148
- package/agents/spawn_agent.js +0 -160
- package/agents/stability.js +0 -173
- package/agents/todo_agent.js +0 -175
- package/bin/codeDave +0 -58
- package/docs/agent-dave-websocket-protocol.md +0 -180
- package/docs/agent-manager.md +0 -244
- package/docs/codeserver-pattern.md +0 -191
- package/docs/generic-toolset.md +0 -326
- package/docs/howtos/agent-networking.md +0 -253
- package/docs/howtos/spawn-agents.md.bak +0 -200
- package/docs/howtos/spawn-agents.md.bak_new +0 -200
- package/docs/multi-agent-clusters.md +0 -265
- package/docs/music-toolsets.md +0 -137
- package/docs/path-resolution-best-practices.md +0 -104
- package/docs/plans/minimax-music-generation.md +0 -80
- package/docs/plans/unified-agent-architecture.md +0 -146
- package/docs/plans/websocket-streaming-plan.md.bak +0 -317
- package/docs/prompt/spawn_agent.md +0 -175
- package/docs/prompt/spawn_agent.md.bak +0 -201
- package/docs/prompt/task_clarification_and_documentation.md +0 -35
- package/docs/prompt-class.md +0 -141
- package/docs/todo-archive-infra-2026-04-21.md +0 -15
- package/docs/todo-archive-v0.0.8.md +0 -1
- package/docs/todo-archive-v0.1.0.md +0 -32
- package/docs/todo-archive.md +0 -44
- package/docs/tools-syntax-validation.md +0 -121
- package/docs/toolset.md +0 -164
- package/docs/xai-responses.md +0 -111
- package/docs/xai_collections.md +0 -106
- package/lib/API/x.ai/ImageToolset.js +0 -165
- package/lib/API/x.ai/text.js +0 -415
- package/lib/AgentClient.js +0 -248
- package/lib/AgentManager.js +0 -245
- package/lib/AgentServer.js +0 -404
- package/lib/wsCli.js +0 -287
- package/lib/wsIO.js +0 -90
- package/types/API/x.ai/text.d.ts +0 -286
- package/types/AgentClient.d.ts +0 -109
- package/types/AgentManager.d.ts +0 -100
- package/types/AgentServer.d.ts +0 -89
- package/types/wsCli.d.ts +0 -17
- package/types/wsIO.d.ts +0 -30
- package/utils/test.sh +0 -46
- /package/docs/{suggestions.md → _notes/token-counts.md} +0 -0
- /package/lib/API/openai.com/{reponses/MESSAGES.md → MESSAGES.md} +0 -0
- /package/types/API/{x.ai/ImageToolset.d.ts → mureka/MusicToolset.d.ts} +0 -0
- /package/types/{CdnToolset.d.ts → cdnToolset.d.ts} +0 -0
package/lib/API/x.ai/text.js
DELETED
|
@@ -1,415 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* [api documentation](https://docs.x.ai/docs/overview)
|
|
3
|
-
*/
|
|
4
|
-
import { GLOBAL } from '../../fafs.js'
|
|
5
|
-
import { request as doRequest } from '@j-o-r/apiserver';
|
|
6
|
-
import { sleep } from '@j-o-r/sh';
|
|
7
|
-
/**
|
|
8
|
-
* @typedef {import('../../Prompt.js').default} Prompt
|
|
9
|
-
* @typedef {import('../../ToolSet.js').default} ToolSet
|
|
10
|
-
*/
|
|
11
|
-
/**
|
|
12
|
-
* @typedef {"grok-4"|"grok-3"|"grok-3-mini"|"grok-3-fast"|"grok-3-mini-fast"} grokModels
|
|
13
|
-
* @typedef {"low"|"high"} grokReason
|
|
14
|
-
*/
|
|
15
|
-
/**
|
|
16
|
-
* @typedef {Object} SearchParameters
|
|
17
|
-
* @property {"on"|"auto"} mode
|
|
18
|
-
* @property {string} [from_date] ISO-8601 date (YYYY-MM-DD)
|
|
19
|
-
* @property {string} [to_date] ISO-8601 date (YYYY-MM-DD)
|
|
20
|
-
* @property {(RssSource|WebSource|NewsSource|XSource)[]} [sources]
|
|
21
|
-
*
|
|
22
|
-
* @typedef {Object} RssSource
|
|
23
|
-
* @property {"rss"} type
|
|
24
|
-
* @property {string[]} links
|
|
25
|
-
*
|
|
26
|
-
* @typedef {Object} WebSource
|
|
27
|
-
* @property {"web"} type
|
|
28
|
-
* @property {string} [country] ISO-3166-1 alpha-2
|
|
29
|
-
* @property {boolean} [safe_search=true]
|
|
30
|
-
* @property {string[]} [allowed_websites] // cannot coexist with excluded_websites
|
|
31
|
-
* @property {string[]} [excluded_websites]
|
|
32
|
-
*
|
|
33
|
-
* @typedef {Object} NewsSource
|
|
34
|
-
* @property {"news"} type
|
|
35
|
-
* @property {string} [country]
|
|
36
|
-
* @property {boolean} [safe_search=true]
|
|
37
|
-
* @property {string[]} [allowed_websites]
|
|
38
|
-
* @property {string[]} [excluded_websites]
|
|
39
|
-
*
|
|
40
|
-
* @typedef {Object} XSource
|
|
41
|
-
* @property {"x"} type
|
|
42
|
-
*/
|
|
43
|
-
/**
|
|
44
|
-
* @typedef {object} XRequest
|
|
45
|
-
* @property {XOptions} body
|
|
46
|
-
* @property {Headers} headers
|
|
47
|
-
* @property {string} url -
|
|
48
|
-
*/
|
|
49
|
-
/**
|
|
50
|
-
* @typedef {Object} XFunctionCall
|
|
51
|
-
* @property {string} name - The name of the function to call.
|
|
52
|
-
* @property {string} arguments - The arguments for the function call in JSON string format.
|
|
53
|
-
* @typedef {Object} XToolCall
|
|
54
|
-
* @property {string} id - The unique identifier for the tool call.
|
|
55
|
-
* @property {string} type - The type of the tool call, e.g., "function".
|
|
56
|
-
* @property {XFunctionCall} function - The function call details.
|
|
57
|
-
*/
|
|
58
|
-
/**
|
|
59
|
-
* @typedef {Object} XFunctionResponse
|
|
60
|
-
* @property {string} role - must be 'tool'
|
|
61
|
-
* @property {string} content - The arguments for the function call in JSON string format.
|
|
62
|
-
* @property {string} tool_call_id - The unique identifier for the tool call.
|
|
63
|
-
*/
|
|
64
|
-
/**
|
|
65
|
-
* @typedef {Object} XMessageResponse
|
|
66
|
-
* @property {number} index - The index of the message.
|
|
67
|
-
* @property {Object} message - The message details.
|
|
68
|
-
* @property {string} message.role - The role of the sender (e.g., "assistant").
|
|
69
|
-
* @property {string} message.content - The content of the message.
|
|
70
|
-
* @property {string} [message.reasoning_content] - The reasoning behind the response.
|
|
71
|
-
* @property {?string} message.refusal - Any refusal content, if applicable.
|
|
72
|
-
* @property {string} finish_reason - The reason for finishing (e.g., "stop").
|
|
73
|
-
* @property {XToolCall[]} tools_calls - The reason for finishing (e.g., "stop").
|
|
74
|
-
*/
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* https://docs.x.ai/api/endpoints#chat-completions
|
|
78
|
-
* @typedef {object} XOptions
|
|
79
|
-
* @property {grokModels} [model] - What model to use
|
|
80
|
-
* @property {Array<*>} [messages] - the actual prompt
|
|
81
|
-
* @property {XToolCall[]} [tools], callable functions
|
|
82
|
-
* @property {string} [tool_choice] - Default 'none' when no function, 'auto' when present, or required
|
|
83
|
-
* @property {Object} [response_format] - Response format
|
|
84
|
-
* @property {string} [response_format.type] - The role of the sender (e.g., "assistant").
|
|
85
|
-
* @property {number} [temperature] - What sampling temperature to use, between 0 and 2.
|
|
86
|
-
* @property {number} [max_completion_tokens] - The maximum number of tokens allowed for the generated answer.
|
|
87
|
-
* @property {number} [presence_penalty] - Number between -2.0 and 2.0.
|
|
88
|
-
* @property {number} [frequency_penalty] - Number between -2.0 and 2.0.
|
|
89
|
-
* @property {number} [top_p] - Number between -2.0 and 2.0.
|
|
90
|
-
* @property {number} [n] - How many chat completion choices to generate for each input message. default 1
|
|
91
|
-
* @property {boolean} [stream] - Chunk/stream request default null
|
|
92
|
-
* @property {boolean} [parallel_tool_calls] - Multiple calls at once
|
|
93
|
-
* @property {grokReason} [reasoning_effort] - Who i am
|
|
94
|
-
* @property {string} [user] - Who i am
|
|
95
|
-
* @property {number} [seed] - see options
|
|
96
|
-
* @property {SearchParameters} [search_parameters] - live search
|
|
97
|
-
* @property {string[]} [stop] - Up to 4 sequences where the API will stop generating further tokens.
|
|
98
|
-
*/
|
|
99
|
-
const API_URL = 'https://api.x.ai/v1/chat/completions';
|
|
100
|
-
/** @type {XOptions} */
|
|
101
|
-
const defaultSettings = {
|
|
102
|
-
model: 'grok-4',
|
|
103
|
-
messages: [
|
|
104
|
-
{
|
|
105
|
-
role: 'system',
|
|
106
|
-
content: 'Be precise and concise'
|
|
107
|
-
}
|
|
108
|
-
],
|
|
109
|
-
temperature: 0.2,
|
|
110
|
-
// response_format: { type: 'text' },
|
|
111
|
-
parallel_tool_calls: true,
|
|
112
|
-
// reasoning_effort: null,
|
|
113
|
-
// max_completion_tokens: 2000,
|
|
114
|
-
// presence_penalty: 0,
|
|
115
|
-
// frequency_penalty: 0,
|
|
116
|
-
// top_p: 1,
|
|
117
|
-
// stop: []
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Get the default headers
|
|
123
|
-
* @returns {object}
|
|
124
|
-
*/
|
|
125
|
-
const getHeaders = () => {
|
|
126
|
-
if (!process.env['XAIKEY']) {
|
|
127
|
-
throw new Error('Missing XAIKEY! export XAIKEY=<XAIKEY>')
|
|
128
|
-
}
|
|
129
|
-
const KEY = process.env['XAIKEY'];
|
|
130
|
-
return {
|
|
131
|
-
'Content-Type': 'application/json',
|
|
132
|
-
'Authorization': `Bearer ${KEY}`
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
/**
|
|
136
|
-
* Get the text from content
|
|
137
|
-
* @param {import('../../Prompt.js').Content[]} content
|
|
138
|
-
* @returns {string}
|
|
139
|
-
*/
|
|
140
|
-
function getTextFromContent(content) {
|
|
141
|
-
let res = '';
|
|
142
|
-
let i = 0;
|
|
143
|
-
const len = content.length;
|
|
144
|
-
for (; i < len; i++) {
|
|
145
|
-
if (content[i].type === 'text') {
|
|
146
|
-
// @ts-ignore
|
|
147
|
-
res = `${res}\n${content[i].text} `
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
return res.trim();
|
|
151
|
-
}
|
|
152
|
-
/**
|
|
153
|
-
* Convert messages to XAI
|
|
154
|
-
* @param {Prompt} prompt
|
|
155
|
-
* @returns {Array<*>}
|
|
156
|
-
*/
|
|
157
|
-
const generateHistory = (prompt) => {
|
|
158
|
-
const messages = prompt.messages
|
|
159
|
-
const result = [];
|
|
160
|
-
let i = 0;
|
|
161
|
-
const len = messages.length;
|
|
162
|
-
for (; i < len; i++) {
|
|
163
|
-
const msg = messages[i];
|
|
164
|
-
const role = msg.role;
|
|
165
|
-
if (['system', 'assistant', 'user'].includes(role)) {
|
|
166
|
-
// Get the text
|
|
167
|
-
const text = getTextFromContent(msg.content);
|
|
168
|
-
const newMesg = {
|
|
169
|
-
role,
|
|
170
|
-
content: text,
|
|
171
|
-
refusal: null
|
|
172
|
-
};
|
|
173
|
-
// Add initial toolcalls
|
|
174
|
-
const toolCalls = msg.content
|
|
175
|
-
.filter(item => item.type === 'function_request')
|
|
176
|
-
.map(req => ({
|
|
177
|
-
// @ts-ignore
|
|
178
|
-
id: req.function_request.id,
|
|
179
|
-
type: "function",
|
|
180
|
-
function: {
|
|
181
|
-
// @ts-ignore
|
|
182
|
-
arguments: req.function_request.parameters,
|
|
183
|
-
// @ts-ignore
|
|
184
|
-
name: req.function_request.name,
|
|
185
|
-
}
|
|
186
|
-
}));
|
|
187
|
-
if (toolCalls.length > 0) {
|
|
188
|
-
newMesg.tool_calls = toolCalls;
|
|
189
|
-
}
|
|
190
|
-
result.push(newMesg);
|
|
191
|
-
} else if (role === 'tool') {
|
|
192
|
-
const content = msg.content;
|
|
193
|
-
let it = 0;
|
|
194
|
-
const lent = content.length;
|
|
195
|
-
for (; it < lent; it++) {
|
|
196
|
-
/** @type {import('../..//Prompt.js').FunctionResponse} */
|
|
197
|
-
// @ts-ignore
|
|
198
|
-
const item = content[it];
|
|
199
|
-
if (item.type === 'function_response') {
|
|
200
|
-
// Add tool function response
|
|
201
|
-
result.push({
|
|
202
|
-
role: 'tool',
|
|
203
|
-
name: item.function_response.name,
|
|
204
|
-
call_id: item.function_response.call_id,
|
|
205
|
-
content: item.function_response.response
|
|
206
|
-
});
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
return result;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* Convert a toolset to something openai understands
|
|
216
|
-
* @param {ToolSet} toolset
|
|
217
|
-
* @returns {XToolCall[]}
|
|
218
|
-
*/
|
|
219
|
-
const generateXAIToolCalls = (toolset) => {
|
|
220
|
-
const list = toolset.list();
|
|
221
|
-
/** @type {XToolCall[]} */
|
|
222
|
-
const result = [];
|
|
223
|
-
list.forEach((item) => {
|
|
224
|
-
result.push({
|
|
225
|
-
type: 'function', function: {
|
|
226
|
-
name: item.name,
|
|
227
|
-
// @ts-ignore
|
|
228
|
-
description: item.description,
|
|
229
|
-
parameters: item.parameters
|
|
230
|
-
}
|
|
231
|
-
})
|
|
232
|
-
});
|
|
233
|
-
return result;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Create an anthropic request
|
|
238
|
-
* @param {Prompt} prompt
|
|
239
|
-
* @param {ToolSet|void} [tools]
|
|
240
|
-
* @param {XOptions} [opts] overwrite default request settings
|
|
241
|
-
* @param {object} [hdrs] - optional headers to pass
|
|
242
|
-
* @returns {XRequest}
|
|
243
|
-
* @throws {Error}
|
|
244
|
-
*/
|
|
245
|
-
const generateRequest = (prompt, tools, opts = {}, hdrs = {}) => {
|
|
246
|
-
/** @type {XOptions} */
|
|
247
|
-
const body = { ...defaultSettings, ...opts };
|
|
248
|
-
const headers = { ...getHeaders(), ...hdrs };
|
|
249
|
-
// Sanity check
|
|
250
|
-
// basePromptCheck(prompt);
|
|
251
|
-
// body.messages = generateXAIMessages(prompt) || [];
|
|
252
|
-
body.messages = generateHistory(prompt);
|
|
253
|
-
if (body.messages.length == 0) {
|
|
254
|
-
throw new Error('No messages found');
|
|
255
|
-
}
|
|
256
|
-
body.tools = (tools) ? generateXAIToolCalls(tools) : [];
|
|
257
|
-
body.tool_choice = (tools) ? tools.toolChoice : '';
|
|
258
|
-
if (body.tools.length === 0) {
|
|
259
|
-
delete body.tools;
|
|
260
|
-
delete body.tool_choice;
|
|
261
|
-
}
|
|
262
|
-
return { body, headers, url: API_URL };
|
|
263
|
-
};
|
|
264
|
-
|
|
265
|
-
// RESPONSE PARSER
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* @typedef {Object} XResponse
|
|
269
|
-
* @property {string} id - The unique identifier for the response.
|
|
270
|
-
* @property {string} object - The type of object returned, typically "chat.completion".
|
|
271
|
-
* @property {number} created - The timestamp of when the response was created.
|
|
272
|
-
* @property {string} model - The model used to generate the response.
|
|
273
|
-
* @property {Array<XChoice>} choices - An array of choice objects containing the response details.
|
|
274
|
-
* @property {XUsage} usage - An object containing token usage information.
|
|
275
|
-
* @property {string} system_fingerprint - The system fingerprint for the response.
|
|
276
|
-
* @property {Object} http_headers - HTTP headers associated with the response.
|
|
277
|
-
*/
|
|
278
|
-
/**
|
|
279
|
-
* @typedef {Object} XChoice
|
|
280
|
-
* @property {number} index - The index of the choice in the response.
|
|
281
|
-
* @property {XMessageResponse} message - The message object containing the role and content.
|
|
282
|
-
* @property {null} logprobs - Log probabilities, typically null.
|
|
283
|
-
* @property {string} finish_reason - The reason why the response finished.
|
|
284
|
-
*/
|
|
285
|
-
/**
|
|
286
|
-
* @typedef {Object} XUsage
|
|
287
|
-
* @property {number} prompt_tokens - The number of tokens in the prompt.
|
|
288
|
-
* @property {number} completion_tokens - The number of tokens in the completion.
|
|
289
|
-
* @property {number} total_tokens - The total number of tokens used.
|
|
290
|
-
*/
|
|
291
|
-
|
|
292
|
-
const parseMessages = (response, prompt) => {
|
|
293
|
-
/** @type {import('../../Prompt.js').FunctionRequest[]} */
|
|
294
|
-
const function_requests = [];
|
|
295
|
-
const messages = response.choices;
|
|
296
|
-
if (response.citations && response.citations.length > 0) {
|
|
297
|
-
const cits = response.citations.map((item, index) => `${index + 1}. ${item}`).join('\n');
|
|
298
|
-
prompt.add('log', cits);
|
|
299
|
-
}
|
|
300
|
-
let i = 0;
|
|
301
|
-
const len = messages.length;
|
|
302
|
-
for (; i < len; i++) {
|
|
303
|
-
const msg = messages[i];
|
|
304
|
-
if (msg.message.reasoning_content) {
|
|
305
|
-
// Add reasoning content
|
|
306
|
-
// Handy for debugging prompts
|
|
307
|
-
prompt.add('reasoning', msg.message.reasoning_content);
|
|
308
|
-
}
|
|
309
|
-
if (msg.refusal) {
|
|
310
|
-
// Wrong question in relation to policies
|
|
311
|
-
prompt.add('assistant', msg.refusal);
|
|
312
|
-
// console.log(msg);
|
|
313
|
-
continue;
|
|
314
|
-
}
|
|
315
|
-
// Add a text message
|
|
316
|
-
if (
|
|
317
|
-
msg.message.role === 'assistant' &&
|
|
318
|
-
typeof msg.message.content === 'string') {
|
|
319
|
-
prompt.add('assistant', msg.message.content);
|
|
320
|
-
}
|
|
321
|
-
// Get function request
|
|
322
|
-
if (msg.message.tool_calls) {
|
|
323
|
-
for (const toolCall of msg.message.tool_calls) {
|
|
324
|
-
function_requests.push(
|
|
325
|
-
{
|
|
326
|
-
type: 'function_request',
|
|
327
|
-
function_request: {
|
|
328
|
-
name: toolCall.function.name,
|
|
329
|
-
id: toolCall.id,
|
|
330
|
-
call_id: toolCall.id,
|
|
331
|
-
parameters: toolCall.function.arguments
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
);
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
if (function_requests.length > 0) {
|
|
339
|
-
prompt.addMultiModal('assistant', function_requests);
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
/**
|
|
344
|
-
* Process an openai response
|
|
345
|
-
* @param {number} duration - the time is MS before and after the request
|
|
346
|
-
* @param {import('@j-o-r/apiserver/types/request.js').FetchResponseObject} res
|
|
347
|
-
* @param {Prompt} prompt
|
|
348
|
-
* @param {ToolSet} [toolset]
|
|
349
|
-
* @returns {Promise<void>}
|
|
350
|
-
* @throws {Error}
|
|
351
|
-
*/
|
|
352
|
-
const parseResponse = async (duration, prompt, res, toolset) => {
|
|
353
|
-
// @todo - Put some effort in the parsing, this is quick and dirty
|
|
354
|
-
if (res.status !== 200) {
|
|
355
|
-
new Error(`${res.status}: res.response`)
|
|
356
|
-
}
|
|
357
|
-
const record = prompt.templateRecord();
|
|
358
|
-
record.model = res.response.model;
|
|
359
|
-
record.id = res.response.id;
|
|
360
|
-
record.environment = 'openai';
|
|
361
|
-
record.isoDate = new Date(res.response.created * 1000).toISOString();
|
|
362
|
-
record.tokensIn = res.response.usage.prompt_tokens;
|
|
363
|
-
record.tokensOut = res.response.usage.completion_tokens;
|
|
364
|
-
record.duration = duration;
|
|
365
|
-
prompt.addRecord(record);
|
|
366
|
-
parseMessages(res.response, prompt);
|
|
367
|
-
if (toolset) {
|
|
368
|
-
// Inspect for function_request and execute if so
|
|
369
|
-
await toolset.execute(prompt);
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
/**
|
|
374
|
-
* Do a request
|
|
375
|
-
* @param {Prompt} prompt
|
|
376
|
-
* @param {ToolSet|null} toolset
|
|
377
|
-
* @param {XOptions} [options]:
|
|
378
|
-
* @param {number} [counter] - leave empty this counts the number of requests when doing recursive request calls
|
|
379
|
-
* @return {Promise<import('../../Session.js').Message>}
|
|
380
|
-
*/
|
|
381
|
-
async function request(prompt, toolset = null, options, counter = 0) {
|
|
382
|
-
// Max number of recurusive calls
|
|
383
|
-
const counterMax = GLOBAL.max_recursive_requests;
|
|
384
|
-
const start = new Date().getTime();
|
|
385
|
-
// Generate the request
|
|
386
|
-
const { url, headers, body } = generateRequest(prompt, toolset, options);
|
|
387
|
-
prompt.emit(prompt.EVENTS.http_request, {url, counter, body});
|
|
388
|
-
const res = await doRequest(url, 'POST', headers, body);
|
|
389
|
-
prompt.emit(prompt.EVENTS.http_response, res);
|
|
390
|
-
if (res.status !== 200) {
|
|
391
|
-
throw new Error(`${res.status}: ${JSON.stringify(res.response, null, ' ')}`)
|
|
392
|
-
}
|
|
393
|
-
const duration = new Date().getTime() - start;
|
|
394
|
-
await parseResponse(duration, prompt, res, toolset);
|
|
395
|
-
counter = 1 + counter;
|
|
396
|
-
if (counter >= counterMax) {
|
|
397
|
-
throw new Error('Max number of recursive calls reached');
|
|
398
|
-
}
|
|
399
|
-
const lastMessage = prompt.getLastMessage();
|
|
400
|
-
if (!lastMessage) throw new Error('No message found');
|
|
401
|
-
const role = lastMessage.role;
|
|
402
|
-
if (role === 'tool') {
|
|
403
|
-
// need to do another roundtrip to include the function_responses
|
|
404
|
-
// Go easy on the speed, do not hit limits to soon
|
|
405
|
-
await sleep('30s');
|
|
406
|
-
return request(prompt, toolset, options, counter)
|
|
407
|
-
} else {
|
|
408
|
-
return lastMessage
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
export {
|
|
412
|
-
generateRequest,
|
|
413
|
-
parseResponse,
|
|
414
|
-
request
|
|
415
|
-
}
|
package/lib/AgentClient.js
DELETED
|
@@ -1,248 +0,0 @@
|
|
|
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
|
-
*/
|
|
7
|
-
|
|
8
|
-
/**
|
|
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
|
-
*/
|
|
20
|
-
/**
|
|
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
|
-
|
|
32
|
-
/**
|
|
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
|
-
*/
|
|
48
|
-
class AgentClient {
|
|
49
|
-
/** @private @type {Prompt} */
|
|
50
|
-
#prompt;
|
|
51
|
-
/** @private @type {string} */
|
|
52
|
-
#description = '';
|
|
53
|
-
/** @private @type {string} */
|
|
54
|
-
#name;
|
|
55
|
-
/** @private @type {string} */
|
|
56
|
-
#secret = '';
|
|
57
|
-
/** @private @type {import('@j-o-r/apiserver').WebSocketClient} */
|
|
58
|
-
#ws;
|
|
59
|
-
/** @private @type {string} */
|
|
60
|
-
#url = 'ws://127.0.0.1:8000/ws';
|
|
61
|
-
|
|
62
|
-
/** @private @type {Array<Object>} Message queue for sequential processing. */
|
|
63
|
-
#queue = [];
|
|
64
|
-
/** @private @type {boolean} Flag to prevent reentrant processing. */
|
|
65
|
-
#processing = false;
|
|
66
|
-
/** @private @type {number} Epoch counter; increments on reset to invalidate in-flight work. */
|
|
67
|
-
#epoch = 0;
|
|
68
|
-
|
|
69
|
-
/** @private @type {NodeJS.Timeout|null} Interval ID for scheduler. */
|
|
70
|
-
#intervalId = null;
|
|
71
|
-
/** @private @type {number} Queue polling interval (ms). */
|
|
72
|
-
#intervalMs = 2000;
|
|
73
|
-
|
|
74
|
-
/**
|
|
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.
|
|
80
|
-
*/
|
|
81
|
-
constructor(options) {
|
|
82
|
-
if (options.url) this.#url = options.url;
|
|
83
|
-
this.#prompt = options.prompt;
|
|
84
|
-
this.#description = options.description;
|
|
85
|
-
this.#name = options.name;
|
|
86
|
-
this.#secret = options.secret;
|
|
87
|
-
if (typeof options.intervalMs === 'number') this.#intervalMs = Math.max(1, options.intervalMs);
|
|
88
|
-
this.#registerPromptEvents();
|
|
89
|
-
this._start();
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* @private
|
|
94
|
-
* Registers Prompt events for logging tool requests/errors.
|
|
95
|
-
* @returns {void}
|
|
96
|
-
*/
|
|
97
|
-
#registerPromptEvents() {
|
|
98
|
-
const events = Object.keys(this.#prompt.EVENTS);
|
|
99
|
-
events.forEach((evt) => {
|
|
100
|
-
this.#prompt.on(evt, (_msg) => {
|
|
101
|
-
console.log(`** ${this.#name} e:${evt}**`);
|
|
102
|
-
if (evt === 'tool_request') {
|
|
103
|
-
console.log(`tool execute: ${_msg.name} ${_msg.call_id}`);
|
|
104
|
-
} else if (evt === 'tool_error') {
|
|
105
|
-
console.log(`tool error:`);
|
|
106
|
-
console.log(JSON.stringify(_msg, null, ' '));
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
});
|
|
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
|
-
*/
|
|
118
|
-
_start() {
|
|
119
|
-
const url = this.#url + '?wssrc_id=' + this.#secret;
|
|
120
|
-
this.#ws = new WebSocketClient(url);
|
|
121
|
-
this.#ws.onopen = () => {
|
|
122
|
-
this.#ws.send(JSON.stringify({
|
|
123
|
-
action: 'agent_introduction',
|
|
124
|
-
name: this.#name,
|
|
125
|
-
content: this.#description,
|
|
126
|
-
id: new Date().getTime()
|
|
127
|
-
}));
|
|
128
|
-
console.log('introduction_send:>>');
|
|
129
|
-
console.log(this.#name);
|
|
130
|
-
console.log(this.#description);
|
|
131
|
-
};
|
|
132
|
-
this.#ws.onmessage = (m) => {
|
|
133
|
-
this.incoming(m);
|
|
134
|
-
};
|
|
135
|
-
this.#ws.onclose = () => {
|
|
136
|
-
console.error('CLOSE: Lost Connection, retry in 5 seconds');
|
|
137
|
-
this.#stopInterval();
|
|
138
|
-
setTimeout(() => {
|
|
139
|
-
this._start();
|
|
140
|
-
}, 5000);
|
|
141
|
-
};
|
|
142
|
-
this.#ws.onerror = (e) => {};
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
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
|
-
*/
|
|
152
|
-
incoming(e) {
|
|
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
|
-
}
|
|
160
|
-
if (message?.action === "reset") {
|
|
161
|
-
console.log("<RESET:incoming>");
|
|
162
|
-
this.#epoch++;
|
|
163
|
-
this.#queue = [];
|
|
164
|
-
this.#stopInterval();
|
|
165
|
-
this.#prompt.reset();
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
this.#queue.push(message);
|
|
169
|
-
this.#startInterval();
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* @private
|
|
174
|
-
* Starts the interval ticker to process one queued message per tick.
|
|
175
|
-
* Idempotent; skips if already running.
|
|
176
|
-
* @returns {void}
|
|
177
|
-
*/
|
|
178
|
-
#startInterval() {
|
|
179
|
-
if (this.#intervalId) return;
|
|
180
|
-
this.#intervalId = setInterval(() => {
|
|
181
|
-
void this.#processOne();
|
|
182
|
-
}, this.#intervalMs);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* @private
|
|
187
|
-
* Stops the processing interval.
|
|
188
|
-
* @returns {void}
|
|
189
|
-
*/
|
|
190
|
-
#stopInterval() {
|
|
191
|
-
if (this.#intervalId) {
|
|
192
|
-
clearInterval(this.#intervalId);
|
|
193
|
-
this.#intervalId = null;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* @private
|
|
199
|
-
* Processes exactly one queued message (guards reentrancy).
|
|
200
|
-
* Stops interval if queue empty post-process.
|
|
201
|
-
* @returns {Promise<void>}
|
|
202
|
-
*/
|
|
203
|
-
async #processOne() {
|
|
204
|
-
if (this.#processing) return;
|
|
205
|
-
const message = this.#queue.shift();
|
|
206
|
-
if (!message) {
|
|
207
|
-
this.#stopInterval();
|
|
208
|
-
return;
|
|
209
|
-
}
|
|
210
|
-
this.#processing = true;
|
|
211
|
-
try {
|
|
212
|
-
const epochAtStart = this.#epoch;
|
|
213
|
-
await this.#handleMessage(message, epochAtStart);
|
|
214
|
-
} finally {
|
|
215
|
-
this.#processing = false;
|
|
216
|
-
if (this.#queue.length === 0) this.#stopInterval();
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/**
|
|
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>}
|
|
227
|
-
*/
|
|
228
|
-
async #handleMessage(message, epochAtStart) {
|
|
229
|
-
if (message.action === 'agent_query') {
|
|
230
|
-
const id = message.id;
|
|
231
|
-
try {
|
|
232
|
-
console.log('IN:>>\n' + message.content);
|
|
233
|
-
const content = await this.#prompt.call(message.content);
|
|
234
|
-
console.log('OUT:>>\n' + content);
|
|
235
|
-
this.#ws.send(JSON.stringify({ action: 'agent_response', content, id }));
|
|
236
|
-
} catch (err) {
|
|
237
|
-
this.#ws.send(JSON.stringify({ action: 'agent_error', content: String(err?.message || err), id }));
|
|
238
|
-
}
|
|
239
|
-
} else if (message.action === 'reset') {
|
|
240
|
-
console.log('<RESET>');
|
|
241
|
-
this.#queue = [];
|
|
242
|
-
this.#epoch++;
|
|
243
|
-
this.#prompt.reset();
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
export default AgentClient;
|