@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.
- package/CHANGELOG.md +21 -0
- package/README.md +445 -160
- package/README.md.backup +269 -0
- package/README.md.bak +481 -0
- package/README.md.bak.1774780058 +338 -0
- package/README.md.bak2 +455 -0
- package/bin/dave.js +165 -0
- package/docs.bak.1774780058/agent-manager.md +167 -0
- package/docs.bak.1774780058/agent-manager.md.bak +137 -0
- package/docs.bak.1774780058/agent-manager.md.bak2 +157 -0
- package/docs.bak.1774780058/codeserver-pattern.md +191 -0
- package/docs.bak.1774780058/path-resolution-best-practices.md +104 -0
- package/docs.bak.1774780058/project-overview.md +67 -0
- package/docs.bak.1774780058/project-overview.md.bak +67 -0
- package/docs.bak.1774780058/prompt-class.md +141 -0
- package/docs.bak.1774780058/prompt-class.md.bak +142 -0
- package/docs.bak.1774780058/tools-syntax-validation.md +121 -0
- package/docs.bak.1774780058/tools-syntax-validation.md.bak2 +125 -0
- package/docs.bak.1774780058/tools-syntax-validation.md.bak3 +125 -0
- package/docs.bak.1774780058/tools-syntax-validation.md.bak4 +106 -0
- package/docs.bak.1774780058/tools-syntax-validation.md.bak_path +106 -0
- package/docs.bak.1774780058/toolset.md +164 -0
- package/docs.bak.1774780058/toolset.md.bak +94 -0
- package/docs.bak.1774780058/toolset.md.bak3 +161 -0
- package/docs.bak.1774780058/toolset.md.bak4 +161 -0
- package/docs.bak.1774780058/toolset.md.bak5 +161 -0
- package/docs.bak.1774780058/toolset.md.bak6 +163 -0
- package/docs.bak.1774780058/toolset.md.bak_path +163 -0
- package/docs.bak.1774780058/toolset.md.bak_syntax +161 -0
- package/docs.bak.1774780058/xai-responses.md +111 -0
- package/docs.bak.1774780058/xai-responses.md.bak +107 -0
- package/docs.bak.1774780058/xai-responses.md.bak2 +107 -0
- package/docs.bak.1774780058/xai_collections.md +106 -0
- package/examples/ask_agent.js +137 -0
- package/examples/code_agent.js +149 -0
- package/examples/coderev_agent.js +136 -0
- package/examples/codeserver.sh +47 -0
- package/examples/daisy_agent.js +170 -0
- package/examples/docs_agent.js +148 -0
- package/examples/gpt_agent.js +125 -0
- package/examples/grok_agent.js +132 -0
- package/examples/grok_agent.js.bak +98 -0
- package/examples/grok_agent.js.bak.2 +99 -0
- package/examples/grok_agent.js.bak.3 +1 -0
- package/examples/grok_agent.js.bak.4 +124 -0
- package/examples/grok_agent.js.bak.5 +1 -0
- package/examples/grok_agent.js.bak.6 +1 -0
- package/examples/memory_agent.js +152 -0
- package/examples/npm_agent.js +202 -0
- package/examples/npm_agent.js.bak.3 +2 -0
- package/examples/npm_agent.js.bak.4 +205 -0
- package/examples/npm_agent.js.bak.5 +1 -0
- package/examples/npm_agent.js.bak.6 +1 -0
- package/examples/prompt_agent.js +133 -0
- package/examples/readme_agent.js +148 -0
- package/examples/spawn_agent.js +293 -0
- package/examples/test_agent.js +187 -0
- package/examples/todo_agent.js +175 -0
- package/examples.bak.1774780058/ask_agent.js +114 -0
- package/examples.bak.1774780058/code_agent.js +149 -0
- package/examples.bak.1774780058/coderev_agent.js +72 -0
- package/examples.bak.1774780058/codeserver.sh +47 -0
- package/examples.bak.1774780058/daisy_agent.js +177 -0
- package/examples.bak.1774780058/docs_agent.js +119 -0
- package/{bin/hdAsk.js → examples.bak.1774780058/gpt_agent.js} +46 -40
- package/examples.bak.1774780058/grok_agent.js +98 -0
- package/examples.bak.1774780058/memory_agent.js +112 -0
- package/examples.bak.1774780058/npm_agent.js +175 -0
- package/examples.bak.1774780058/prompt_agent.js +112 -0
- package/examples.bak.1774780058/readme_agent.js +144 -0
- package/examples.bak.1774780058/spawn_agent.js +263 -0
- package/examples.bak.1774780058/test_agent.js +162 -0
- package/examples.bak.1774780058/todo_agent.js +138 -0
- package/lib/API/openai.com/reponses/text.js +12 -18
- package/lib/API/x.ai/collections.js +354 -0
- package/lib/API/x.ai/files.js +218 -0
- package/lib/API/x.ai/responses.js +492 -0
- package/lib/API/x.ai/text.js +1 -1
- package/lib/AgentClient.js +13 -6
- package/lib/AgentManager.js +80 -10
- package/lib/AgentServer.js +50 -22
- package/lib/Cli.js +7 -1
- package/lib/Prompt.js +4 -2
- package/lib/ToolSet.js +2 -1
- package/lib/genericToolset.js +258 -88
- package/lib/genericToolset.js.bak_syntax +402 -0
- package/lib/index.js +4 -2
- package/lib/wsCli.js +256 -0
- package/lib/wsIO.js +96 -0
- package/package.json +26 -21
- package/scenarios.bak.1774780058/data/eval_node_message.json +9 -0
- package/scenarios.bak.1774780058/data/hist_oa.json +66 -0
- package/scenarios.bak.1774780058/data/o3_response1.json +96 -0
- package/scenarios.bak.1774780058/data/oa_reasoning_parse.json +112 -0
- package/scenarios.bak.1774780058/data/tool_oa.json +96 -0
- package/scenarios.bak.1774780058/data/tool_xai.json +59 -0
- package/scenarios.bak.1774780058/data/tool_xai2.json +40 -0
- package/scenarios.bak.1774780058/data/xai-response-1.json +59 -0
- package/scenarios.bak.1774780058/data/xai-response-2.json +10 -0
- package/scenarios.bak.1774780058/data/xai_reasoning_tools_resp.json +59 -0
- package/scenarios.bak.1774780058/data/xai_search_response.json +58 -0
- package/scenarios.bak.1774780058/environment.js +10 -0
- package/scenarios.bak.1774780058/example.js +17 -0
- package/scenarios.bak.1774780058/genericToolset.test.js +182 -0
- package/scenarios.bak.1774780058/grok.js +113 -0
- package/scenarios.bak.1774780058/memory-tools.js +51 -0
- package/scenarios.bak.1774780058/openai-o3.js +137 -0
- package/scenarios.bak.1774780058/openai-prompt.js +155 -0
- package/scenarios.bak.1774780058/openai-session.js +148 -0
- package/scenarios.bak.1774780058/openai.js +102 -0
- package/scenarios.bak.1774780058/prompt.js +118 -0
- package/scenarios.bak.1774780058/promptFishbowl.js +76 -0
- package/scenarios.bak.1774780058/search.brave.com.js +25 -0
- package/scenarios.bak.1774780058/sh.js +15 -0
- package/scenarios.bak.1774780058/test-wsio.js +26 -0
- package/scenarios.bak.1774780058/testToolset.js +42 -0
- package/scenarios.bak.1774780058/toolset.js +16 -0
- package/scenarios.bak.1774780058/toolset.test.js +141 -0
- package/scenarios.bak.1774780058/write_file_syntax.test.js +145 -0
- package/scenarios.bak.1774780058/write_file_validation/README.md +30 -0
- package/scenarios.bak.1774780058/write_file_validation/bad.js +3 -0
- package/scenarios.bak.1774780058/write_file_validation/good.js +4 -0
- package/scenarios.bak.1774780058/write_file_validation/test.sh +43 -0
- package/scenarios.bak.1774780058/wsClient.js +69 -0
- package/scenarios.bak.1774780058/xai_responses.integration.test.js +57 -0
- package/scenarios.bak.1774780058/xai_responses.test.js +154 -0
- package/scenarios.bak.1774780058/xaicoll.js +50 -0
- package/scenarios.bak.1774780058/xaifiles.js +48 -0
- package/types/API/openai.com/reponses/text.d.ts +17 -3
- package/types/API/x.ai/collections.d.ts +167 -0
- package/types/API/x.ai/files.d.ts +84 -0
- package/types/API/x.ai/responses.d.ts +379 -0
- package/types/AgentClient.d.ts +5 -0
- package/types/AgentManager.d.ts +25 -31
- package/types/AgentServer.d.ts +5 -1
- package/types/Prompt.d.ts +4 -2
- package/types/ToolSet.d.ts +1 -0
- package/types/index.d.ts +4 -3
- package/types/wsCli.d.ts +3 -0
- package/types/wsIO.d.ts +26 -0
- package/utils/bars.js +40 -0
- package/utils/clear_sessions.sh +54 -0
- package/{bin/hdInspect.js → utils/format_log.js} +5 -0
- package/utils/list_sessions.sh +46 -0
- package/utils/search_sessions.sh +73 -0
- package/utils/syntax_check.sh +61 -0
- package/utils/test.sh +46 -0
- package/bin/hdClear.js +0 -13
- package/bin/hdCode.js +0 -115
- package/bin/hdConnect.js +0 -230
- package/bin/hdNpm.js +0 -114
- package/bin/hdPrompt.js +0 -108
- package/examples/claude-test.js +0 -89
- package/examples/claude.js +0 -143
- package/examples/gpt.js +0 -127
- package/examples/gpt_code.js +0 -125
- package/examples/gpt_note_keeping.js +0 -117
- package/examples/grok.js +0 -119
- package/examples/grok_code.js +0 -114
- package/examples/grok_note_keeping.js +0 -111
- package/module.md +0 -189
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {assert, Test } from '@j-o-r/sh';
|
|
3
|
+
import Prompt from '../lib/Prompt.js';
|
|
4
|
+
|
|
5
|
+
const isNpm = process.env.npm_lifecycle_event ? true : false;
|
|
6
|
+
const test = new Test(isNpm);
|
|
7
|
+
const createText = (text, nr) => {
|
|
8
|
+
let result = '';
|
|
9
|
+
const len = nr;
|
|
10
|
+
let i = 0;
|
|
11
|
+
for(;i < len; i++) {
|
|
12
|
+
result += `${text} `;
|
|
13
|
+
}
|
|
14
|
+
return result;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
test.add('Create a 500 tokens prompt', async () => {
|
|
18
|
+
const prompt = new Prompt(500);
|
|
19
|
+
prompt.add('system', createText('system', 50), true); // 0
|
|
20
|
+
prompt.add('user', createText('user', 50), true); // 1
|
|
21
|
+
prompt.add('assistant', 'yes', true); // 2
|
|
22
|
+
prompt.add('user', createText('user2', 50)); // 3
|
|
23
|
+
prompt.add('assistant', createText('assistant 2', 100)); // 4
|
|
24
|
+
prompt.add('user', createText('user3', 50)); // 5
|
|
25
|
+
prompt.add('assistant', createText('assistant 3', 100)); // 6
|
|
26
|
+
prompt.add('user', createText('user 4', 50)); // 7
|
|
27
|
+
prompt.add('assistant', createText('assistant 4', 100)); // 8
|
|
28
|
+
assert.equal(prompt.length, 9);
|
|
29
|
+
const reduced = prompt.truncate();
|
|
30
|
+
assert.equal(prompt.length, 5);
|
|
31
|
+
assert.equal(reduced, true);
|
|
32
|
+
assert.equal(prompt.contextLength, 500);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
test.add('Create a 500 tokens prompt with function calls',async () => {
|
|
37
|
+
const prompt = new Prompt(500);
|
|
38
|
+
prompt.add('system', createText('system', 50), true); // 0
|
|
39
|
+
prompt.add('user', createText('user', 50), true); // 1
|
|
40
|
+
prompt.add('assistant', 'yes', true); // 2
|
|
41
|
+
prompt.add('user', 'Wat is the temperatuur in Den Haag');
|
|
42
|
+
/** @type {import('../lib/Prompt.js').PRFunctionRequest} */
|
|
43
|
+
const fr = {
|
|
44
|
+
type: 'function_request',
|
|
45
|
+
function_request: {
|
|
46
|
+
name: 'get_current_weather',
|
|
47
|
+
id: 'call_zXFv3espCtpa3zfEu9ElOkJw',
|
|
48
|
+
parameters: "{\"location\":\"Den·Haag\",\"unit\":\"celsius\"}"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
prompt.addMultiModal('assistant', [fr]);
|
|
52
|
+
/** @type {import('../lib/Prompt.js').PRFunctionResponse} */
|
|
53
|
+
const res = {
|
|
54
|
+
type: 'function_response',
|
|
55
|
+
function_response: {
|
|
56
|
+
name: 'get_current_weather',
|
|
57
|
+
id: 'call_zXFv3espCtpa3zfEu9ElOkJw',
|
|
58
|
+
response: "{\"temperature\":24}"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
prompt.addMultiModal('tool', [res]);
|
|
62
|
+
prompt.add('assistant', 'Het is 24 graden Celsius in Den Haag.');
|
|
63
|
+
prompt.add('user', createText('user2', 50)); // 3
|
|
64
|
+
prompt.add('assistant', createText('assistant 2', 100)); // 4
|
|
65
|
+
prompt.add('user', createText('user3', 50)); // 5
|
|
66
|
+
prompt.add('assistant', createText('assistant 3', 100)); // 6
|
|
67
|
+
prompt.add('user', createText('user 4', 50)); // 7
|
|
68
|
+
prompt.add('assistant', createText('assistant 4', 100)); // 8
|
|
69
|
+
prompt.truncate();
|
|
70
|
+
assert.equal(prompt.length, 5);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const report = await test.run();
|
|
74
|
+
if (report.errors > 0) {
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Test, assert } from '@j-o-r/sh'
|
|
3
|
+
import {request} from '../lib/API/brave.com/search.js';
|
|
4
|
+
|
|
5
|
+
const test = new Test();
|
|
6
|
+
|
|
7
|
+
test.add('simple brave search', async () => {
|
|
8
|
+
/** @type {import('../lib/search/brave.com/index.js').BRSearchOptions} */
|
|
9
|
+
const options = {search_lang: 'nl', summary: 1, count: 3};
|
|
10
|
+
const res = await request('What is the most populair behringer synth?', options);
|
|
11
|
+
console.log(res);
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
test.add('extended simple brave search', async () => {
|
|
15
|
+
/** @type {import('../lib/search/brave.com/search.js').BRSearchOptions} */
|
|
16
|
+
// const options = {
|
|
17
|
+
// summary: 1,
|
|
18
|
+
// count: 6,
|
|
19
|
+
// freshness: 'py',
|
|
20
|
+
// result_filter: ''
|
|
21
|
+
// }
|
|
22
|
+
const res = await request('"openapi doc" "openai response models" API calls');
|
|
23
|
+
console.log(res);
|
|
24
|
+
})
|
|
25
|
+
await test.run([0]);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {SH} from '@j-o-r/sh'; // Note: relative path
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
async function main() {
|
|
6
|
+
try {
|
|
7
|
+
const res = await SH`node --check bin/dave.js`.run()
|
|
8
|
+
console.log(res);
|
|
9
|
+
} catch (error) {
|
|
10
|
+
console.log('------ error ------');
|
|
11
|
+
console.error(error)
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
main();
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import wsio from './lib/wsIO.js'; // Note: relative path
|
|
3
|
+
|
|
4
|
+
const connectionUrl = 'ws://localhost:8080/ws'; // Your server
|
|
5
|
+
const secret = '123'; // Or your secret
|
|
6
|
+
|
|
7
|
+
async function main() {
|
|
8
|
+
try {
|
|
9
|
+
console.log('=== User Input ===');
|
|
10
|
+
const inputResp = await wsio(connectionUrl, secret, 'user_request', 'Hello, what is the date?');
|
|
11
|
+
console.log(inputResp);
|
|
12
|
+
|
|
13
|
+
console.log('\n=== Server Info ===');
|
|
14
|
+
const infoResp = await wsio(connectionUrl, secret, 'user_info');
|
|
15
|
+
console.log(infoResp);
|
|
16
|
+
|
|
17
|
+
console.log('\n=== Reset ===');
|
|
18
|
+
const resetResp = await wsio(connectionUrl, secret, 'user_reset');
|
|
19
|
+
console.log(resetResp);
|
|
20
|
+
} catch (error) {
|
|
21
|
+
console.error('Error:', error.message);
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
main();
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import ToolSet from '../lib/ToolSet.js'
|
|
2
|
+
// Generic TEST toolset
|
|
3
|
+
const tools = new ToolSet('auto');
|
|
4
|
+
tools.add(
|
|
5
|
+
'get_current_weather', // name
|
|
6
|
+
'Get the current weather in a given location', // desciption
|
|
7
|
+
{
|
|
8
|
+
type: 'object',
|
|
9
|
+
properties: {
|
|
10
|
+
location: {
|
|
11
|
+
type: 'string',
|
|
12
|
+
description: 'The city and country'
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
required: ["location"]
|
|
16
|
+
},
|
|
17
|
+
async (params) => {
|
|
18
|
+
if (params.location.trim() === '') {
|
|
19
|
+
throw new Error('Missing location.');
|
|
20
|
+
// return { records, response };
|
|
21
|
+
}
|
|
22
|
+
const response = {current_weather:'24 C, Cloudy'};
|
|
23
|
+
return response;
|
|
24
|
+
}
|
|
25
|
+
);
|
|
26
|
+
tools.add(
|
|
27
|
+
'get_date_time', // name
|
|
28
|
+
'Get the current date and time', // desciption
|
|
29
|
+
{
|
|
30
|
+
type: 'object',
|
|
31
|
+
properties: {
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
async (_params) => {
|
|
35
|
+
const response = {
|
|
36
|
+
date_time: new Date().toISOString(),
|
|
37
|
+
}
|
|
38
|
+
return response;
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
export default tools;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Test , assert} from '@j-o-r/sh'
|
|
3
|
+
// import ToolSet from '../lib/ToolSet.js'
|
|
4
|
+
import tools from './testToolset.js';
|
|
5
|
+
const test = new Test();
|
|
6
|
+
test.add('Basic', async () => {
|
|
7
|
+
assert.equal(tools.has('get_current_weather'), true);
|
|
8
|
+
assert.equal(tools.has('i_am_not_here'), false);
|
|
9
|
+
const ob = await tools.call('get_current_weather', { location: 'Den haag' })
|
|
10
|
+
assert.equal(ob.current_weather, '24 C, Cloudy')
|
|
11
|
+
const list = tools.list();
|
|
12
|
+
assert.equal(list.length, 2);
|
|
13
|
+
assert.equal(list[0].name, 'get_current_weather');;
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
await test.run();
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Test, assert, jsType } from '@j-o-r/sh';
|
|
3
|
+
import ToolSet from '../lib/ToolSet.js';
|
|
4
|
+
|
|
5
|
+
const t = new Test();
|
|
6
|
+
|
|
7
|
+
// Constructor
|
|
8
|
+
t.add('Constructor default auto', () => {
|
|
9
|
+
const ts = new ToolSet();
|
|
10
|
+
assert.strictEqual(ts.toolChoice, 'auto');
|
|
11
|
+
assert.strictEqual(ts.length, 0);
|
|
12
|
+
assert.strictEqual(jsType(ts), 'ToolSet');
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
t.add('Constructor valid choices', () => {
|
|
16
|
+
['auto', 'none', 'required'].forEach(choice => {
|
|
17
|
+
const ts = new ToolSet(choice);
|
|
18
|
+
assert.strictEqual(ts.toolChoice, choice);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
t.add('Constructor invalid choice throws', () => {
|
|
23
|
+
try {
|
|
24
|
+
new ToolSet('invalid');
|
|
25
|
+
assert.fail('Should throw on invalid choice');
|
|
26
|
+
} catch (e) {
|
|
27
|
+
assert.ok(e.message.includes('Tool choice not defined'));
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// add method
|
|
32
|
+
t.add('add invalid name throws', () => {
|
|
33
|
+
const ts = new ToolSet();
|
|
34
|
+
try {
|
|
35
|
+
ts.add('a', 'desc', { type: 'object' }, async () => {});
|
|
36
|
+
assert.fail('Should throw invalid name');
|
|
37
|
+
} catch (e) {
|
|
38
|
+
assert.ok(e.message.includes('Invalid name'));
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
t.add('add valid tool', () => {
|
|
43
|
+
const ts = new ToolSet();
|
|
44
|
+
const mockMethod = async (params) => ({ received: params });
|
|
45
|
+
ts.add('valid_tool', 'Valid tool description', {
|
|
46
|
+
type: 'object',
|
|
47
|
+
properties: { foo: { type: 'string' } },
|
|
48
|
+
required: ['foo']
|
|
49
|
+
}, mockMethod);
|
|
50
|
+
assert.strictEqual(ts.length, 1);
|
|
51
|
+
assert.strictEqual(ts.has('valid_tool'), true);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
t.add('add duplicate no throw, overwrites', () => {
|
|
55
|
+
const ts = new ToolSet();
|
|
56
|
+
const method1 = async () => 'first';
|
|
57
|
+
const method2 = async () => 'second';
|
|
58
|
+
ts.add('dup', 'desc', { type: 'object' }, method1);
|
|
59
|
+
ts.add('dup', 'desc', { type: 'object' }, method2);
|
|
60
|
+
assert.strictEqual(ts.length, 1);
|
|
61
|
+
const tool = ts.get('dup');
|
|
62
|
+
assert.strictEqual(tool.description, 'desc'); // last one
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
t.add('get throws not found', () => {
|
|
66
|
+
const ts = new ToolSet();
|
|
67
|
+
try {
|
|
68
|
+
ts.get('missing');
|
|
69
|
+
assert.fail('Should throw');
|
|
70
|
+
} catch (e) {
|
|
71
|
+
assert.ok(e.message.includes('Function not found'));
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
t.add('get existing tool', () => {
|
|
76
|
+
const ts = new ToolSet();
|
|
77
|
+
ts.add('gettool', 'desc', { type: 'object' }, async () => {});
|
|
78
|
+
const tool = ts.get('gettool');
|
|
79
|
+
assert.strictEqual(jsType(tool), 'Object');
|
|
80
|
+
assert.strictEqual(tool.description, 'desc');
|
|
81
|
+
assert.strictEqual(jsType(tool.parameters), 'Object');
|
|
82
|
+
assert.strictEqual(jsType(tool.method), 'AsyncFunction');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// delete
|
|
86
|
+
t.add('delete reduces length', () => {
|
|
87
|
+
const ts = new ToolSet();
|
|
88
|
+
ts.add('to_delete', 'desc', { type: 'object' }, async () => {});
|
|
89
|
+
assert.strictEqual(ts.length, 1);
|
|
90
|
+
ts.delete('to_delete');
|
|
91
|
+
assert.strictEqual(ts.length, 0);
|
|
92
|
+
assert.strictEqual(ts.has('to_delete'), false);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
t.add('delete non-existing no error', () => {
|
|
96
|
+
const ts = new ToolSet();
|
|
97
|
+
ts.delete('nonexistent');
|
|
98
|
+
assert.strictEqual(ts.length, 0);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// list
|
|
102
|
+
t.add('list empty', () => {
|
|
103
|
+
const ts = new ToolSet();
|
|
104
|
+
const list = ts.list();
|
|
105
|
+
assert.strictEqual(list.length, 0);
|
|
106
|
+
assert.strictEqual(jsType(list), 'Array');
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
t.add('list sorted by name', () => {
|
|
110
|
+
const ts = new ToolSet();
|
|
111
|
+
ts.add('b_tool', 'b desc', { type: 'object' }, async () => {});
|
|
112
|
+
ts.add('a_tool', 'a desc', { type: 'object' }, async () => {});
|
|
113
|
+
ts.add('c_tool', 'c desc', { type: 'object' }, async () => {});
|
|
114
|
+
const list = ts.list();
|
|
115
|
+
assert.strictEqual(list.length, 3);
|
|
116
|
+
assert.strictEqual(list[0].name, 'a_tool');
|
|
117
|
+
assert.strictEqual(list[1].name, 'b_tool');
|
|
118
|
+
assert.strictEqual(list[2].name, 'c_tool');
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// call
|
|
122
|
+
t.add('call success', async () => {
|
|
123
|
+
const ts = new ToolSet();
|
|
124
|
+
const expected = { result: 42 };
|
|
125
|
+
ts.add('calc', 'calc', { type: 'object' }, async () => expected);
|
|
126
|
+
const res = await ts.call('calc', {});
|
|
127
|
+
assert.deepStrictEqual(res, expected);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
t.add('call not found throws', async () => {
|
|
131
|
+
const ts = new ToolSet();
|
|
132
|
+
try {
|
|
133
|
+
await ts.call('missing', {});
|
|
134
|
+
assert.fail('Should throw');
|
|
135
|
+
} catch (e) {
|
|
136
|
+
assert.ok(e.message.includes('Function not found'));
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const report = await t.run();
|
|
141
|
+
process.exit(report.errors > 0 ? 1 : 0);
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Test, assert, jsType } from '@j-o-r/sh';
|
|
3
|
+
import { execSync } from 'child_process';
|
|
4
|
+
import { mkdtempSync, writeFileSync, rmSync, mkdirSync } from 'fs';
|
|
5
|
+
import { tmpdir } from 'os';
|
|
6
|
+
import { join, dirname } from 'path';
|
|
7
|
+
|
|
8
|
+
const t = new Test();
|
|
9
|
+
const TMP = mkdtempSync(join(tmpdir(), 'syntax_test_'));
|
|
10
|
+
process.on('exit', () => rmSync(TMP, { recursive: true, force: true }));
|
|
11
|
+
|
|
12
|
+
const checkSyntax = (file) => {
|
|
13
|
+
try {
|
|
14
|
+
execSync(`./utils/syntax_check.sh "${file}"`, { cwd: process.cwd(), stdio: 'pipe', timeout: 5000 });
|
|
15
|
+
return true;
|
|
16
|
+
} catch (e) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const writeTemp = (relpath, content) => {
|
|
22
|
+
const file = join(TMP, relpath);
|
|
23
|
+
mkdirSync(dirname(file), { recursive: true });
|
|
24
|
+
writeFileSync(file, content);
|
|
25
|
+
return file;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
t.add('checkSyntax returns boolean', () => {
|
|
29
|
+
const file = writeTemp('test.js', 'console.log("ok");');
|
|
30
|
+
assert.strictEqual(jsType(checkSyntax(file)), 'Boolean');
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
t.add('syntax_check: JS valid', () => {
|
|
34
|
+
const file = writeTemp('valid.js', '// Valid JS\nconsole.log("ok");');
|
|
35
|
+
assert.strictEqual(checkSyntax(file), true);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
t.add('syntax_check: JS invalid (unexpected token)', () => {
|
|
39
|
+
const file = writeTemp('invalid.js', 'const x = ; console.log(x);');
|
|
40
|
+
assert.strictEqual(checkSyntax(file), false);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
t.add('syntax_check: JS invalid unterminated quote', () => {
|
|
44
|
+
const file = writeTemp('invalid-quote.js', 'console.log("hi );');
|
|
45
|
+
assert.strictEqual(checkSyntax(file), false);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
t.add('syntax_check: JS invalid unbalanced paren', () => {
|
|
49
|
+
const file = writeTemp('invalid-paren.js', 'if (true {\n console.log("ok");\n}');
|
|
50
|
+
assert.strictEqual(checkSyntax(file), false);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
t.add('syntax_check: JS valid ESM import', () => {
|
|
54
|
+
const file = writeTemp('valid-esm.js', 'import { Test } from "@j-o-r/sh";\nconsole.log("ok");');
|
|
55
|
+
assert.strictEqual(checkSyntax(file), true);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
t.add('syntax_check: JS shebang valid', () => {
|
|
59
|
+
const file = writeTemp('valid-shebang.js', '#!/usr/bin/env node\nimport { Test } from "@j-o-r/sh";');
|
|
60
|
+
assert.strictEqual(checkSyntax(file), true);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
t.add('syntax_check: JS subdir valid', () => {
|
|
64
|
+
const file = writeTemp('subdir/valid.js', 'console.log("ok");');
|
|
65
|
+
assert.strictEqual(checkSyntax(file), true);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// PY invalid: missing indent
|
|
69
|
+
t.add('syntax_check: PY invalid (indent err)', () => {
|
|
70
|
+
const file = writeTemp('invalid.py', 'def f():\nprint("hi")');
|
|
71
|
+
assert.strictEqual(checkSyntax(file), false);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// PY valid
|
|
75
|
+
t.add('syntax_check: PY valid', () => {
|
|
76
|
+
const file = writeTemp('valid.py', '#!/usr/bin/env python3\ndef f():\n print("hi")\nf()');
|
|
77
|
+
assert.strictEqual(checkSyntax(file), true);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// SH invalid: missing fi
|
|
81
|
+
t.add('syntax_check: SH invalid (missing fi)', () => {
|
|
82
|
+
const file = writeTemp('invalid.sh', '#!/bin/bash\nif true; then\necho "hi"');
|
|
83
|
+
assert.strictEqual(checkSyntax(file), false);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// SH valid
|
|
87
|
+
t.add('syntax_check: SH valid', () => {
|
|
88
|
+
const file = writeTemp('valid.sh', '#!/bin/bash\necho "ok"');
|
|
89
|
+
assert.strictEqual(checkSyntax(file), true);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// SH shebang + if/fi
|
|
93
|
+
t.add('syntax_check: SH valid (if/fi)', () => {
|
|
94
|
+
const file = writeTemp('valid-if.sh', '#!/usr/bin/env bash\nif true; then\n echo "ok"\nfi');
|
|
95
|
+
assert.strictEqual(checkSyntax(file), true);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// JSON invalid: trailing comma
|
|
99
|
+
t.add('syntax_check: JSON invalid', () => {
|
|
100
|
+
const file = writeTemp('invalid.json', '{ "key": "value", }');
|
|
101
|
+
assert.strictEqual(checkSyntax(file), false);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// JSON valid
|
|
105
|
+
t.add('syntax_check: JSON valid', () => {
|
|
106
|
+
const file = writeTemp('valid.json', '{ "key": "value" }');
|
|
107
|
+
assert.strictEqual(checkSyntax(file), true);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Unknown ext: non-fatal pass
|
|
111
|
+
t.add('syntax_check: unknown ext (txt)', () => {
|
|
112
|
+
const file = writeTemp('test.txt', 'plain text');
|
|
113
|
+
assert.strictEqual(checkSyntax(file), true);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// write_file sim: invalid → reject (PY/SH/JSON/JS)
|
|
117
|
+
t.add('syntax_check: write_file sim JS reject', () => {
|
|
118
|
+
const file = writeTemp('sim_invalid.js', 'console.log("hi );');
|
|
119
|
+
assert.strictEqual(checkSyntax(file), false);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
t.add('syntax_check: write_file sim PY reject', () => {
|
|
123
|
+
const file = writeTemp('sim_invalid.py', 'def f():\nprint("hi")');
|
|
124
|
+
assert.strictEqual(checkSyntax(file), false);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
t.add('syntax_check: write_file sim SH reject', () => {
|
|
128
|
+
const file = writeTemp('sim_invalid.sh', '#!/bin/bash\nif true; then echo hi');
|
|
129
|
+
assert.strictEqual(checkSyntax(file), false);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
t.add('syntax_check: write_file sim JSON reject', () => {
|
|
133
|
+
const file = writeTemp('sim_invalid.json', '{invalid}');
|
|
134
|
+
assert.strictEqual(checkSyntax(file), false);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
t.add('syntax_check: async valid JS', async () => {
|
|
138
|
+
const file = writeTemp('async-valid.js', 'console.log("ok");');
|
|
139
|
+
await new Promise(r => setTimeout(r, 10));
|
|
140
|
+
assert.strictEqual(checkSyntax(file), true);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
const report = await t.run();
|
|
144
|
+
assert.strictEqual(jsType(report), 'Object');
|
|
145
|
+
process.exit(report.errors > 0 ? 1 : 0);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# write_file Auto-Validation Test Suite
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
Tests the enhanced \`write_file\` tool in \`lib/genericToolset.js\`:
|
|
5
|
+
- **JS Syntax Check**: \`node --check\` on .js/shebang files → blocks invalid.
|
|
6
|
+
- **Error Guidance**: Forces LLM retry with \\\` fix hints.
|
|
7
|
+
- **chmod +x**: Auto for shebangs.
|
|
8
|
+
- **Self-Healing**: LLM sees error → regenerates valid JS.
|
|
9
|
+
|
|
10
|
+
## Files
|
|
11
|
+
- \`bad.js\`: Intentional syntax error (unclosed template literal \`console.log(\`).
|
|
12
|
+
- \`good.js\`: Fixed (properly escaped \`console.log(\\\\\\`hello\\\\\\\`); \`).
|
|
13
|
+
- \`test.sh\`: Runs write_file simulation → expect error on bad → success on good.
|
|
14
|
+
|
|
15
|
+
## Run
|
|
16
|
+
```bash
|
|
17
|
+
cd scenarios/write_file_validation
|
|
18
|
+
chmod +x test.sh
|
|
19
|
+
./test.sh
|
|
20
|
+
```
|
|
21
|
+
Expected:
|
|
22
|
+
```
|
|
23
|
+
❌ Write bad.js → SYNTAX ERROR (node --check fails)
|
|
24
|
+
✅ Write good.js → ✓ JS syntax OK + chmod +x (if shebang)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## LLM Test (via CodeServer)
|
|
28
|
+
Query: \"Use write_file to create bad.js with console.log(\`hi\`); then fix it.\" → Auto-triggers retry loop.
|
|
29
|
+
|
|
30
|
+
Current date: March 27, 2026.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
echo "=== write_file Auto-Validation Test ==="
|
|
5
|
+
cd "$(dirname "$0")"
|
|
6
|
+
|
|
7
|
+
# Simulate toolset write_file (manual for demo; real uses lib/genericToolset.js)
|
|
8
|
+
echo "1. Write BAD JS (expect SYNTAX ERROR)..."
|
|
9
|
+
cat > temp_bad.js << 'EOF'
|
|
10
|
+
#!/usr/bin/env node
|
|
11
|
+
console.log(`Unclosed backtick! // ERROR: Missing closing \`
|
|
12
|
+
EOF
|
|
13
|
+
|
|
14
|
+
# Manual node --check (mimics tool)
|
|
15
|
+
if node --check temp_bad.js 2>&1; then
|
|
16
|
+
echo "❌ FAIL: Bad JS passed check!"
|
|
17
|
+
else
|
|
18
|
+
echo "✅ PASS: Bad JS correctly rejected ($(node --check temp_bad.js 2>&1 | head -1))"
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
echo "2. Write GOOD JS (expect ✓ OK + chmod)..."
|
|
22
|
+
cat > temp_good.js << 'EOF'
|
|
23
|
+
#!/usr/bin/env node
|
|
24
|
+
console.log(`Fixed template!`);
|
|
25
|
+
console.log('All good.');
|
|
26
|
+
EOF
|
|
27
|
+
|
|
28
|
+
if node --check temp_good.js 2>&1; then
|
|
29
|
+
echo "✅ PASS: Good JS syntax OK"
|
|
30
|
+
chmod +x temp_good.js
|
|
31
|
+
echo "✅ PASS: chmod +x applied"
|
|
32
|
+
./temp_good.js # Runs!
|
|
33
|
+
else
|
|
34
|
+
echo "❌ FAIL: Good JS failed check!"
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
# Real toolset test (requires running agent)
|
|
38
|
+
echo "3. REAL TOOL TEST (run via CodeServer):"
|
|
39
|
+
echo " echo 'write_file scenarios/write_file_validation/new.js: console.log(\`test\`);' | dave --connect ws://...:8081/ws"
|
|
40
|
+
echo " → If bad: Error → LLM fixes → ✓ OK"
|
|
41
|
+
|
|
42
|
+
rm -f temp_*.js
|
|
43
|
+
echo "=== ALL TESTS PASS ✅ ==="
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import cli from '@j-o-r/cli';
|
|
3
|
+
import { WebSocketClient } from "@j-o-r/apiserver";
|
|
4
|
+
const NAME = 'clarification';
|
|
5
|
+
const wsUser = new WebSocketClient('ws://localhost:2000/ws?test=param'); // Match server port/path
|
|
6
|
+
|
|
7
|
+
const queryMessages = new Map();
|
|
8
|
+
|
|
9
|
+
/*
|
|
10
|
+
HANDSHAKE:
|
|
11
|
+
|
|
12
|
+
1: requests an introduction with 'introduce'
|
|
13
|
+
2: get a response 'introduction'
|
|
14
|
+
|
|
15
|
+
This must be DONE before anything else can take place
|
|
16
|
+
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
cli.registerKeyMappings([
|
|
20
|
+
{ name: 'd', ctrl: true, meta: false, shift: false, handler: async () => {
|
|
21
|
+
process.exit(0);
|
|
22
|
+
}},
|
|
23
|
+
{ name: 'r', ctrl: true, meta: false, shift: false, handler: async () => {
|
|
24
|
+
cli.clear();
|
|
25
|
+
}}
|
|
26
|
+
|
|
27
|
+
]);
|
|
28
|
+
// @ts-ignore
|
|
29
|
+
cli.inputHandler = async (s, role) => {
|
|
30
|
+
const message = {
|
|
31
|
+
action: 'query',
|
|
32
|
+
content: s,
|
|
33
|
+
}
|
|
34
|
+
wsUser.send(JSON.stringify(message));
|
|
35
|
+
cli.startSpinner();
|
|
36
|
+
}
|
|
37
|
+
cli.focus('log');
|
|
38
|
+
cli.write('CTRL - d exit');
|
|
39
|
+
cli.write('CTRL - r clear screen / reset');
|
|
40
|
+
// cli.focus('user', true);
|
|
41
|
+
|
|
42
|
+
wsUser.onopen = () => {
|
|
43
|
+
cli.focus('log');
|
|
44
|
+
cli.write('Jorrit connected');
|
|
45
|
+
// Send my introduction to the server
|
|
46
|
+
wsUser.send(JSON.stringify({
|
|
47
|
+
action: 'introduction',
|
|
48
|
+
name: NAME,
|
|
49
|
+
content: 'I am a human named Jorrit. Query me for questions that needs clearfication',
|
|
50
|
+
id: new Date().getTime()
|
|
51
|
+
}));
|
|
52
|
+
cli.focus('user', true);
|
|
53
|
+
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* @type {MessageEvent} event
|
|
57
|
+
*/
|
|
58
|
+
wsUser.onmessage = (event) => {
|
|
59
|
+
const data = JSON.parse(event.data); // Forwarded HTTP request
|
|
60
|
+
console.log('Received request:', data);
|
|
61
|
+
cli.focus('user', true);
|
|
62
|
+
};
|
|
63
|
+
wsUser.onclose = () => {
|
|
64
|
+
console.log('WS closed');
|
|
65
|
+
process.exit();
|
|
66
|
+
}
|
|
67
|
+
wsUser.onerror = (err) => {
|
|
68
|
+
console.error('WS error:', err);
|
|
69
|
+
}
|