@j-o-r/hello-dave 0.0.2 → 0.0.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.
Files changed (161) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +445 -160
  3. package/README.md.backup +269 -0
  4. package/README.md.bak +481 -0
  5. package/README.md.bak.1774780058 +338 -0
  6. package/README.md.bak2 +455 -0
  7. package/bin/dave.js +165 -0
  8. package/docs.bak.1774780058/agent-manager.md +167 -0
  9. package/docs.bak.1774780058/agent-manager.md.bak +137 -0
  10. package/docs.bak.1774780058/agent-manager.md.bak2 +157 -0
  11. package/docs.bak.1774780058/codeserver-pattern.md +191 -0
  12. package/docs.bak.1774780058/path-resolution-best-practices.md +104 -0
  13. package/docs.bak.1774780058/project-overview.md +67 -0
  14. package/docs.bak.1774780058/project-overview.md.bak +67 -0
  15. package/docs.bak.1774780058/prompt-class.md +141 -0
  16. package/docs.bak.1774780058/prompt-class.md.bak +142 -0
  17. package/docs.bak.1774780058/tools-syntax-validation.md +121 -0
  18. package/docs.bak.1774780058/tools-syntax-validation.md.bak2 +125 -0
  19. package/docs.bak.1774780058/tools-syntax-validation.md.bak3 +125 -0
  20. package/docs.bak.1774780058/tools-syntax-validation.md.bak4 +106 -0
  21. package/docs.bak.1774780058/tools-syntax-validation.md.bak_path +106 -0
  22. package/docs.bak.1774780058/toolset.md +164 -0
  23. package/docs.bak.1774780058/toolset.md.bak +94 -0
  24. package/docs.bak.1774780058/toolset.md.bak3 +161 -0
  25. package/docs.bak.1774780058/toolset.md.bak4 +161 -0
  26. package/docs.bak.1774780058/toolset.md.bak5 +161 -0
  27. package/docs.bak.1774780058/toolset.md.bak6 +163 -0
  28. package/docs.bak.1774780058/toolset.md.bak_path +163 -0
  29. package/docs.bak.1774780058/toolset.md.bak_syntax +161 -0
  30. package/docs.bak.1774780058/xai-responses.md +111 -0
  31. package/docs.bak.1774780058/xai-responses.md.bak +107 -0
  32. package/docs.bak.1774780058/xai-responses.md.bak2 +107 -0
  33. package/docs.bak.1774780058/xai_collections.md +106 -0
  34. package/examples/ask_agent.js +137 -0
  35. package/examples/code_agent.js +149 -0
  36. package/examples/coderev_agent.js +136 -0
  37. package/examples/codeserver.sh +47 -0
  38. package/examples/daisy_agent.js +170 -0
  39. package/examples/docs_agent.js +148 -0
  40. package/examples/gpt_agent.js +125 -0
  41. package/examples/grok_agent.js +132 -0
  42. package/examples/grok_agent.js.bak +98 -0
  43. package/examples/grok_agent.js.bak.2 +99 -0
  44. package/examples/grok_agent.js.bak.3 +1 -0
  45. package/examples/grok_agent.js.bak.4 +124 -0
  46. package/examples/grok_agent.js.bak.5 +1 -0
  47. package/examples/grok_agent.js.bak.6 +1 -0
  48. package/examples/memory_agent.js +152 -0
  49. package/examples/npm_agent.js +202 -0
  50. package/examples/npm_agent.js.bak.3 +2 -0
  51. package/examples/npm_agent.js.bak.4 +205 -0
  52. package/examples/npm_agent.js.bak.5 +1 -0
  53. package/examples/npm_agent.js.bak.6 +1 -0
  54. package/examples/prompt_agent.js +133 -0
  55. package/examples/readme_agent.js +148 -0
  56. package/examples/spawn_agent.js +293 -0
  57. package/examples/test_agent.js +187 -0
  58. package/examples/todo_agent.js +175 -0
  59. package/examples.bak.1774780058/ask_agent.js +114 -0
  60. package/examples.bak.1774780058/code_agent.js +149 -0
  61. package/examples.bak.1774780058/coderev_agent.js +72 -0
  62. package/examples.bak.1774780058/codeserver.sh +47 -0
  63. package/examples.bak.1774780058/daisy_agent.js +177 -0
  64. package/examples.bak.1774780058/docs_agent.js +119 -0
  65. package/{bin/hdAsk.js → examples.bak.1774780058/gpt_agent.js} +46 -40
  66. package/examples.bak.1774780058/grok_agent.js +98 -0
  67. package/examples.bak.1774780058/memory_agent.js +112 -0
  68. package/examples.bak.1774780058/npm_agent.js +175 -0
  69. package/examples.bak.1774780058/prompt_agent.js +112 -0
  70. package/examples.bak.1774780058/readme_agent.js +144 -0
  71. package/examples.bak.1774780058/spawn_agent.js +263 -0
  72. package/examples.bak.1774780058/test_agent.js +162 -0
  73. package/examples.bak.1774780058/todo_agent.js +138 -0
  74. package/lib/API/openai.com/reponses/text.js +12 -18
  75. package/lib/API/x.ai/collections.js +354 -0
  76. package/lib/API/x.ai/files.js +218 -0
  77. package/lib/API/x.ai/responses.js +492 -0
  78. package/lib/API/x.ai/text.js +1 -1
  79. package/lib/AgentClient.js +13 -6
  80. package/lib/AgentManager.js +80 -10
  81. package/lib/AgentServer.js +50 -22
  82. package/lib/Cli.js +7 -1
  83. package/lib/Prompt.js +4 -2
  84. package/lib/ToolSet.js +2 -1
  85. package/lib/genericToolset.js +258 -88
  86. package/lib/genericToolset.js.bak_syntax +402 -0
  87. package/lib/index.js +4 -2
  88. package/lib/wsCli.js +256 -0
  89. package/lib/wsIO.js +96 -0
  90. package/package.json +26 -21
  91. package/scenarios.bak.1774780058/data/eval_node_message.json +9 -0
  92. package/scenarios.bak.1774780058/data/hist_oa.json +66 -0
  93. package/scenarios.bak.1774780058/data/o3_response1.json +96 -0
  94. package/scenarios.bak.1774780058/data/oa_reasoning_parse.json +112 -0
  95. package/scenarios.bak.1774780058/data/tool_oa.json +96 -0
  96. package/scenarios.bak.1774780058/data/tool_xai.json +59 -0
  97. package/scenarios.bak.1774780058/data/tool_xai2.json +40 -0
  98. package/scenarios.bak.1774780058/data/xai-response-1.json +59 -0
  99. package/scenarios.bak.1774780058/data/xai-response-2.json +10 -0
  100. package/scenarios.bak.1774780058/data/xai_reasoning_tools_resp.json +59 -0
  101. package/scenarios.bak.1774780058/data/xai_search_response.json +58 -0
  102. package/scenarios.bak.1774780058/environment.js +10 -0
  103. package/scenarios.bak.1774780058/example.js +17 -0
  104. package/scenarios.bak.1774780058/genericToolset.test.js +182 -0
  105. package/scenarios.bak.1774780058/grok.js +113 -0
  106. package/scenarios.bak.1774780058/memory-tools.js +51 -0
  107. package/scenarios.bak.1774780058/openai-o3.js +137 -0
  108. package/scenarios.bak.1774780058/openai-prompt.js +155 -0
  109. package/scenarios.bak.1774780058/openai-session.js +148 -0
  110. package/scenarios.bak.1774780058/openai.js +102 -0
  111. package/scenarios.bak.1774780058/prompt.js +118 -0
  112. package/scenarios.bak.1774780058/promptFishbowl.js +76 -0
  113. package/scenarios.bak.1774780058/search.brave.com.js +25 -0
  114. package/scenarios.bak.1774780058/sh.js +15 -0
  115. package/scenarios.bak.1774780058/test-wsio.js +26 -0
  116. package/scenarios.bak.1774780058/testToolset.js +42 -0
  117. package/scenarios.bak.1774780058/toolset.js +16 -0
  118. package/scenarios.bak.1774780058/toolset.test.js +141 -0
  119. package/scenarios.bak.1774780058/write_file_syntax.test.js +145 -0
  120. package/scenarios.bak.1774780058/write_file_validation/README.md +30 -0
  121. package/scenarios.bak.1774780058/write_file_validation/bad.js +3 -0
  122. package/scenarios.bak.1774780058/write_file_validation/good.js +4 -0
  123. package/scenarios.bak.1774780058/write_file_validation/test.sh +43 -0
  124. package/scenarios.bak.1774780058/wsClient.js +69 -0
  125. package/scenarios.bak.1774780058/xai_responses.integration.test.js +57 -0
  126. package/scenarios.bak.1774780058/xai_responses.test.js +154 -0
  127. package/scenarios.bak.1774780058/xaicoll.js +50 -0
  128. package/scenarios.bak.1774780058/xaifiles.js +48 -0
  129. package/types/API/openai.com/reponses/text.d.ts +17 -3
  130. package/types/API/x.ai/collections.d.ts +167 -0
  131. package/types/API/x.ai/files.d.ts +84 -0
  132. package/types/API/x.ai/responses.d.ts +379 -0
  133. package/types/AgentClient.d.ts +5 -0
  134. package/types/AgentManager.d.ts +25 -31
  135. package/types/AgentServer.d.ts +5 -1
  136. package/types/Prompt.d.ts +4 -2
  137. package/types/ToolSet.d.ts +1 -0
  138. package/types/index.d.ts +4 -3
  139. package/types/wsCli.d.ts +3 -0
  140. package/types/wsIO.d.ts +26 -0
  141. package/utils/bars.js +40 -0
  142. package/utils/clear_sessions.sh +54 -0
  143. package/{bin/hdInspect.js → utils/format_log.js} +5 -0
  144. package/utils/list_sessions.sh +46 -0
  145. package/utils/search_sessions.sh +73 -0
  146. package/utils/syntax_check.sh +61 -0
  147. package/utils/test.sh +46 -0
  148. package/bin/hdClear.js +0 -13
  149. package/bin/hdCode.js +0 -115
  150. package/bin/hdConnect.js +0 -230
  151. package/bin/hdNpm.js +0 -114
  152. package/bin/hdPrompt.js +0 -108
  153. package/examples/claude-test.js +0 -89
  154. package/examples/claude.js +0 -143
  155. package/examples/gpt.js +0 -127
  156. package/examples/gpt_code.js +0 -125
  157. package/examples/gpt_note_keeping.js +0 -117
  158. package/examples/grok.js +0 -119
  159. package/examples/grok_code.js +0 -114
  160. package/examples/grok_note_keeping.js +0 -111
  161. package/module.md +0 -189
@@ -0,0 +1,492 @@
1
+ /*
2
+ Allthough we can use store = true and previous_response_id: response.id,
3
+ Stil all tokens are billed.
4
+ */
5
+ import { GLOBAL } from '../../fafs.js'
6
+ import { request as doRequest } from '@j-o-r/apiserver';
7
+ import { sleep } from '@j-o-r/sh';
8
+ /**
9
+ * @typedef {import('../../Prompt.js').default} Prompt
10
+ * @typedef {import('../../ToolSet.js').default} ToolSet
11
+ */
12
+ /**
13
+ * @typedef {'code_interpreter_call.outputs'|'computer_call_output.output.image_url'|'file_search_call.results'|'message.input_image.image_url'|'message.output_text.logprobs'|'reasoning.encrypted_conten'} Includes
14
+ */
15
+ /**
16
+ * @typedef {Object} XAIOptions
17
+ * @property {?string} [include=null] - Optional include parameter.
18
+ * @property {XAIInput[]} [input=[]] - Array of input objects.
19
+ * @property {string} [instructions=''] - Instructions for the model.
20
+ * @property {number} [max_output_tokens=4000] - Maximum number of output tokens.
21
+ * @property {number} [max_tool_calls=10] - Maximum number of tool calls allowed.
22
+ * @property {?Object} [metadata=null] - Optional metadata object.
23
+ * @property {'grok-4-1-fast-reasoning'|'grok-4-1-fast-non-reasoning'|'grok-code-fast-1'|'grok-4-fast-reasoning'|'grok-4-fast-non-reasoning'} [model='grok-4-fast-non-reasoning'] - Model version to use.
24
+ * @property {?string} [prompt=null] - Reusable prompt string.
25
+ * @property {Object} [reasoning={effort: 'medium', summary: 'auto'}] - Reasoning configuration.
26
+ * @property {'low'|'medium'|'high'|null} reasoning.effort - Effort level for reasoning.
27
+ * @property {'auto'|'concise'|'detailed'} reasoning.summary - Summary type for reasoning.
28
+ * @property {'low'|'medium'|'high'} [search]
29
+ * @property {'auto'} [service_tier='auto'] - Service tier option, default is auto-selected.
30
+ * @property {boolean} [store=false] - Whether to store the response or not.
31
+ * @property {boolean} [stream=false] - Whether to stream the response or not.
32
+ * @property {number} [temperature=1] - Sampling temperature between 0 and 2.
33
+ * @property {Object} [text={format: {type: "text"}}] - text format
34
+ * @property {'text'|'json_schema'} text.format - Summary type for reasoning.
35
+ * @property {boolean} [parallel_tool_calls=true] - Allow parallel tool calls if true.
36
+ * @property {'auto'} [tool_choice='auto'] - Tool choice setting, default is auto-selected.
37
+ * @property {Array<XSearchTool|XAIFunctionTool|MCPTool|CodeInterpreterTool|FileSearchTool|XAIWebSearchTool>} [tools=[]] Array of tool call objects.
38
+ * @property {?number } [top_logprobs=null] - An integer between 0 and 20 specifying the number of most likely tokens to return at each token position, each with an associated log probability.
39
+ * @property {?number } [top_p] Top-p sampling value between 0 and 1.
40
+ * @property {?string} [previous_response_id] - Needed reponse_id to validate tool calls on the next request
41
+ */
42
+ /// [start] ----- tools ----
43
+ /**
44
+ * @typedef {Object} XAIFunctionTool
45
+ * @property {'function'} type - The type of the tool call, e.g., "function".
46
+ * @property {string} name - The name of the function.
47
+ * @property {string} description - A brief description of what the function does.
48
+ * @property {Object} parameters - The parameters required by the function.
49
+ * @property {string} parameters.type - The type of parameters object, usually "object".
50
+ * @property {Object.<string, ParameterProperty>} parameters.properties - An object describing each parameter property.
51
+ * @property {string[]} [parameters.required] - An array of required parameter names.
52
+ */
53
+ /**
54
+ * @typedef {Object} ParameterProperty
55
+ * @property {string} type - The data type of the parameter, e.g., "string".
56
+ * @property {string} description - A brief description of the parameter.
57
+ */
58
+
59
+ /**
60
+ * @typedef {Object} WebSearchFilters
61
+ * @property {string[]|null} [allowed_domains] - Whitelist of domains (max 5); cannot use with excluded_domains.
62
+ * @property {string[]|null} [excluded_domains] - Blacklist of domains (max 5); cannot use with allowed_domains.
63
+ * @property {("low"|"medium"|"high")|null} [search_context_size] - Context size; for OpenAI compatibility (reject if set).
64
+ * @property {UserLocation|null} [user_location] - User location; for OpenAI compatibility (reject if set).
65
+ */
66
+ /**
67
+ * @typedef {Object} UserLocation
68
+ * @property {string|null} [city] - City of the user's location.
69
+ * @property {string|null} [country] - ISO 3166-1 alpha-2 country code.
70
+ * @property {string|null} [region] - Region of the user's location.
71
+ * @property {string|null} [timezone] - IANA timezone.
72
+ * @property {"approximate"} type
73
+ */
74
+ /**
75
+ * @typedef {Object} XAIWebSearchTool
76
+ * @property {string[]|null} [allowed_domains] - Whitelist of domains (max 5); cannot use with excluded_domains.
77
+ * @property {boolean|null} [enable_image_understanding] - Enable image understanding.
78
+ * @property {string[]|null} [excluded_domains] - Blacklist of domains (max 5); cannot use with allowed_domains.
79
+ * @property {boolean|null} [external_web_access] - For OpenAI compatibility (reject if set).
80
+ * @property {WebSearchFilters|null} [filters] - Filters; for OpenAI compatibility.
81
+ * @property {"web_search"} type
82
+ */
83
+ /**
84
+ * @typedef {Object} XSearchTool
85
+ * @property {string[]|null} [allowed_x_handles] - Whitelist of X handles; cannot use with excluded_x_handles.
86
+ * @property {boolean|null} [enable_image_understanding] - Enable image understanding.
87
+ * @property {boolean|null} [enable_video_understanding] - Enable video understanding.
88
+ * @property {string[]|null} [excluded_x_handles] - Blacklist of X handles; cannot use with allowed_x_handles.
89
+ * @property {string|null} [from_date] - ISO-8601 date (YYYY-MM-DD).
90
+ * @property {string|null} [to_date] - ISO-8601 date (YYYY-MM-DD).
91
+ * @property {"x_search"} type
92
+ */
93
+ /**
94
+ * @typedef {Object} FileSearchTool
95
+ * @property {Object} filters - For OpenAI compatibility (reject if set).
96
+ * @property {number|null} [max_num_results] - Max results (min 1).
97
+ * @property {Object} ranking_options - For OpenAI compatibility (reject if set).
98
+ * @property {string[]} vector_store_ids - List of vector store IDs.
99
+ * @property {"file_search"} type
100
+ */
101
+ /**
102
+ * @typedef {Object} CodeInterpreterTool
103
+ * @property {string|Object} container - Container ID or uploaded files object; for OpenAI compatibility (reject if set).
104
+ * @property {"code_interpreter"} type
105
+ */
106
+ /**
107
+ * @typedef {Object} MCPTool
108
+ * @property {string[]|null} [allowed_tools] - Allowed tools.
109
+ * @property {string|null} [authorization] - Authorization details.
110
+ * @property {string|null} [connector_id] - Connector ID.
111
+ * @property {Object|null} [headers] - Headers.
112
+ * @property {string|null} [require_approval] - Approval requirement.
113
+ * @property {string|null} [server_description] - Server description.
114
+ * @property {string} server_label - Server label.
115
+ * @property {string} server_url - Server URL.
116
+ * @property {"mcp"} type
117
+ */
118
+ /// [end] ---- tools ----
119
+
120
+ /**
121
+ * @typedef {Object} XAIMessage
122
+ * @property {'assistant'|'user'} role - The role of the participant (e.g., "assistant", "user").
123
+ * @property {Array<XAIContent>} content - The content of the message.
124
+ */
125
+ /**
126
+ * @typedef {Object} XAIInputMessage
127
+ * @property {'assistant'|'user'|'system'} role - The role of the participant (e.g., "assistant", "user").
128
+ * @property {string} content - The content of the message.
129
+ */
130
+ /**
131
+ * @typedef {Object} XAIContent
132
+ * @property {'output_text'|'input_text'} type - The type of content (e.g., "output_text", "input_text").
133
+ * @property {string} text - The text content.
134
+ */
135
+ /**
136
+ * @typedef {Object} XAIFunctionCall
137
+ * @property {string} id - Unique identifier for the function call.
138
+ * @property {'function_call'} type - Indicates this is a function call (e.g., "function_call").
139
+ * @property {string} call_id - Unique identifier for the specific function call instance.
140
+ * @property {string} name - The name of the function being called.
141
+ * @property {string} arguments - JSON string representing arguments passed to the function.
142
+ */
143
+ /**
144
+ * @typedef {Object} XAIFunctionCallOutput
145
+ * @property {'function_call_output'} type - Indicates this is a function call output (e.g., "function_call_output").
146
+ * @property {string} call_id - Identifier linking to the related function call.
147
+ * @property {string} output - JSON string representing the output from the function call.
148
+ */
149
+ /**
150
+ * Represents an OpenAI API response request INPUT structure.
151
+ *
152
+ * @typedef {(XAIInputMessage|XAIFunctionCall|XAIFunctionCallOutput)} XAIInput
153
+ */
154
+
155
+ const API_URL = 'https://api.x.ai/v1/responses';
156
+
157
+ /**
158
+ * Get the default headers
159
+ * @returns {object}
160
+ */
161
+ const getHeaders = () => {
162
+ if (!process.env['XAIKEY']) {
163
+ throw new Error('Missing XAIKEY! export XAIKEY=[XAIKEY]')
164
+ }
165
+ const KEY = process.env['XAIKEY'];
166
+ return {
167
+ 'Content-Type': 'application/json',
168
+ 'Authorization': `Bearer ${KEY}`
169
+ }
170
+ }
171
+ /**
172
+ * Convert a toolset to something openai understands
173
+ * @param {ToolSet} toolset
174
+ * @returns {XAIFunctionTool[]}
175
+ */
176
+ const generateTools = (toolset) => {
177
+ const list = toolset.list();
178
+ /** @type {XAIFunctionTool[]} */
179
+ const result = [];
180
+ list.forEach((item) => {
181
+ result.push({
182
+ type: 'function',
183
+ name: item.name,
184
+ description: item.description,
185
+ parameters: item.parameters
186
+ })
187
+ });
188
+ return result;
189
+ }
190
+
191
+ /**
192
+ * Convert messages to OPENAI requirements
193
+ * @param {import("lib/Session").Message[]} messages
194
+ * @returns {XAIInput[]}
195
+ */
196
+ const generateHistory = (messages) => {
197
+ return messages.reduce((result, msg) => {
198
+ delete msg.sticky;
199
+ delete msg.ts;
200
+ if (['assistant', 'user'].includes(msg.role)) {
201
+ /** @type {XAIFunctionCall[]} */
202
+ // @ts-ignore
203
+ const fr = msg.content.map(
204
+ /** @param {import('../../Prompt.js').FunctionRequest} item */
205
+ (item) => {
206
+ // Transform function requests
207
+ if (item.type === 'function_request') {
208
+ return {
209
+ // @ts-ignore
210
+ // id: item.function_request.id,
211
+ type: 'function_call',
212
+ call_id: item.function_request.call_id,
213
+ name: item.function_request.name,
214
+ arguments: item.function_request.parameters
215
+ }
216
+ }
217
+ }).filter(item => item !== undefined);
218
+ if (fr.length > 0) {
219
+ result.push(...fr);
220
+ }
221
+ // transform normal text input
222
+ const content = msg.content.map((item) => {
223
+ if (item.type == 'text') {
224
+ item.type = msg.role === 'user' ? 'input_text' : 'output_text'
225
+ return item;
226
+ }
227
+ }).filter(item => item !== undefined);
228
+ if (content.length > 0) {
229
+ msg.content = content;
230
+ result.push(msg);
231
+ }
232
+ } else if (['tool'].includes(msg.role)) {
233
+ // transform function responses
234
+ const ar = msg.content.map(
235
+ /** @param {import('../../Prompt.js').FunctionResponse} item */
236
+ (item) => {
237
+ if (item.type === 'function_response') {
238
+ return {
239
+ type: 'function_call_output',
240
+ call_id: item.function_response.call_id,
241
+ output: item.function_response.response
242
+ }
243
+ }
244
+ }).filter(item => item !== undefined);
245
+ if (ar.length > 0) {
246
+ result.push(...ar);
247
+ }
248
+ }
249
+ return result;
250
+ }, []);
251
+ }
252
+ /** @type SearchSources */
253
+ const webSearch = [
254
+ {
255
+ type: 'x',
256
+ },
257
+ {
258
+ type: 'web',
259
+ safe_search: false
260
+ },
261
+ {
262
+ type: 'news',
263
+ safe_search: false
264
+ }
265
+
266
+ ]
267
+
268
+ /** @type {XAIOptions} */
269
+ const defaultSettings = {
270
+ model: 'grok-4-fast-reasoning',
271
+ input: [
272
+ {
273
+ role: 'system',
274
+ content: 'Be precise and concise'
275
+ }
276
+ ],
277
+ temperature: 0.2,
278
+ parallel_tool_calls: true,
279
+ tools: [],
280
+ // search_parameters: {
281
+ // from_date: null,
282
+ // max_search_results: 15,
283
+ // mode: 'off',
284
+ // return_citations: false,
285
+ // sources: webSearch,
286
+ // to_date: null
287
+ // },
288
+ store: false
289
+ };
290
+
291
+
292
+ // tools": [{"type": "web_search_preview"}],
293
+
294
+ /**
295
+ * Generate the POST body of a request
296
+ * @param {Prompt} prompt
297
+ * @param {ToolSet} [toolset]
298
+ * @param {XAIOptions} [options]
299
+ */
300
+ function getBody(prompt, toolset, options) {
301
+ // From the messages I only want assistant and user
302
+ /** @type {XAIOptions} */
303
+ // @ts-ignore
304
+ const body = { ...defaultSettings, ...(options || {}) };
305
+ // const body = options ? mergeOptions(DEFAULT_OPTIONS, options) : DEFAULT_OPTIONS;
306
+ body.instructions = prompt.hasSystemprompt ? prompt.system_prompt : '';
307
+ // the last messages should be a role tool or user else the model cannot handle the request
308
+ const messages = prompt.messages;
309
+ if (!['user', 'tool'].includes(messages[messages.length - 1].role)) {
310
+ throw new Error('Missing last user question or tool');
311
+ }
312
+
313
+ body.input = generateHistory(messages);
314
+ if (toolset) {
315
+ // @ts-ignore
316
+ body.tool_choice = toolset.toolChoice;
317
+ body.tools = [...body.tools, ...generateTools(toolset)]
318
+ body.parallel_tool_calls = true;
319
+ // parallel_tool_calls
320
+ }
321
+ // Add OPENAI SEARCH
322
+ // in the toolset
323
+ // if (body.search) {
324
+ // if (!body.tools) {
325
+ // body.tools = [];
326
+ // }
327
+ // body.tools.push({
328
+ // type: 'web_search_preview',
329
+ // // @ts-ignore
330
+ // search_context_size: body.search
331
+ // })
332
+ // }
333
+ delete body.search;
334
+ return body;
335
+ }
336
+ /**
337
+ * @param {Prompt} prompt
338
+ * @param {ToolSet} [toolset]
339
+ * @param {XAIOptions} [options]
340
+ */
341
+ function generateRequest(prompt, toolset, options) {
342
+ const headers = getHeaders();
343
+ const url = API_URL;
344
+ const body = getBody(prompt, toolset, options);
345
+ return { url, headers, body }
346
+ }
347
+ /**
348
+ * Parse response messages (output)
349
+ * @param {Array<*>} messages
350
+ * @param {Prompt} prompt
351
+ */
352
+ function parseMessages(messages, prompt) {
353
+ /** @type {import('../../Prompt.js').FunctionRequest[]} */
354
+ const toolcall = [];
355
+ let i = 0;
356
+ const len = messages.length;
357
+ for (; i < len; i++) {
358
+ const msg = messages[i];
359
+ // types:
360
+ const type = msg.type;
361
+ if (type === 'reasoning') {
362
+ let messages = msg.summary.map((item) => {
363
+ if (item.type === 'summary_text') {
364
+ return { type: 'text', text: item.text }
365
+ }
366
+ });
367
+ messages = messages.filter(item => item !== undefined);
368
+ if (messages.length > 0) {
369
+ prompt.addMultiModal('reasoning', messages);
370
+ }
371
+ } else if (type === 'message') {
372
+ let annotations = '';
373
+ let messages = msg.content.map((item) => {
374
+ if (item.type === 'output_text') {
375
+ if (item['annotations'] && item.annotations.length > 0) {
376
+ const ann = item.annotations;
377
+ ann.forEach((a) => {
378
+ if (a.type === 'url_citation') {
379
+ annotations += `${a.url}\n`;
380
+ }
381
+ })
382
+ }
383
+ return { type: 'text', text: item.text }
384
+ }
385
+ });
386
+ if (annotations !== '') {
387
+ prompt.add('log', annotations)
388
+ }
389
+ messages = messages.filter(item => item !== undefined);
390
+ if (messages.length > 0) {
391
+ prompt.addMultiModal('assistant', messages);
392
+ }
393
+ } else if (type === 'image_generation_call') {
394
+ prompt.addMultiModal('assistant', [{ type: 'image_url', url: msg.result }]);
395
+ } else if (type === 'function_call' || msg.status === 'complete') {
396
+ toolcall.push({
397
+ type: 'function_request',
398
+ function_request: {
399
+ name: msg.name,
400
+ id: msg.id,
401
+ call_id: msg.call_id,
402
+ parameters: msg.arguments
403
+ }
404
+
405
+ });
406
+ }
407
+ }
408
+ if (toolcall.length > 0) {
409
+ prompt.addMultiModal('assistant', toolcall);
410
+ }
411
+ }
412
+
413
+ /**
414
+ * Parse a response
415
+ * @param {number} duration - Fetch time in MS
416
+ * @param {Prompt} prompt
417
+ * @param {import('@j-o-r/apiserver/types/request.js').FetchResponseObject} res
418
+ * @param {import('../../ToolSet.js').default} [toolset]
419
+ */
420
+ async function parseResponse(duration, prompt, res, toolset) {
421
+ if (res.status !== 200) {
422
+ throw new Error(`${res.status}: ${JSON.stringify(res.response, null, ' ')}`)
423
+ }
424
+ // 1 = make a records
425
+ const record = prompt.templateRecord();
426
+ record.model = res.response.model;
427
+ record.id = res.response.id;
428
+ record.environment = API_URL;
429
+ record.isoDate = new Date(res.response.created_at * 1000).toISOString();
430
+ record.tokensIn = res.response.usage.input_tokens;
431
+ record.tokensOut = res.response.usage.output_tokens;
432
+ record.duration = duration;
433
+ // Parse the messages and and those to the prompt
434
+ parseMessages(res.response.output, prompt);
435
+ if (toolset) {
436
+ // Inspect for function_request and execute if so
437
+ await toolset.execute(prompt);
438
+ }
439
+ prompt.addRecord(record);
440
+ }
441
+
442
+ /**
443
+ * Do a request
444
+ * @param {Prompt} prompt
445
+ * @param {ToolSet|null} toolset
446
+ * @param {XAIOptions} [options]:
447
+ * @param {number} [counter] - leave empty this counts the number of requests when doing recursive request calls
448
+ * @return {Promise<import('../../Session.js').Message>}
449
+ */
450
+ async function request(prompt, toolset = null, options = {}, counter = 0) {
451
+ // Max number of recurusive calls
452
+ const counterMax = GLOBAL.max_recursive_requests;
453
+ const start = new Date().getTime();
454
+ // if (counter === 0) {
455
+ // Fresh request
456
+ delete options.previous_response_id
457
+ // }
458
+ // Generate the request
459
+ const { url, headers, body } = generateRequest(prompt, toolset, options);
460
+ prompt.emit(prompt.EVENTS.http_request, {url, counter, body});
461
+ const res = await doRequest(url, 'POST', headers, body);
462
+ prompt.emit(prompt.EVENTS.http_response, res);
463
+ if (res.status !== 200) {
464
+ throw new Error(`${res.status}: ${JSON.stringify(res.response, null, ' ')}`)
465
+ }
466
+ /*
467
+ https://platform.openai.com/docs/assistants/deep-dive#runs-and-run-steps
468
+ status` can be: in_progress, completed, incomplete (plus searching / generating / failed for some tool-call items)
469
+ */
470
+ const duration = new Date().getTime() - start;
471
+ await parseResponse(duration, prompt, res, toolset);
472
+ const previousId = res.response.id;
473
+ counter = 1 + counter;
474
+ if (counter >= counterMax) {
475
+ throw new Error('Max number of recursive calls reached');
476
+ }
477
+ const lastMessage = prompt.getLastMessage();
478
+ if (!lastMessage) throw new Error('No message found');
479
+ if (lastMessage.role === 'tool') {
480
+ // need to do another roundtrip to include the funtion_responses
481
+ // And add the previousId for toolsets to work
482
+ if (!options) {
483
+ options = {};
484
+ }
485
+ options.previous_response_id = previousId;
486
+ await sleep('2s');
487
+ return request(prompt, toolset, options, counter)
488
+ } else {
489
+ return lastMessage
490
+ }
491
+ }
492
+ export { generateRequest, parseResponse, request }
@@ -106,7 +106,7 @@ const defaultSettings = {
106
106
  content: 'Be precise and concise'
107
107
  }
108
108
  ],
109
- // temperature: 0.2,
109
+ temperature: 0.2,
110
110
  // response_format: { type: 'text' },
111
111
  parallel_tool_calls: true,
112
112
  // reasoning_effort: null,
@@ -21,6 +21,7 @@ import { WebSocketClient } from "@j-o-r/apiserver";
21
21
  * @property {ToolSet} [toolset] - The toolset
22
22
  * @property {string} description - Custom introduction message.
23
23
  * @property {string} name - Logical name: e.g. search, code, os, support.
24
+ * @property {string} secret - Websocket server access secret.
24
25
  * @property {string} [url='ws://127.0.0.1:8000/ws?params=1234']
25
26
  * @property {number} [intervalMs=250] - How often to pull one message from the queue.
26
27
  */
@@ -33,6 +34,7 @@ class AgentClient {
33
34
  #prompt;
34
35
  #description = '';
35
36
  #name;
37
+ #secret = '';
36
38
  /** @type {WebSocketClient} */
37
39
  #ws;
38
40
  #url = 'ws://127.0.0.1:8000/ws';
@@ -57,6 +59,7 @@ class AgentClient {
57
59
  this.#prompt = options.prompt;
58
60
  this.#description = options.description;
59
61
  this.#name = options.name;
62
+ this.#secret = options.secret;
60
63
  if (typeof options.intervalMs === 'number') this.#intervalMs = Math.max(1, options.intervalMs);
61
64
  this.#registerPromptEvents();
62
65
  this._start();
@@ -69,15 +72,19 @@ class AgentClient {
69
72
  const events = Object.keys(this.#prompt.EVENTS);
70
73
  events.forEach((evt) => {
71
74
  this.#prompt.on(evt, (_msg) => {
72
- if (evt === 'tool_error') {
73
- console.log(JSON.stringify(_msg, null, ' '));
74
- }
75
- console.log(evt);
75
+ console.log(`** ${this.#name} e:${evt}**`);
76
+ if (evt === 'tool_request') {
77
+ console.log(`tool execute: ${_msg.name} ${_msg.call_id}`);
78
+ } else if (evt === 'tool_error') {
79
+ console.log(`tool error:`);
80
+ console.log(JSON.stringify(_msg, null, ' '));
81
+ }
76
82
  });
77
83
  });
78
84
  }
79
85
  _start() {
80
- this.#ws = new WebSocketClient(this.#url); // Match server port/path
86
+ const url = this.#url + '?wssrc_id=' + this.#secret;
87
+ this.#ws = new WebSocketClient(url); // Match server port/path
81
88
  this.#ws.onopen = () => {
82
89
  // Send my introduction to the server
83
90
  this.#ws.send(JSON.stringify({
@@ -86,7 +93,7 @@ class AgentClient {
86
93
  content: this.#description,
87
94
  id: new Date().getTime()
88
95
  }));
89
- console.log('INIT:>>')
96
+ console.log('introduction_send:>>')
90
97
  console.log(this.#name);
91
98
  console.log(this.#description);
92
99
  };