sis-tools 0.1.0 → 0.1.2
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 +311 -0
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
# sis-tools (Node.js)
|
|
2
|
+
|
|
3
|
+
Semantic Integration System (SIS) is a tool-resolution layer that uses embeddings to select the most relevant tools for a query at runtime.
|
|
4
|
+
|
|
5
|
+
Instead of sending every tool schema to an LLM up front, you resolve the top-k tools for the user’s query and only inject the relevant schemas.
|
|
6
|
+
|
|
7
|
+
## Why SIS?
|
|
8
|
+
|
|
9
|
+
- **Context savings**: Only send relevant tool schemas to the LLM
|
|
10
|
+
- **Scalability**: Register hundreds of tools without bloating context
|
|
11
|
+
- **Semantic matching**: Uses embeddings to find tools by intent, not keywords
|
|
12
|
+
- **Flexible**: Works with OpenAI, Anthropic, Google, Cohere, and custom providers
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install sis-tools
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
SIS supports optional embedding providers. Install only what you use:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install openai # OpenAI embeddings
|
|
24
|
+
npm install @google/generative-ai # Google embeddings
|
|
25
|
+
npm install cohere-ai # Cohere embeddings
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quick start
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import { SIS } from "sis-tools";
|
|
32
|
+
|
|
33
|
+
const sis = new SIS({
|
|
34
|
+
embeddingProvider: "openai",
|
|
35
|
+
providerOptions: {
|
|
36
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
37
|
+
},
|
|
38
|
+
defaultTopK: 5,
|
|
39
|
+
defaultThreshold: 0.3,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
sis.register({
|
|
43
|
+
name: "web_search",
|
|
44
|
+
description: "Search the web for current information",
|
|
45
|
+
parameters: { query: { type: "string" } },
|
|
46
|
+
semanticHints: ["google", "lookup", "find online"],
|
|
47
|
+
handler: async ({ query }) => {
|
|
48
|
+
// your implementation
|
|
49
|
+
return String(query);
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
await sis.initialize();
|
|
54
|
+
|
|
55
|
+
const tools = await sis.resolve("search for latest news");
|
|
56
|
+
// tools: [{ name, schema, score, handler? }, ...]
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Configuration
|
|
60
|
+
|
|
61
|
+
### Constructor options
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
interface SISOptions {
|
|
65
|
+
embeddingProvider?: "openai" | "cohere" | "google" | EmbeddingProvider;
|
|
66
|
+
providerOptions?: {
|
|
67
|
+
apiKey?: string;
|
|
68
|
+
model?: string;
|
|
69
|
+
dimensions?: number;
|
|
70
|
+
[key: string]: unknown;
|
|
71
|
+
};
|
|
72
|
+
defaultTopK?: number; // default: 5
|
|
73
|
+
defaultThreshold?: number; // default: 0.3
|
|
74
|
+
similarity?: SimilarityFunction;
|
|
75
|
+
scoring?: ScoringFunction;
|
|
76
|
+
validators?: ValidatorRegistry;
|
|
77
|
+
validateOnRegister?: boolean;
|
|
78
|
+
validateOnExecute?: boolean;
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Tool registration
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
interface RegisterOptions {
|
|
86
|
+
name: string;
|
|
87
|
+
description: string;
|
|
88
|
+
parameters?: ToolParameters;
|
|
89
|
+
handler?: ToolHandler;
|
|
90
|
+
semanticHints?: string[];
|
|
91
|
+
examples?: ToolExample[];
|
|
92
|
+
metadata?: ToolMetadata;
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Resolve formats
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
await sis.resolve("query", { format: "openai" });
|
|
100
|
+
await sis.resolve("query", { format: "anthropic" });
|
|
101
|
+
await sis.resolve("query", { format: "raw" });
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Examples
|
|
105
|
+
|
|
106
|
+
### Use with OpenAI function calling
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
import { OpenAI } from "openai";
|
|
110
|
+
import { SIS } from "sis-tools";
|
|
111
|
+
|
|
112
|
+
const openai = new OpenAI();
|
|
113
|
+
const sis = new SIS({ embeddingProvider: "openai" });
|
|
114
|
+
|
|
115
|
+
sis.register({
|
|
116
|
+
name: "web_search",
|
|
117
|
+
description: "Search the web",
|
|
118
|
+
parameters: { query: { type: "string" } },
|
|
119
|
+
handler: async ({ query }) => searchApi(query),
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
await sis.initialize();
|
|
123
|
+
|
|
124
|
+
async function runAgent(userMessage: string) {
|
|
125
|
+
const tools = await sis.resolve(userMessage, { format: "openai" });
|
|
126
|
+
|
|
127
|
+
const response = await openai.chat.completions.create({
|
|
128
|
+
model: "gpt-4.1",
|
|
129
|
+
messages: [{ role: "user", content: userMessage }],
|
|
130
|
+
tools,
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
const toolCall = response.choices[0]?.message?.tool_calls?.[0];
|
|
134
|
+
if (toolCall) {
|
|
135
|
+
const result = await sis.execute(
|
|
136
|
+
toolCall.function.name,
|
|
137
|
+
JSON.parse(toolCall.function.arguments)
|
|
138
|
+
);
|
|
139
|
+
return result;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Use with Anthropic tool use
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
148
|
+
import { SIS } from "sis-tools";
|
|
149
|
+
|
|
150
|
+
const anthropic = new Anthropic();
|
|
151
|
+
const sis = new SIS({ embeddingProvider: "openai" });
|
|
152
|
+
|
|
153
|
+
await sis.initialize();
|
|
154
|
+
|
|
155
|
+
async function runAgent(userMessage: string) {
|
|
156
|
+
const tools = await sis.resolve(userMessage, { format: "anthropic" });
|
|
157
|
+
|
|
158
|
+
const response = await anthropic.messages.create({
|
|
159
|
+
model: "claude-3-5-sonnet-20241022",
|
|
160
|
+
max_tokens: 1024,
|
|
161
|
+
messages: [{ role: "user", content: userMessage }],
|
|
162
|
+
tools,
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
const toolUse = response.content.find((b) => b.type === "tool_use");
|
|
166
|
+
if (toolUse) {
|
|
167
|
+
const result = await sis.execute(toolUse.name, toolUse.input);
|
|
168
|
+
return result;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Bring your own embeddings
|
|
174
|
+
|
|
175
|
+
```ts
|
|
176
|
+
import { SIS } from "sis-tools";
|
|
177
|
+
import type { EmbeddingProvider } from "sis-tools";
|
|
178
|
+
|
|
179
|
+
class MyEmbeddings implements EmbeddingProvider {
|
|
180
|
+
readonly dimensions = 768;
|
|
181
|
+
|
|
182
|
+
async embed(text: string): Promise<number[]> {
|
|
183
|
+
const res = await fetch("https://my-embedding-service/embed", {
|
|
184
|
+
method: "POST",
|
|
185
|
+
headers: { "Content-Type": "application/json" },
|
|
186
|
+
body: JSON.stringify({ text }),
|
|
187
|
+
});
|
|
188
|
+
const { embedding } = await res.json();
|
|
189
|
+
return embedding;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
async embedBatch(texts: string[]): Promise<number[][]> {
|
|
193
|
+
const res = await fetch("https://my-embedding-service/embed-batch", {
|
|
194
|
+
method: "POST",
|
|
195
|
+
headers: { "Content-Type": "application/json" },
|
|
196
|
+
body: JSON.stringify({ texts }),
|
|
197
|
+
});
|
|
198
|
+
const { embeddings } = await res.json();
|
|
199
|
+
return embeddings;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const sis = new SIS({ embeddingProvider: new MyEmbeddings() });
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Custom scoring (priority boost)
|
|
207
|
+
|
|
208
|
+
```ts
|
|
209
|
+
import { SIS, PriorityScoring } from "sis-tools";
|
|
210
|
+
|
|
211
|
+
const sis = new SIS({
|
|
212
|
+
embeddingProvider: "openai",
|
|
213
|
+
scoring: new PriorityScoring(1.0),
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
sis.register({
|
|
217
|
+
name: "important_tool",
|
|
218
|
+
description: "An important tool",
|
|
219
|
+
metadata: { priority: 2.0 },
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
await sis.initialize();
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Validation on register/execute
|
|
226
|
+
|
|
227
|
+
```ts
|
|
228
|
+
import { SIS, createStrictValidator } from "sis-tools";
|
|
229
|
+
|
|
230
|
+
const sis = new SIS({
|
|
231
|
+
embeddingProvider: "openai",
|
|
232
|
+
validators: createStrictValidator(),
|
|
233
|
+
validateOnRegister: true,
|
|
234
|
+
validateOnExecute: true,
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
// Throws ValidationError if tool schema is invalid
|
|
238
|
+
sis.register({
|
|
239
|
+
name: "bad_tool",
|
|
240
|
+
description: "x", // too short
|
|
241
|
+
parameters: {},
|
|
242
|
+
});
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## API
|
|
246
|
+
|
|
247
|
+
### SIS
|
|
248
|
+
|
|
249
|
+
```ts
|
|
250
|
+
class SIS {
|
|
251
|
+
constructor(options: SISOptions)
|
|
252
|
+
|
|
253
|
+
register(options: RegisterOptions): Tool
|
|
254
|
+
store(options: StoreOptions): void
|
|
255
|
+
async initialize(): Promise<void>
|
|
256
|
+
|
|
257
|
+
async resolve(query: string, options?: ResolveOptions): Promise<ResolvedTool[]>
|
|
258
|
+
async resolveOne(query: string, threshold?: number): Promise<ResolvedTool | null>
|
|
259
|
+
|
|
260
|
+
async execute(toolName: string, params: object): Promise<unknown>
|
|
261
|
+
|
|
262
|
+
getTool(name: string): Tool | undefined
|
|
263
|
+
listTools(): string[]
|
|
264
|
+
get toolCount(): number
|
|
265
|
+
|
|
266
|
+
// Customization
|
|
267
|
+
get hooks(): HookRegistry
|
|
268
|
+
get validators(): ValidatorRegistry | undefined
|
|
269
|
+
get similarity(): SimilarityFunction
|
|
270
|
+
set similarity(fn: SimilarityFunction)
|
|
271
|
+
get scoring(): ScoringFunction
|
|
272
|
+
set scoring(fn: ScoringFunction)
|
|
273
|
+
registerHook(hook: Hook): void
|
|
274
|
+
unregisterHook(hook: Hook): boolean
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### ResolveOptions
|
|
279
|
+
|
|
280
|
+
```ts
|
|
281
|
+
interface ResolveOptions {
|
|
282
|
+
topK?: number;
|
|
283
|
+
threshold?: number;
|
|
284
|
+
format?: "raw" | "openai" | "anthropic" | string | ToolFormatter;
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## Troubleshooting
|
|
289
|
+
|
|
290
|
+
### Provider not found
|
|
291
|
+
|
|
292
|
+
If you see an error like `requires the openai package`, install the peer dependency:
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
npm install openai
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### No tools returned
|
|
299
|
+
|
|
300
|
+
- Lower `defaultThreshold` (try `0.0` to see all matches)
|
|
301
|
+
- Increase `defaultTopK`
|
|
302
|
+
- Check tool descriptions and `semanticHints` for clarity
|
|
303
|
+
|
|
304
|
+
### Slow initialization
|
|
305
|
+
|
|
306
|
+
- Use a faster embedding model (e.g., `text-embedding-3-small`)
|
|
307
|
+
- Consider caching embeddings or using a persistent vector store
|
|
308
|
+
|
|
309
|
+
## License
|
|
310
|
+
|
|
311
|
+
MIT
|