@j-o-r/hello-dave 0.0.0
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/LICENSE +73 -0
- package/README.md +207 -0
- package/bin/hdAsk.js +103 -0
- package/bin/hdClear.js +13 -0
- package/bin/hdCode.js +110 -0
- package/bin/hdConnect.js +230 -0
- package/bin/hdInspect.js +28 -0
- package/bin/hdNpm.js +114 -0
- package/bin/hdPrompt.js +108 -0
- package/examples/claude-test.js +89 -0
- package/examples/claude.js +143 -0
- package/examples/gpt.js +127 -0
- package/examples/gpt_code.js +125 -0
- package/examples/gpt_note_keeping.js +117 -0
- package/examples/grok.js +119 -0
- package/examples/grok_code.js +114 -0
- package/examples/grok_note_keeping.js +111 -0
- package/lib/API/anthropic.com/text.js +402 -0
- package/lib/API/brave.com/search.js +239 -0
- package/lib/API/openai.com/README.md +1 -0
- package/lib/API/openai.com/reponses/MESSAGES.md +69 -0
- package/lib/API/openai.com/reponses/text.js +416 -0
- package/lib/API/x.ai/text.js +415 -0
- package/lib/AgentClient.js +197 -0
- package/lib/AgentManager.js +144 -0
- package/lib/AgentServer.js +336 -0
- package/lib/Cli.js +256 -0
- package/lib/Prompt.js +728 -0
- package/lib/Session.js +231 -0
- package/lib/ToolSet.js +186 -0
- package/lib/fafs.js +93 -0
- package/lib/genericToolset.js +170 -0
- package/lib/index.js +34 -0
- package/lib/promptHelpers.js +132 -0
- package/lib/testToolset.js +42 -0
- package/module.md +189 -0
- package/package.json +49 -0
- package/types/API/anthropic.com/text.d.ts +207 -0
- package/types/API/brave.com/search.d.ts +156 -0
- package/types/API/openai.com/reponses/text.d.ts +225 -0
- package/types/API/x.ai/text.d.ts +286 -0
- package/types/AgentClient.d.ts +70 -0
- package/types/AgentManager.d.ts +112 -0
- package/types/AgentServer.d.ts +38 -0
- package/types/Cli.d.ts +52 -0
- package/types/Prompt.d.ts +298 -0
- package/types/Session.d.ts +31 -0
- package/types/ToolSet.d.ts +95 -0
- package/types/fafs.d.ts +47 -0
- package/types/genericToolset.d.ts +3 -0
- package/types/index.d.ts +23 -0
- package/types/promptHelpers.d.ts +1 -0
- package/types/testToolset.d.ts +3 -0
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
/*
|
|
2
|
+
https://platform.openai.com/docs/api-reference/responses/create
|
|
3
|
+
Allthough we can use store = true and previous_response_id: response.id,
|
|
4
|
+
Stil all tokens are billed.
|
|
5
|
+
*/
|
|
6
|
+
import { GLOBAL } from '../../../fafs.js'
|
|
7
|
+
import { request as doRequest } from '@j-o-r/apiserver';
|
|
8
|
+
import { sleep } from '@j-o-r/sh';
|
|
9
|
+
/**
|
|
10
|
+
* @typedef {import('../../../Prompt.js').default} Prompt
|
|
11
|
+
* @typedef {import('../../../ToolSet.js').default} ToolSet
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* @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
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* @typedef {Object} OAOptions
|
|
18
|
+
* @property {boolean} [background=false] - Whether to run in the background.
|
|
19
|
+
* @property {?string} [include=null] - Optional include parameter.
|
|
20
|
+
* @property {OAInput[]} [input=[]] - Array of input objects.
|
|
21
|
+
* @property {string} [instructions=''] - Instructions for the model.
|
|
22
|
+
* @property {number} [max_output_tokens=4000] - Maximum number of output tokens.
|
|
23
|
+
* @property {number} [max_tool_calls=10] - Maximum number of tool calls allowed.
|
|
24
|
+
* @property {?Object} [metadata=null] - Optional metadata object.
|
|
25
|
+
* @property {'gpt-4.1'|'GPT-4o'|'o3'|'o3-mini'|'o4-mini'|'o1'|'o3-pro'} [model='gpt-4.1'] - Model version to use.
|
|
26
|
+
* @property {?string} [prompt=null] - Reusable prompt string.
|
|
27
|
+
* @property {Object} [reasoning={effort: 'medium', summary: 'auto'}] - Reasoning configuration.
|
|
28
|
+
* @property {'low'|'medium'|'high'|null} reasoning.effort - Effort level for reasoning.
|
|
29
|
+
* @property {'auto'|'concise'|'detailed'} reasoning.summary - Summary type for reasoning.
|
|
30
|
+
* @property {'low'|'medium'|'high'} [search]
|
|
31
|
+
* @property {'auto'} [service_tier='auto'] - Service tier option, default is auto-selected.
|
|
32
|
+
* @property {boolean} [store=false] - Whether to store the response or not.
|
|
33
|
+
* @property {boolean} [stream=false] - Whether to stream the response or not.
|
|
34
|
+
* @property {number} [temperature=1] - Sampling temperature between 0 and 2.
|
|
35
|
+
* @property {Object} [text={format: {type: "text"}}] - text format
|
|
36
|
+
* @property {'text'|'json_schema'} text.format - Summary type for reasoning.
|
|
37
|
+
* @property {boolean} [parallel_tool_calls=true] - Allow parallel tool calls if true.
|
|
38
|
+
* @property {'auto'} [tool_choice='auto'] - Tool choice setting, default is auto-selected.
|
|
39
|
+
* @property {OAToolCall[]} tools=[] Array of tool call objects.
|
|
40
|
+
* @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.
|
|
41
|
+
* @property {?number } top_p=1 Top-p sampling value between 0 and 1.
|
|
42
|
+
* @property {?string} [previous_response_id] - Needed reponse_id to validate tool calls on the next request
|
|
43
|
+
*/
|
|
44
|
+
/**
|
|
45
|
+
* @typedef {Object} OAToolCall
|
|
46
|
+
* @property {string} type - The type of the tool call, e.g., "function".
|
|
47
|
+
* @property {string} name - The name of the function.
|
|
48
|
+
* @property {string} description - A brief description of what the function does.
|
|
49
|
+
* @property {Object} parameters - The parameters required by the function.
|
|
50
|
+
* @property {string} parameters.type - The type of parameters object, usually "object".
|
|
51
|
+
* @property {Object.<string, OAParameterProperty>} parameters.properties - An object describing each parameter property.
|
|
52
|
+
* @property {string[]} [parameters.required] - An array of required parameter names.
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @typedef {Object} OAParameterProperty
|
|
57
|
+
* @property {string} type - The data type of the parameter, e.g., "string".
|
|
58
|
+
* @property {string} description - A brief description of the parameter.
|
|
59
|
+
*/
|
|
60
|
+
/**
|
|
61
|
+
* @typedef {Object} OAMessage
|
|
62
|
+
* @property {'assistant'|'user'} role - The role of the participant (e.g., "assistant", "user").
|
|
63
|
+
* @property {Array<OAContent>} content - The content of the message.
|
|
64
|
+
*/
|
|
65
|
+
/**
|
|
66
|
+
* @typedef {Object} OAContent
|
|
67
|
+
* @property {'output_text'|'input_text'} type - The type of content (e.g., "output_text", "input_text").
|
|
68
|
+
* @property {string} text - The text content.
|
|
69
|
+
*/
|
|
70
|
+
/**
|
|
71
|
+
* @typedef {Object} OAFunctionCall
|
|
72
|
+
* @property {string} id - Unique identifier for the function call.
|
|
73
|
+
* @property {'function_call'} type - Indicates this is a function call (e.g., "function_call").
|
|
74
|
+
* @property {string} call_id - Unique identifier for the specific function call instance.
|
|
75
|
+
* @property {string} name - The name of the function being called.
|
|
76
|
+
* @property {string} arguments - JSON string representing arguments passed to the function.
|
|
77
|
+
*/
|
|
78
|
+
/**
|
|
79
|
+
* @typedef {Object} OAFunctionCallOutput
|
|
80
|
+
* @property {'function_call_output'} type - Indicates this is a function call output (e.g., "function_call_output").
|
|
81
|
+
* @property {string} call_id - Identifier linking to the related function call.
|
|
82
|
+
* @property {string} output - JSON string representing the output from the function call.
|
|
83
|
+
*/
|
|
84
|
+
/**
|
|
85
|
+
* Represents an OpenAI API response request INPUT structure.
|
|
86
|
+
*
|
|
87
|
+
* @typedef {(OAMessage|OAFunctionCall|OAFunctionCallOutput)} OAInput
|
|
88
|
+
*/
|
|
89
|
+
|
|
90
|
+
const API_URL = 'https://api.openai.com/v1/responses';
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Get the default headers
|
|
94
|
+
* @returns {object}
|
|
95
|
+
*/
|
|
96
|
+
const getHeaders = (USER_AGENT = '@j-o-r/agents') => {
|
|
97
|
+
if (!process.env['OPENAIKEY']) {
|
|
98
|
+
throw new Error('Missing OPENAIKEY!export OPENAIKEY=<OPENAI_API_KEY>')
|
|
99
|
+
}
|
|
100
|
+
const KEY = process.env['OPENAIKEY'];
|
|
101
|
+
return {
|
|
102
|
+
'User-Agent': USER_AGENT,
|
|
103
|
+
'Content-Type': 'application/json',
|
|
104
|
+
'Authorization': `Bearer ${KEY}`
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Convert a toolset to something openai understands
|
|
111
|
+
* @param {ToolSet} toolset
|
|
112
|
+
* @returns {OAToolCall[]}
|
|
113
|
+
*/
|
|
114
|
+
const generateTools = (toolset) => {
|
|
115
|
+
const list = toolset.list();
|
|
116
|
+
/** @type {OAToolCall[]} */
|
|
117
|
+
const result = [];
|
|
118
|
+
list.forEach((item) => {
|
|
119
|
+
result.push({
|
|
120
|
+
type: 'function',
|
|
121
|
+
name: item.name,
|
|
122
|
+
description: item.description,
|
|
123
|
+
parameters: item.parameters
|
|
124
|
+
})
|
|
125
|
+
});
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Convert messages to OPENAI requirements
|
|
131
|
+
* @param {import("lib/Session").Message[]} messages
|
|
132
|
+
* @returns {OAInput[]}
|
|
133
|
+
*/
|
|
134
|
+
const generateHistory = (messages) => {
|
|
135
|
+
return messages.reduce((result, msg) => {
|
|
136
|
+
delete msg.sticky;
|
|
137
|
+
delete msg.ts;
|
|
138
|
+
if (['assistant', 'user'].includes(msg.role)) {
|
|
139
|
+
/** @type {OAFunctionCall[]} */
|
|
140
|
+
// @ts-ignore
|
|
141
|
+
const fr = msg.content.map(
|
|
142
|
+
/** @param {import('../../../Prompt.js').FunctionRequest} item */
|
|
143
|
+
(item) => {
|
|
144
|
+
// Transform function requests
|
|
145
|
+
if (item.type === 'function_request') {
|
|
146
|
+
return {
|
|
147
|
+
// @ts-ignore
|
|
148
|
+
// id: item.function_request.id,
|
|
149
|
+
type: 'function_call',
|
|
150
|
+
call_id: item.function_request.call_id,
|
|
151
|
+
name: item.function_request.name,
|
|
152
|
+
arguments: item.function_request.parameters
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}).filter(item => item !== undefined);
|
|
156
|
+
if (fr.length > 0) {
|
|
157
|
+
result.push(...fr);
|
|
158
|
+
}
|
|
159
|
+
// transform normal text input
|
|
160
|
+
const content = msg.content.map((item) => {
|
|
161
|
+
if (item.type == 'text') {
|
|
162
|
+
item.type = msg.role === 'user' ? 'input_text' : 'output_text'
|
|
163
|
+
return item;
|
|
164
|
+
}
|
|
165
|
+
}).filter(item => item !== undefined);
|
|
166
|
+
if (content.length > 0) {
|
|
167
|
+
msg.content = content;
|
|
168
|
+
result.push(msg);
|
|
169
|
+
}
|
|
170
|
+
} else if (['tool'].includes(msg.role)) {
|
|
171
|
+
// transform function responses
|
|
172
|
+
const ar = msg.content.map(
|
|
173
|
+
/** @param {import('../../../Prompt.js').FunctionResponse} item */
|
|
174
|
+
(item) => {
|
|
175
|
+
if (item.type === 'function_response') {
|
|
176
|
+
return {
|
|
177
|
+
type: 'function_call_output',
|
|
178
|
+
call_id: item.function_response.call_id,
|
|
179
|
+
output: item.function_response.response
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}).filter(item => item !== undefined);
|
|
183
|
+
if (ar.length > 0) {
|
|
184
|
+
result.push(...ar);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return result;
|
|
188
|
+
}, []);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
// tools": [{"type": "web_search_preview"}],
|
|
194
|
+
//** @type {OAOptions} */
|
|
195
|
+
const defaultSettings = {
|
|
196
|
+
background: false,
|
|
197
|
+
// search: undefined,
|
|
198
|
+
// include: null,
|
|
199
|
+
// input: [],
|
|
200
|
+
// instructions: '',
|
|
201
|
+
// max_output_tokens: 4000,
|
|
202
|
+
// metadata: null,
|
|
203
|
+
model: 'o3',
|
|
204
|
+
// // https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts
|
|
205
|
+
// prompt: null,
|
|
206
|
+
// https://platform.openai.com/docs/api-reference/responses/create#responses-create-reasoning
|
|
207
|
+
// reasoning must be present fot the function_calls to work
|
|
208
|
+
// reasoning: {
|
|
209
|
+
// effort: null, // null|'low'|'medium'|'high'
|
|
210
|
+
// summary: null // auto, concise, or detailed
|
|
211
|
+
// },
|
|
212
|
+
// service_tier: 'auto',
|
|
213
|
+
// store: false,
|
|
214
|
+
stream: false,
|
|
215
|
+
// temperature: 0.2, // value between 0 -2
|
|
216
|
+
// text: { format: { type: "text" } }, // optional
|
|
217
|
+
parallel_tool_calls: true,
|
|
218
|
+
max_tool_calls: 10,
|
|
219
|
+
// // tool_choice: 'auto', // optional
|
|
220
|
+
// // tools: [],
|
|
221
|
+
// top_logprobs: 0,
|
|
222
|
+
// top_p: 1,
|
|
223
|
+
// truncation: null,
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Generate the POST body of a request
|
|
230
|
+
* @param {Prompt} prompt
|
|
231
|
+
* @param {ToolSet} [toolset]
|
|
232
|
+
* @param {OAOptions} [options]
|
|
233
|
+
*/
|
|
234
|
+
function getBody(prompt, toolset, options) {
|
|
235
|
+
// From the messages I only want assistant and user
|
|
236
|
+
/** @type {OAOptions} */
|
|
237
|
+
// @ts-ignore
|
|
238
|
+
const body = { ...defaultSettings, ...options };
|
|
239
|
+
// const body = options ? mergeOptions(DEFAULT_OPTIONS, options) : DEFAULT_OPTIONS;
|
|
240
|
+
body.instructions = prompt.hasSystemprompt ? prompt.system_prompt : '';
|
|
241
|
+
// the last messages should be a role tool or user else the model cannot handle the request
|
|
242
|
+
const messages = prompt.messages;
|
|
243
|
+
if (!['user', 'tool'].includes(messages[messages.length - 1].role)) {
|
|
244
|
+
throw new Error('Missing last user question or tool');
|
|
245
|
+
}
|
|
246
|
+
body.input = generateHistory(messages);
|
|
247
|
+
if (toolset) {
|
|
248
|
+
// @ts-ignore
|
|
249
|
+
body.tool_choice = toolset.toolChoice;
|
|
250
|
+
body.tools = generateTools(toolset);
|
|
251
|
+
body.parallel_tool_calls = true;
|
|
252
|
+
// parallel_tool_calls
|
|
253
|
+
}
|
|
254
|
+
// Add OPENAI SEARCH
|
|
255
|
+
// in the toolset
|
|
256
|
+
if (body.search) {
|
|
257
|
+
if (!body.tools) {
|
|
258
|
+
body.tools = [];
|
|
259
|
+
}
|
|
260
|
+
body.tools.push({
|
|
261
|
+
type: 'web_search_preview',
|
|
262
|
+
// @ts-ignore
|
|
263
|
+
search_context_size: body.search
|
|
264
|
+
})
|
|
265
|
+
}
|
|
266
|
+
delete body.search;
|
|
267
|
+
return body;
|
|
268
|
+
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* @param {Prompt} prompt
|
|
272
|
+
* @param {ToolSet} [toolset]
|
|
273
|
+
* @param {OAOptions} [options]
|
|
274
|
+
*/
|
|
275
|
+
function generateRequest(prompt, toolset, options) {
|
|
276
|
+
const headers = getHeaders();
|
|
277
|
+
const url = API_URL;
|
|
278
|
+
const body = getBody(prompt, toolset, options);
|
|
279
|
+
return { url, headers, body }
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Parse response messages (output)
|
|
283
|
+
* @param {Array<*>} messages
|
|
284
|
+
* @param {Prompt} prompt
|
|
285
|
+
*/
|
|
286
|
+
function parseMessages(messages, prompt) {
|
|
287
|
+
/** @type {import('../../../Prompt.js').FunctionRequest[]} */
|
|
288
|
+
const toolcall = [];
|
|
289
|
+
let i = 0;
|
|
290
|
+
const len = messages.length;
|
|
291
|
+
for (; i < len; i++) {
|
|
292
|
+
const msg = messages[i];
|
|
293
|
+
// types:
|
|
294
|
+
const type = msg.type;
|
|
295
|
+
if (type === 'reasoning') {
|
|
296
|
+
let messages = msg.summary.map((item) => {
|
|
297
|
+
if (item.type === 'summary_text') {
|
|
298
|
+
return { type: 'text', text: item.text }
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
messages = messages.filter(item => item !== undefined);
|
|
302
|
+
if (messages.length > 0) {
|
|
303
|
+
prompt.addMultiModal('reasoning', messages);
|
|
304
|
+
}
|
|
305
|
+
} else if (type === 'message') {
|
|
306
|
+
let messages = msg.content.map((item) => {
|
|
307
|
+
if (item.type === 'output_text') {
|
|
308
|
+
return { type: 'text', text: item.text }
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
messages = messages.filter(item => item !== undefined);
|
|
312
|
+
if (messages.length > 0) {
|
|
313
|
+
prompt.addMultiModal('assistant', messages);
|
|
314
|
+
}
|
|
315
|
+
} else if (type === 'image_generation_call') {
|
|
316
|
+
prompt.addMultiModal('assistant', [{ type: 'image_url', url: msg.result }]);
|
|
317
|
+
} else if (type === 'function_call' || msg.status === 'complete') {
|
|
318
|
+
toolcall.push({
|
|
319
|
+
type: 'function_request',
|
|
320
|
+
function_request: {
|
|
321
|
+
name: msg.name,
|
|
322
|
+
id: msg.id,
|
|
323
|
+
call_id: msg.call_id,
|
|
324
|
+
parameters: msg.arguments
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
if (toolcall.length > 0) {
|
|
331
|
+
prompt.addMultiModal('assistant', toolcall);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Parse a response
|
|
337
|
+
* @param {number} duration - Fetch time in MS
|
|
338
|
+
* @param {Prompt} prompt
|
|
339
|
+
* @param {import('../../../request.js').FetchResponse} res
|
|
340
|
+
* @param {import('../../../ToolSet.js').default} [toolset]
|
|
341
|
+
*/
|
|
342
|
+
async function parseResponse(duration, prompt, res, toolset) {
|
|
343
|
+
if (res.status !== 200) {
|
|
344
|
+
throw new Error(`${res.status}: ${JSON.stringify(res.response, null, ' ')}`)
|
|
345
|
+
}
|
|
346
|
+
// 1 = make a records
|
|
347
|
+
const record = prompt.templateRecord();
|
|
348
|
+
record.model = res.response.model;
|
|
349
|
+
record.id = res.response.id;
|
|
350
|
+
record.environment = API_URL;
|
|
351
|
+
record.isoDate = new Date(res.response.created_at * 1000).toISOString();
|
|
352
|
+
record.tokensIn = res.response.usage.input_tokens;
|
|
353
|
+
record.tokensOut = res.response.usage.output_tokens;
|
|
354
|
+
record.duration = duration;
|
|
355
|
+
// Parse the messages and and those to the prompt
|
|
356
|
+
parseMessages(res.response.output, prompt);
|
|
357
|
+
if (toolset) {
|
|
358
|
+
// Inspect for function_request and execute if so
|
|
359
|
+
await toolset.execute(prompt);
|
|
360
|
+
}
|
|
361
|
+
prompt.addRecord(record);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Do a request
|
|
366
|
+
* @param {Prompt} prompt
|
|
367
|
+
* @param {ToolSet|null} toolset
|
|
368
|
+
* @param {OAOptions} [options]:
|
|
369
|
+
* @param {number} [counter] - leave empty this counts the number of requests when doing recursive request calls
|
|
370
|
+
* @return {Promise<import('../../../Session.js').Message>}
|
|
371
|
+
*/
|
|
372
|
+
async function request(prompt, toolset = null, options, counter = 0) {
|
|
373
|
+
// Max number of recurusive calls
|
|
374
|
+
const counterMax = GLOBAL.max_recursive_requests;
|
|
375
|
+
const start = new Date().getTime();
|
|
376
|
+
if (counter === 0) {
|
|
377
|
+
// Fresh request
|
|
378
|
+
delete options.previous_response_id
|
|
379
|
+
}
|
|
380
|
+
// Generate the request
|
|
381
|
+
const { url, headers, body } = generateRequest(prompt, toolset, options);
|
|
382
|
+
prompt.emit(prompt.EVENTS.http_request, {url, counter, body});
|
|
383
|
+
const res = await doRequest(url, 'POST', headers, body);
|
|
384
|
+
prompt.emit(prompt.EVENTS.http_response, res);
|
|
385
|
+
if (res.status !== 200) {
|
|
386
|
+
throw new Error(`${res.status}: ${JSON.stringify(res.response, null, ' ')}`)
|
|
387
|
+
}
|
|
388
|
+
/*
|
|
389
|
+
https://platform.openai.com/docs/assistants/deep-dive#runs-and-run-steps
|
|
390
|
+
status` can be: in_progress, completed, incomplete (plus searching / generating / failed for some tool-call items)
|
|
391
|
+
*/
|
|
392
|
+
const duration = new Date().getTime() - start;
|
|
393
|
+
await parseResponse(duration, prompt, res, toolset);
|
|
394
|
+
const previousId = res.response.id;
|
|
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
|
+
if (lastMessage.role === 'tool') {
|
|
402
|
+
// need to do another roundtrip to include the funtion_responses
|
|
403
|
+
// And add the previousId for toolsets to work
|
|
404
|
+
if (!options) {
|
|
405
|
+
// @ts-ignore
|
|
406
|
+
options = {previous_response_id: previousId}
|
|
407
|
+
} else {
|
|
408
|
+
options.previous_response_id = previousId
|
|
409
|
+
}
|
|
410
|
+
await sleep('2s');
|
|
411
|
+
return request(prompt, toolset, options, counter)
|
|
412
|
+
} else {
|
|
413
|
+
return lastMessage
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
export { generateRequest, parseResponse, request }
|