@peebles-group/agentlib-js 1.0.2 → 1.0.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peebles-group/agentlib-js",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "A minimal JavaScript library implementing concurrent async agents for illustrating multi-agent systems and other agentic design patterns including recursive ones purely through function calling loops.",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -20,7 +20,7 @@
20
20
  "js-yaml": "^4.1.0",
21
21
  "mongodb": "^6.20.0",
22
22
  "openai": "^5.16.0",
23
- "agentlib-js": "^1.0.0",
23
+ "@peebles-group/agentlib-js": "^1.0.0",
24
24
  "playwright": "^1.55.0",
25
25
  "prompt-sync": "^4.2.0",
26
26
  "sqlite": "^5.1.1",
package/src/Agent.js CHANGED
@@ -3,7 +3,7 @@ import { defaultModel } from "./config.js";
3
3
  import { MCPManager } from "./mcp/MCPManager.js";
4
4
 
5
5
  export class Agent {
6
- constructor(provider, apiKey, {model = defaultModel, tools = [], inputSchema = null, outputSchema = null, enableMCP = false} = {}) {
6
+ constructor(provider, apiKey, {model = defaultModel, tools = [], inputSchema = null, outputSchema = null, enableMCP = false, ...options} = {}) {
7
7
  this.llmService = new LLMService(provider, apiKey);
8
8
  this.model = model;
9
9
  this.nativeTools = tools;
@@ -11,6 +11,7 @@ export class Agent {
11
11
  this.outputSchema = outputSchema;
12
12
  this.mcpManager = enableMCP ? new MCPManager() : null;
13
13
  this.updateSystemPrompt();
14
+ this.options = options;
14
15
  }
15
16
 
16
17
  async addMCPServer(serverName, config) {
@@ -31,6 +32,34 @@ export class Agent {
31
32
  return result;
32
33
  }
33
34
 
35
+ addTool(tool) {
36
+ if (!tool || typeof tool !== 'object') {
37
+ throw new Error("Invalid tool: expected an object");
38
+ }
39
+ const { name, func } = tool;
40
+ if (typeof name !== 'string' || name.trim() === '') {
41
+ throw new Error("Invalid tool: missing valid 'name' (string)");
42
+ }
43
+ if (typeof func !== 'function') {
44
+ throw new Error("Invalid tool: missing 'func' (function)");
45
+ }
46
+
47
+ // Prevent name collisions across native and MCP tools
48
+ const nameExistsInNative = this.nativeTools.some(t => t && t.name === name);
49
+ const nameExistsInMCP = this.mcpManager ? this.mcpManager.getAllTools().some(t => t && t.name === name) : false;
50
+ if (nameExistsInNative || nameExistsInMCP) {
51
+ throw new Error(`Tool with name '${name}' already exists`);
52
+ }
53
+
54
+ if (typeof tool.description !== 'string') {
55
+ tool.description = '';
56
+ }
57
+
58
+ this.nativeTools.push(tool);
59
+ this.updateSystemPrompt();
60
+ return tool;
61
+ }
62
+
34
63
  getAllTools() {
35
64
  const mcpTools = this.mcpManager ? this.mcpManager.getAllTools() : [];
36
65
  return [...this.nativeTools, ...mcpTools];
@@ -63,27 +92,29 @@ export class Agent {
63
92
  */
64
93
  async run() {
65
94
  const allTools = this.getAllTools();
95
+ const executed = []
66
96
 
67
97
  // Step 1: send input to model
68
98
  let response = await this.llmService.chat(this.input, {
69
99
  model: this.model,
70
100
  outputSchema: this.outputSchema,
71
101
  tools: allTools,
102
+ ...this.options,
72
103
  });
73
104
 
74
105
  const { output, rawResponse } = response;
75
106
 
76
107
  // Step 2: Clean and add the response to input history
77
- // Remove parsed_arguments (if it exists) from function calls before adding to history
78
- const cleanedOutput = rawResponse.output.map(item => {
79
- if (item.type === "function_call" && item.parsed_arguments) {
80
- const { parsed_arguments, ...cleanItem } = item;
81
- return cleanItem;
108
+ rawResponse.output.forEach(item => {
109
+ if (item.type === "function_call") {
110
+ // Remove parsed_arguments if it exists
111
+ const { parsed_arguments, ...rest } = item;
112
+ const cleanedItem = { ...rest, arguments: JSON.stringify(item.arguments) };
113
+ this.addInput(cleanedItem);
114
+ } else {
115
+ this.addInput(item);
82
116
  }
83
- return item;
84
117
  });
85
-
86
- this.input = this.input.concat(cleanedOutput);
87
118
 
88
119
  // Step 3: collect all function calls
89
120
  const functionCalls = rawResponse.output.filter(item => item.type === "function_call");
@@ -91,12 +122,9 @@ export class Agent {
91
122
  if (functionCalls.length > 0) {
92
123
  for (const call of functionCalls) {
93
124
  let args;
94
- try {
95
- args = JSON.parse(call.arguments);
96
- } catch (err) {
97
- console.error("Failed to parse function call arguments:", call.arguments);
98
- continue;
99
- }
125
+ args = JSON.parse(call.arguments);
126
+ call.arguments = args
127
+ executed.push(call)
100
128
 
101
129
  const tool = allTools.find(t => t.name === call.name);
102
130
  if (!tool || !tool.func) {
@@ -113,7 +141,7 @@ export class Agent {
113
141
  output: JSON.stringify(result),
114
142
  });
115
143
  }
116
-
144
+
117
145
  // Step 6: send updated input back to model for final response
118
146
  response = await this.llmService.chat(this.input, {
119
147
  tools: allTools,
@@ -121,6 +149,7 @@ export class Agent {
121
149
  outputSchema: this.outputSchema,
122
150
  });
123
151
  }
152
+ response.executed = executed;
124
153
  return response;
125
154
  }
126
155
 
package/src/config.js CHANGED
@@ -1 +1 @@
1
- export const defaultModel = 'gpt-4o-mini';
1
+ export const defaultModel = 'gpt-5';