@mozaik-ai/core 3.8.4 → 3.8.6
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 +72 -106
- package/package.json +3 -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
|
|
|
@@ -169,71 +200,6 @@ export class TranscriptLogger extends Participant {
|
|
|
169
200
|
}
|
|
170
201
|
```
|
|
171
202
|
|
|
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
203
|
---
|
|
238
204
|
|
|
239
205
|
## Context and models (reference)
|
|
@@ -264,51 +230,28 @@ const response = await runtime.infer(new InferenceRequest(new Gpt54(), context))
|
|
|
264
230
|
|
|
265
231
|
---
|
|
266
232
|
|
|
267
|
-
##
|
|
233
|
+
## Overriding Generators
|
|
268
234
|
|
|
269
|
-
|
|
235
|
+
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
236
|
|
|
271
237
|
### Custom `InputStream`
|
|
272
238
|
|
|
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
239
|
```ts
|
|
284
240
|
import { InputStream } from "@mozaik-ai/core"
|
|
285
241
|
|
|
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
|
-
}
|
|
242
|
+
export class HelloInputStream implements InputStream {
|
|
243
|
+
async *stream(): AsyncIterable<string> {
|
|
244
|
+
yield "Hello"
|
|
245
|
+
yield "World"
|
|
303
246
|
}
|
|
304
247
|
}
|
|
305
248
|
```
|
|
306
249
|
|
|
307
|
-
|
|
250
|
+
Each yielded string is delivered to other participants through `onMessage(message: string)`.
|
|
308
251
|
|
|
309
252
|
### Custom `InferenceRunner`
|
|
310
253
|
|
|
311
|
-
|
|
254
|
+
An `InferenceRunner` can yield `ReasoningItem`, `FunctionCallItem`, and `ModelMessageItem`.
|
|
312
255
|
|
|
313
256
|
```ts
|
|
314
257
|
import {
|
|
@@ -336,11 +279,9 @@ export class OpenAIInferenceRunner implements InferenceRunner {
|
|
|
336
279
|
}
|
|
337
280
|
```
|
|
338
281
|
|
|
339
|
-
Replace the body with a streaming runtime and items will flow into the environment as soon as the model produces them.
|
|
340
|
-
|
|
341
282
|
### Custom `FunctionCallRunner`
|
|
342
283
|
|
|
343
|
-
|
|
284
|
+
A `FunctionCallRunner` can only produce `FunctionCallOutputItem`.
|
|
344
285
|
|
|
345
286
|
```ts
|
|
346
287
|
import { FunctionCallRunner, FunctionCallItem, FunctionCallOutputItem, Tool } from "@mozaik-ai/core"
|
|
@@ -364,7 +305,7 @@ export class ToolRegistryFunctionCallRunner implements FunctionCallRunner {
|
|
|
364
305
|
import { BaseAgentParticipant, AgenticEnvironment } from "@mozaik-ai/core"
|
|
365
306
|
|
|
366
307
|
const agent = new BaseAgentParticipant(
|
|
367
|
-
new
|
|
308
|
+
new HelloInputStream(),
|
|
368
309
|
new OpenAIInferenceRunner(),
|
|
369
310
|
new ToolRegistryFunctionCallRunner(tools),
|
|
370
311
|
)
|
|
@@ -372,16 +313,41 @@ const agent = new BaseAgentParticipant(
|
|
|
372
313
|
agent.join(new AgenticEnvironment())
|
|
373
314
|
```
|
|
374
315
|
|
|
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
316
|
---
|
|
378
317
|
|
|
379
318
|
## Made with Mozaik
|
|
380
319
|
|
|
381
320
|
- **[baro](https://github.com/Lotus015/baro)** — a Claude agent orchestrator where ten specialized participants (planner, executors, reviewer, fixer, librarian, auditor, and more) work fully concurrently on the same goal, like a team collaborating in real time instead of a single agent doing everything alone.
|
|
382
321
|
|
|
322
|
+
```mermaid
|
|
323
|
+
flowchart LR
|
|
324
|
+
Conductor[Conductor] -->|"RunStart / LevelCompute / StorySpawn"| Bus(("Mozaik Bus"))
|
|
325
|
+
Factory[StoryFactory] -->|"spawn StoryAgent"| Bus
|
|
326
|
+
Story[StoryAgent] -->|"StoryResult / retries"| Bus
|
|
327
|
+
Librarian[Librarian] -->|"index exploration outputs"| Bus
|
|
328
|
+
Sentry[Sentry] -->|"flag file conflicts"| Bus
|
|
329
|
+
Critic[Critic] -->|"per-turn verdict"| Bus
|
|
330
|
+
Surgeon[Surgeon] -->|"emit ReplanItem"| Bus
|
|
331
|
+
Operator[Operator] -->|"bridge TUI commands"| Bus
|
|
332
|
+
Auditor[Auditor] -->|"write JSONL log"| Bus
|
|
333
|
+
Cartographer[Cartographer] -->|"emit UI frames"| Bus
|
|
334
|
+
Bus -->|"StorySpawnRequest"| Factory
|
|
335
|
+
Bus -->|"StoryResult / LevelCompleted"| Conductor
|
|
336
|
+
Bus -->|"tool calls"| Librarian
|
|
337
|
+
Bus -->|"Edit/Write calls"| Sentry
|
|
338
|
+
Bus -->|"agent turns"| Critic
|
|
339
|
+
Bus -->|"terminal failure"| Surgeon
|
|
340
|
+
Bus -->|"user input"| Operator
|
|
341
|
+
Bus -->|"all events"| Auditor
|
|
342
|
+
Bus -->|"all events"| Cartographer
|
|
343
|
+
```
|
|
344
|
+
|
|
383
345
|
---
|
|
384
346
|
|
|
347
|
+
## Contributing
|
|
348
|
+
|
|
349
|
+
Contributions are welcome. Please read the [Contributing Guidelines](./CONTRIBUTING.md) before opening an issue or pull request.
|
|
350
|
+
|
|
385
351
|
## Author & License
|
|
386
352
|
|
|
387
353
|
Created by the [JigJoy](https://jigjoy.io) team.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mozaik-ai/core",
|
|
3
|
-
"version": "3.8.
|
|
3
|
+
"version": "3.8.6",
|
|
4
4
|
"description": "A TypeScript framework for building reactive agents",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -36,11 +36,13 @@
|
|
|
36
36
|
"keywords": [
|
|
37
37
|
"agentic-environment",
|
|
38
38
|
"reactive-agents",
|
|
39
|
+
"collaborative-agents",
|
|
39
40
|
"non-blocking agents",
|
|
40
41
|
"event-driven agents",
|
|
41
42
|
"ai-infrastructure",
|
|
42
43
|
"ai-developer-tools",
|
|
43
44
|
"context-management",
|
|
45
|
+
"agent-swarms",
|
|
44
46
|
"llm-framework",
|
|
45
47
|
"openai",
|
|
46
48
|
"typescript framework"
|