@syncagent/js 0.1.5 → 0.1.7

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
@@ -25,6 +25,7 @@ interface ChatOptions {
25
25
  onComplete?: (text: string) => void;
26
26
  onError?: (error: Error) => void;
27
27
  onToolCall?: (toolName: string, args: Record<string, any>, result: any) => void;
28
+ onStatus?: (step: string, label: string) => void;
28
29
  signal?: AbortSignal;
29
30
  }
30
31
  interface ChatResult {
package/dist/index.d.ts CHANGED
@@ -25,6 +25,7 @@ interface ChatOptions {
25
25
  onComplete?: (text: string) => void;
26
26
  onError?: (error: Error) => void;
27
27
  onToolCall?: (toolName: string, args: Record<string, any>, result: any) => void;
28
+ onStatus?: (step: string, label: string) => void;
28
29
  signal?: AbortSignal;
29
30
  }
30
31
  interface ChatResult {
package/dist/index.js CHANGED
@@ -25,13 +25,25 @@ __export(index_exports, {
25
25
  module.exports = __toCommonJS(index_exports);
26
26
 
27
27
  // src/stream.ts
28
- function parseDataStreamChunk(chunk) {
29
- if (!chunk) return [];
28
+ var STATUS_PREFIX = "__sa_status:";
29
+ function parseChunkFull(chunk) {
30
+ return parseChunk(chunk);
31
+ }
32
+ function parseChunk(chunk) {
33
+ if (!chunk) return { tokens: [] };
30
34
  const tokens = [];
35
+ let status;
31
36
  const lines = chunk.split("\n");
32
37
  for (let i = 0; i < lines.length; i++) {
33
38
  const line = lines[i];
34
39
  const trimmed = line.trim();
40
+ if (trimmed.startsWith(STATUS_PREFIX)) {
41
+ try {
42
+ status = JSON.parse(trimmed.slice(STATUS_PREFIX.length));
43
+ } catch {
44
+ }
45
+ continue;
46
+ }
35
47
  if (trimmed.startsWith("data:") || trimmed.startsWith("event:") || trimmed.startsWith("id:") || trimmed === "") {
36
48
  continue;
37
49
  }
@@ -47,7 +59,7 @@ function parseDataStreamChunk(chunk) {
47
59
  }
48
60
  tokens.push(line + (i < lines.length - 1 ? "\n" : ""));
49
61
  }
50
- return tokens;
62
+ return { tokens, status };
51
63
  }
52
64
 
53
65
  // src/client.ts
@@ -84,11 +96,11 @@ var SyncAgentClient = class {
84
96
  return serialized;
85
97
  }
86
98
  async chat(messages, options = {}) {
87
- const { onToken, onComplete, onError, onToolCall, signal } = options;
99
+ const { onToken, onComplete, onError, onToolCall, onStatus, signal } = options;
88
100
  const wireMessages = this.toWireMessages(messages);
89
101
  const clientTools = this.serializeTools();
90
102
  try {
91
- const fullText = await this.chatLoop(wireMessages, clientTools, { onToken, onToolCall, signal });
103
+ const fullText = await this.chatLoop(wireMessages, clientTools, { onToken, onToolCall, onStatus, signal });
92
104
  onComplete?.(fullText);
93
105
  return { text: fullText };
94
106
  } catch (e) {
@@ -117,27 +129,25 @@ var SyncAgentClient = class {
117
129
  const reader = res.body?.getReader();
118
130
  if (!reader) throw new Error("No response body");
119
131
  const decoder = new TextDecoder();
120
- let roundText = "";
121
132
  let pendingToolCalls = [];
122
133
  while (true) {
123
134
  const { done, value } = await reader.read();
124
135
  if (done) break;
125
136
  const chunk = decoder.decode(value, { stream: true });
137
+ const { tokens, status } = parseChunkFull(chunk);
138
+ if (status) opts.onStatus?.(status.step, status.label);
126
139
  for (const line of chunk.split("\n")) {
127
140
  if (line.startsWith("a:")) {
128
141
  try {
129
142
  const data = JSON.parse(line.slice(2));
130
143
  if (data.type === "client_tool_call") {
131
144
  pendingToolCalls.push({ id: data.id, name: data.name, args: data.args });
132
- continue;
133
145
  }
134
146
  } catch {
135
147
  }
136
148
  }
137
149
  }
138
- const tokens = parseDataStreamChunk(chunk);
139
150
  for (const token of tokens) {
140
- roundText += token;
141
151
  fullText += token;
142
152
  opts.onToken?.(token);
143
153
  }
@@ -151,6 +161,7 @@ var SyncAgentClient = class {
151
161
  continue;
152
162
  }
153
163
  try {
164
+ opts.onStatus?.("querying", `Running ${tc.name}...`);
154
165
  const result = await toolDef.execute(tc.args);
155
166
  opts.onToolCall?.(tc.name, tc.args, result);
156
167
  toolResults.push({ id: tc.id, name: tc.name, result });
package/dist/index.mjs CHANGED
@@ -1,11 +1,23 @@
1
1
  // src/stream.ts
2
- function parseDataStreamChunk(chunk) {
3
- if (!chunk) return [];
2
+ var STATUS_PREFIX = "__sa_status:";
3
+ function parseChunkFull(chunk) {
4
+ return parseChunk(chunk);
5
+ }
6
+ function parseChunk(chunk) {
7
+ if (!chunk) return { tokens: [] };
4
8
  const tokens = [];
9
+ let status;
5
10
  const lines = chunk.split("\n");
6
11
  for (let i = 0; i < lines.length; i++) {
7
12
  const line = lines[i];
8
13
  const trimmed = line.trim();
14
+ if (trimmed.startsWith(STATUS_PREFIX)) {
15
+ try {
16
+ status = JSON.parse(trimmed.slice(STATUS_PREFIX.length));
17
+ } catch {
18
+ }
19
+ continue;
20
+ }
9
21
  if (trimmed.startsWith("data:") || trimmed.startsWith("event:") || trimmed.startsWith("id:") || trimmed === "") {
10
22
  continue;
11
23
  }
@@ -21,7 +33,7 @@ function parseDataStreamChunk(chunk) {
21
33
  }
22
34
  tokens.push(line + (i < lines.length - 1 ? "\n" : ""));
23
35
  }
24
- return tokens;
36
+ return { tokens, status };
25
37
  }
26
38
 
27
39
  // src/client.ts
@@ -58,11 +70,11 @@ var SyncAgentClient = class {
58
70
  return serialized;
59
71
  }
60
72
  async chat(messages, options = {}) {
61
- const { onToken, onComplete, onError, onToolCall, signal } = options;
73
+ const { onToken, onComplete, onError, onToolCall, onStatus, signal } = options;
62
74
  const wireMessages = this.toWireMessages(messages);
63
75
  const clientTools = this.serializeTools();
64
76
  try {
65
- const fullText = await this.chatLoop(wireMessages, clientTools, { onToken, onToolCall, signal });
77
+ const fullText = await this.chatLoop(wireMessages, clientTools, { onToken, onToolCall, onStatus, signal });
66
78
  onComplete?.(fullText);
67
79
  return { text: fullText };
68
80
  } catch (e) {
@@ -91,27 +103,25 @@ var SyncAgentClient = class {
91
103
  const reader = res.body?.getReader();
92
104
  if (!reader) throw new Error("No response body");
93
105
  const decoder = new TextDecoder();
94
- let roundText = "";
95
106
  let pendingToolCalls = [];
96
107
  while (true) {
97
108
  const { done, value } = await reader.read();
98
109
  if (done) break;
99
110
  const chunk = decoder.decode(value, { stream: true });
111
+ const { tokens, status } = parseChunkFull(chunk);
112
+ if (status) opts.onStatus?.(status.step, status.label);
100
113
  for (const line of chunk.split("\n")) {
101
114
  if (line.startsWith("a:")) {
102
115
  try {
103
116
  const data = JSON.parse(line.slice(2));
104
117
  if (data.type === "client_tool_call") {
105
118
  pendingToolCalls.push({ id: data.id, name: data.name, args: data.args });
106
- continue;
107
119
  }
108
120
  } catch {
109
121
  }
110
122
  }
111
123
  }
112
- const tokens = parseDataStreamChunk(chunk);
113
124
  for (const token of tokens) {
114
- roundText += token;
115
125
  fullText += token;
116
126
  opts.onToken?.(token);
117
127
  }
@@ -125,6 +135,7 @@ var SyncAgentClient = class {
125
135
  continue;
126
136
  }
127
137
  try {
138
+ opts.onStatus?.("querying", `Running ${tc.name}...`);
128
139
  const result = await toolDef.execute(tc.args);
129
140
  opts.onToolCall?.(tc.name, tc.args, result);
130
141
  toolResults.push({ id: tc.id, name: tc.name, result });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syncagent/js",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "SyncAgent JavaScript SDK — AI database agent for any app",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",