@p-sw/brainbox 0.1.2-alpha.12 → 0.1.2-alpha.13

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.
Files changed (2) hide show
  1. package/dist/index.js +69 -69
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -597,6 +597,42 @@ function readAuthString(auth, key, envName) {
597
597
  }
598
598
 
599
599
  class LLMExecutor {
600
+ async chatWithToolExecution(model, options) {
601
+ const messages = options.messages.slice();
602
+ const maxSteps = options.maxSteps ?? 20;
603
+ let last;
604
+ for (let step = 0;step < maxSteps; step += 1) {
605
+ log2.debug(`chatWithToolExecution: step ${step + 1}/${maxSteps} msgs=${messages.length}`);
606
+ last = await this.chatWithTools(model, {
607
+ instruction: options.instruction,
608
+ messages,
609
+ tools: options.tools,
610
+ caller: options.caller,
611
+ reasoningEffort: options.reasoningEffort,
612
+ parallelToolCalls: options.parallelToolCalls,
613
+ toolChoice: options.toolChoice
614
+ });
615
+ const toolCalls = last.message.toolCalls ?? [];
616
+ log2.debug(`chatWithToolExecution: step ${step + 1} toolCalls=${toolCalls.length}`);
617
+ if (toolCalls.length === 0)
618
+ return last;
619
+ messages.push({
620
+ role: "assistant",
621
+ content: last.message.content,
622
+ toolCalls
623
+ });
624
+ for (const call of toolCalls) {
625
+ const content = await options.executeTool(call);
626
+ messages.push({
627
+ role: "tool",
628
+ toolCallId: call.id,
629
+ content
630
+ });
631
+ }
632
+ }
633
+ log2.warn(`chatWithToolExecution: reached maxSteps (${maxSteps}) without final reply`);
634
+ return last;
635
+ }
600
636
  static providers = [];
601
637
  static registerProvider(p) {
602
638
  LLMExecutor.providers.push(p);
@@ -3141,75 +3177,46 @@ class Brain {
3141
3177
  content: userPrompt
3142
3178
  }
3143
3179
  ];
3144
- for (let step = 0;step < maxSteps; step += 1) {
3145
- log7.debug(`sendMessage: step ${step + 1}/${maxSteps} → model`);
3146
- let choice;
3147
- try {
3148
- choice = await llm.chatWithTools(llm.models.conversation, {
3149
- caller: initiate ? "start-conversation" : "send-message",
3150
- instruction: `${this.brainbase.baseSystemPrompt}
3180
+ try {
3181
+ await llm.chatWithToolExecution(llm.models.conversation, {
3182
+ caller: initiate ? "start-conversation" : "send-message",
3183
+ instruction: `${this.brainbase.baseSystemPrompt}
3151
3184
 
3152
3185
  ${instruction}`,
3153
- messages,
3154
- tools
3155
- });
3156
- } catch (error) {
3157
- const reason = error instanceof Error ? error.message : String(error);
3158
- logger.error(`sendMessage: LLM call failed at step ${step}: ${reason}`);
3159
- return replyMessages;
3160
- }
3161
- const assistantMessage = choice.message;
3162
- const toolCalls = assistantMessage.toolCalls ?? [];
3163
- const hasContent = typeof assistantMessage.content === "string" && assistantMessage.content.length > 0;
3164
- log7.debug(`sendMessage: step ${step + 1} → toolCalls=${toolCalls.length} hasContent=${hasContent}`);
3165
- if (toolCalls.length === 0) {
3166
- log7.debug(`sendMessage: model returned no tool calls; finalising with ${replyMessages.length} replies`);
3167
- return replyMessages;
3168
- }
3169
- messages.push(stripAssistantForHistory(assistantMessage));
3170
- for (const call of toolCalls) {
3171
- if (call.function.name === "addReplyMessage") {
3172
- const content = parseAddReplyMessageArguments(call.function.arguments);
3173
- if (content !== null) {
3174
- log7.debug(`sendMessage: addReplyMessage[${replyMessages.length}] (${content.length} chars)`);
3175
- send(content);
3176
- replyMessages.push(content);
3177
- } else {
3186
+ messages,
3187
+ tools,
3188
+ maxSteps,
3189
+ executeTool: async (call) => {
3190
+ if (call.function.name === "addReplyMessage") {
3191
+ const content = parseAddReplyMessageArguments(call.function.arguments);
3192
+ if (content !== null) {
3193
+ log7.debug(`sendMessage: addReplyMessage[${replyMessages.length}] (${content.length} chars)`);
3194
+ await send(content);
3195
+ replyMessages.push(content);
3196
+ return JSON.stringify({
3197
+ ok: true,
3198
+ index: replyMessages.length - 1
3199
+ });
3200
+ }
3178
3201
  log7.debug(`sendMessage: addReplyMessage rejected (invalid arguments: ${call.function.arguments})`);
3202
+ return JSON.stringify({ ok: false, error: "invalid arguments" });
3179
3203
  }
3180
- messages.push({
3181
- role: "tool",
3182
- toolCallId: call.id,
3183
- content: content === null ? JSON.stringify({ ok: false, error: "invalid arguments" }) : JSON.stringify({ ok: true, index: replyMessages.length - 1 })
3184
- });
3185
- continue;
3186
- }
3187
- if (call.function.name === "searchMemory") {
3188
- log7.debug(`sendMessage: searchMemory tool call`);
3189
- const result = await this.executeSearchTool(call.function.arguments);
3190
- messages.push({
3191
- role: "tool",
3192
- toolCallId: call.id,
3193
- content: result
3194
- });
3195
- continue;
3196
- }
3197
- log7.debug(`sendMessage: unknown tool "${call.function.name}"`);
3198
- messages.push({
3199
- role: "tool",
3200
- toolCallId: call.id,
3201
- content: JSON.stringify({
3204
+ if (call.function.name === "searchMemory") {
3205
+ log7.debug(`sendMessage: searchMemory tool call`);
3206
+ return this.executeSearchTool(call.function.arguments);
3207
+ }
3208
+ log7.debug(`sendMessage: unknown tool "${call.function.name}"`);
3209
+ return JSON.stringify({
3202
3210
  ok: false,
3203
3211
  error: `Unknown tool: ${call.function.name}`
3204
- })
3205
- });
3206
- }
3207
- if (!hasContent && toolCalls.every((c) => c.function.name === "searchMemory")) {
3208
- log7.debug(`sendMessage: step was pure searchMemory, looping back`);
3209
- continue;
3210
- }
3212
+ });
3213
+ }
3214
+ });
3215
+ } catch (error) {
3216
+ const reason = error instanceof Error ? error.message : String(error);
3217
+ logger.error(`sendMessage: LLM call failed: ${reason}`);
3211
3218
  }
3212
- logger.warn(`sendMessage: reached maxSteps (${maxSteps}) without final reply`);
3219
+ log7.debug(`sendMessage: done with ${replyMessages.length} replies`);
3213
3220
  return replyMessages;
3214
3221
  }
3215
3222
  async buildMemoryBlock() {
@@ -3461,13 +3468,6 @@ function parseSearchArguments(json) {
3461
3468
  }
3462
3469
  return null;
3463
3470
  }
3464
- function stripAssistantForHistory(message) {
3465
- return {
3466
- role: "assistant",
3467
- content: message.content,
3468
- toolCalls: message.toolCalls
3469
- };
3470
- }
3471
3471
 
3472
3472
  // src/channel/discord.ts
3473
3473
  import {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@p-sw/brainbox",
3
- "version": "0.1.2-alpha.12",
3
+ "version": "0.1.2-alpha.13",
4
4
  "module": "dist/index.js",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",