@syncagent/js 0.1.8 → 0.2.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/dist/index.d.mts CHANGED
@@ -15,17 +15,35 @@ interface SyncAgentConfig {
15
15
  connectionString: string;
16
16
  /** Custom tools the AI agent can call — executed client-side in your app */
17
17
  tools?: Record<string, ToolDefinition>;
18
+ /**
19
+ * Override the API base URL. Defaults to https://syncagent.dev
20
+ * Use this in development: baseUrl: "http://localhost:3100"
21
+ */
22
+ baseUrl?: string;
18
23
  }
19
24
  interface Message {
20
25
  role: "user" | "assistant";
21
26
  content: string;
22
27
  }
28
+ /** Structured data returned from a DB tool call */
29
+ interface ToolData {
30
+ /** The tool that produced this data */
31
+ tool: string;
32
+ /** Collection/table that was queried */
33
+ collection: string;
34
+ /** Raw result rows/documents */
35
+ data: Record<string, any>[];
36
+ /** Total count if available */
37
+ count?: number;
38
+ }
23
39
  interface ChatOptions {
24
40
  onToken?: (token: string) => void;
25
41
  onComplete?: (text: string) => void;
26
42
  onError?: (error: Error) => void;
27
43
  onToolCall?: (toolName: string, args: Record<string, any>, result: any) => void;
28
44
  onStatus?: (step: string, label: string) => void;
45
+ /** Called whenever a DB tool returns structured data */
46
+ onData?: (data: ToolData) => void;
29
47
  signal?: AbortSignal;
30
48
  }
31
49
  interface ChatResult {
@@ -50,11 +68,12 @@ declare class SyncAgentClient {
50
68
  constructor(config: SyncAgentConfig);
51
69
  private headers;
52
70
  private toWireMessages;
53
- /** Serialize tool definitions for the API (strips execute functions) */
54
71
  private serializeTools;
55
- chat(messages: Message[], options?: ChatOptions): Promise<ChatResult>;
72
+ chat(messages: Message[], options?: ChatOptions & {
73
+ context?: Record<string, any>;
74
+ }): Promise<ChatResult>;
56
75
  private chatLoop;
57
76
  getSchema(): Promise<CollectionSchema[]>;
58
77
  }
59
78
 
60
- export { type ChatOptions, type ChatResult, type CollectionSchema, type Message, type SchemaField, SyncAgentClient, type SyncAgentConfig, type ToolDefinition, type ToolParameter };
79
+ export { type ChatOptions, type ChatResult, type CollectionSchema, type Message, type SchemaField, SyncAgentClient, type SyncAgentConfig, type ToolData, type ToolDefinition, type ToolParameter };
package/dist/index.d.ts CHANGED
@@ -15,17 +15,35 @@ interface SyncAgentConfig {
15
15
  connectionString: string;
16
16
  /** Custom tools the AI agent can call — executed client-side in your app */
17
17
  tools?: Record<string, ToolDefinition>;
18
+ /**
19
+ * Override the API base URL. Defaults to https://syncagent.dev
20
+ * Use this in development: baseUrl: "http://localhost:3100"
21
+ */
22
+ baseUrl?: string;
18
23
  }
19
24
  interface Message {
20
25
  role: "user" | "assistant";
21
26
  content: string;
22
27
  }
28
+ /** Structured data returned from a DB tool call */
29
+ interface ToolData {
30
+ /** The tool that produced this data */
31
+ tool: string;
32
+ /** Collection/table that was queried */
33
+ collection: string;
34
+ /** Raw result rows/documents */
35
+ data: Record<string, any>[];
36
+ /** Total count if available */
37
+ count?: number;
38
+ }
23
39
  interface ChatOptions {
24
40
  onToken?: (token: string) => void;
25
41
  onComplete?: (text: string) => void;
26
42
  onError?: (error: Error) => void;
27
43
  onToolCall?: (toolName: string, args: Record<string, any>, result: any) => void;
28
44
  onStatus?: (step: string, label: string) => void;
45
+ /** Called whenever a DB tool returns structured data */
46
+ onData?: (data: ToolData) => void;
29
47
  signal?: AbortSignal;
30
48
  }
31
49
  interface ChatResult {
@@ -50,11 +68,12 @@ declare class SyncAgentClient {
50
68
  constructor(config: SyncAgentConfig);
51
69
  private headers;
52
70
  private toWireMessages;
53
- /** Serialize tool definitions for the API (strips execute functions) */
54
71
  private serializeTools;
55
- chat(messages: Message[], options?: ChatOptions): Promise<ChatResult>;
72
+ chat(messages: Message[], options?: ChatOptions & {
73
+ context?: Record<string, any>;
74
+ }): Promise<ChatResult>;
56
75
  private chatLoop;
57
76
  getSchema(): Promise<CollectionSchema[]>;
58
77
  }
59
78
 
60
- export { type ChatOptions, type ChatResult, type CollectionSchema, type Message, type SchemaField, SyncAgentClient, type SyncAgentConfig, type ToolDefinition, type ToolParameter };
79
+ export { type ChatOptions, type ChatResult, type CollectionSchema, type Message, type SchemaField, SyncAgentClient, type SyncAgentConfig, type ToolData, type ToolDefinition, type ToolParameter };
package/dist/index.js CHANGED
@@ -26,6 +26,7 @@ module.exports = __toCommonJS(index_exports);
26
26
 
27
27
  // src/stream.ts
28
28
  var STATUS_PREFIX = "__sa_status:";
29
+ var DATA_PREFIX = "__sa_data:";
29
30
  function parseChunkFull(chunk) {
30
31
  return parseChunk(chunk);
31
32
  }
@@ -33,6 +34,7 @@ function parseChunk(chunk) {
33
34
  if (!chunk) return { tokens: [] };
34
35
  const tokens = [];
35
36
  let status;
37
+ let data;
36
38
  const lines = chunk.split("\n");
37
39
  for (let i = 0; i < lines.length; i++) {
38
40
  const line = lines[i];
@@ -44,6 +46,13 @@ function parseChunk(chunk) {
44
46
  }
45
47
  continue;
46
48
  }
49
+ if (trimmed.startsWith(DATA_PREFIX)) {
50
+ try {
51
+ data = JSON.parse(trimmed.slice(DATA_PREFIX.length));
52
+ } catch {
53
+ }
54
+ continue;
55
+ }
47
56
  if (trimmed.startsWith("data:") || trimmed.startsWith("event:") || trimmed.startsWith("id:") || trimmed === "") {
48
57
  continue;
49
58
  }
@@ -59,7 +68,7 @@ function parseChunk(chunk) {
59
68
  }
60
69
  tokens.push(line + (i < lines.length - 1 ? "\n" : ""));
61
70
  }
62
- return { tokens, status };
71
+ return { tokens, status, data };
63
72
  }
64
73
 
65
74
  // src/client.ts
@@ -69,7 +78,7 @@ var SyncAgentClient = class {
69
78
  if (!config.apiKey) throw new Error("SyncAgent: apiKey is required");
70
79
  if (!config.connectionString) throw new Error("SyncAgent: connectionString is required");
71
80
  this.apiKey = config.apiKey;
72
- this.baseUrl = SYNCAGENT_API_URL;
81
+ this.baseUrl = (config.baseUrl || SYNCAGENT_API_URL).replace(/\/$/, "");
73
82
  this.connectionString = config.connectionString;
74
83
  this.tools = config.tools || {};
75
84
  }
@@ -79,14 +88,22 @@ var SyncAgentClient = class {
79
88
  Authorization: `Bearer ${this.apiKey}`
80
89
  };
81
90
  }
82
- toWireMessages(messages) {
83
- return messages.map((m) => ({
91
+ toWireMessages(messages, context) {
92
+ const wire = messages.map((m) => ({
84
93
  id: Math.random().toString(36).slice(2),
85
94
  role: m.role,
86
95
  parts: [{ type: "text", text: m.content }]
87
96
  }));
97
+ if (context && Object.keys(context).length > 0) {
98
+ const last = wire[wire.length - 1];
99
+ if (last?.role === "user") {
100
+ last.parts[0].text += `
101
+
102
+ [Context: ${JSON.stringify(context)}]`;
103
+ }
104
+ }
105
+ return wire;
88
106
  }
89
- /** Serialize tool definitions for the API (strips execute functions) */
90
107
  serializeTools() {
91
108
  if (!Object.keys(this.tools).length) return void 0;
92
109
  const serialized = {};
@@ -96,11 +113,11 @@ var SyncAgentClient = class {
96
113
  return serialized;
97
114
  }
98
115
  async chat(messages, options = {}) {
99
- const { onToken, onComplete, onError, onToolCall, onStatus, signal } = options;
100
- const wireMessages = this.toWireMessages(messages);
116
+ const { onToken, onComplete, onError, onToolCall, onStatus, onData, signal, context } = options;
117
+ const wireMessages = this.toWireMessages(messages, context);
101
118
  const clientTools = this.serializeTools();
102
119
  try {
103
- const fullText = await this.chatLoop(wireMessages, clientTools, { onToken, onToolCall, onStatus, signal });
120
+ const fullText = await this.chatLoop(wireMessages, clientTools, { onToken, onToolCall, onStatus, onData, signal });
104
121
  onComplete?.(fullText);
105
122
  return { text: fullText };
106
123
  } catch (e) {
@@ -134,14 +151,15 @@ var SyncAgentClient = class {
134
151
  const { done, value } = await reader.read();
135
152
  if (done) break;
136
153
  const chunk = decoder.decode(value, { stream: true });
137
- const { tokens, status } = parseChunkFull(chunk);
154
+ const { tokens, status, data } = parseChunkFull(chunk);
138
155
  if (status) opts.onStatus?.(status.step, status.label);
156
+ if (data) opts.onData?.(data);
139
157
  for (const line of chunk.split("\n")) {
140
158
  if (line.startsWith("a:")) {
141
159
  try {
142
- const data = JSON.parse(line.slice(2));
143
- if (data.type === "client_tool_call") {
144
- pendingToolCalls.push({ id: data.id, name: data.name, args: data.args });
160
+ const data2 = JSON.parse(line.slice(2));
161
+ if (data2.type === "client_tool_call") {
162
+ pendingToolCalls.push({ id: data2.id, name: data2.name, args: data2.args });
145
163
  }
146
164
  } catch {
147
165
  }
package/dist/index.mjs CHANGED
@@ -1,5 +1,6 @@
1
1
  // src/stream.ts
2
2
  var STATUS_PREFIX = "__sa_status:";
3
+ var DATA_PREFIX = "__sa_data:";
3
4
  function parseChunkFull(chunk) {
4
5
  return parseChunk(chunk);
5
6
  }
@@ -7,6 +8,7 @@ function parseChunk(chunk) {
7
8
  if (!chunk) return { tokens: [] };
8
9
  const tokens = [];
9
10
  let status;
11
+ let data;
10
12
  const lines = chunk.split("\n");
11
13
  for (let i = 0; i < lines.length; i++) {
12
14
  const line = lines[i];
@@ -18,6 +20,13 @@ function parseChunk(chunk) {
18
20
  }
19
21
  continue;
20
22
  }
23
+ if (trimmed.startsWith(DATA_PREFIX)) {
24
+ try {
25
+ data = JSON.parse(trimmed.slice(DATA_PREFIX.length));
26
+ } catch {
27
+ }
28
+ continue;
29
+ }
21
30
  if (trimmed.startsWith("data:") || trimmed.startsWith("event:") || trimmed.startsWith("id:") || trimmed === "") {
22
31
  continue;
23
32
  }
@@ -33,7 +42,7 @@ function parseChunk(chunk) {
33
42
  }
34
43
  tokens.push(line + (i < lines.length - 1 ? "\n" : ""));
35
44
  }
36
- return { tokens, status };
45
+ return { tokens, status, data };
37
46
  }
38
47
 
39
48
  // src/client.ts
@@ -43,7 +52,7 @@ var SyncAgentClient = class {
43
52
  if (!config.apiKey) throw new Error("SyncAgent: apiKey is required");
44
53
  if (!config.connectionString) throw new Error("SyncAgent: connectionString is required");
45
54
  this.apiKey = config.apiKey;
46
- this.baseUrl = SYNCAGENT_API_URL;
55
+ this.baseUrl = (config.baseUrl || SYNCAGENT_API_URL).replace(/\/$/, "");
47
56
  this.connectionString = config.connectionString;
48
57
  this.tools = config.tools || {};
49
58
  }
@@ -53,14 +62,22 @@ var SyncAgentClient = class {
53
62
  Authorization: `Bearer ${this.apiKey}`
54
63
  };
55
64
  }
56
- toWireMessages(messages) {
57
- return messages.map((m) => ({
65
+ toWireMessages(messages, context) {
66
+ const wire = messages.map((m) => ({
58
67
  id: Math.random().toString(36).slice(2),
59
68
  role: m.role,
60
69
  parts: [{ type: "text", text: m.content }]
61
70
  }));
71
+ if (context && Object.keys(context).length > 0) {
72
+ const last = wire[wire.length - 1];
73
+ if (last?.role === "user") {
74
+ last.parts[0].text += `
75
+
76
+ [Context: ${JSON.stringify(context)}]`;
77
+ }
78
+ }
79
+ return wire;
62
80
  }
63
- /** Serialize tool definitions for the API (strips execute functions) */
64
81
  serializeTools() {
65
82
  if (!Object.keys(this.tools).length) return void 0;
66
83
  const serialized = {};
@@ -70,11 +87,11 @@ var SyncAgentClient = class {
70
87
  return serialized;
71
88
  }
72
89
  async chat(messages, options = {}) {
73
- const { onToken, onComplete, onError, onToolCall, onStatus, signal } = options;
74
- const wireMessages = this.toWireMessages(messages);
90
+ const { onToken, onComplete, onError, onToolCall, onStatus, onData, signal, context } = options;
91
+ const wireMessages = this.toWireMessages(messages, context);
75
92
  const clientTools = this.serializeTools();
76
93
  try {
77
- const fullText = await this.chatLoop(wireMessages, clientTools, { onToken, onToolCall, onStatus, signal });
94
+ const fullText = await this.chatLoop(wireMessages, clientTools, { onToken, onToolCall, onStatus, onData, signal });
78
95
  onComplete?.(fullText);
79
96
  return { text: fullText };
80
97
  } catch (e) {
@@ -108,14 +125,15 @@ var SyncAgentClient = class {
108
125
  const { done, value } = await reader.read();
109
126
  if (done) break;
110
127
  const chunk = decoder.decode(value, { stream: true });
111
- const { tokens, status } = parseChunkFull(chunk);
128
+ const { tokens, status, data } = parseChunkFull(chunk);
112
129
  if (status) opts.onStatus?.(status.step, status.label);
130
+ if (data) opts.onData?.(data);
113
131
  for (const line of chunk.split("\n")) {
114
132
  if (line.startsWith("a:")) {
115
133
  try {
116
- const data = JSON.parse(line.slice(2));
117
- if (data.type === "client_tool_call") {
118
- pendingToolCalls.push({ id: data.id, name: data.name, args: data.args });
134
+ const data2 = JSON.parse(line.slice(2));
135
+ if (data2.type === "client_tool_call") {
136
+ pendingToolCalls.push({ id: data2.id, name: data2.name, args: data2.args });
119
137
  }
120
138
  } catch {
121
139
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syncagent/js",
3
- "version": "0.1.8",
3
+ "version": "0.2.0",
4
4
  "description": "SyncAgent JavaScript SDK — AI database agent for any app",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",