@open1s/ezbos 1.2.4 → 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 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, onToken: (token: any) => void): Promise<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
  }
@@ -0,0 +1,4 @@
1
+ import * as jsbos from '@open1s/jsbos';
2
+ export declare const Content: typeof jsbos.Content;
3
+ export declare const ContentPart: typeof jsbos.ContentPart;
4
+ export declare const Binary: typeof jsbos.Binary;
@@ -0,0 +1,4 @@
1
+ import * as jsbos from '@open1s/jsbos';
2
+ export const Content = jsbos.Content;
3
+ export const ContentPart = jsbos.ContentPart;
4
+ export const Binary = jsbos.Binary;
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.2.4",
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.2.11"
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, onToken: (token: any) => void): Promise<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
@@ -0,0 +1,5 @@
1
+ import * as jsbos from '@open1s/jsbos';
2
+
3
+ export const Content = jsbos.Content;
4
+ export const ContentPart = jsbos.ContentPart;
5
+ export const Binary = jsbos.Binary;
package/src/index.ts CHANGED
@@ -9,6 +9,7 @@ export * from './mcp.js';
9
9
  export * from './skills.js';
10
10
  export * from './agent.js';
11
11
  export * from './brainos.js';
12
+ export * from './content.js';
12
13
 
13
14
  export const version = jsbos.version;
14
15
  export const initTracing = jsbos.initTracing;