goblin-agents 3.2.0 → 3.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.
@@ -0,0 +1,4 @@
1
+ const {Elf} = require('xcraft-core-goblin');
2
+ const {ContextCache, ContextCacheLogic} = require('./lib/contextCache.js');
3
+
4
+ exports.xcraftCommands = Elf.birth(ContextCache, ContextCacheLogic);
@@ -0,0 +1,69 @@
1
+ // @ts-check
2
+ const {Elf} = require('xcraft-core-goblin');
3
+ const {record, string} = require('xcraft-core-stones');
4
+
5
+ class ContextCacheShape {
6
+ id = string;
7
+ contexts = record(string, string);
8
+ }
9
+
10
+ class ContextCacheState extends Elf.Sculpt(ContextCacheShape) {}
11
+
12
+ class ContextCacheLogic extends Elf.Spirit {
13
+ state = new ContextCacheState({
14
+ id: 'contextCache',
15
+ contexts: {},
16
+ });
17
+
18
+ append(contextId, markdown) {
19
+ const current = this.state.contexts[contextId] || '';
20
+ this.state.contexts[contextId] = current + markdown;
21
+ }
22
+
23
+ clear(contextId) {
24
+ delete this.state.contexts[contextId];
25
+ }
26
+ }
27
+
28
+ class ContextCache extends Elf.Alone {
29
+ logic = Elf.getLogic(ContextCacheLogic);
30
+ state = new ContextCacheState();
31
+
32
+ async init() {
33
+ return this;
34
+ }
35
+
36
+ async append(contextId, markdown) {
37
+ if (typeof contextId !== 'string') {
38
+ throw new TypeError('contextId must be a string');
39
+ }
40
+ if (typeof markdown !== 'string') {
41
+ throw new TypeError('markdown must be a string');
42
+ }
43
+
44
+ this.logic.append(contextId, markdown);
45
+ }
46
+
47
+ async read(contextId) {
48
+ if (typeof contextId !== 'string') {
49
+ throw new TypeError('contextId must be a string');
50
+ }
51
+
52
+ return this.state.contexts[contextId] || '';
53
+ }
54
+
55
+ async clear(contextId) {
56
+ if (typeof contextId !== 'string') {
57
+ throw new TypeError('contextId must be a string');
58
+ }
59
+
60
+ this.logic.clear(contextId);
61
+ }
62
+ }
63
+
64
+ module.exports = {
65
+ ContextCache,
66
+ ContextCacheLogic,
67
+ ContextCacheShape,
68
+ ContextCacheState,
69
+ };
@@ -497,8 +497,8 @@ class AiAgent extends Elf {
497
497
  return cleanText(res);
498
498
  }
499
499
 
500
- async reset(contextId, save = false) {
501
- if (!contextId) {
500
+ async reset(contextId = null, save = false) {
501
+ if (contextId === null) {
502
502
  for (const contextId of Object.keys(this.state.messages)) {
503
503
  await this.reset(contextId);
504
504
  }
@@ -770,7 +770,7 @@ ${context}
770
770
 
771
771
  async callTools(contextId, message, userDesktopId) {
772
772
  const {tool_calls} = message;
773
- if (!tool_calls || !userDesktopId) {
773
+ if (!tool_calls?.length || !userDesktopId) {
774
774
  return false;
775
775
  }
776
776
  this.logic.callTools(contextId, tool_calls);
@@ -780,20 +780,19 @@ ${context}
780
780
  function: {name},
781
781
  } = tool;
782
782
 
783
- let result = '';
784
- let toolArguments = {};
785
- if (
786
- tool.function.arguments &&
787
- typeof tool.function.arguments === 'string'
788
- ) {
789
- toolArguments = JSON.parse(tool.function.arguments);
790
- } else if (
791
- tool.function.arguments &&
792
- typeof tool.function.arguments === 'object'
793
- ) {
794
- toolArguments = tool.function.arguments;
795
- }
796
783
  try {
784
+ let toolArguments = {};
785
+ if (
786
+ tool.function.arguments &&
787
+ typeof tool.function.arguments === 'string'
788
+ ) {
789
+ toolArguments = JSON.parse(tool.function.arguments);
790
+ } else if (
791
+ tool.function.arguments &&
792
+ typeof tool.function.arguments === 'object'
793
+ ) {
794
+ toolArguments = tool.function.arguments;
795
+ }
797
796
  const payload = {
798
797
  id: this.state.toolServiceId,
799
798
  desktopId: userDesktopId,
@@ -803,10 +802,18 @@ ${context}
803
802
  const toolNamespace = this.state.toolServiceId?.split('@', 1)[0];
804
803
  const toolCmd = `${toolNamespace}.${name}`;
805
804
  this.log.dbg(`🔧 Tool call: ${toolCmd}(${JSON.stringify(payload)})`);
806
- result = await this.quest.cmd(toolCmd, payload);
807
- await this.addToolMessage(contextId, id, name, result);
805
+ const result = await this.quest.cmd(toolCmd, payload);
806
+ const content =
807
+ typeof result === 'string' ? result : JSON.stringify(result ?? null);
808
+ await this.addToolMessage(contextId, id, name, content);
808
809
  } catch (err) {
809
810
  this.log.dbg(`🔧 Tool error : ${err.message}`);
811
+ await this.addToolMessage(
812
+ contextId,
813
+ id,
814
+ name,
815
+ JSON.stringify({status: 'error', message: err.message})
816
+ );
810
817
  }
811
818
  }
812
819
  return true;
package/lib/llm/utils.js CHANGED
@@ -49,6 +49,9 @@ const getPDFImages = async (pdfPath, pagesToProcess) => {
49
49
  };
50
50
 
51
51
  const cleanHtmlContent = (html) => {
52
+ if (typeof html !== 'string') {
53
+ return '';
54
+ }
52
55
  const decodedHtml = HtmlEntities.decode(html);
53
56
  const textOnly = decodedHtml.replace(/<[^>]+>/g, '');
54
57
  const cleanedText = textOnly.replace(/\s+/g, ' ').trim();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "goblin-agents",
3
- "version": "3.2.0",
3
+ "version": "3.3.0",
4
4
  "description": "AI Agents framework",
5
5
  "author": "Epsitec SA",
6
6
  "contributors": [