symposium 2.4.2 → 3.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/Agent.js +509 -219
- package/CLAUDE.md +101 -0
- package/Contexts/MCPResource.js +19 -0
- package/{GetContextTool.js → GetContextToolkit.js} +5 -5
- package/InputChannel.js +42 -0
- package/MCPServer.js +160 -0
- package/MIGRATION.md +369 -0
- package/Model.js +32 -25
- package/Models/AnthropicModel.js +66 -20
- package/Models/GrokModel.js +8 -8
- package/Models/GroqModel.js +61 -35
- package/Models/LegacyOpenAIModel.js +61 -35
- package/Models/OllamaModel.js +57 -31
- package/Models/OpenAIModel.js +74 -20
- package/README.md +458 -396
- package/Summarizer.js +5 -5
- package/Symposium.js +12 -12
- package/{Tool.js → Toolkit.js} +4 -4
- package/index.js +10 -2
- package/package.json +7 -3
- package/test/agent.test.js +698 -0
- package/test/helpers/mockSdk.js +52 -0
- package/test/mcp.test.js +216 -0
- package/test/models/anthropic.test.js +135 -0
- package/test/models/groq.test.js +71 -0
- package/test/models/legacyOpenai.test.js +87 -0
- package/test/models/ollama.test.js +90 -0
- package/test/models/openai.test.js +168 -0
- package/BufferedEventEmitter.js +0 -28
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import {test} from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
|
|
4
|
+
import OpenAIModel from '../../Models/OpenAIModel.js';
|
|
5
|
+
import Message from '../../Message.js';
|
|
6
|
+
import {openAiResponsesStream, fakeThread, drain} from '../helpers/mockSdk.js';
|
|
7
|
+
|
|
8
|
+
function buildModelDef(overrides = {}) {
|
|
9
|
+
return {
|
|
10
|
+
name: 'gpt-5',
|
|
11
|
+
tokens: 400000,
|
|
12
|
+
tools: true,
|
|
13
|
+
structured_output: true,
|
|
14
|
+
...overrides,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function installFakeOpenAi(modelInstance, stream) {
|
|
19
|
+
modelInstance.getOpenAi = () => ({
|
|
20
|
+
responses: {
|
|
21
|
+
stream() {
|
|
22
|
+
return stream;
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
test('OpenAIModel streams text deltas and returns a text Message[]', async () => {
|
|
29
|
+
const m = new OpenAIModel();
|
|
30
|
+
const stream = openAiResponsesStream(
|
|
31
|
+
[
|
|
32
|
+
{type: 'response.output_text.delta', delta: 'Hello'},
|
|
33
|
+
{type: 'response.output_text.delta', delta: ' world'},
|
|
34
|
+
],
|
|
35
|
+
{
|
|
36
|
+
output: [
|
|
37
|
+
{
|
|
38
|
+
type: 'message',
|
|
39
|
+
content: [{text: 'Hello world'}],
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
},
|
|
43
|
+
);
|
|
44
|
+
installFakeOpenAi(m, stream);
|
|
45
|
+
|
|
46
|
+
const {deltas, value} = await drain(m.generate(buildModelDef(), fakeThread()));
|
|
47
|
+
|
|
48
|
+
assert.deepEqual(deltas, [
|
|
49
|
+
{type: 'text_delta', content: 'Hello'},
|
|
50
|
+
{type: 'text_delta', content: ' world'},
|
|
51
|
+
]);
|
|
52
|
+
|
|
53
|
+
assert.equal(value.length, 1);
|
|
54
|
+
assert.ok(value[0] instanceof Message);
|
|
55
|
+
assert.equal(value[0].role, 'assistant');
|
|
56
|
+
assert.deepEqual(value[0].content, [{type: 'text', content: 'Hello world'}]);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test('OpenAIModel yields tool_call on output_item.done and assembles a function block', async () => {
|
|
60
|
+
const m = new OpenAIModel();
|
|
61
|
+
const stream = openAiResponsesStream(
|
|
62
|
+
[
|
|
63
|
+
{
|
|
64
|
+
type: 'response.output_item.done',
|
|
65
|
+
item: {
|
|
66
|
+
type: 'function_call',
|
|
67
|
+
call_id: 'call_abc',
|
|
68
|
+
name: 'do_thing',
|
|
69
|
+
arguments: '{"a":1}',
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
{
|
|
74
|
+
output: [
|
|
75
|
+
{
|
|
76
|
+
type: 'function_call',
|
|
77
|
+
call_id: 'call_abc',
|
|
78
|
+
name: 'do_thing',
|
|
79
|
+
arguments: '{"a":1}',
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
);
|
|
84
|
+
installFakeOpenAi(m, stream);
|
|
85
|
+
|
|
86
|
+
const {deltas, value} = await drain(m.generate(buildModelDef(), fakeThread()));
|
|
87
|
+
|
|
88
|
+
assert.deepEqual(deltas, [
|
|
89
|
+
{
|
|
90
|
+
type: 'tool_call',
|
|
91
|
+
content: {id: 'call_abc', name: 'do_thing', arguments: {a: 1}},
|
|
92
|
+
},
|
|
93
|
+
]);
|
|
94
|
+
|
|
95
|
+
assert.deepEqual(value[0].content, [
|
|
96
|
+
{
|
|
97
|
+
type: 'tool_call',
|
|
98
|
+
content: [{id: 'call_abc', name: 'do_thing', arguments: {a: 1}}],
|
|
99
|
+
},
|
|
100
|
+
]);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test('OpenAIModel emits reasoning_delta and final reasoning block', async () => {
|
|
104
|
+
const m = new OpenAIModel();
|
|
105
|
+
const reasoningOutput = {
|
|
106
|
+
type: 'reasoning',
|
|
107
|
+
summary: [{text: 'thinking step'}],
|
|
108
|
+
};
|
|
109
|
+
const stream = openAiResponsesStream(
|
|
110
|
+
[
|
|
111
|
+
{type: 'response.reasoning_summary_text.delta', delta: 'thinking '},
|
|
112
|
+
{type: 'response.reasoning_summary_text.delta', delta: 'step'},
|
|
113
|
+
{type: 'response.output_text.delta', delta: 'done'},
|
|
114
|
+
],
|
|
115
|
+
{
|
|
116
|
+
output: [
|
|
117
|
+
reasoningOutput,
|
|
118
|
+
{type: 'message', content: [{text: 'done'}]},
|
|
119
|
+
],
|
|
120
|
+
},
|
|
121
|
+
);
|
|
122
|
+
installFakeOpenAi(m, stream);
|
|
123
|
+
|
|
124
|
+
const {deltas, value} = await drain(m.generate(buildModelDef(), fakeThread()));
|
|
125
|
+
|
|
126
|
+
assert.deepEqual(deltas, [
|
|
127
|
+
{type: 'reasoning_delta', content: 'thinking '},
|
|
128
|
+
{type: 'reasoning_delta', content: 'step'},
|
|
129
|
+
{type: 'text_delta', content: 'done'},
|
|
130
|
+
]);
|
|
131
|
+
|
|
132
|
+
assert.equal(value[0].content.length, 2);
|
|
133
|
+
assert.deepEqual(value[0].content[0], {
|
|
134
|
+
type: 'reasoning',
|
|
135
|
+
content: 'thinking step',
|
|
136
|
+
original: reasoningOutput,
|
|
137
|
+
});
|
|
138
|
+
assert.deepEqual(value[0].content[1], {type: 'text', content: 'done'});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
test('OpenAIModel emits image delta and final image block', async () => {
|
|
142
|
+
const m = new OpenAIModel();
|
|
143
|
+
const imageItem = {
|
|
144
|
+
type: 'image_generation_call',
|
|
145
|
+
id: 'img_1',
|
|
146
|
+
status: 'completed',
|
|
147
|
+
output_format: 'png',
|
|
148
|
+
result: 'BASE64DATA',
|
|
149
|
+
revised_prompt: 'cute cat',
|
|
150
|
+
size: '1024x1024',
|
|
151
|
+
};
|
|
152
|
+
const stream = openAiResponsesStream(
|
|
153
|
+
[{type: 'response.output_item.done', item: imageItem}],
|
|
154
|
+
{output: [imageItem]},
|
|
155
|
+
);
|
|
156
|
+
installFakeOpenAi(m, stream);
|
|
157
|
+
|
|
158
|
+
const {deltas, value} = await drain(m.generate(buildModelDef({image_generation: true}), fakeThread(), [], {image_generation: true}));
|
|
159
|
+
|
|
160
|
+
assert.equal(deltas.length, 1);
|
|
161
|
+
assert.equal(deltas[0].type, 'image');
|
|
162
|
+
assert.equal(deltas[0].content.mime, 'image/png');
|
|
163
|
+
assert.equal(deltas[0].content.data, 'BASE64DATA');
|
|
164
|
+
assert.equal(deltas[0].meta.id, 'img_1');
|
|
165
|
+
|
|
166
|
+
assert.equal(value[0].content[0].type, 'image');
|
|
167
|
+
assert.equal(value[0].content[0].meta.prompt, 'cute cat');
|
|
168
|
+
});
|
package/BufferedEventEmitter.js
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import EventEmitter from 'events';
|
|
2
|
-
|
|
3
|
-
export default class BufferedEventEmitter extends EventEmitter {
|
|
4
|
-
#buffer = [];
|
|
5
|
-
|
|
6
|
-
emit(eventName, ...args) {
|
|
7
|
-
if (this.listenerCount(eventName) > 0)
|
|
8
|
-
return super.emit(eventName, ...args);
|
|
9
|
-
|
|
10
|
-
this.#buffer.push({eventName, args});
|
|
11
|
-
return true;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
#flush() {
|
|
15
|
-
for (const {eventName, args} of this.#buffer)
|
|
16
|
-
if (this.listenerCount(eventName) > 0)
|
|
17
|
-
super.emit(eventName, ...args);
|
|
18
|
-
|
|
19
|
-
this.#buffer = this.#buffer.filter(({eventName}) => this.listenerCount(eventName) === 0);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
on(eventName, listener, flush = true) {
|
|
23
|
-
super.on(eventName, listener);
|
|
24
|
-
if (flush)
|
|
25
|
-
this.#flush();
|
|
26
|
-
return this;
|
|
27
|
-
}
|
|
28
|
-
}
|