@mozaik-ai/core 3.6.6 → 3.8.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 +21 -0
- package/README.md +226 -161
- package/dist/index.d.mts +56 -8
- package/dist/index.d.ts +56 -8
- package/dist/index.js +149 -30
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +148 -30
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 JigJoy
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# Mozaik
|
|
2
2
|
|
|
3
|
-
**Mozaik** is an open-source TypeScript framework for building AI agents that share an **agentic environment** instead of being orchestrated through rigid
|
|
3
|
+
**Mozaik** is an open-source TypeScript framework for building reactive AI agents that share an **agentic environment** instead of being orchestrated through rigid workflows.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
  
|
|
6
|
+
|
|
7
|
+
In Mozaik, humans, agents, observers, and tools are all `Participant`s of the same `AgenticEnvironment`. Each participant runs **non-blocking** and produces typed events — function calls, function call outputs, reasoning, model messages, and plain-text messages — into the environment. Every other participant sees those events in real time and can react, intercept, or stay silent — without any central scheduler.
|
|
6
8
|
|
|
7
9
|
---
|
|
8
10
|
|
|
@@ -23,16 +25,26 @@ OPENAI_API_KEY=your-openai-key-here
|
|
|
23
25
|
|
|
24
26
|
## The agentic environment
|
|
25
27
|
|
|
26
|
-
`AgenticEnvironment` is a broadcast bus for typed
|
|
28
|
+
`AgenticEnvironment` is a broadcast bus for typed events. `Participant`s `join()` it, and anything produced by one participant is delivered to every subscriber through a **dedicated typed callback** — one per event kind, with separate handlers for items the participant emitted itself versus items emitted by someone else:
|
|
29
|
+
|
|
30
|
+
| Producer call | Self handler | External handler |
|
|
31
|
+
| ---------------------------------------- | ----------------------- | ----------------------------------------- |
|
|
32
|
+
| `deliverFunctionCall(source, item)` | `onFunctionCall` | `onExternalFunctionCall(source, …)` |
|
|
33
|
+
| `deliverFunctionCallOutput(source, item)`| `onFunctionCallOutput` | `onExternalFunctionCallOutput(source, …)` |
|
|
34
|
+
| `deliverReasoning(source, item)` | `onReasoning` | `onExternalReasoning(source, …)` |
|
|
35
|
+
| `deliverModelMessage(source, item)` | `onModelMessage` | `onExternalModelMessage(source, …)` |
|
|
36
|
+
| `deliverMessage(source, message)` | _(not delivered)_ | `onMessage(message)` |
|
|
37
|
+
|
|
38
|
+
Messages are plain `string`s exchanged between participants. Every other event flows as a typed `ContextItem` (`FunctionCallItem`, `FunctionCallOutputItem`, `ReasoningItem`, `ModelMessageItem`).
|
|
27
39
|
|
|
28
40
|
```mermaid
|
|
29
41
|
flowchart LR
|
|
30
42
|
Human[BaseHumanParticipant] -->|streamInput| Env(("AgenticEnvironment"))
|
|
31
43
|
Agent[BaseAgentParticipant] -->|"runInference / executeFunctionCall"| Env
|
|
32
44
|
Observer[Custom Participant] -->|join| Env
|
|
33
|
-
Env -->|
|
|
34
|
-
Env -->|
|
|
35
|
-
Env -->|
|
|
45
|
+
Env -->|"onMessage / onExternal*"| Human
|
|
46
|
+
Env -->|"onFunctionCall / onReasoning / …"| Agent
|
|
47
|
+
Env -->|"onExternal*"| Observer
|
|
36
48
|
```
|
|
37
49
|
|
|
38
50
|
---
|
|
@@ -41,35 +53,45 @@ flowchart LR
|
|
|
41
53
|
|
|
42
54
|
Mozaik ships two ready-to-use participants:
|
|
43
55
|
|
|
44
|
-
| Participant
|
|
45
|
-
|
|
|
46
|
-
| `BaseHumanParticipant` | `InputCapable`
|
|
47
|
-
| `BaseAgentParticipant` | `InputCapable`, `InferenceCapable`, `FunctionCallCapable` | `
|
|
48
|
-
|
|
49
|
-
Each capability method is **non-blocking**: it returns `Promise<void>`, and as the underlying generator yields items
|
|
50
|
-
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
56
|
+
| Participant | Capabilities | Pulls from |
|
|
57
|
+
| ---------------------- | --------------------------------------------------------- | ----------------------------------------------------- |
|
|
58
|
+
| `BaseHumanParticipant` | `InputCapable` | `InputStream` |
|
|
59
|
+
| `BaseAgentParticipant` | `InputCapable`, `InferenceCapable`, `FunctionCallCapable` | `InputStream`, `InferenceRunner`, `FunctionCallRunner`|
|
|
60
|
+
|
|
61
|
+
Each capability method is **non-blocking**: it returns `Promise<void>`, and as the underlying generator yields, items are streamed into the environment one-by-one through the matching typed `deliverX` method. For example, `runInference` dispatches each yielded item to `deliverReasoning`, `deliverFunctionCall`, or `deliverModelMessage`:
|
|
62
|
+
|
|
63
|
+
```81:100:src/application/agent.ts
|
|
64
|
+
async runInference(
|
|
65
|
+
environment: AgenticEnvironment,
|
|
66
|
+
context: ModelContext,
|
|
67
|
+
model: GenerativeModel,
|
|
68
|
+
signal?: AbortSignal,
|
|
69
|
+
): Promise<void> {
|
|
70
|
+
if (!this.isJoinedTo(environment)) return
|
|
71
|
+
|
|
72
|
+
const stream = this.inferenceRunner.run(context, model, signal)
|
|
73
|
+
|
|
74
|
+
for await (const item of stream) {
|
|
75
|
+
if (item.type === "reasoning") {
|
|
76
|
+
await environment.deliverReasoning(this, item)
|
|
77
|
+
} else if (item.type === "function_call") {
|
|
78
|
+
await environment.deliverFunctionCall(this, item)
|
|
79
|
+
} else if (item.type === "message" && item.role === "assistant") {
|
|
80
|
+
await environment.deliverModelMessage(this, item)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
62
84
|
```
|
|
63
85
|
|
|
64
86
|
Because each call is a fresh promise that wraps an async iterable, multiple participants can act on the same environment **concurrently**:
|
|
65
87
|
|
|
66
88
|
```ts
|
|
67
89
|
import {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
90
|
+
AgenticEnvironment,
|
|
91
|
+
BaseAgentParticipant,
|
|
92
|
+
BaseHumanParticipant,
|
|
93
|
+
Gpt54Mini,
|
|
94
|
+
ModelContext,
|
|
73
95
|
} from "@mozaik-ai/core"
|
|
74
96
|
|
|
75
97
|
const environment = new AgenticEnvironment()
|
|
@@ -94,84 +116,149 @@ The environment fans every item out to every subscriber synchronously and withou
|
|
|
94
116
|
|
|
95
117
|
---
|
|
96
118
|
|
|
97
|
-
## Intercepting
|
|
119
|
+
## Intercepting events from other participants
|
|
120
|
+
|
|
121
|
+
Instead of a single catch-all callback, `Participant` exposes **one typed handler per event kind**, with a clear split between events the participant emitted itself and events emitted by someone else. A participant can:
|
|
122
|
+
|
|
123
|
+
- **Observe** events from other participants via the `onExternal*` family (telemetry, audit, UI streaming) and `onMessage` for plain-text messages.
|
|
124
|
+
- **React** to its own outputs via the self handlers (e.g. execute a `FunctionCallItem` it just produced), or to others' outputs via the external handlers.
|
|
125
|
+
- **Ignore** events it doesn't care about — every handler defaults to a no-op in the bundled participants.
|
|
126
|
+
|
|
127
|
+
The intercept surface, taken from `Participant`:
|
|
128
|
+
|
|
129
|
+
```38:54:src/domain/agentic-environment/participant.ts
|
|
130
|
+
abstract onFunctionCall(item: FunctionCallItem): Promise<void>
|
|
131
|
+
|
|
132
|
+
abstract onExternalFunctionCall(source: Participant, item: FunctionCallItem): Promise<void>
|
|
133
|
+
|
|
134
|
+
abstract onFunctionCallOutput(item: FunctionCallOutputItem): Promise<void>
|
|
135
|
+
|
|
136
|
+
abstract onExternalFunctionCallOutput(source: Participant, item: FunctionCallOutputItem): Promise<void>
|
|
137
|
+
|
|
138
|
+
abstract onReasoning(item: ReasoningItem): Promise<void>
|
|
139
|
+
|
|
140
|
+
abstract onExternalReasoning(source: Participant, item: ReasoningItem): Promise<void>
|
|
98
141
|
|
|
99
|
-
|
|
142
|
+
abstract onModelMessage(item: ModelMessageItem): Promise<void>
|
|
100
143
|
|
|
101
|
-
|
|
102
|
-
- **React** to items by triggering its own capabilities (turn a `UserMessageItem` into an inference run, turn a `FunctionCallItem` into a tool execution).
|
|
103
|
-
- **Ignore** items it doesn't care about — it is just a method call.
|
|
144
|
+
abstract onExternalModelMessage(source: Participant, item: ModelMessageItem): Promise<void>
|
|
104
145
|
|
|
105
|
-
|
|
146
|
+
abstract onMessage(message: string): Promise<void>
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
The typed `ContextItem`s involved are defined in [src/domain/model-context/context-item](src/domain/model-context/context-item):
|
|
106
150
|
|
|
107
|
-
- Client-produced: `UserMessageItem
|
|
151
|
+
- Client-produced: `FunctionCallOutputItem` (and `UserMessageItem` / `DeveloperMessageItem` / `SystemMessageItem` when building a `ModelContext` directly)
|
|
108
152
|
- Model-produced: `ModelMessageItem`, `FunctionCallItem`, `ReasoningItem`
|
|
109
153
|
|
|
154
|
+
Plain conversational input flows as a `string` through `onMessage` — participants exchange messages without committing to a specific `ContextItem` shape on the wire.
|
|
155
|
+
|
|
110
156
|
### Passive observer
|
|
111
157
|
|
|
158
|
+
A passive observer subclasses `Participant` and overrides only the handlers it cares about:
|
|
159
|
+
|
|
112
160
|
```ts
|
|
113
|
-
import {
|
|
161
|
+
import {
|
|
162
|
+
Participant,
|
|
163
|
+
FunctionCallItem,
|
|
164
|
+
FunctionCallOutputItem,
|
|
165
|
+
ReasoningItem,
|
|
166
|
+
ModelMessageItem,
|
|
167
|
+
} from "@mozaik-ai/core"
|
|
114
168
|
|
|
115
169
|
export class TranscriptLogger extends Participant {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
170
|
+
async onMessage(message: string): Promise<void> {
|
|
171
|
+
console.log("[message]", message)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
async onExternalFunctionCall(source: Participant, item: FunctionCallItem): Promise<void> {
|
|
175
|
+
console.log(`[${source.constructor.name}] function_call`, item.toJSON())
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
async onExternalFunctionCallOutput(source: Participant, item: FunctionCallOutputItem): Promise<void> {
|
|
179
|
+
console.log(`[${source.constructor.name}] function_call_output`, item.toJSON())
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
async onExternalReasoning(source: Participant, item: ReasoningItem): Promise<void> {
|
|
183
|
+
console.log(`[${source.constructor.name}] reasoning`, item.toJSON())
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
async onExternalModelMessage(source: Participant, item: ModelMessageItem): Promise<void> {
|
|
187
|
+
console.log(`[${source.constructor.name}] model_message`, item.toJSON())
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Self-emitted handlers (onFunctionCall, onReasoning, …) can be no-ops for a pure observer.
|
|
191
|
+
async onFunctionCall(): Promise<void> {}
|
|
192
|
+
async onFunctionCallOutput(): Promise<void> {}
|
|
193
|
+
async onReasoning(): Promise<void> {}
|
|
194
|
+
async onModelMessage(): Promise<void> {}
|
|
119
195
|
}
|
|
120
196
|
```
|
|
121
197
|
|
|
122
198
|
### Reactive agent
|
|
123
199
|
|
|
124
|
-
A reactive agent extends `BaseAgentParticipant` and
|
|
200
|
+
A reactive agent extends `BaseAgentParticipant` and overrides the handlers it wants to react on. Each handler is already a no-op in the base class, so only the relevant ones need bodies:
|
|
125
201
|
|
|
126
202
|
```ts
|
|
127
203
|
import {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
FunctionCallRunner,
|
|
204
|
+
BaseAgentParticipant,
|
|
205
|
+
Participant,
|
|
206
|
+
UserMessageItem,
|
|
207
|
+
FunctionCallItem,
|
|
208
|
+
AgenticEnvironment,
|
|
209
|
+
ModelContext,
|
|
210
|
+
GenerativeModel,
|
|
211
|
+
InputStream,
|
|
212
|
+
InferenceRunner,
|
|
213
|
+
FunctionCallRunner,
|
|
139
214
|
} from "@mozaik-ai/core"
|
|
140
215
|
|
|
141
216
|
export class ReactiveAgent extends BaseAgentParticipant {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
217
|
+
constructor(
|
|
218
|
+
inputSource: InputStream,
|
|
219
|
+
inferenceRunner: InferenceRunner,
|
|
220
|
+
functionCallRunner: FunctionCallRunner,
|
|
221
|
+
private readonly environment: AgenticEnvironment,
|
|
222
|
+
private readonly context: ModelContext,
|
|
223
|
+
private readonly model: GenerativeModel,
|
|
224
|
+
) {
|
|
225
|
+
super(inputSource, inferenceRunner, functionCallRunner)
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// A message from a human (or any other participant) → record it and think.
|
|
229
|
+
async onMessage(message: string): Promise<void> {
|
|
230
|
+
this.context.addContextItem(UserMessageItem.create(message))
|
|
231
|
+
this.runInference(this.environment, this.context, this.model)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// The agent just produced a function call → execute it.
|
|
235
|
+
async onFunctionCall(item: FunctionCallItem): Promise<void> {
|
|
236
|
+
this.context.addContextItem(item)
|
|
237
|
+
this.executeFunctionCall(this.environment, item)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// The tool just produced an output → feed it back and run inference again.
|
|
241
|
+
async onFunctionCallOutput(item: FunctionCallOutputItem): Promise<void> {
|
|
242
|
+
this.context.addContextItem(item)
|
|
243
|
+
this.runInference(this.environment, this.context, this.model)
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Keep the local context in sync with model-emitted reasoning and replies.
|
|
247
|
+
async onReasoning(item: ReasoningItem): Promise<void> {
|
|
248
|
+
this.context.addContextItem(item)
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
async onModelMessage(item: ModelMessageItem): Promise<void> {
|
|
252
|
+
this.context.addContextItem(item)
|
|
253
|
+
}
|
|
168
254
|
}
|
|
169
255
|
```
|
|
170
256
|
|
|
171
|
-
|
|
257
|
+
Three things to note:
|
|
172
258
|
|
|
173
|
-
1. The
|
|
174
|
-
2.
|
|
259
|
+
1. The split between self handlers and `onExternal*` handlers means a participant can encode "act on my own outputs" separately from "observe others", without inspecting `source` by hand.
|
|
260
|
+
2. The agent never `await`s its own capability calls inside the handlers — those methods are non-blocking, so the environment keeps delivering events while inference and tool execution run in the background.
|
|
261
|
+
3. Behaviors compose by **reaction**, not orchestration. Add a second agent that overrides `onExternalModelMessage` and you get a critique loop. Add a `TranscriptLogger` and you get a UI stream. Neither change touches the existing participants.
|
|
175
262
|
|
|
176
263
|
---
|
|
177
264
|
|
|
@@ -180,16 +267,11 @@ Two things to note:
|
|
|
180
267
|
`ModelContext` is the ordered list of `ContextItem`s a `GenerativeModel` is asked to reason over. It is constructed and mutated explicitly — typically inside a participant in response to delivered items.
|
|
181
268
|
|
|
182
269
|
```ts
|
|
183
|
-
import {
|
|
184
|
-
ModelContext,
|
|
185
|
-
DeveloperMessageItem,
|
|
186
|
-
UserMessageItem,
|
|
187
|
-
InMemoryModelContextRepository,
|
|
188
|
-
} from "@mozaik-ai/core"
|
|
270
|
+
import { ModelContext, DeveloperMessageItem, UserMessageItem, InMemoryModelContextRepository } from "@mozaik-ai/core"
|
|
189
271
|
|
|
190
272
|
const context = ModelContext.create("project-id")
|
|
191
|
-
|
|
192
|
-
|
|
273
|
+
.addContextItem(DeveloperMessageItem.create("You are a helpful assistant."))
|
|
274
|
+
.addContextItem(UserMessageItem.create("What is the capital of France?"))
|
|
193
275
|
|
|
194
276
|
const repo = new InMemoryModelContextRepository()
|
|
195
277
|
await repo.save(context)
|
|
@@ -197,7 +279,7 @@ await repo.save(context)
|
|
|
197
279
|
|
|
198
280
|
Implement `ModelContextRepository` to plug in any storage backend.
|
|
199
281
|
|
|
200
|
-
The default OpenAI provider is `OpenAIResponses`, implementing the [OpenResponses](https://www.openresponses.org/) spec. It maps `ModelContext` to the OpenAI Responses API and back into typed `ContextItem`s. Bundled models: `Gpt54`, `Gpt54Mini`, `Gpt54Nano`.
|
|
282
|
+
The default OpenAI provider is `OpenAIResponses`, implementing the [OpenResponses](https://www.openresponses.org/) spec. It maps `ModelContext` to the OpenAI Responses API and back into typed `ContextItem`s. Bundled models: `Gpt54`, `Gpt54Mini`, `Gpt54Nano`, `Gpt55`.
|
|
201
283
|
|
|
202
284
|
```ts
|
|
203
285
|
import { OpenAIResponses, InferenceRequest, Gpt54 } from "@mozaik-ai/core"
|
|
@@ -210,42 +292,37 @@ const response = await runtime.infer(new InferenceRequest(new Gpt54(), context))
|
|
|
210
292
|
|
|
211
293
|
## Advanced: overriding generators
|
|
212
294
|
|
|
213
|
-
`BaseAgentParticipant` and `BaseHumanParticipant` are deliberately thin shells around three generator interfaces. Swap any of them to change
|
|
295
|
+
`BaseAgentParticipant` and `BaseHumanParticipant` are deliberately thin shells around three generator interfaces. Swap any of them to change _how_ events are produced without touching the environment, the participants, or any consumers.
|
|
214
296
|
|
|
215
|
-
### Custom `
|
|
297
|
+
### Custom `InputStream`
|
|
216
298
|
|
|
217
|
-
|
|
218
|
-
import {
|
|
219
|
-
InputItemSource,
|
|
220
|
-
UserMessageItem,
|
|
221
|
-
DeveloperMessageItem,
|
|
222
|
-
SystemMessageItem,
|
|
223
|
-
} from "@mozaik-ai/core"
|
|
299
|
+
An `InputStream` yields plain `string` messages, which are then broadcast to every other participant through `onMessage`:
|
|
224
300
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
301
|
+
```ts
|
|
302
|
+
import { InputStream } from "@mozaik-ai/core"
|
|
303
|
+
|
|
304
|
+
export class QueueInputStream implements InputStream {
|
|
305
|
+
private readonly queue: string[] = []
|
|
306
|
+
private resolveNext?: () => void
|
|
307
|
+
|
|
308
|
+
push(message: string) {
|
|
309
|
+
this.queue.push(message)
|
|
310
|
+
this.resolveNext?.()
|
|
311
|
+
this.resolveNext = undefined
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
async *stream(signal?: AbortSignal): AsyncIterable<string> {
|
|
315
|
+
while (!signal?.aborted) {
|
|
316
|
+
while (this.queue.length > 0) {
|
|
317
|
+
yield this.queue.shift()!
|
|
318
|
+
}
|
|
319
|
+
await new Promise<void>((resolve) => (this.resolveNext = resolve))
|
|
320
|
+
}
|
|
321
|
+
}
|
|
245
322
|
}
|
|
246
323
|
```
|
|
247
324
|
|
|
248
|
-
Use it for stdin, websockets, an HTTP queue, or anything that produces
|
|
325
|
+
Use it for stdin, websockets, an HTTP queue, or anything that produces messages over time. Participants decide for themselves what to do with the string — e.g. wrap it in a `UserMessageItem` before adding it to a `ModelContext`.
|
|
249
326
|
|
|
250
327
|
### Custom `InferenceRunner`
|
|
251
328
|
|
|
@@ -253,31 +330,27 @@ Wrap any model runtime — including `OpenAIResponses` — and decide how its ou
|
|
|
253
330
|
|
|
254
331
|
```ts
|
|
255
332
|
import {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
333
|
+
InferenceRunner,
|
|
334
|
+
InferenceRequest,
|
|
335
|
+
ModelContext,
|
|
336
|
+
GenerativeModel,
|
|
337
|
+
OpenAIResponses,
|
|
338
|
+
ReasoningItem,
|
|
339
|
+
FunctionCallItem,
|
|
340
|
+
ModelMessageItem,
|
|
264
341
|
} from "@mozaik-ai/core"
|
|
265
342
|
|
|
266
343
|
type InferenceItem = ReasoningItem | FunctionCallItem | ModelMessageItem
|
|
267
344
|
|
|
268
345
|
export class OpenAIInferenceRunner implements InferenceRunner {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
for (const item of response.contextItems) {
|
|
278
|
-
yield item as InferenceItem
|
|
279
|
-
}
|
|
280
|
-
}
|
|
346
|
+
private readonly runtime = new OpenAIResponses()
|
|
347
|
+
|
|
348
|
+
async *run(context: ModelContext, model: GenerativeModel, signal?: AbortSignal): AsyncIterable<InferenceItem> {
|
|
349
|
+
const response = await this.runtime.infer(new InferenceRequest(model, context))
|
|
350
|
+
for (const item of response.contextItems) {
|
|
351
|
+
yield item as InferenceItem
|
|
352
|
+
}
|
|
353
|
+
}
|
|
281
354
|
}
|
|
282
355
|
```
|
|
283
356
|
|
|
@@ -288,26 +361,18 @@ Replace the body with a streaming runtime and items will flow into the environme
|
|
|
288
361
|
Resolve a `FunctionCallItem` against a tool registry and yield its output:
|
|
289
362
|
|
|
290
363
|
```ts
|
|
291
|
-
import {
|
|
292
|
-
FunctionCallRunner,
|
|
293
|
-
FunctionCallItem,
|
|
294
|
-
FunctionCallOutputItem,
|
|
295
|
-
Tool,
|
|
296
|
-
} from "@mozaik-ai/core"
|
|
364
|
+
import { FunctionCallRunner, FunctionCallItem, FunctionCallOutputItem, Tool } from "@mozaik-ai/core"
|
|
297
365
|
|
|
298
366
|
export class ToolRegistryFunctionCallRunner implements FunctionCallRunner {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
const result = await tool.invoke(JSON.parse(call.args))
|
|
309
|
-
yield FunctionCallOutputItem.create(call.callId, JSON.stringify(result))
|
|
310
|
-
}
|
|
367
|
+
constructor(private readonly tools: Tool[]) {}
|
|
368
|
+
|
|
369
|
+
async *run(call: FunctionCallItem, signal?: AbortSignal): AsyncIterable<FunctionCallOutputItem> {
|
|
370
|
+
const tool = this.tools.find((t) => t.name === call.name)
|
|
371
|
+
if (!tool) throw new Error(`Unknown tool: ${call.name}`)
|
|
372
|
+
|
|
373
|
+
const result = await tool.invoke(JSON.parse(call.args))
|
|
374
|
+
yield FunctionCallOutputItem.create(call.callId, JSON.stringify(result))
|
|
375
|
+
}
|
|
311
376
|
}
|
|
312
377
|
```
|
|
313
378
|
|
|
@@ -317,9 +382,9 @@ export class ToolRegistryFunctionCallRunner implements FunctionCallRunner {
|
|
|
317
382
|
import { BaseAgentParticipant, AgenticEnvironment } from "@mozaik-ai/core"
|
|
318
383
|
|
|
319
384
|
const agent = new BaseAgentParticipant(
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
385
|
+
new QueueInputStream(),
|
|
386
|
+
new OpenAIInferenceRunner(),
|
|
387
|
+
new ToolRegistryFunctionCallRunner(tools),
|
|
323
388
|
)
|
|
324
389
|
|
|
325
390
|
agent.join(new AgenticEnvironment())
|
package/dist/index.d.mts
CHANGED
|
@@ -298,7 +298,11 @@ declare class AgenticEnvironment {
|
|
|
298
298
|
private isActive;
|
|
299
299
|
subscribe(subscriber: Participant): void;
|
|
300
300
|
unsubscribe(user: Participant): void;
|
|
301
|
-
|
|
301
|
+
deliverFunctionCall(source: Participant, item: FunctionCallItem): void;
|
|
302
|
+
deliverModelMessage(source: Participant, item: ModelMessageItem): void;
|
|
303
|
+
deliverReasoning(source: Participant, item: ReasoningItem): void;
|
|
304
|
+
deliverFunctionCallOutput(source: Participant, item: FunctionCallOutputItem): void;
|
|
305
|
+
deliverMessage(source: Participant, message: string): void;
|
|
302
306
|
start(): Promise<void>;
|
|
303
307
|
stop(): void;
|
|
304
308
|
}
|
|
@@ -309,7 +313,15 @@ declare abstract class Participant {
|
|
|
309
313
|
leave(environment: AgenticEnvironment): void;
|
|
310
314
|
protected isJoinedTo(environment: AgenticEnvironment): boolean;
|
|
311
315
|
getEnvironments(): AgenticEnvironment[];
|
|
312
|
-
abstract
|
|
316
|
+
abstract onFunctionCall(item: FunctionCallItem): Promise<void>;
|
|
317
|
+
abstract onExternalFunctionCall(source: Participant, item: FunctionCallItem): Promise<void>;
|
|
318
|
+
abstract onFunctionCallOutput(item: FunctionCallOutputItem): Promise<void>;
|
|
319
|
+
abstract onExternalFunctionCallOutput(source: Participant, item: FunctionCallOutputItem): Promise<void>;
|
|
320
|
+
abstract onReasoning(item: ReasoningItem): Promise<void>;
|
|
321
|
+
abstract onExternalReasoning(source: Participant, item: ReasoningItem): Promise<void>;
|
|
322
|
+
abstract onModelMessage(item: ModelMessageItem): Promise<void>;
|
|
323
|
+
abstract onExternalModelMessage(source: Participant, item: ModelMessageItem): Promise<void>;
|
|
324
|
+
abstract onMessage(message: string): Promise<void>;
|
|
313
325
|
}
|
|
314
326
|
|
|
315
327
|
interface InputCapable {
|
|
@@ -330,16 +342,25 @@ interface FunctionCallRunner {
|
|
|
330
342
|
run(functionCallItem: FunctionCallItem, signal?: AbortSignal): AsyncIterable<FunctionCallOutputItem>;
|
|
331
343
|
}
|
|
332
344
|
|
|
333
|
-
interface
|
|
334
|
-
stream(signal?: AbortSignal): AsyncIterable<
|
|
345
|
+
interface InputStream {
|
|
346
|
+
stream(signal?: AbortSignal): AsyncIterable<string>;
|
|
335
347
|
}
|
|
336
348
|
|
|
337
349
|
declare class BaseAgentParticipant extends Participant implements InputCapable, InferenceCapable, FunctionCallCapable {
|
|
338
350
|
private inputSource;
|
|
339
351
|
private inferenceRunner;
|
|
340
352
|
private functionCallRunner;
|
|
341
|
-
constructor(inputSource:
|
|
342
|
-
|
|
353
|
+
constructor(inputSource: InputStream, inferenceRunner: InferenceRunner, functionCallRunner: FunctionCallRunner);
|
|
354
|
+
onInternalContextItem(item: ContextItem): Promise<void>;
|
|
355
|
+
onFunctionCall(item: FunctionCallItem): Promise<void>;
|
|
356
|
+
onExternalFunctionCall(source: Participant, item: FunctionCallItem): Promise<void>;
|
|
357
|
+
onFunctionCallOutput(item: FunctionCallOutputItem): Promise<void>;
|
|
358
|
+
onExternalFunctionCallOutput(source: Participant, item: FunctionCallOutputItem): Promise<void>;
|
|
359
|
+
onReasoning(item: ReasoningItem): Promise<void>;
|
|
360
|
+
onExternalReasoning(source: Participant, item: ReasoningItem): Promise<void>;
|
|
361
|
+
onModelMessage(item: ModelMessageItem): Promise<void>;
|
|
362
|
+
onExternalModelMessage(source: Participant, item: ModelMessageItem): Promise<void>;
|
|
363
|
+
onMessage(message: string): Promise<void>;
|
|
343
364
|
executeFunctionCall(environment: AgenticEnvironment, functionCallItem: FunctionCallItem, signal?: AbortSignal): Promise<void>;
|
|
344
365
|
runInference(environment: AgenticEnvironment, context: ModelContext, model: GenerativeModel, signal?: AbortSignal): Promise<void>;
|
|
345
366
|
streamInput(environment: AgenticEnvironment): Promise<void>;
|
|
@@ -347,8 +368,17 @@ declare class BaseAgentParticipant extends Participant implements InputCapable,
|
|
|
347
368
|
|
|
348
369
|
declare class BaseHumanParticipant extends Participant implements InputCapable {
|
|
349
370
|
private inputSource;
|
|
350
|
-
constructor(inputSource:
|
|
371
|
+
constructor(inputSource: InputStream);
|
|
372
|
+
onFunctionCall(item: FunctionCallItem): Promise<void>;
|
|
373
|
+
onExternalFunctionCall(source: Participant, item: FunctionCallItem): Promise<void>;
|
|
351
374
|
onContextItem(source: Participant, item: ContextItem): Promise<void>;
|
|
375
|
+
onFunctionCallOutput(item: FunctionCallOutputItem): Promise<void>;
|
|
376
|
+
onExternalFunctionCallOutput(source: Participant, item: FunctionCallOutputItem): Promise<void>;
|
|
377
|
+
onReasoning(item: ReasoningItem): Promise<void>;
|
|
378
|
+
onExternalReasoning(source: Participant, item: ReasoningItem): Promise<void>;
|
|
379
|
+
onModelMessage(item: ModelMessageItem): Promise<void>;
|
|
380
|
+
onExternalModelMessage(source: Participant, item: ModelMessageItem): Promise<void>;
|
|
381
|
+
onMessage(message: string): Promise<void>;
|
|
352
382
|
streamInput(environment: AgenticEnvironment): Promise<void>;
|
|
353
383
|
}
|
|
354
384
|
|
|
@@ -364,4 +394,22 @@ declare class DefaultFunctionCallRunner implements FunctionCallRunner {
|
|
|
364
394
|
run(call: FunctionCallItem, signal?: AbortSignal): AsyncIterable<FunctionCallOutputItem>;
|
|
365
395
|
}
|
|
366
396
|
|
|
367
|
-
|
|
397
|
+
declare class Gpt55 implements GenerativeModel, ReasoningEffort<OpenAIReasoningEffortType>, ToolCallingCapability {
|
|
398
|
+
readonly specification: {
|
|
399
|
+
name: string;
|
|
400
|
+
supportReasoningEffort: boolean;
|
|
401
|
+
defaultReasoningEffort: OpenAIReasoningEffortType;
|
|
402
|
+
supportStreaming: boolean;
|
|
403
|
+
contextWindowSize: number;
|
|
404
|
+
maxOutputTokens: number;
|
|
405
|
+
supportFunctionCalling: boolean;
|
|
406
|
+
};
|
|
407
|
+
private tools;
|
|
408
|
+
setTools(tools: Tool[]): void;
|
|
409
|
+
getTools(): Tool[];
|
|
410
|
+
private readonly effort;
|
|
411
|
+
setReasoningEffort(effort: OpenAIReasoningEffortType): void;
|
|
412
|
+
getReasoningEffort(): OpenAIReasoningEffortType;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
export { AgenticEnvironment, BaseAgentParticipant, BaseHumanParticipant, ContextItem, DefaultFunctionCallRunner, DeveloperMessageItem, FunctionCallItem, FunctionCallOutputItem, type FunctionCallRunner, type GenerativeModel, Gpt54, Gpt54Mini, Gpt54Nano, Gpt55, InMemoryModelContextRepository, InferenceRequest, InferenceResponse, type InferenceRunner, type InputStream, InputTokenDetails, ModelContext, type ModelContextRepository, ModelMessageItem, OpenAIInferenceRunner, OpenAIResponses, OutputTokenDetails, Participant, ReasoningItem, SystemMessageItem, TokenUsage, type Tool, UserMessageItem };
|