saico 2.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 wanderli-ai
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,398 @@
1
+ # Saico - Simple AI-agent Conversation Orchestrator
2
+
3
+ `Saico` is a minimal yet powerful JavaScript/Node.js library for managing AI conversations with hierarchical context, token-aware summarization, and **enterprise-grade tool calling capabilities**. It's designed to support complex nested conversations while maintaining clean summaries and parent context, making it ideal for AI agents, assistants, and customer support bots.
4
+
5
+ ---
6
+
7
+ ## โœจ Features
8
+
9
+ - ๐Ÿ“š **Hierarchical Conversations** โ€” Track parent-child chat contexts with summary propagation.
10
+ - ๐Ÿงต **Scoped Memory** โ€” Manage sub-conversations independently while maintaining parent relevance.
11
+ - ๐Ÿ” **Token-Aware Summarization** โ€” Automatically summarize message history based on token thresholds.
12
+ - ๐Ÿ’ฌ **Message-Level Metadata** โ€” Track reply state, summaries, and custom flags.
13
+ - ๐Ÿ› ๏ธ **OpenAI-Compatible Format** โ€” Built for seamless interaction with OpenAI-compatible APIs.
14
+ - ๐Ÿงฐ **Proxy-Based Interface** โ€” Interact with message history like an array, with extra powers.
15
+ - **๐Ÿš€ NEW: Tool Calls** โ€” Complete tool calling system with depth control, deferred execution, and safety features.
16
+
17
+ ---
18
+
19
+ ## ๐Ÿ”ง Tool Calls System
20
+
21
+ Saico now includes a sophisticated tool calling system with enterprise-grade safety and control features:
22
+
23
+ ### Key Features:
24
+ - **๐ŸŽ›๏ธ Depth Control** โ€” Prevent infinite recursion with configurable depth limits
25
+ - **๐Ÿ”„ Deferred Execution** โ€” Tool calls automatically defer and resume when depth limits reached
26
+ - **๐Ÿšซ Duplicate Protection** โ€” Identical tool calls blocked while active to prevent resource waste
27
+ - **โฑ๏ธ Timeout Handling** โ€” Configurable timeouts (default: 5s) with graceful failure
28
+ - **๐Ÿ” Repetition Prevention** โ€” Block excessive repeated tool calls (default: 20 max)
29
+ - **๐Ÿ“ฅ Message Queuing** โ€” Messages automatically queue when tool calls are pending
30
+ - **๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ Parent-Child Inheritance** โ€” Unresponded tool calls move from parent to child contexts
31
+
32
+ ---
33
+
34
+ ## ๐Ÿ“ฆ Installation
35
+
36
+ ```bash
37
+ npm install saico-ai-thread --save
38
+ ```
39
+
40
+ Or clone manually:
41
+
42
+ ```bash
43
+ git clone https://github.com/wanderli-ai/saico
44
+ cd saico
45
+ ```
46
+
47
+ ---
48
+
49
+ ## ๐Ÿง‘โ€๐Ÿ’ป Usage
50
+
51
+ ### Basic Setup with Tool Handler
52
+
53
+ ```js
54
+ const { createQ } = require('saico');
55
+
56
+ // Define your tool handler
57
+ async function toolHandler(toolName, argumentsString) {
58
+ const args = JSON.parse(argumentsString);
59
+
60
+ switch (toolName) {
61
+ case 'get_weather':
62
+ return `Weather in ${args.location}: 72ยฐF, sunny`;
63
+ case 'book_hotel':
64
+ return `Booked ${args.hotel} for ${args.nights} nights`;
65
+ default:
66
+ return 'Tool not found';
67
+ }
68
+ }
69
+
70
+ // Create conversation with tool support
71
+ const q = createQ(
72
+ "You are a helpful assistant.", // prompt
73
+ null, // parent (null for root)
74
+ "main", // tag
75
+ 4000, // token limit
76
+ null, // initial messages
77
+ toolHandler, // tool handler function
78
+ { max_depth: 5, max_tool_repetition: 20 } // config
79
+ );
80
+
81
+ // Send a message that might trigger tool calls
82
+ await q.sendMessage('user', 'What\'s the weather in New York?');
83
+ ```
84
+
85
+ ### Create a Sub-Conversation with Tool Inheritance
86
+
87
+ ```js
88
+ const subQ = q.spawnChild(
89
+ "Now focus only on hotel bookings.", // prompt
90
+ "hotels", // tag
91
+ null, // token limit (inherits from parent)
92
+ null, // initial messages
93
+ null, // tool handler (inherits from parent)
94
+ { max_depth: 3 } // custom config
95
+ );
96
+
97
+ await subQ.sendMessage('user', 'Book me something in Rome.');
98
+ await subQ.close(); // Automatically summarizes and passes back to parent
99
+ ```
100
+
101
+ ### Advanced Tool Configuration
102
+
103
+ ```js
104
+ const q = createQ(
105
+ "You are a travel assistant.",
106
+ null,
107
+ "travel",
108
+ 8000,
109
+ null,
110
+ toolHandler,
111
+ {
112
+ max_depth: 8, // Allow deeper tool call chains
113
+ max_tool_repetition: 10 // Be more strict about repetitions
114
+ }
115
+ );
116
+
117
+ // Send message with custom tool options
118
+ await q.sendMessage('user', 'Plan my trip', null, {
119
+ handler: customToolHandler, // Override default tool handler
120
+ timeout: 10000, // 10 second timeout for this message's tools
121
+ nofunc: false // Ensure tool calls are enabled
122
+ });
123
+ ```
124
+
125
+ ### Hierarchy Example with Tool Calls
126
+
127
+ ```text
128
+ [Main] (toolHandler: generalTools)
129
+ โ”œโ”€โ”€ [hotels] (inherits generalTools) โžœ tool calls + summary returned to [Main]
130
+ โ””โ”€โ”€ [flights] (inherits generalTools) โžœ tool calls + summary returned to [Main]
131
+ ```
132
+
133
+ ---
134
+
135
+ ## ๐Ÿง  Enhanced Message API
136
+
137
+ Each message is stored with enhanced tool call support:
138
+
139
+ ```js
140
+ {
141
+ msg: {
142
+ role, // 'user', 'assistant', 'tool', 'system'
143
+ content, // Message content
144
+ name?, // Optional name for user/tool messages
145
+ tool_calls?, // Array of tool calls from assistant
146
+ tool_call_id? // ID linking tool responses to calls
147
+ },
148
+ opts: {
149
+ summary?, // Is this a summary message?
150
+ noreply?, // Skip AI reply for this message
151
+ nofunc?, // Disable tool calls for this message
152
+ handler?, // Custom tool handler override
153
+ timeout? // Custom timeout for tool calls
154
+ },
155
+ msgid: String, // Unique message identifier
156
+ replied: 0 | 1 | 3 // 0=pending, 1=user sent, 3=AI replied
157
+ }
158
+ ```
159
+
160
+ ### Enhanced API Methods
161
+
162
+ * `q[0]` โ€” Access nth message
163
+ * `q.length` โ€” Total messages
164
+ * `q.pushSummary(summary)` โ€” Manually inject a summary
165
+ * `q.getMsgContext()` โ€” Get summarized parent chain
166
+ * `q.serialize()` โ€” Export current state
167
+ * **NEW**: `q._hasPendingToolCalls()` โ€” Check for pending tool executions
168
+ * **NEW**: `q._processWaitingQueue()` โ€” Manually process queued messages
169
+
170
+ ---
171
+
172
+ ## ๐Ÿ›ก๏ธ Tool Call Safety Features
173
+
174
+ ### Depth Control & Deferred Execution
175
+ ```js
176
+ const q = createQ("Assistant", null, "main", 4000, null, toolHandler, {
177
+ max_depth: 3 // Tool calls defer at depth 4+
178
+ });
179
+
180
+ // When max depth reached:
181
+ // 1. Tool calls are deferred (not executed immediately)
182
+ // 2. Conversation continues normally
183
+ // 3. Deferred tools execute when depth reduces
184
+ // 4. Results are seamlessly integrated back
185
+ ```
186
+
187
+ ### Repetition Prevention
188
+ ```js
189
+ const q = createQ("Assistant", null, "main", 4000, null, toolHandler, {
190
+ max_tool_repetition: 5 // Block tools called >5 times consecutively
191
+ });
192
+
193
+ // Automatically filters excessive repeated tool calls
194
+ // Logs: "Dropping excessive tool call: get_weather (hit max_tool_repetition=5)"
195
+ ```
196
+
197
+ ### Duplicate Detection
198
+ ```js
199
+ // If two identical tool calls (same name + arguments) are active:
200
+ // Second call returns: "Duplicate call detected. Please wait for previous call to complete."
201
+ ```
202
+
203
+ ### Timeout Handling
204
+ ```js
205
+ // Tool calls automatically timeout (default: 5s)
206
+ // Returns: "Tool call 'slow_function' timed out after 5 seconds"
207
+
208
+ // Custom timeout per message:
209
+ await q.sendMessage('user', 'Run slow analysis', null, { timeout: 30000 });
210
+ ```
211
+
212
+ ---
213
+
214
+ ## ๐Ÿงช Summary Behavior
215
+
216
+ Summaries trigger when total token count exceeds 85% of the limit and are always triggered when `close()` is called.
217
+ Summaries are:
218
+
219
+ * Injected as special `[SUMMARY]: ...` messages
220
+ * Bubbled up into the parent context
221
+ * Excluded from re-summarization unless explicitly kept
222
+ * **NEW**: Include tool call results in summarization context
223
+
224
+ ---
225
+
226
+ ## ๐Ÿ”„ Redis Integration (Persistent Observable State)
227
+
228
+ This library includes an optional Redis-based persistence layer to automatically store and update conversation objects (or any JS object) using a **proxy-based observable**.
229
+
230
+ It supports:
231
+
232
+ * ๐Ÿ”„ **Auto-saving on change** (with debounce)
233
+ * ๐Ÿง  **Selective serialization** (skips internal/private `_` properties)
234
+ * ๐Ÿ—ƒ๏ธ **Support for serializing `Messages` class**
235
+ * ๐Ÿ” **Efficient diff-checking** (saves only when changed)
236
+ * **NEW**: **Tool call state persistence** (active calls, deferred calls, waiting queues)
237
+
238
+ ### ๐Ÿ”ง Setup
239
+
240
+ 1. Install `redis`:
241
+
242
+ ```bash
243
+ npm install redis
244
+ ```
245
+
246
+ 2. Initialize Redis:
247
+
248
+ ```js
249
+ const { init, createObservableForRedis } = require('./redis-store');
250
+ await init(); // connects to redis://localhost:6379
251
+ ```
252
+
253
+ 3. Wrap a tool-enabled conversation:
254
+
255
+ ```js
256
+ const { createQ } = require('./saico');
257
+ const q = createQ("Travel assistant", null, "flights", 3000, null, toolHandler);
258
+
259
+ // Wrap with Redis observable - tool states auto-persist
260
+ const obsQ = createObservableForRedis("q:session:12345", q);
261
+ ```
262
+
263
+ Now, any changes to `obsQ` including tool call states, deferred calls, and message queues are **automatically saved** to Redis.
264
+
265
+ ---
266
+
267
+ ## ๐Ÿงผ Auto-Sanitization Rules
268
+
269
+ When saving to Redis:
270
+
271
+ * All keys starting with `_` are ignored.
272
+ * Custom `.serialize()` methods (like on `Messages`) are respected.
273
+ * Object updates are **debounced (1s)** and only saved if actual changes are detected.
274
+ * **NEW**: Tool call tracking data is sanitized automatically
275
+
276
+ ---
277
+
278
+ ## ๐Ÿ”Œ OpenAI Integration
279
+
280
+ This library supports the modern OpenAI Tools API:
281
+
282
+ * **NEW**: Native `tool_calls` support (OpenAI's current standard)
283
+ * Backward compatibility with legacy `functions` format
284
+ * Automatic format conversion in openai.js
285
+ * Built-in retry logic with exponential backoff for rate limits
286
+
287
+ ```js
288
+ // OpenAI will return tool_calls in responses:
289
+ {
290
+ role: 'assistant',
291
+ content: 'I need to check the weather',
292
+ tool_calls: [{
293
+ id: 'call_abc123',
294
+ type: 'function',
295
+ function: {
296
+ name: 'get_weather',
297
+ arguments: '{"location": "New York"}'
298
+ }
299
+ }]
300
+ }
301
+
302
+ // Saico handles the complete tool execution cycle automatically
303
+ ```
304
+
305
+ ---
306
+
307
+ ## ๐Ÿงช Testing
308
+
309
+ Comprehensive test suite with **37 tests** covering:
310
+
311
+ * Core conversation management (25 tests)
312
+ * **NEW**: Tool calls functionality (12 tests):
313
+ - Basic tool execution
314
+ - Depth limits and deferred execution
315
+ - Repetition prevention and filtering
316
+ - Duplicate detection
317
+ - Message queuing systems
318
+ - Timeout handling
319
+ - Parent-child tool inheritance
320
+
321
+ ```bash
322
+ npm test # Run full test suite
323
+ ```
324
+
325
+ ---
326
+
327
+ ## ๐Ÿ“ Project Structure
328
+
329
+ ```
330
+ .
331
+ โ”œโ”€โ”€ saico.js # Core implementation with tool calls
332
+ โ”œโ”€โ”€ openai.js # OpenAI API wrapper with tools support
333
+ โ”œโ”€โ”€ redis.js # Saico compatible redis wrapper
334
+ โ”œโ”€โ”€ util.js # Utilities: token counting, etc.
335
+ โ”œโ”€โ”€ test.js # Comprehensive test suite
336
+ โ”œโ”€โ”€ msgs.js # Original enhanced version (reference)
337
+ โ””โ”€โ”€ README.md # This file
338
+ ```
339
+
340
+ ---
341
+
342
+ ## ๐Ÿš€ Migration Guide
343
+
344
+ If upgrading from older versions:
345
+
346
+ ### Old API:
347
+ ```js
348
+ const q = createQ(prompt, opts, msgs, parent);
349
+ ```
350
+
351
+ ### New API:
352
+ ```js
353
+ const q = createQ(prompt, parent, tag, token_limit, msgs, tool_handler, config);
354
+ ```
355
+
356
+ ### Breaking Changes:
357
+ - Constructor parameter order changed
358
+ - `opts.tag` โ†’ `tag` parameter
359
+ - `opts.token_limit` โ†’ `token_limit` parameter
360
+ - Added `tool_handler` and `config` parameters
361
+ - `function_call` โ†’ `tool_calls` in OpenAI responses
362
+
363
+ ---
364
+
365
+ ## ๐Ÿ” License
366
+
367
+ MIT License ยฉ [Wanderli.ai]
368
+
369
+ ---
370
+
371
+ ## ๐Ÿ™Œ Contributing
372
+
373
+ Pull requests, issues, and suggestions welcome! Please fork the repo and open a PR, or submit issues directly.
374
+
375
+ Areas where contributions are especially welcome:
376
+ - Additional tool call safety features
377
+ - Performance optimizations for large conversations
378
+ - Extended test coverage
379
+ - Documentation improvements
380
+
381
+ ---
382
+
383
+ ## ๐Ÿ“ฃ Acknowledgements
384
+
385
+ This project was inspired by the need for a lightweight, non-opinionated alternative to LangChain's memory modules, with full support for real-world LLM conversation flows and enterprise-grade tool calling capabilities.
386
+
387
+ ---
388
+
389
+ ## ๐Ÿ”ฎ Roadmap
390
+
391
+ - [ ] **Multi-model support** (Anthropic, Google, etc.)
392
+ - [ ] **Advanced tool call analytics** and monitoring
393
+ - [ ] **Custom summarization strategies**
394
+ - [ ] **Tool call result caching**
395
+ - [ ] **Streaming tool call responses**
396
+ - [ ] **Tool call permission systems**
397
+
398
+ Let me know if you'd like to see any of these features prioritized!