@promptbook/core 0.105.0-3 → 0.105.0-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 CHANGED
@@ -322,19 +322,20 @@ Rest of the documentation is common for **entire promptbook ecosystem**:
322
322
 
323
323
  ## 📖 The Book Whitepaper
324
324
 
325
- For most business applications nowadays, the biggest challenge isn't about the raw capabilities of AI models. Large language models like GPT-5 or Claude-4.1 are extremely capable.
325
+ Nowadays, the biggest challenge for most business applications isn't the raw capabilities of AI models. Large language models such as GPT-5.2 and Claude-4.5 are incredibly capable.
326
326
 
327
- The main challenge is to narrow it down, constrain it, set the proper **context, rules, knowledge, and personality**. There are a lot of tools which can do exactly this. On one side, there are no-code platforms which can launch your agent in seconds. On the other side, there are heavy frameworks like Langchain or Semantic Kernel, which can give you deep control.
327
+ The main challenge lies in **managing the context**, providing rules and knowledge, and narrowing the personality.
328
328
 
329
- Promptbook takes the best from both worlds. You are defining your AI behavior by simple **books**, which are very explicit. They are automatically enforced, but they are very easy to understand, very easy to write, and very reliable and portable.
329
+ In Promptbook, you can define your context **using simple Books** that are very explicit, easy to understand and write, reliable, and highly portable.
330
330
 
331
331
  <table style="border: 1px solid #777; border-radius: 10px;"><tr><td>
332
332
 
333
- **<ins>Paul Smith & Associés</ins>**<br/>
333
+ **<ins>Paul Smith</ins>**<br/>
334
334
  <br/>
335
335
  **PERSONA** You are a company lawyer.<br/>
336
336
  Your job is to provide legal advice and support to the company and its employees.<br/>
337
- You are knowledgeable, professional, and detail-oriented.<br/>
337
+ **RULE** You are knowledgeable, professional, and detail-oriented.<br/>
338
+ TEAM You are part of the legal team of Paul Smith & Associés, you discuss with {Emily White}, the head of the compliance department. {George Brown} is expert in corporate law and {Sophia Black} is expert in labor law.<br/>
338
339
 
339
340
  </td></tr></table>
340
341
 
@@ -344,7 +345,9 @@ You are knowledgeable, professional, and detail-oriented.<br/>
344
345
 
345
346
  We have created a language called **Book**, which allows you to write AI agents in their native language and create your own AI persona. Book provides a guide to define all the traits and commitments.
346
347
 
347
- You can look at it as prompting (or writing a system message), but decorated by **commitments**.
348
+ You can look at it as "prompting" _(or writing a system message)_, but decorated by **commitments**.
349
+
350
+ **Commitments** are special syntax elements that define contracts between you and the AI agent. They are transformed by Promptbook Engine into low-level parameters like which model to use, its temperature, system message, RAG index, MCP servers, and many other parameters. For some commitments _(for example `RULE` commitment)_ Promptbook Engine can even create adversary agents and extra checks to enforce the rules.
348
351
 
349
352
  #### `Persona` commitment
350
353
 
@@ -355,8 +358,6 @@ Personas define the character of your AI persona, its role, and how it should in
355
358
  **<ins>Paul Smith & Associés</ins>**<br/>
356
359
  <br/>
357
360
  **PERSONA** You are a company lawyer.<br/>
358
- Your job is to provide legal advice and support to the company and its employees.<br/>
359
- You are knowledgeable, professional, and detail-oriented.<br/>
360
361
 
361
362
  </td></tr></table>
362
363
 
@@ -376,7 +377,7 @@ Promptbook Engine will automatically enforce this knowledge during interactions.
376
377
  Your job is to provide legal advice and support to the company and its employees.<br/>
377
378
  You are knowledgeable, professional, and detail-oriented.<br/>
378
379
  <br/>
379
- **KNOWLEDGE** https://company.com/company-policies.pdf<br/>
380
+ **KNOWLEDGE** https://company.com/company-policies.pdf<br/>
380
381
  **KNOWLEDGE** https://company.com/internal-documents/employee-handbook.docx<br/>
381
382
 
382
383
  </td></tr></table>
@@ -398,14 +399,14 @@ You are knowledgeable, professional, and detail-oriented.<br/>
398
399
  **RULE** Always ensure compliance with laws and regulations.<br/>
399
400
  **RULE** Never provide legal advice outside your area of expertise.<br/>
400
401
  **RULE** Never provide legal advice about criminal law.<br/>
401
- **KNOWLEDGE** https://company.com/company-policies.pdf<br/>
402
+ **KNOWLEDGE** https://company.com/company-policies.pdf<br/>
402
403
  **KNOWLEDGE** https://company.com/internal-documents/employee-handbook.docx<br/>
403
404
 
404
405
  </td></tr></table>
405
406
 
406
- #### `Action` commitment
407
+ #### `Team` commitment
407
408
 
408
- Action Commitment allows you to define specific actions that the AI can take during interactions. This can include things like posting on a social media platform, sending emails, creating calendar events, or interacting with your internal systems.
409
+ Team commitment allows you to define the team structure and advisory fellow members the AI can consult with. This allows the AI to simulate collaboration and consultation with other experts, enhancing the quality of its responses.
409
410
 
410
411
  <table style="border: 1px solid #777; border-radius: 10px;"><tr><td>
411
412
 
@@ -418,81 +419,36 @@ You are knowledgeable, professional, and detail-oriented.<br/>
418
419
  **RULE** Always ensure compliance with laws and regulations.<br/>
419
420
  **RULE** Never provide legal advice outside your area of expertise.<br/>
420
421
  **RULE** Never provide legal advice about criminal law.<br/>
421
- **KNOWLEDGE** https://company.com/company-policies.pdf<br/>
422
+ **KNOWLEDGE** https://company.com/company-policies.pdf<br/>
422
423
  **KNOWLEDGE** https://company.com/internal-documents/employee-handbook.docx<br/>
423
- **ACTION** When a user asks about an issue that could be treated as a crime, notify legal@company.com.<br/>
424
+ TEAM You are part of the legal team of Paul Smith & Associés, you discuss with {Emily White}, the head of the compliance department. {George Brown} is expert in corporate law and {Sophia Black} is expert in labor law.<br/>
424
425
 
425
426
  </td></tr></table>
426
427
 
427
- [Read more about the language](./BLUEPRINT.md)
428
-
429
- <div style="page-break-after: always;"></div>
430
-
431
- ### Where to use your AI agent in book
432
-
433
- Books can be useful in various applications and scenarios. Here are some examples:
434
-
435
- #### Chat apps:
436
428
 
437
- Create your own chat shopping assistant and place it in your eShop.
438
- You will be able to answer customer questions, help them find products, and provide personalized recommendations. Everything is tightly controlled by the book you have written.
439
429
 
440
- #### Reply Agent:
430
+ ### Promptbook Ecosystem
441
431
 
442
- Create your own AI agent, which will look at your emails and reply to them. It can even create drafts for you to review before sending.
432
+ !!!@@@
443
433
 
444
- #### Coding Agent:
445
-
446
- Do you love Vibecoding, but the AI code is not always aligned with your coding style and architecture, rules, security, etc.? Create your own coding agent to help enforce your specific coding standards and practices.
447
-
448
- This can be integrated to almost any Vibecoding platform, like GitHub Copilot, Amazon CodeWhisperer, Cursor, Cline, Kilocode, Roocode,...
449
-
450
- They will work the same as you are used to, but with your specific rules written in book.
451
-
452
- #### Internal Expertise
453
-
454
- Do you have an app written in TypeScript, Python, C#, Java, or any other language, and you are integrating the AI.
455
-
456
- You can avoid struggle with choosing the best model, its settings like temperature, max tokens, etc., by writing a book agent and using it as your AI expertise.
457
-
458
- Doesn't matter if you do automations, data analysis, customer support, sentiment analysis, classification, or any other task. Your AI agent will be tailored to your specific needs and requirements.
459
-
460
- Even works in no-code platforms!
461
-
462
- <div style="page-break-after: always;"></div>
434
+ #### Promptbook Server
463
435
 
464
- ### How to create your AI agent in book
436
+ !!!@@@
465
437
 
466
- Now you want to use it. There are several ways how to write your first book:
438
+ #### Promptbook Engine
467
439
 
468
- #### From scratch with help from Paul
440
+ !!!@@@
469
441
 
470
- We have written ai asistant in book who can help you with writing your first book.
471
442
 
472
- #### Your AI twin
473
443
 
474
- Copy your own behavior, personality, and knowledge into book and create your AI twin. It can help you with your work, personal life, or any other task.
475
444
 
476
- #### AI persona workpool
477
445
 
478
- Or you can pick from our library of pre-written books for various roles and tasks. You can find books for customer support, coding, marketing, sales, HR, legal, and many other roles.
479
446
 
480
447
 
481
448
 
482
449
 
483
450
 
484
451
 
485
- ## 🚀 Get started
486
-
487
- Take a look at the simple starter kit with books integrated into the **Hello World** sample applications:
488
-
489
- - [Hello Book](https://github.com/webgptorg/hello-world)
490
- - [Hello Book in Node.js](https://github.com/webgptorg/hello-world-node-js)
491
- - [Hello Book in Next.js](https://github.com/webgptorg/hello-world-next-js)
492
-
493
-
494
-
495
-
496
452
 
497
453
 
498
454
  ## 💜 The Promptbook Project
@@ -508,33 +464,32 @@ Promptbook project is ecosystem of multiple projects and tools, following is a l
508
464
  </thead>
509
465
  <tbody>
510
466
  <tr>
511
- <td><a href="https://github.com/webgptorg/book">Book language</a></td>
467
+ <td><a href="https://gallery.ptbk.io/">Agents Server</a></td>
512
468
  <td>
513
- Book is a human-understandable markup language for writing AI applications such as chatbots, knowledge bases, agents, avarars, translators, automations and more.
514
- <hr>
515
- There is also <a href="https://github.com/webgptorg/book-extension">a plugin for VSCode</a> to support <code>.book</code> file extension
469
+ Place where you "AI agents live". It allows to create, manage, deploy, and interact with AI agents created in Book language.
516
470
  </td>
517
471
  </tr>
518
472
  <tr>
519
- <td><a href="https://github.com/webgptorg/promptbook">Promptbook Engine</a></td>
473
+ <td><a href="https://github.com/webgptorg/book">Book language</a></td>
520
474
  <td>
521
- Promptbook engine can run applications written in Book language. It is released as <a href="https://www.npmjs.com/package/@promptbook/core#-packages-for-developers">multiple NPM packages</a> and <a href="https://hub.docker.com/r/hejny/promptbook">Docker HUB</a>
475
+ Human-friendly, high-level language that abstracts away low-level details of AI. It allows to focus on personality, behavior, knowledge, and rules of AI agents rather than on models, parameters, and prompt engineering.
476
+ <hr>
477
+ There is also <a href="https://github.com/webgptorg/book-extension">a plugin for VSCode</a> to support <code>.book</code> file extension
522
478
  </td>
523
479
  </tr>
524
480
  <tr>
525
- <td><a href="https://promptbook.studio">Promptbook Studio</a></td>
481
+ <td><a href="https://github.com/webgptorg/promptbook">Promptbook Engine</a></td>
526
482
  <td>
527
- Promptbook.studio is a web-based editor and runner for book applications. It is still in the experimental MVP stage.
483
+ Promptbook engine can run AI agents based on Book language.
484
+ It is released as <a href="https://www.npmjs.com/package/@promptbook/core#-packages-for-developers">multiple NPM packages</a> and <a href="https://hub.docker.com/r/hejny/promptbook">Promptbook Agent Server as Docker Package</a>
485
+ Agent Server is based on Promptbook Engine.
528
486
  </td>
529
487
  </tr>
488
+
530
489
  </tbody>
531
490
  </table>
532
491
 
533
- Hello world examples:
534
492
 
535
- - [Hello world](https://github.com/webgptorg/hello-world)
536
- - [Hello world in Node.js](https://github.com/webgptorg/hello-world-node-js)
537
- - [Hello world in Next.js](https://github.com/webgptorg/hello-world-next-js)
538
493
 
539
494
  ### 🌐 Community & Social Media
540
495
 
@@ -592,6 +547,8 @@ Join our growing community of developers and users:
592
547
 
593
548
 
594
549
 
550
+
551
+
595
552
  ## 📚 Documentation
596
553
 
597
554
  See detailed guides and API reference in the [docs](https://github.com/webgptorg/promptbook/discussions/categories/concepts) or [online](https://discord.gg/x3QWNaa89N).
@@ -668,6 +625,8 @@ The following glossary is used to clarify certain concepts:
668
625
 
669
626
  _Note: This section is not a complete dictionary, more list of general AI / LLM terms that has connection with Promptbook_
670
627
 
628
+
629
+
671
630
  ### 💯 Core concepts
672
631
 
673
632
  - [📚 Collection of pipelines](https://github.com/webgptorg/promptbook/discussions/65)
package/esm/index.es.js CHANGED
@@ -27,7 +27,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
27
27
  * @generated
28
28
  * @see https://github.com/webgptorg/promptbook
29
29
  */
30
- const PROMPTBOOK_ENGINE_VERSION = '0.105.0-3';
30
+ const PROMPTBOOK_ENGINE_VERSION = '0.105.0-5';
31
31
  /**
32
32
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
33
33
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -11500,7 +11500,12 @@ class UseTimeCommitmentDefinition extends BaseCommitmentDefinition {
11500
11500
  description: 'Get the current date and time in ISO 8601 format.',
11501
11501
  parameters: {
11502
11502
  type: 'object',
11503
- properties: {},
11503
+ properties: {
11504
+ timezone: {
11505
+ type: 'string',
11506
+ description: 'Optional timezone name (e.g. "Europe/Prague", "UTC", "America/New_York").',
11507
+ },
11508
+ },
11504
11509
  required: [],
11505
11510
  },
11506
11511
  },
@@ -11520,9 +11525,36 @@ class UseTimeCommitmentDefinition extends BaseCommitmentDefinition {
11520
11525
  */
11521
11526
  getToolFunctions() {
11522
11527
  return {
11523
- async get_current_time() {
11524
- console.log('!!!! [Tool] get_current_time called');
11525
- return new Date().toISOString();
11528
+ async get_current_time(args) {
11529
+ var _a;
11530
+ console.log('!!!! [Tool] get_current_time called', { args });
11531
+ const { timezone } = args;
11532
+ if (!timezone) {
11533
+ return new Date().toISOString();
11534
+ }
11535
+ try {
11536
+ // Note: Returning ISO 8601 string but in the requested timezone
11537
+ const formatter = new Intl.DateTimeFormat('en-CA', {
11538
+ timeZone: timezone,
11539
+ year: 'numeric',
11540
+ month: '2-digit',
11541
+ day: '2-digit',
11542
+ hour: '2-digit',
11543
+ minute: '2-digit',
11544
+ second: '2-digit',
11545
+ hour12: false,
11546
+ timeZoneName: 'shortOffset',
11547
+ });
11548
+ const parts = formatter.formatToParts(new Date());
11549
+ const part = (type) => { var _a; return (_a = parts.find((p) => p.type === type)) === null || _a === void 0 ? void 0 : _a.value; };
11550
+ // en-CA format is YYYY-MM-DD
11551
+ const isoString = `${part('year')}-${part('month')}-${part('day')}T${part('hour')}:${part('minute')}:${part('second')}${(_a = part('timeZoneName')) === null || _a === void 0 ? void 0 : _a.replace('GMT', '')}`;
11552
+ return isoString;
11553
+ }
11554
+ catch (error) {
11555
+ // Fallback to UTC if timezone is invalid
11556
+ return new Date().toISOString();
11557
+ }
11526
11558
  },
11527
11559
  };
11528
11560
  }
@@ -12438,26 +12470,52 @@ function parseAgentSource(agentSource) {
12438
12470
  });
12439
12471
  continue;
12440
12472
  }
12473
+ if (commitment.type === 'FROM') {
12474
+ const content = spaceTrim$2(commitment.content).split('\n')[0] || '';
12475
+ if (content === 'Adam' || content === '' /* <- Note: Adam is implicit */) {
12476
+ continue;
12477
+ }
12478
+ let label = content;
12479
+ let iconName = 'SquareArrowOutUpRight'; // Inheritance remote
12480
+ if (content.startsWith('./') || content.startsWith('../') || content.startsWith('/')) {
12481
+ label = content.split('/').pop() || content;
12482
+ iconName = 'SquareArrowUpRight'; // Inheritance local
12483
+ }
12484
+ if (content === 'VOID') {
12485
+ label = 'VOID';
12486
+ iconName = 'ShieldAlert'; // [🧠] Or some other icon for VOID
12487
+ }
12488
+ capabilities.push({
12489
+ type: 'inheritance',
12490
+ label,
12491
+ iconName,
12492
+ agentUrl: content,
12493
+ });
12494
+ continue;
12495
+ }
12441
12496
  if (commitment.type === 'IMPORT') {
12442
12497
  const content = spaceTrim$2(commitment.content).split('\n')[0] || '';
12443
12498
  let label = content;
12444
- const iconName = 'Download';
12499
+ let iconName = 'ExternalLink'; // Import remote
12445
12500
  try {
12446
12501
  if (content.startsWith('http://') || content.startsWith('https://')) {
12447
12502
  const url = new URL(content);
12448
12503
  label = url.hostname.replace(/^www\./, '') + '.../' + url.pathname.split('/').pop();
12504
+ iconName = 'ExternalLink';
12449
12505
  }
12450
12506
  else if (content.startsWith('./') || content.startsWith('../') || content.startsWith('/')) {
12451
12507
  label = content.split('/').pop() || content;
12508
+ iconName = 'Link'; // Import local
12452
12509
  }
12453
12510
  }
12454
12511
  catch (e) {
12455
12512
  // Invalid URL or path, keep default label
12456
12513
  }
12457
12514
  capabilities.push({
12458
- type: 'knowledge',
12515
+ type: 'import',
12459
12516
  label,
12460
12517
  iconName,
12518
+ agentUrl: content,
12461
12519
  });
12462
12520
  continue;
12463
12521
  }
@@ -18770,20 +18828,29 @@ class OpenAiCompatibleExecutionTools {
18770
18828
  });
18771
18829
  return availableModels;
18772
18830
  }
18831
+ /**
18832
+ * Calls OpenAI compatible API to use a chat model.
18833
+ */
18773
18834
  /**
18774
18835
  * Calls OpenAI compatible API to use a chat model.
18775
18836
  */
18776
18837
  async callChatModel(prompt) {
18838
+ return this.callChatModelStream(prompt, () => { });
18839
+ }
18840
+ /**
18841
+ * Calls OpenAI compatible API to use a chat model with streaming.
18842
+ */
18843
+ async callChatModelStream(prompt, onProgress) {
18777
18844
  // Deep clone prompt and modelRequirements to avoid mutation across calls
18778
18845
  const clonedPrompt = JSON.parse(JSON.stringify(prompt));
18779
18846
  // Use local Set for retried parameters to ensure independence and thread safety
18780
18847
  const retriedUnsupportedParameters = new Set();
18781
- return this.callChatModelWithRetry(clonedPrompt, clonedPrompt.modelRequirements, [], retriedUnsupportedParameters);
18848
+ return this.callChatModelWithRetry(clonedPrompt, clonedPrompt.modelRequirements, [], retriedUnsupportedParameters, onProgress);
18782
18849
  }
18783
18850
  /**
18784
18851
  * Internal method that handles parameter retry for chat model calls
18785
18852
  */
18786
- async callChatModelWithRetry(prompt, currentModelRequirements, attemptStack = [], retriedUnsupportedParameters = new Set()) {
18853
+ async callChatModelWithRetry(prompt, currentModelRequirements, attemptStack = [], retriedUnsupportedParameters = new Set(), onProgress) {
18787
18854
  var _a;
18788
18855
  if (this.options.isVerbose) {
18789
18856
  console.info(`💬 ${this.title} callChatModel call`, { prompt, currentModelRequirements });
@@ -18889,6 +18956,23 @@ class OpenAiCompatibleExecutionTools {
18889
18956
  const usage = this.computeUsage(content || '', responseMessage.content || '', rawResponse);
18890
18957
  totalUsage = addUsage(totalUsage, usage);
18891
18958
  if (responseMessage.tool_calls && responseMessage.tool_calls.length > 0) {
18959
+ if (onProgress) {
18960
+ onProgress({
18961
+ content: responseMessage.content || '',
18962
+ modelName: rawResponse.model || modelName,
18963
+ timing: { start, complete: $getCurrentDate() },
18964
+ usage: totalUsage,
18965
+ toolCalls: responseMessage.tool_calls.map((toolCall) => ({
18966
+ name: toolCall.function.name,
18967
+ arguments: toolCall.function.arguments,
18968
+ result: '',
18969
+ rawToolCall: toolCall,
18970
+ })),
18971
+ rawPromptContent,
18972
+ rawRequest,
18973
+ rawResponse,
18974
+ });
18975
+ }
18892
18976
  await forEachAsync(responseMessage.tool_calls, {}, async (toolCall) => {
18893
18977
  const functionName = toolCall.function.name;
18894
18978
  const functionArgs = toolCall.function.arguments;
@@ -18910,7 +18994,7 @@ class OpenAiCompatibleExecutionTools {
18910
18994
  const args = ${functionArgs};
18911
18995
  return await ${functionName}(args);
18912
18996
  `,
18913
- parameters: {}, // <- TODO: [🧠] What parameters to pass?
18997
+ parameters: prompt.parameters,
18914
18998
  });
18915
18999
  }
18916
19000
  catch (error) {
@@ -19016,7 +19100,7 @@ class OpenAiCompatibleExecutionTools {
19016
19100
  });
19017
19101
  // Remove the unsupported parameter and retry
19018
19102
  const modifiedModelRequirements = removeUnsupportedModelRequirement(currentModelRequirements, unsupportedParameter);
19019
- return this.callChatModelWithRetry(prompt, modifiedModelRequirements, attemptStack, retriedUnsupportedParameters);
19103
+ return this.callChatModelWithRetry(prompt, modifiedModelRequirements, attemptStack, retriedUnsupportedParameters, onProgress);
19020
19104
  }
19021
19105
  }
19022
19106
  throw new PipelineExecutionError(`Tool calling loop did not return a result from ${this.title}`);
@@ -19711,6 +19795,15 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
19711
19795
  // [🐱‍🚀] When tools are present, we need to use the non-streaming Runs API
19712
19796
  // because streaming doesn't support tool execution flow properly
19713
19797
  if (hasTools) {
19798
+ onProgress({
19799
+ content: '',
19800
+ modelName: 'assistant',
19801
+ timing: { start, complete: $getCurrentDate() },
19802
+ usage: UNCERTAIN_USAGE,
19803
+ rawPromptContent,
19804
+ rawRequest: null,
19805
+ rawResponse: null,
19806
+ });
19714
19807
  const rawRequest = {
19715
19808
  assistant_id: this.assistantId,
19716
19809
  thread: {
@@ -19734,6 +19827,23 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
19734
19827
  if (toolCall.type === 'function') {
19735
19828
  const functionName = toolCall.function.name;
19736
19829
  const functionArgs = JSON.parse(toolCall.function.arguments);
19830
+ onProgress({
19831
+ content: '',
19832
+ modelName: 'assistant',
19833
+ timing: { start, complete: $getCurrentDate() },
19834
+ usage: UNCERTAIN_USAGE,
19835
+ rawPromptContent,
19836
+ rawRequest: null,
19837
+ rawResponse: null,
19838
+ toolCalls: [
19839
+ {
19840
+ name: functionName,
19841
+ arguments: toolCall.function.arguments,
19842
+ result: '',
19843
+ rawToolCall: toolCall,
19844
+ },
19845
+ ],
19846
+ });
19737
19847
  if (this.options.isVerbose) {
19738
19848
  console.info(`🔧 Executing tool: ${functionName}`, functionArgs);
19739
19849
  }
@@ -19756,7 +19866,7 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
19756
19866
  const args = ${JSON.stringify(functionArgs)};
19757
19867
  return await ${functionName}(args);
19758
19868
  `,
19759
- parameters: {}, // <- TODO: [🧠] What parameters to pass?
19869
+ parameters: prompt.parameters,
19760
19870
  });
19761
19871
  if (this.options.isVerbose) {
19762
19872
  console.info(`✅ Tool ${functionName} executed:`, functionResponse);
@@ -20883,6 +20993,35 @@ class RemoteAgent extends Agent {
20883
20993
  doneReading = !!done;
20884
20994
  if (value) {
20885
20995
  const textChunk = decoder.decode(value, { stream: true });
20996
+ let isHandled = false;
20997
+ try {
20998
+ const lines = textChunk.split('\n');
20999
+ for (const line of lines) {
21000
+ const trimmedLine = line.trim();
21001
+ if (trimmedLine.startsWith('{') && trimmedLine.endsWith('}')) {
21002
+ const chunk = JSON.parse(trimmedLine);
21003
+ if (chunk.toolCalls) {
21004
+ onProgress({
21005
+ content,
21006
+ modelName: this.modelName,
21007
+ timing: {},
21008
+ usage: {},
21009
+ rawPromptContent: {},
21010
+ rawRequest: {},
21011
+ rawResponse: {},
21012
+ toolCalls: chunk.toolCalls,
21013
+ });
21014
+ isHandled = true;
21015
+ }
21016
+ }
21017
+ }
21018
+ }
21019
+ catch (error) {
21020
+ // Ignore non-json chunks
21021
+ }
21022
+ if (isHandled) {
21023
+ continue;
21024
+ }
20886
21025
  // console.debug('RemoteAgent chunk:', textChunk);
20887
21026
  content += textChunk;
20888
21027
  onProgress({