@j-o-r/hello-dave 0.0.5 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -26
- package/README.md +161 -522
- package/README.md.bak +144 -449
- package/{examples → agents}/ask_agent.js +5 -5
- package/{examples → agents}/codeserver.sh +14 -14
- package/{examples → agents}/daisy_agent.js +5 -5
- package/{examples → agents}/docs_agent.js +5 -5
- package/{examples → agents}/gpt_agent.js +5 -5
- package/{examples → agents}/grok_agent.js +5 -5
- package/agents/memory_agent.js +263 -0
- package/{examples → agents}/npm_agent.js +5 -5
- package/{examples → agents}/prompt_agent.js +5 -5
- package/agents/spawn_agent.js +137 -0
- package/{examples → agents}/test_agent.js +6 -8
- package/{examples → agents}/todo_agent.js +5 -5
- package/bin/codeDave +58 -0
- package/bin/dave.js +114 -96
- package/lib/AgentClient.js +111 -67
- package/lib/AgentManager.js +111 -80
- package/lib/AgentServer.js +144 -104
- package/lib/Cli.js +126 -93
- package/lib/Prompt.js +38 -5
- package/lib/Session.js +102 -79
- package/lib/ToolSet.js +79 -60
- package/lib/fafs.js +54 -19
- package/lib/genericToolset.js +109 -213
- package/lib/wsCli.js +50 -19
- package/lib/wsIO.js +11 -17
- package/package.json +2 -2
- package/types/AgentClient.d.ts +69 -35
- package/types/AgentManager.d.ts +50 -56
- package/types/AgentServer.d.ts +63 -16
- package/types/Cli.d.ts +56 -10
- package/types/Prompt.d.ts +36 -4
- package/types/Session.d.ts +23 -9
- package/types/ToolSet.d.ts +49 -32
- package/types/fafs.d.ts +68 -25
- package/types/wsCli.d.ts +14 -0
- package/types/wsIO.d.ts +9 -5
- package/utils/search_sessions.sh +100 -53
- package/README.md.backup +0 -269
- package/README.md.bak.1774780058 +0 -338
- package/README.md.bak2 +0 -531
- package/bin/spawn_agent.js +0 -293
- package/docs.bak.1774780058/agent-manager.md +0 -167
- package/docs.bak.1774780058/agent-manager.md.bak +0 -137
- package/docs.bak.1774780058/agent-manager.md.bak2 +0 -157
- package/docs.bak.1774780058/codeserver-pattern.md +0 -191
- package/docs.bak.1774780058/path-resolution-best-practices.md +0 -104
- package/docs.bak.1774780058/project-overview.md +0 -67
- package/docs.bak.1774780058/project-overview.md.bak +0 -67
- package/docs.bak.1774780058/prompt-class.md +0 -141
- package/docs.bak.1774780058/prompt-class.md.bak +0 -142
- package/docs.bak.1774780058/tools-syntax-validation.md +0 -121
- package/docs.bak.1774780058/tools-syntax-validation.md.bak2 +0 -125
- package/docs.bak.1774780058/tools-syntax-validation.md.bak3 +0 -125
- package/docs.bak.1774780058/tools-syntax-validation.md.bak4 +0 -106
- package/docs.bak.1774780058/tools-syntax-validation.md.bak_path +0 -106
- package/docs.bak.1774780058/toolset.md +0 -164
- package/docs.bak.1774780058/toolset.md.bak +0 -94
- package/docs.bak.1774780058/toolset.md.bak3 +0 -161
- package/docs.bak.1774780058/toolset.md.bak4 +0 -161
- package/docs.bak.1774780058/toolset.md.bak5 +0 -161
- package/docs.bak.1774780058/toolset.md.bak6 +0 -163
- package/docs.bak.1774780058/toolset.md.bak_path +0 -163
- package/docs.bak.1774780058/toolset.md.bak_syntax +0 -161
- package/docs.bak.1774780058/xai-responses.md +0 -111
- package/docs.bak.1774780058/xai-responses.md.bak +0 -107
- package/docs.bak.1774780058/xai-responses.md.bak2 +0 -107
- package/docs.bak.1774780058/xai_collections.md +0 -106
- package/examples/memory_agent.js +0 -152
- package/examples.bak.1774780058/ask_agent.js +0 -114
- package/examples.bak.1774780058/code_agent.js +0 -149
- package/examples.bak.1774780058/coderev_agent.js +0 -72
- package/examples.bak.1774780058/codeserver.sh +0 -47
- package/examples.bak.1774780058/daisy_agent.js +0 -177
- package/examples.bak.1774780058/docs_agent.js +0 -119
- package/examples.bak.1774780058/gpt_agent.js +0 -109
- package/examples.bak.1774780058/grok_agent.js +0 -98
- package/examples.bak.1774780058/memory_agent.js +0 -112
- package/examples.bak.1774780058/npm_agent.js +0 -175
- package/examples.bak.1774780058/prompt_agent.js +0 -112
- package/examples.bak.1774780058/readme_agent.js +0 -144
- package/examples.bak.1774780058/spawn_agent.js +0 -263
- package/examples.bak.1774780058/test_agent.js +0 -162
- package/examples.bak.1774780058/todo_agent.js +0 -138
- package/lib/genericToolset.js.bak_syntax +0 -402
- package/scenarios.bak.1774780058/data/eval_node_message.json +0 -9
- package/scenarios.bak.1774780058/data/hist_oa.json +0 -66
- package/scenarios.bak.1774780058/data/o3_response1.json +0 -96
- package/scenarios.bak.1774780058/data/oa_reasoning_parse.json +0 -112
- package/scenarios.bak.1774780058/data/tool_oa.json +0 -96
- package/scenarios.bak.1774780058/data/tool_xai.json +0 -59
- package/scenarios.bak.1774780058/data/tool_xai2.json +0 -40
- package/scenarios.bak.1774780058/data/xai-response-1.json +0 -59
- package/scenarios.bak.1774780058/data/xai-response-2.json +0 -10
- package/scenarios.bak.1774780058/data/xai_reasoning_tools_resp.json +0 -59
- package/scenarios.bak.1774780058/data/xai_search_response.json +0 -58
- package/scenarios.bak.1774780058/environment.js +0 -10
- package/scenarios.bak.1774780058/example.js +0 -17
- package/scenarios.bak.1774780058/genericToolset.test.js +0 -182
- package/scenarios.bak.1774780058/grok.js +0 -113
- package/scenarios.bak.1774780058/memory-tools.js +0 -51
- package/scenarios.bak.1774780058/openai-o3.js +0 -137
- package/scenarios.bak.1774780058/openai-prompt.js +0 -155
- package/scenarios.bak.1774780058/openai-session.js +0 -148
- package/scenarios.bak.1774780058/openai.js +0 -102
- package/scenarios.bak.1774780058/prompt.js +0 -118
- package/scenarios.bak.1774780058/promptFishbowl.js +0 -76
- package/scenarios.bak.1774780058/search.brave.com.js +0 -25
- package/scenarios.bak.1774780058/sh.js +0 -15
- package/scenarios.bak.1774780058/test-wsio.js +0 -26
- package/scenarios.bak.1774780058/testToolset.js +0 -42
- package/scenarios.bak.1774780058/toolset.js +0 -16
- package/scenarios.bak.1774780058/toolset.test.js +0 -141
- package/scenarios.bak.1774780058/write_file_syntax.test.js +0 -145
- package/scenarios.bak.1774780058/write_file_validation/README.md +0 -30
- package/scenarios.bak.1774780058/write_file_validation/bad.js +0 -3
- package/scenarios.bak.1774780058/write_file_validation/good.js +0 -4
- package/scenarios.bak.1774780058/write_file_validation/test.sh +0 -43
- package/scenarios.bak.1774780058/wsClient.js +0 -69
- package/scenarios.bak.1774780058/xai_responses.integration.test.js +0 -57
- package/scenarios.bak.1774780058/xai_responses.test.js +0 -154
- package/scenarios.bak.1774780058/xaicoll.js +0 -50
- package/scenarios.bak.1774780058/xaifiles.js +0 -48
- /package/{examples → agents}/code_agent.js +0 -0
- /package/{examples → agents}/readme_agent.js +0 -0
|
@@ -1,145 +0,0 @@
|
|
|
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);
|
|
@@ -1,30 +0,0 @@
|
|
|
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.
|
|
@@ -1,43 +0,0 @@
|
|
|
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 ✅ ==="
|
|
@@ -1,69 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { Test, assert } from '@j-o-r/sh';
|
|
3
|
-
import { request } from '../lib/API/x.ai/responses.js';
|
|
4
|
-
import Prompt from '../lib/Prompt.js';
|
|
5
|
-
import tools from './testToolset.js'; // Reuse weather mock for recursion
|
|
6
|
-
|
|
7
|
-
const t = new Test();
|
|
8
|
-
|
|
9
|
-
// Real API: tools + recursion (default model)
|
|
10
|
-
t.add('request: real with tools (recursion)', async () => {
|
|
11
|
-
const p = new Prompt();
|
|
12
|
-
p.add('system', 'You are helpful. Use tools for weather.', true);
|
|
13
|
-
p.add('user', 'Weather in Amsterdam?');
|
|
14
|
-
const msg = await request(p, tools);
|
|
15
|
-
assert.strictEqual(msg.role, 'assistant');
|
|
16
|
-
assert.ok(msg.content.some(c => c.type === 'text'), 'Final text response');
|
|
17
|
-
const toolMsg = p.messages.find(m => m.role === 'tool');
|
|
18
|
-
assert.ok(toolMsg, 'Tool executed');
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
// Real API: custom options (non-reasoning model)
|
|
22
|
-
t.add('request: real options (model/temp/store)', async () => {
|
|
23
|
-
const p = new Prompt();
|
|
24
|
-
p.add('system', 'Answer in JSON.', true);
|
|
25
|
-
p.add('user', '2+2 as JSON.');
|
|
26
|
-
const msg = await request(p, null, {
|
|
27
|
-
model: 'grok-4-fast-non-reasoning',
|
|
28
|
-
temperature: 0.1,
|
|
29
|
-
store: true,
|
|
30
|
-
max_output_tokens: 100
|
|
31
|
-
});
|
|
32
|
-
assert.strictEqual(msg.role, 'assistant');
|
|
33
|
-
assert.ok(msg.content[0].text.includes('4'), 'JSON with 4');
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
// Real API: reasoning rejected (unsupported on default model)
|
|
37
|
-
t.add('request: reasoning rejected on incompatible model', async () => {
|
|
38
|
-
const p = new Prompt();
|
|
39
|
-
p.add('user', 'Why is sky blue?');
|
|
40
|
-
await assert.rejects(
|
|
41
|
-
() => request(p, null, { reasoning: { effort: 'high', summary: 'concise' } }),
|
|
42
|
-
/invalid argument|reasoningEffort/
|
|
43
|
-
);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
// Real API: invalid model rejects (4xx)
|
|
47
|
-
t.add('request: invalid model rejects', async () => {
|
|
48
|
-
const p = new Prompt();
|
|
49
|
-
p.add('user', 'Hi');
|
|
50
|
-
await assert.rejects(
|
|
51
|
-
() => request(p, null, { model: 'invalid-xyz' }),
|
|
52
|
-
/Error.*4\\d{2}|Model not found|400/
|
|
53
|
-
);
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
const report = await t.run();
|
|
57
|
-
process.exit(report.errors > 0 ? 1 : 0);
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { Test, assert } from '@j-o-r/sh';
|
|
3
|
-
import { generateRequest, parseResponse, request } from '../lib/API/x.ai/responses.js';
|
|
4
|
-
import Prompt from '../lib/Prompt.js';
|
|
5
|
-
import ToolSet from '../lib/ToolSet.js';
|
|
6
|
-
import tools from './testToolset.js';
|
|
7
|
-
|
|
8
|
-
const t = new Test();
|
|
9
|
-
|
|
10
|
-
// Fake response helpers
|
|
11
|
-
const fakeTextRes = () => ({
|
|
12
|
-
status: 200,
|
|
13
|
-
response: {
|
|
14
|
-
id: 'fake-text',
|
|
15
|
-
model: 'grok-beta',
|
|
16
|
-
created_at: Math.floor(Date.now() / 1000),
|
|
17
|
-
usage: { input_tokens: 10, output_tokens: 5 },
|
|
18
|
-
output: [{ type: 'message', content: [{ type: 'output_text', text: 'Hello!' }] }]
|
|
19
|
-
}
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
const fakeReasoningRes = () => ({
|
|
23
|
-
status: 200,
|
|
24
|
-
response: {
|
|
25
|
-
id: 'fake-reason',
|
|
26
|
-
model: 'grok-beta',
|
|
27
|
-
created_at: Math.floor(Date.now() / 1000),
|
|
28
|
-
usage: { input_tokens: 10, output_tokens: 5 },
|
|
29
|
-
output: [{ type: 'reasoning', summary: [{ type: 'summary_text', text: 'Thought.' }] }]
|
|
30
|
-
}
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
const fakeCitationRes = () => ({
|
|
34
|
-
status: 200,
|
|
35
|
-
response: {
|
|
36
|
-
id: 'fake-cit',
|
|
37
|
-
model: 'grok-beta',
|
|
38
|
-
created_at: Math.floor(Date.now() / 1000),
|
|
39
|
-
usage: { input_tokens: 10, output_tokens: 5 },
|
|
40
|
-
output: [{ type: 'message', content: [{ type: 'output_text', text: 'Text', annotations: [{ type: 'url_citation', url: 'https://ex.com' }] }] }]
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
const fakeToolRes = (name = 'get_current_weather', args = '{"location":"Amsterdam"}') => ({
|
|
45
|
-
status: 200,
|
|
46
|
-
response: {
|
|
47
|
-
id: 'fake-tool',
|
|
48
|
-
model: 'grok-beta',
|
|
49
|
-
created_at: Math.floor(Date.now() / 1000),
|
|
50
|
-
usage: { input_tokens: 20, output_tokens: 10 },
|
|
51
|
-
output: [{ type: 'function_call', name, id: 'fid', call_id: 'fcid', arguments: args, status: 'complete' }]
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
t.add('generateRequest: basic', () => {
|
|
56
|
-
const p = new Prompt();
|
|
57
|
-
p.add('system', 'Helpful', true);
|
|
58
|
-
p.add('user', 'Hi');
|
|
59
|
-
const { url, headers, body } = generateRequest(p);
|
|
60
|
-
assert.strictEqual(url, 'https://api.x.ai/v1/responses');
|
|
61
|
-
assert.strictEqual(headers['Content-Type'], 'application/json');
|
|
62
|
-
assert.ok(headers.Authorization.startsWith('Bearer'));
|
|
63
|
-
assert.strictEqual(body.model, 'grok-4-fast-reasoning');
|
|
64
|
-
assert.strictEqual(body.instructions, 'Helpful');
|
|
65
|
-
assert.strictEqual(body.input.length, 1);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
t.add('generateRequest: tools', () => {
|
|
69
|
-
const p = new Prompt();
|
|
70
|
-
p.add('user', 'Weather');
|
|
71
|
-
const { body } = generateRequest(p, tools);
|
|
72
|
-
assert.ok(body.tools.some(tl => tl.name === 'get_current_weather'));
|
|
73
|
-
assert.strictEqual(body.parallel_tool_calls, true);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
t.add('generateRequest: options', () => {
|
|
77
|
-
const p = new Prompt();
|
|
78
|
-
p.add('user', 'Hi');
|
|
79
|
-
const { body } = generateRequest(p, null, { model: 'grok-4-1-fast-reasoning' });
|
|
80
|
-
assert.strictEqual(body.model, 'grok-4-1-fast-reasoning');
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
t.add('generateRequest: throws bad last role', () => {
|
|
84
|
-
const p = new Prompt();
|
|
85
|
-
p.add('system', '', true);
|
|
86
|
-
p.add('assistant', 'bad');
|
|
87
|
-
assert.throws(() => generateRequest(p));
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
t.add('parseResponse: text', async () => {
|
|
91
|
-
const p = new Prompt();
|
|
92
|
-
p.add('user', 'Hi');
|
|
93
|
-
await parseResponse(100, p, fakeTextRes());
|
|
94
|
-
const msg = p.getLastMessage();
|
|
95
|
-
assert.strictEqual(msg.role, 'assistant');
|
|
96
|
-
assert.strictEqual(msg.content[0].text, 'Hello!');
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
t.add('parseResponse: reasoning', async () => {
|
|
100
|
-
const p = new Prompt();
|
|
101
|
-
await parseResponse(100, p, fakeReasoningRes());
|
|
102
|
-
const msg = p.getLastMessage();
|
|
103
|
-
assert.strictEqual(msg.role, 'reasoning');
|
|
104
|
-
assert.strictEqual(msg.content[0].text, 'Thought.');
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
t.add('parseResponse: citations', async () => {
|
|
108
|
-
const p = new Prompt();
|
|
109
|
-
await parseResponse(100, p, fakeCitationRes());
|
|
110
|
-
const log = p.messages.find(m => m.role === 'log');
|
|
111
|
-
assert.ok(log);
|
|
112
|
-
assert.ok(log.content[0].text.includes('https://ex.com'));
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
t.add('parseResponse: function_call', async () => {
|
|
116
|
-
const p = new Prompt();
|
|
117
|
-
p.add('user', 'Weather');
|
|
118
|
-
await parseResponse(100, p, fakeToolRes());
|
|
119
|
-
const msg = p.getLastMessage();
|
|
120
|
-
assert.strictEqual(msg.role, 'assistant');
|
|
121
|
-
assert.strictEqual(msg.content[0].type, 'function_request');
|
|
122
|
-
assert.strictEqual(msg.content[0].function_request.name, 'get_current_weather');
|
|
123
|
-
assert.strictEqual(msg.content[0].function_request.parameters, '{"location":"Amsterdam"}');
|
|
124
|
-
assert.strictEqual(msg.content[0].function_request.call_id, 'fcid');
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
t.add('parseResponse: toolset exec', async () => {
|
|
128
|
-
const p = new Prompt();
|
|
129
|
-
p.add('user', 'Weather Amsterdam');
|
|
130
|
-
await parseResponse(100, p, fakeToolRes('get_current_weather', '{"location":"Amsterdam"}'), tools);
|
|
131
|
-
const toolMsg = p.getLastMessage();
|
|
132
|
-
assert.strictEqual(toolMsg.role, 'tool');
|
|
133
|
-
assert.strictEqual(toolMsg.content[0].type, 'function_response');
|
|
134
|
-
assert.strictEqual(toolMsg.content[0].function_response.name, 'get_current_weather');
|
|
135
|
-
assert.ok(toolMsg.content[0].function_response.response.includes('24 C'));
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
t.add('parseResponse: non-200 rejects', async () => {
|
|
139
|
-
const p = new Prompt();
|
|
140
|
-
const bad = { status: 400, response: { error: 'bad' } };
|
|
141
|
-
await assert.rejects(async () => parseResponse(100, p, bad), /400: /);
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
t.add('request: real simple', async () => {
|
|
145
|
-
const p = new Prompt();
|
|
146
|
-
p.add('system', 'You are a helpful assistant. Answer briefly.', true);
|
|
147
|
-
p.add('user', 'What is 2+2?');
|
|
148
|
-
const msg = await request(p);
|
|
149
|
-
assert.strictEqual(msg.role, 'assistant');
|
|
150
|
-
assert.ok(msg.content.some(c => c.type === 'text' && c.text.includes('4')), 'Expected 4');
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
const report = await t.run();
|
|
154
|
-
process.exit(report.errors > 0 ? 1 : 0);
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { Test, assert, SH } from '@j-o-r/sh'
|
|
3
|
-
import collections from '../lib/API/x.ai/collections.js';
|
|
4
|
-
import path from 'node:path'
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import Prompt from '../lib/Prompt.js';
|
|
8
|
-
import tools from './testToolset.js';
|
|
9
|
-
|
|
10
|
-
function LOG(me) {
|
|
11
|
-
console.log(JSON.stringify(me, null, ' '));
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const test = new Test();
|
|
15
|
-
|
|
16
|
-
test.add('List collections, start in a clean state', async () => {
|
|
17
|
-
const list = await collections.list();
|
|
18
|
-
let i = 0;
|
|
19
|
-
const len = list.length;
|
|
20
|
-
for (; i < len; i++) {
|
|
21
|
-
const col = list[i];
|
|
22
|
-
if (col.collection_name === 'test_col' || col.collection_name === 'test_col2') {
|
|
23
|
-
const check = await collections.get(col.collection_id);
|
|
24
|
-
assert.equal(check.collection_id, col.collection_id);
|
|
25
|
-
// Delete all test collections
|
|
26
|
-
await collections.del(check.collection_id);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
test.add('Add, update, delete a collection', async () => {
|
|
32
|
-
const coll_id = await collections.create('test_col');
|
|
33
|
-
let coll = await collections.get(coll_id);
|
|
34
|
-
assert.strictEqual(coll_id, coll.collection_id);
|
|
35
|
-
await collections.update(coll_id, 'test_col2');
|
|
36
|
-
coll = await collections.get(coll_id);
|
|
37
|
-
assert.strictEqual(coll.collection_name, 'test_col2');
|
|
38
|
-
await collections.del(coll_id);
|
|
39
|
-
// DELETED
|
|
40
|
-
await assert.rejects(
|
|
41
|
-
async () => await collections.get(coll_id),
|
|
42
|
-
(err) => {
|
|
43
|
-
return err.toString().includes('doesn\'t exist or your team');
|
|
44
|
-
}
|
|
45
|
-
)
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
await test.run();
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { Test, assert, SH } from '@j-o-r/sh'
|
|
3
|
-
import { files } from '../lib/API/x.ai/files.js';
|
|
4
|
-
import path from 'node:path'
|
|
5
|
-
|
|
6
|
-
import Prompt from '../lib/Prompt.js';
|
|
7
|
-
import tools from './testToolset.js';
|
|
8
|
-
|
|
9
|
-
function LOG(me) {
|
|
10
|
-
console.log(JSON.stringify(me, null, ' '));
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const test = new Test();
|
|
14
|
-
|
|
15
|
-
test.add('List files', async () => {
|
|
16
|
-
const fp = path.resolve('docs', 'toolset.md');
|
|
17
|
-
const list = (await files.list()).data;
|
|
18
|
-
let i = 0;
|
|
19
|
-
const len = list.length;
|
|
20
|
-
for(;i < len; i++) {
|
|
21
|
-
const f = list[i];
|
|
22
|
-
if (f.filename === 'test.md' || f.filename === fp) {
|
|
23
|
-
await files.rm(f.id);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
test.add('create, add and remove files', async () => {
|
|
29
|
-
const fp = path.resolve('docs', 'toolset.md');
|
|
30
|
-
const res = await files.upload(fp);
|
|
31
|
-
const content = await files.get(res.id);
|
|
32
|
-
assert.equal(content.length, res.bytes);
|
|
33
|
-
const meta = await files.getMeta(res.id);
|
|
34
|
-
assert.equal(content.length, meta.bytes);
|
|
35
|
-
await files.rm(res.id);
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
test.add('create, add and remove files with custom content', async () => {
|
|
39
|
-
const fp = 'test.md';
|
|
40
|
-
// Add custom content to a file instead of reading the file itself
|
|
41
|
-
const res = await files.upload(fp, 'Hello World');
|
|
42
|
-
const content = await files.get(res.id);
|
|
43
|
-
assert.equal(content, 'Hello World');
|
|
44
|
-
const meta = await files.getMeta(res.id);
|
|
45
|
-
assert.equal(content.length, meta.bytes);
|
|
46
|
-
await files.rm(res.id);
|
|
47
|
-
})
|
|
48
|
-
await test.run();
|
|
File without changes
|
|
File without changes
|