@syncagent/js 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 +149 -25
- package/dist/index.js +14 -5
- package/dist/index.mjs +14 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @syncagent/js
|
|
2
2
|
|
|
3
|
-
Core JavaScript SDK for SyncAgent — add an AI database agent to any app.
|
|
3
|
+
Core JavaScript/TypeScript SDK for [SyncAgent](https://syncagent.dev) — add an AI database agent to any app.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -8,53 +8,177 @@ Core JavaScript SDK for SyncAgent — add an AI database agent to any app.
|
|
|
8
8
|
npm install @syncagent/js
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Quick Start
|
|
12
12
|
|
|
13
13
|
```typescript
|
|
14
14
|
import { SyncAgentClient } from "@syncagent/js";
|
|
15
15
|
|
|
16
16
|
const agent = new SyncAgentClient({
|
|
17
17
|
apiKey: "sa_your_api_key",
|
|
18
|
-
|
|
19
|
-
connectionString: process.env.DATABASE_URL, // your DB — never stored on our servers
|
|
18
|
+
connectionString: process.env.DATABASE_URL, // never stored on SyncAgent servers
|
|
20
19
|
});
|
|
21
20
|
|
|
22
|
-
// Streaming
|
|
21
|
+
// Streaming
|
|
23
22
|
await agent.chat(
|
|
24
23
|
[{ role: "user", content: "Show me all active users" }],
|
|
25
24
|
{
|
|
26
25
|
onToken: (token) => process.stdout.write(token),
|
|
27
|
-
onComplete: (text) => console.log("\
|
|
26
|
+
onComplete: (text) => console.log("\nDone"),
|
|
28
27
|
}
|
|
29
28
|
);
|
|
30
29
|
|
|
31
|
-
// Non-streaming
|
|
32
|
-
const result = await agent.chat([
|
|
30
|
+
// Non-streaming (await full response)
|
|
31
|
+
const result = await agent.chat([
|
|
32
|
+
{ role: "user", content: "How many orders were placed this month?" }
|
|
33
|
+
]);
|
|
33
34
|
console.log(result.text);
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Configuration
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
new SyncAgentClient(config: SyncAgentConfig)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
| Option | Type | Required | Description |
|
|
44
|
+
| ------------------ | --------------------------------- | -------- | ------------------------------------------------ |
|
|
45
|
+
| `apiKey` | `string` | ✅ | Your SyncAgent API key (`sa_...`) |
|
|
46
|
+
| `connectionString` | `string` | ✅ | Your database URL — sent at runtime, never stored |
|
|
47
|
+
| `tools` | `Record<string, ToolDefinition>` | — | Custom tools the agent can call client-side |
|
|
34
48
|
|
|
35
|
-
|
|
49
|
+
## `client.chat(messages, options?)`
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
const result = await agent.chat(messages, options);
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**`messages`** — `Message[]`
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
{ role: "user" | "assistant"; content: string }
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**`options`** — `ChatOptions`
|
|
62
|
+
|
|
63
|
+
| Option | Type | Description |
|
|
64
|
+
| ------------ | ------------------------------------------------------- | ------------------------------------ |
|
|
65
|
+
| `onToken` | `(token: string) => void` | Called for each streamed text chunk |
|
|
66
|
+
| `onComplete` | `(text: string) => void` | Called with the full response text |
|
|
67
|
+
| `onError` | `(error: Error) => void` | Called on error |
|
|
68
|
+
| `onToolCall` | `(name: string, args: any, result: any) => void` | Called when a custom tool executes |
|
|
69
|
+
| `signal` | `AbortSignal` | Cancel the request |
|
|
70
|
+
|
|
71
|
+
**Returns** `Promise<ChatResult>` → `{ text: string }`
|
|
72
|
+
|
|
73
|
+
## `client.getSchema()`
|
|
74
|
+
|
|
75
|
+
Discovers and returns your database schema.
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
36
78
|
const schema = await agent.getSchema();
|
|
79
|
+
// schema: CollectionSchema[]
|
|
80
|
+
// [{ name: "users", fields: [{ name: "email", type: "string" }], documentCount: 1200 }]
|
|
37
81
|
```
|
|
38
82
|
|
|
39
|
-
##
|
|
83
|
+
## Custom Tools
|
|
40
84
|
|
|
41
|
-
|
|
85
|
+
Give the agent capabilities beyond your database — send emails, trigger webhooks, create invoices. Tools run entirely in your code; SyncAgent only sees the schema and the result you return.
|
|
42
86
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
| `apiKey` | string | ✅ | Your SyncAgent API key |
|
|
46
|
-
| `baseUrl` | string | ✅ | Your SyncAgent instance URL |
|
|
47
|
-
| `connectionString` | string | ✅ | Your database URL (sent at runtime, not stored) |
|
|
87
|
+
```typescript
|
|
88
|
+
import { SyncAgentClient } from "@syncagent/js";
|
|
48
89
|
|
|
49
|
-
|
|
90
|
+
const agent = new SyncAgentClient({
|
|
91
|
+
apiKey: "sa_your_api_key",
|
|
92
|
+
connectionString: process.env.DATABASE_URL,
|
|
93
|
+
tools: {
|
|
94
|
+
sendEmail: {
|
|
95
|
+
description: "Send an email to a user",
|
|
96
|
+
inputSchema: {
|
|
97
|
+
to: { type: "string", description: "Recipient email address" },
|
|
98
|
+
subject: { type: "string", description: "Email subject line" },
|
|
99
|
+
body: { type: "string", description: "Email body (plain text)" },
|
|
100
|
+
},
|
|
101
|
+
execute: async ({ to, subject, body }) => {
|
|
102
|
+
await mailer.send({ to, subject, text: body });
|
|
103
|
+
return { sent: true, to };
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
createInvoice: {
|
|
107
|
+
description: "Create a Stripe invoice for a customer",
|
|
108
|
+
inputSchema: {
|
|
109
|
+
customerId: { type: "string", description: "Stripe customer ID" },
|
|
110
|
+
amount: { type: "number", description: "Amount in cents" },
|
|
111
|
+
memo: { type: "string", description: "Invoice memo", required: false },
|
|
112
|
+
},
|
|
113
|
+
execute: async ({ customerId, amount, memo }) => {
|
|
114
|
+
const inv = await stripe.invoices.create({ customer: customerId, description: memo });
|
|
115
|
+
return { invoiceId: inv.id };
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// The agent can now query your DB AND call your tools
|
|
122
|
+
await agent.chat([
|
|
123
|
+
{ role: "user", content: "Find all users with expired subscriptions and email them" }
|
|
124
|
+
], {
|
|
125
|
+
onToolCall: (name, args, result) => console.log(`Tool called: ${name}`, result),
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Tool Definition
|
|
130
|
+
|
|
131
|
+
| Field | Type | Description |
|
|
132
|
+
| -------------------------- | ----------------------------------------------------------- | ------------------------------------------------ |
|
|
133
|
+
| `description` | `string` | What the tool does — the AI reads this |
|
|
134
|
+
| `inputSchema` | `Record<string, ToolParameter>` | Parameters the tool accepts |
|
|
135
|
+
| `inputSchema.*.type` | `"string" \| "number" \| "boolean" \| "object" \| "array"` | Parameter type |
|
|
136
|
+
| `inputSchema.*.description`| `string?` | Helps the AI know what value to pass |
|
|
137
|
+
| `inputSchema.*.required` | `boolean?` | Defaults to `true` — set `false` for optional |
|
|
138
|
+
| `inputSchema.*.enum` | `string[]?` | Restrict to specific values |
|
|
139
|
+
| `execute` | `(args) => any \| Promise<any>` | Your function — runs in your app, not on servers |
|
|
140
|
+
|
|
141
|
+
## Multi-turn Conversations
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
const messages: Message[] = [];
|
|
145
|
+
|
|
146
|
+
// Turn 1
|
|
147
|
+
messages.push({ role: "user", content: "Show me the top 5 customers by revenue" });
|
|
148
|
+
const r1 = await agent.chat(messages);
|
|
149
|
+
messages.push({ role: "assistant", content: r1.text });
|
|
50
150
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
151
|
+
// Turn 2
|
|
152
|
+
messages.push({ role: "user", content: "Now email all of them a thank-you note" });
|
|
153
|
+
const r2 = await agent.chat(messages);
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Abort / Cancel
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
const controller = new AbortController();
|
|
160
|
+
|
|
161
|
+
agent.chat(messages, { signal: controller.signal });
|
|
162
|
+
|
|
163
|
+
// Cancel at any time
|
|
164
|
+
controller.abort();
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## TypeScript Types
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
import type {
|
|
171
|
+
SyncAgentConfig,
|
|
172
|
+
Message,
|
|
173
|
+
ChatOptions,
|
|
174
|
+
ChatResult,
|
|
175
|
+
CollectionSchema,
|
|
176
|
+
SchemaField,
|
|
177
|
+
ToolDefinition,
|
|
178
|
+
ToolParameter,
|
|
179
|
+
} from "@syncagent/js";
|
|
180
|
+
```
|
|
57
181
|
|
|
58
|
-
|
|
182
|
+
## License
|
|
59
183
|
|
|
60
|
-
|
|
184
|
+
MIT
|
package/dist/index.js
CHANGED
|
@@ -30,12 +30,21 @@ function parseDataStreamChunk(chunk) {
|
|
|
30
30
|
const lines = chunk.split("\n");
|
|
31
31
|
for (const line of lines) {
|
|
32
32
|
const trimmed = line.trim();
|
|
33
|
-
if (!trimmed
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
if (!trimmed) continue;
|
|
34
|
+
if (trimmed.startsWith("0:")) {
|
|
35
|
+
try {
|
|
36
|
+
const parsed = JSON.parse(trimmed.substring(2));
|
|
37
|
+
if (typeof parsed === "string") {
|
|
38
|
+
tokens.push(parsed);
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
} catch {
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (/^\d+:/.test(trimmed) || trimmed.startsWith("data:") || trimmed.startsWith("event:")) {
|
|
45
|
+
continue;
|
|
38
46
|
}
|
|
47
|
+
tokens.push(line);
|
|
39
48
|
}
|
|
40
49
|
return tokens;
|
|
41
50
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -4,12 +4,21 @@ function parseDataStreamChunk(chunk) {
|
|
|
4
4
|
const lines = chunk.split("\n");
|
|
5
5
|
for (const line of lines) {
|
|
6
6
|
const trimmed = line.trim();
|
|
7
|
-
if (!trimmed
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
if (!trimmed) continue;
|
|
8
|
+
if (trimmed.startsWith("0:")) {
|
|
9
|
+
try {
|
|
10
|
+
const parsed = JSON.parse(trimmed.substring(2));
|
|
11
|
+
if (typeof parsed === "string") {
|
|
12
|
+
tokens.push(parsed);
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
} catch {
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
if (/^\d+:/.test(trimmed) || trimmed.startsWith("data:") || trimmed.startsWith("event:")) {
|
|
19
|
+
continue;
|
|
12
20
|
}
|
|
21
|
+
tokens.push(line);
|
|
13
22
|
}
|
|
14
23
|
return tokens;
|
|
15
24
|
}
|