@open1s/ezbos 1.2.3 → 1.3.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/README.md +72 -0
- package/dist/agent.d.ts +14 -5
- package/dist/agent.js +39 -5
- package/dist/content.d.ts +4 -0
- package/dist/content.js +4 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/package.json +5 -3
- package/src/agent.ts +50 -10
- package/src/content.ts +5 -0
- package/src/index.ts +1 -0
package/README.md
CHANGED
|
@@ -80,6 +80,55 @@ const agent = brain.agent('name')
|
|
|
80
80
|
const started = await agent.start();
|
|
81
81
|
```
|
|
82
82
|
|
|
83
|
+
## Multimodal Content
|
|
84
|
+
|
|
85
|
+
Send images, audio, and other binary content alongside text.
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
import { Content, ContentPart, Binary } from '@open1s/ezbos';
|
|
89
|
+
|
|
90
|
+
// Text only
|
|
91
|
+
const textContent = Content.text('What is 2 + 2?');
|
|
92
|
+
|
|
93
|
+
// Single image (URL)
|
|
94
|
+
const imageContent = Content.image('https://example.com/photo.jpg');
|
|
95
|
+
|
|
96
|
+
// Audio from base64 data
|
|
97
|
+
const audioContent = Content.audio(base64Data, 'mp3');
|
|
98
|
+
|
|
99
|
+
// Multi-part: text + image
|
|
100
|
+
const multiContent = Content.parts([
|
|
101
|
+
ContentPart.text('Describe this image'),
|
|
102
|
+
ContentPart.image('https://example.com/photo.jpg'),
|
|
103
|
+
]);
|
|
104
|
+
|
|
105
|
+
// Pass to any LLM method
|
|
106
|
+
const result = await agent.ask(multiContent);
|
|
107
|
+
await agent.stream(multiContent, (token) => {
|
|
108
|
+
if (token.type === 'Text') process.stdout.write(token.text);
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Content API
|
|
113
|
+
|
|
114
|
+
| Method | Description |
|
|
115
|
+
|--------|-------------|
|
|
116
|
+
| `Content.text(text)` | Simple text content |
|
|
117
|
+
| `Content.image(url, name?)` | Single image (URL) |
|
|
118
|
+
| `Content.audio(data, format)` | Single audio (base64) |
|
|
119
|
+
| `Content.audioUrl(url, format)` | Single audio (URL) |
|
|
120
|
+
| `Content.parts([...])` | Multi-part content |
|
|
121
|
+
|
|
122
|
+
### ContentPart API
|
|
123
|
+
|
|
124
|
+
| Method | Description |
|
|
125
|
+
|--------|-------------|
|
|
126
|
+
| `ContentPart.text(text)` | Create text part |
|
|
127
|
+
| `ContentPart.image(url, name?)` | Create image part |
|
|
128
|
+
| `ContentPart.audio(data, format)` | Create audio part (base64) |
|
|
129
|
+
| `ContentPart.audioUrl(url, format)` | Create audio part (URL) |
|
|
130
|
+
| `ContentPart.binary(type, data, name?)` | Create binary part |
|
|
131
|
+
|
|
83
132
|
### Resilience
|
|
84
133
|
|
|
85
134
|
Configure circuit breaker and rate limiting:
|
|
@@ -322,6 +371,25 @@ const result2 = await started.react('Calculate the sum');
|
|
|
322
371
|
const result3 = await started.runSimple('Say hello');
|
|
323
372
|
```
|
|
324
373
|
|
|
374
|
+
All methods accept multimodal content (text, images, audio):
|
|
375
|
+
|
|
376
|
+
```ts
|
|
377
|
+
import { Content, ContentPart } from '@open1s/ezbos';
|
|
378
|
+
|
|
379
|
+
// Text + image
|
|
380
|
+
const content = Content.parts([
|
|
381
|
+
ContentPart.text('What do you see?'),
|
|
382
|
+
ContentPart.image('https://example.com/photo.jpg'),
|
|
383
|
+
]);
|
|
384
|
+
const result = await started.ask(content);
|
|
385
|
+
|
|
386
|
+
// Image only
|
|
387
|
+
const imageOnly = Content.image('https://example.com/photo.jpg');
|
|
388
|
+
await started.stream(imageOnly, (token) => {
|
|
389
|
+
if (token.type === 'Text') process.stdout.write(token.text);
|
|
390
|
+
});
|
|
391
|
+
```
|
|
392
|
+
|
|
325
393
|
### Streaming
|
|
326
394
|
|
|
327
395
|
```ts
|
|
@@ -451,6 +519,8 @@ await agent.close();
|
|
|
451
519
|
| `06-session.ts` | Multi-turn conversation, compactSession, save/restore, export/import |
|
|
452
520
|
| `07-agent-advanced.ts` | Streaming, streamCollect, metrics, resilience, config |
|
|
453
521
|
| `08-brainos-messaging.ts` | Query/Queryable, Caller/Callable, Publisher/Subscriber (recv + run) |
|
|
522
|
+
| `09-system-prompt.ts` | System prompt management and configuration |
|
|
523
|
+
| `10-multimodal.ts` | Multimodal content (images, audio), Content/ContentPart API |
|
|
454
524
|
|
|
455
525
|
```bash
|
|
456
526
|
npm run example:tools
|
|
@@ -461,6 +531,8 @@ npm run example:skills
|
|
|
461
531
|
npm run example:session
|
|
462
532
|
npm run example:agent
|
|
463
533
|
npm run example:messaging
|
|
534
|
+
npm run example:system-prompt
|
|
535
|
+
npm run example:multimodal
|
|
464
536
|
```
|
|
465
537
|
|
|
466
538
|
## License
|
package/dist/agent.d.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import * as jsbos from '@open1s/jsbos';
|
|
2
2
|
import { SkillDef } from './skills.js';
|
|
3
|
+
export interface JsContent {
|
|
4
|
+
type: string;
|
|
5
|
+
text?: string;
|
|
6
|
+
contentType?: string;
|
|
7
|
+
url?: string;
|
|
8
|
+
base64?: string;
|
|
9
|
+
name?: string;
|
|
10
|
+
}
|
|
3
11
|
export declare class AgentBuilder {
|
|
4
12
|
private _inner;
|
|
5
13
|
private _tools;
|
|
@@ -56,18 +64,19 @@ export declare class AgentBuilder {
|
|
|
56
64
|
export declare class Agent {
|
|
57
65
|
private _inner;
|
|
58
66
|
constructor(_inner: jsbos.Agent);
|
|
67
|
+
private _resolveContent;
|
|
59
68
|
run(task: string): Promise<string>;
|
|
60
|
-
ask(prompt: string): Promise<string>;
|
|
61
|
-
runSimple(prompt: string): Promise<string>;
|
|
62
|
-
react(task: string): Promise<string>;
|
|
69
|
+
ask(prompt: string | Array<JsContent>): Promise<string>;
|
|
70
|
+
runSimple(prompt: string | Array<JsContent>): Promise<string>;
|
|
71
|
+
react(task: string | Array<JsContent>): Promise<string>;
|
|
63
72
|
compactSession(): Promise<void>;
|
|
64
73
|
saveSession(path: string): void;
|
|
65
74
|
restoreSession(path: string): void;
|
|
66
75
|
clearSession(): void;
|
|
67
76
|
exportSession(): string;
|
|
68
77
|
importSession(json: string): void;
|
|
69
|
-
stream(task: string
|
|
70
|
-
streamCollect(task: string): Promise<any[]>;
|
|
78
|
+
stream(task: string | Array<JsContent>, onToken: (token: any) => void): Promise<string>;
|
|
79
|
+
streamCollect(task: string | Array<JsContent>): Promise<any[]>;
|
|
71
80
|
get tools(): string[];
|
|
72
81
|
get config(): any;
|
|
73
82
|
get inner(): jsbos.Agent;
|
package/dist/agent.js
CHANGED
|
@@ -232,17 +232,51 @@ export class Agent {
|
|
|
232
232
|
constructor(_inner) {
|
|
233
233
|
this._inner = _inner;
|
|
234
234
|
}
|
|
235
|
+
_resolveContent(input) {
|
|
236
|
+
if (input && typeof input === 'object' && input.constructor && input.constructor.name === 'Content') {
|
|
237
|
+
if (input._text !== null && input._text !== undefined) {
|
|
238
|
+
return [{ type: 'text', text: input._text }];
|
|
239
|
+
}
|
|
240
|
+
const parts = input.toJSON();
|
|
241
|
+
if (!Array.isArray(parts))
|
|
242
|
+
return [{ type: 'text', text: typeof parts === 'string' ? parts : JSON.stringify(parts) }];
|
|
243
|
+
return parts.map((p) => {
|
|
244
|
+
if (p.type === 'text') {
|
|
245
|
+
return { type: 'text', text: p.text || '' };
|
|
246
|
+
}
|
|
247
|
+
const b = p.binary || {};
|
|
248
|
+
const source = b.source || {};
|
|
249
|
+
const result = { type: 'binary', contentType: b.content_type || 'image/jpeg', name: b.name };
|
|
250
|
+
if (source.url !== undefined)
|
|
251
|
+
result.url = source.url;
|
|
252
|
+
else if (source.base64 !== undefined)
|
|
253
|
+
result.base64 = source.base64;
|
|
254
|
+
else if (source.type === 'url')
|
|
255
|
+
result.url = source.data;
|
|
256
|
+
else if (source.type === 'base64')
|
|
257
|
+
result.base64 = source.data;
|
|
258
|
+
return result;
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
if (typeof input === 'string') {
|
|
262
|
+
return [{ type: 'text', text: input }];
|
|
263
|
+
}
|
|
264
|
+
if (Array.isArray(input)) {
|
|
265
|
+
return input;
|
|
266
|
+
}
|
|
267
|
+
return [{ type: 'text', text: String(input) }];
|
|
268
|
+
}
|
|
235
269
|
async run(task) {
|
|
236
|
-
return this._inner.runSimple(task);
|
|
270
|
+
return this._inner.runSimple(this._resolveContent(task));
|
|
237
271
|
}
|
|
238
272
|
async ask(prompt) {
|
|
239
|
-
return this._inner.react(prompt);
|
|
273
|
+
return this._inner.react(this._resolveContent(prompt));
|
|
240
274
|
}
|
|
241
275
|
async runSimple(prompt) {
|
|
242
|
-
return this._inner.runSimple(prompt);
|
|
276
|
+
return this._inner.runSimple(this._resolveContent(prompt));
|
|
243
277
|
}
|
|
244
278
|
async react(task) {
|
|
245
|
-
return this._inner.react(task);
|
|
279
|
+
return this._inner.react(this._resolveContent(task));
|
|
246
280
|
}
|
|
247
281
|
async compactSession() {
|
|
248
282
|
const sessionJson = this._inner.getSessionJson();
|
|
@@ -271,7 +305,7 @@ export class Agent {
|
|
|
271
305
|
this._inner.restoreSessionJson(json);
|
|
272
306
|
}
|
|
273
307
|
stream(task, onToken) {
|
|
274
|
-
return this._inner.stream(task, (err, token) => {
|
|
308
|
+
return this._inner.stream(this._resolveContent(task), (err, token) => {
|
|
275
309
|
if (err) {
|
|
276
310
|
onToken({ type: 'Error', error: err.message });
|
|
277
311
|
}
|
package/dist/content.js
ADDED
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export * from './mcp.js';
|
|
|
7
7
|
export * from './skills.js';
|
|
8
8
|
export * from './agent.js';
|
|
9
9
|
export * from './brainos.js';
|
|
10
|
+
export * from './content.js';
|
|
10
11
|
export declare const version: typeof jsbos.version;
|
|
11
12
|
export declare const initTracing: typeof jsbos.initTracing;
|
|
12
13
|
export declare const logTestMessage: typeof jsbos.logTestMessage;
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ export * from './mcp.js';
|
|
|
7
7
|
export * from './skills.js';
|
|
8
8
|
export * from './agent.js';
|
|
9
9
|
export * from './brainos.js';
|
|
10
|
+
export * from './content.js';
|
|
10
11
|
export const version = jsbos.version;
|
|
11
12
|
export const initTracing = jsbos.initTracing;
|
|
12
13
|
export const logTestMessage = jsbos.logTestMessage;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open1s/ezbos",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Simple BrainOS - Easy wrapper for @open1s/jsbos",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -28,7 +28,9 @@
|
|
|
28
28
|
"example:skills": "tsx examples/05-skills.ts",
|
|
29
29
|
"example:session": "tsx examples/06-session.ts",
|
|
30
30
|
"example:agent": "tsx examples/07-agent-advanced.ts",
|
|
31
|
-
"example:messaging": "tsx examples/08-brainos-messaging.ts"
|
|
31
|
+
"example:messaging": "tsx examples/08-brainos-messaging.ts",
|
|
32
|
+
"example:system-prompt": "tsx examples/09-system-prompt.ts",
|
|
33
|
+
"example:multimodal": "tsx examples/10-multimodal.ts"
|
|
32
34
|
},
|
|
33
35
|
"keywords": [
|
|
34
36
|
"ai",
|
|
@@ -38,7 +40,7 @@
|
|
|
38
40
|
],
|
|
39
41
|
"license": "MIT",
|
|
40
42
|
"dependencies": {
|
|
41
|
-
"@open1s/jsbos": "^2.
|
|
43
|
+
"@open1s/jsbos": "^2.3.0"
|
|
42
44
|
},
|
|
43
45
|
"devDependencies": {
|
|
44
46
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
package/src/agent.ts
CHANGED
|
@@ -3,6 +3,16 @@ import { jsbos as jsbosDefault, InternalToolDef } from './tool.js';
|
|
|
3
3
|
import { HookEvent, HookCallback, mergeHooks } from './hook.js';
|
|
4
4
|
import { PluginHandlers, mergePlugins } from './plugin.js';
|
|
5
5
|
import { SkillDef } from './skills.js';
|
|
6
|
+
import { Content } from './content.js';
|
|
7
|
+
|
|
8
|
+
export interface JsContent {
|
|
9
|
+
type: string;
|
|
10
|
+
text?: string;
|
|
11
|
+
contentType?: string;
|
|
12
|
+
url?: string;
|
|
13
|
+
base64?: string;
|
|
14
|
+
name?: string;
|
|
15
|
+
}
|
|
6
16
|
|
|
7
17
|
const DEFAULT_MODEL = 'nvidia/meta/llama-3.1-8b-instruct';
|
|
8
18
|
const DEFAULT_BASE_URL = 'https://integrate.api.nvidia.com/v1';
|
|
@@ -304,20 +314,50 @@ export class AgentBuilder {
|
|
|
304
314
|
export class Agent {
|
|
305
315
|
constructor(private _inner: jsbos.Agent) {}
|
|
306
316
|
|
|
317
|
+
private _resolveContent(input: any): Array<JsContent> {
|
|
318
|
+
if (input && typeof input === 'object' && input.constructor && input.constructor.name === 'Content') {
|
|
319
|
+
if (input._text !== null && input._text !== undefined) {
|
|
320
|
+
return [{ type: 'text', text: input._text }];
|
|
321
|
+
}
|
|
322
|
+
const parts = input.toJSON();
|
|
323
|
+
if (!Array.isArray(parts)) return [{ type: 'text', text: typeof parts === 'string' ? parts : JSON.stringify(parts) }];
|
|
324
|
+
return (parts as Array<any>).map((p: any) => {
|
|
325
|
+
if (p.type === 'text') {
|
|
326
|
+
return { type: 'text', text: p.text || '' };
|
|
327
|
+
}
|
|
328
|
+
const b = p.binary || {};
|
|
329
|
+
const source = b.source || {};
|
|
330
|
+
const result: JsContent = { type: 'binary', contentType: b.content_type || 'image/jpeg', name: b.name };
|
|
331
|
+
if (source.url !== undefined) result.url = source.url;
|
|
332
|
+
else if (source.base64 !== undefined) result.base64 = source.base64;
|
|
333
|
+
else if (source.type === 'url') result.url = source.data;
|
|
334
|
+
else if (source.type === 'base64') result.base64 = source.data;
|
|
335
|
+
return result;
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
if (typeof input === 'string') {
|
|
339
|
+
return [{ type: 'text', text: input }];
|
|
340
|
+
}
|
|
341
|
+
if (Array.isArray(input)) {
|
|
342
|
+
return input;
|
|
343
|
+
}
|
|
344
|
+
return [{ type: 'text', text: String(input) }];
|
|
345
|
+
}
|
|
346
|
+
|
|
307
347
|
async run(task: string): Promise<string> {
|
|
308
|
-
return this._inner.runSimple(task);
|
|
348
|
+
return this._inner.runSimple(this._resolveContent(task) as any);
|
|
309
349
|
}
|
|
310
350
|
|
|
311
|
-
async ask(prompt: string): Promise<string> {
|
|
312
|
-
return this._inner.react(prompt);
|
|
351
|
+
async ask(prompt: string | Array<JsContent>): Promise<string> {
|
|
352
|
+
return this._inner.react(this._resolveContent(prompt) as any);
|
|
313
353
|
}
|
|
314
354
|
|
|
315
|
-
async runSimple(prompt: string): Promise<string> {
|
|
316
|
-
return this._inner.runSimple(prompt);
|
|
355
|
+
async runSimple(prompt: string | Array<JsContent>): Promise<string> {
|
|
356
|
+
return this._inner.runSimple(this._resolveContent(prompt) as any);
|
|
317
357
|
}
|
|
318
358
|
|
|
319
|
-
async react(task: string): Promise<string> {
|
|
320
|
-
return this._inner.react(task);
|
|
359
|
+
async react(task: string | Array<JsContent>): Promise<string> {
|
|
360
|
+
return this._inner.react(this._resolveContent(task) as any);
|
|
321
361
|
}
|
|
322
362
|
|
|
323
363
|
async compactSession(): Promise<void> {
|
|
@@ -356,8 +396,8 @@ export class Agent {
|
|
|
356
396
|
this._inner.restoreSessionJson(json);
|
|
357
397
|
}
|
|
358
398
|
|
|
359
|
-
stream(task: string
|
|
360
|
-
return this._inner.stream(task, (err, token) => {
|
|
399
|
+
stream(task: string | Array<JsContent>, onToken: (token: any) => void): Promise<string> {
|
|
400
|
+
return this._inner.stream(this._resolveContent(task) as any, (err, token) => {
|
|
361
401
|
if (err) {
|
|
362
402
|
onToken({ type: 'Error', error: err.message });
|
|
363
403
|
} else {
|
|
@@ -366,7 +406,7 @@ export class Agent {
|
|
|
366
406
|
});
|
|
367
407
|
}
|
|
368
408
|
|
|
369
|
-
async streamCollect(task: string): Promise<any[]> {
|
|
409
|
+
async streamCollect(task: string | Array<JsContent>): Promise<any[]> {
|
|
370
410
|
const tokens: any[] = [];
|
|
371
411
|
await new Promise<void>((resolve) => {
|
|
372
412
|
this.stream(task, token => {
|
package/src/content.ts
ADDED
package/src/index.ts
CHANGED