@mozaik-ai/core 3.8.4 → 3.8.5
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/README.md +45 -107
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -93,12 +93,25 @@ The environment fans every item out to every subscriber synchronously and withou
|
|
|
93
93
|
|
|
94
94
|
---
|
|
95
95
|
|
|
96
|
-
##
|
|
96
|
+
## Reactive agent
|
|
97
97
|
|
|
98
|
-
|
|
98
|
+
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:
|
|
99
99
|
|
|
100
100
|
```ts
|
|
101
|
-
|
|
101
|
+
import {
|
|
102
|
+
BaseAgentParticipant,
|
|
103
|
+
Participant,
|
|
104
|
+
UserMessageItem,
|
|
105
|
+
FunctionCallItem,
|
|
106
|
+
AgenticEnvironment,
|
|
107
|
+
ModelContext,
|
|
108
|
+
GenerativeModel,
|
|
109
|
+
InputStream,
|
|
110
|
+
InferenceRunner,
|
|
111
|
+
FunctionCallRunner,
|
|
112
|
+
} from "@mozaik-ai/core"
|
|
113
|
+
|
|
114
|
+
export class ReactiveAgent extends BaseAgentParticipant {
|
|
102
115
|
constructor(
|
|
103
116
|
inputSource: InputStream,
|
|
104
117
|
inferenceRunner: InferenceRunner,
|
|
@@ -110,30 +123,48 @@ export class CustomAgent extends BaseAgentParticipant {
|
|
|
110
123
|
super(inputSource, inferenceRunner, functionCallRunner)
|
|
111
124
|
}
|
|
112
125
|
|
|
126
|
+
// A message from a human (or any other participant) → record it and think.
|
|
113
127
|
async onMessage(message: string): Promise<void> {
|
|
114
128
|
this.context.addContextItem(UserMessageItem.create(message))
|
|
115
129
|
this.runInference(this.environment, this.context, this.model)
|
|
116
130
|
}
|
|
117
131
|
|
|
132
|
+
// The agent just produced a function call → execute it.
|
|
118
133
|
async onFunctionCall(item: FunctionCallItem): Promise<void> {
|
|
119
134
|
this.context.addContextItem(item)
|
|
120
135
|
this.executeFunctionCall(this.environment, item)
|
|
121
136
|
}
|
|
122
137
|
|
|
138
|
+
// The tool just produced an output → feed it back and run inference again.
|
|
123
139
|
async onFunctionCallOutput(item: FunctionCallOutputItem): Promise<void> {
|
|
124
140
|
this.context.addContextItem(item)
|
|
125
141
|
this.runInference(this.environment, this.context, this.model)
|
|
126
142
|
}
|
|
143
|
+
|
|
144
|
+
// Keep the local context in sync with model-emitted reasoning and replies.
|
|
145
|
+
async onReasoning(item: ReasoningItem): Promise<void> {
|
|
146
|
+
this.context.addContextItem(item)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async onModelMessage(item: ModelMessageItem): Promise<void> {
|
|
150
|
+
this.context.addContextItem(item)
|
|
151
|
+
}
|
|
127
152
|
}
|
|
128
153
|
```
|
|
129
154
|
|
|
155
|
+
Three things to note:
|
|
156
|
+
|
|
157
|
+
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.
|
|
158
|
+
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.
|
|
159
|
+
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.
|
|
160
|
+
|
|
130
161
|
---
|
|
131
162
|
|
|
132
163
|
## Reacting to external events
|
|
133
164
|
|
|
134
165
|
Participants can listen to external events and react by overriding methods like `onMessage`, `onExternalFunctionCall`, `onExternalFunctionCallOutput`, `onExternalReasoning`, and `onExternalModelMessage`.
|
|
135
166
|
|
|
136
|
-
|
|
167
|
+
## Passive observer
|
|
137
168
|
|
|
138
169
|
You can create observers that don't run inference themselves but watch what's happening in the conversation and take side actions (logging, metrics, persistence, etc.). Subclass `Participant` and override only the handlers you care about:
|
|
139
170
|
|
|
@@ -168,72 +199,6 @@ export class TranscriptLogger extends Participant {
|
|
|
168
199
|
async onModelMessage(): Promise<void> {}
|
|
169
200
|
}
|
|
170
201
|
```
|
|
171
|
-
|
|
172
|
-
### Reactive agent
|
|
173
|
-
|
|
174
|
-
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:
|
|
175
|
-
|
|
176
|
-
```ts
|
|
177
|
-
import {
|
|
178
|
-
BaseAgentParticipant,
|
|
179
|
-
Participant,
|
|
180
|
-
UserMessageItem,
|
|
181
|
-
FunctionCallItem,
|
|
182
|
-
AgenticEnvironment,
|
|
183
|
-
ModelContext,
|
|
184
|
-
GenerativeModel,
|
|
185
|
-
InputStream,
|
|
186
|
-
InferenceRunner,
|
|
187
|
-
FunctionCallRunner,
|
|
188
|
-
} from "@mozaik-ai/core"
|
|
189
|
-
|
|
190
|
-
export class ReactiveAgent extends BaseAgentParticipant {
|
|
191
|
-
constructor(
|
|
192
|
-
inputSource: InputStream,
|
|
193
|
-
inferenceRunner: InferenceRunner,
|
|
194
|
-
functionCallRunner: FunctionCallRunner,
|
|
195
|
-
private readonly environment: AgenticEnvironment,
|
|
196
|
-
private readonly context: ModelContext,
|
|
197
|
-
private readonly model: GenerativeModel,
|
|
198
|
-
) {
|
|
199
|
-
super(inputSource, inferenceRunner, functionCallRunner)
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// A message from a human (or any other participant) → record it and think.
|
|
203
|
-
async onMessage(message: string): Promise<void> {
|
|
204
|
-
this.context.addContextItem(UserMessageItem.create(message))
|
|
205
|
-
this.runInference(this.environment, this.context, this.model)
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// The agent just produced a function call → execute it.
|
|
209
|
-
async onFunctionCall(item: FunctionCallItem): Promise<void> {
|
|
210
|
-
this.context.addContextItem(item)
|
|
211
|
-
this.executeFunctionCall(this.environment, item)
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// The tool just produced an output → feed it back and run inference again.
|
|
215
|
-
async onFunctionCallOutput(item: FunctionCallOutputItem): Promise<void> {
|
|
216
|
-
this.context.addContextItem(item)
|
|
217
|
-
this.runInference(this.environment, this.context, this.model)
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
// Keep the local context in sync with model-emitted reasoning and replies.
|
|
221
|
-
async onReasoning(item: ReasoningItem): Promise<void> {
|
|
222
|
-
this.context.addContextItem(item)
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
async onModelMessage(item: ModelMessageItem): Promise<void> {
|
|
226
|
-
this.context.addContextItem(item)
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
Three things to note:
|
|
232
|
-
|
|
233
|
-
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.
|
|
234
|
-
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.
|
|
235
|
-
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.
|
|
236
|
-
|
|
237
202
|
---
|
|
238
203
|
|
|
239
204
|
## Context and models (reference)
|
|
@@ -264,51 +229,28 @@ const response = await runtime.infer(new InferenceRequest(new Gpt54(), context))
|
|
|
264
229
|
|
|
265
230
|
---
|
|
266
231
|
|
|
267
|
-
##
|
|
232
|
+
## Overriding Generators
|
|
268
233
|
|
|
269
|
-
|
|
234
|
+
Mozaik uses generators for inference, function calls, and message streams — that's what lets the system emit events incrementally so participants can react to them as they arrive. Swap any generator to change _how_ events are produced.
|
|
270
235
|
|
|
271
236
|
### Custom `InputStream`
|
|
272
237
|
|
|
273
|
-
An `InputStream` is the minimal text-source contract a participant uses to feed messages into the environment:
|
|
274
|
-
|
|
275
|
-
```ts
|
|
276
|
-
export interface InputStream {
|
|
277
|
-
stream(signal?: AbortSignal): AsyncIterable<string>
|
|
278
|
-
}
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
Each yielded string is delivered to every other participant through `onMessage(message: string)`. This keeps the wire format dead simple: participants exchange text, and each one decides how to turn that text into a `ContextItem` for its own `ModelContext`.
|
|
282
|
-
|
|
283
238
|
```ts
|
|
284
239
|
import { InputStream } from "@mozaik-ai/core"
|
|
285
240
|
|
|
286
|
-
export class
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
push(message: string) {
|
|
291
|
-
this.queue.push(message)
|
|
292
|
-
this.resolveNext?.()
|
|
293
|
-
this.resolveNext = undefined
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
async *stream(signal?: AbortSignal): AsyncIterable<string> {
|
|
297
|
-
while (!signal?.aborted) {
|
|
298
|
-
while (this.queue.length > 0) {
|
|
299
|
-
yield this.queue.shift()!
|
|
300
|
-
}
|
|
301
|
-
await new Promise<void>((resolve) => (this.resolveNext = resolve))
|
|
302
|
-
}
|
|
241
|
+
export class HelloInputStream implements InputStream {
|
|
242
|
+
async *stream(): AsyncIterable<string> {
|
|
243
|
+
yield "Hello"
|
|
244
|
+
yield "World"
|
|
303
245
|
}
|
|
304
246
|
}
|
|
305
247
|
```
|
|
306
248
|
|
|
307
|
-
|
|
249
|
+
Each yielded string is delivered to other participants through `onMessage(message: string)`.
|
|
308
250
|
|
|
309
251
|
### Custom `InferenceRunner`
|
|
310
252
|
|
|
311
|
-
|
|
253
|
+
An `InferenceRunner` can yield `ReasoningItem`, `FunctionCallItem`, and `ModelMessageItem`.
|
|
312
254
|
|
|
313
255
|
```ts
|
|
314
256
|
import {
|
|
@@ -336,11 +278,9 @@ export class OpenAIInferenceRunner implements InferenceRunner {
|
|
|
336
278
|
}
|
|
337
279
|
```
|
|
338
280
|
|
|
339
|
-
Replace the body with a streaming runtime and items will flow into the environment as soon as the model produces them.
|
|
340
|
-
|
|
341
281
|
### Custom `FunctionCallRunner`
|
|
342
282
|
|
|
343
|
-
|
|
283
|
+
A `FunctionCallRunner` can only produce `FunctionCallOutputItem`.
|
|
344
284
|
|
|
345
285
|
```ts
|
|
346
286
|
import { FunctionCallRunner, FunctionCallItem, FunctionCallOutputItem, Tool } from "@mozaik-ai/core"
|
|
@@ -364,7 +304,7 @@ export class ToolRegistryFunctionCallRunner implements FunctionCallRunner {
|
|
|
364
304
|
import { BaseAgentParticipant, AgenticEnvironment } from "@mozaik-ai/core"
|
|
365
305
|
|
|
366
306
|
const agent = new BaseAgentParticipant(
|
|
367
|
-
new
|
|
307
|
+
new HelloInputStream(),
|
|
368
308
|
new OpenAIInferenceRunner(),
|
|
369
309
|
new ToolRegistryFunctionCallRunner(tools),
|
|
370
310
|
)
|
|
@@ -372,8 +312,6 @@ const agent = new BaseAgentParticipant(
|
|
|
372
312
|
agent.join(new AgenticEnvironment())
|
|
373
313
|
```
|
|
374
314
|
|
|
375
|
-
You now own input, inference, and tool execution end-to-end while keeping the same `Participant` contract — and any other participant in the environment can still observe and react to everything the agent emits.
|
|
376
|
-
|
|
377
315
|
---
|
|
378
316
|
|
|
379
317
|
## Made with Mozaik
|