@buildwithtrace/sdk 0.1.2 → 0.1.3
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 +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +46 -25
- package/dist/index.mjs +46 -25
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -323,7 +323,9 @@ declare class Trace {
|
|
|
323
323
|
/**
|
|
324
324
|
* Execute one tool call. FILE tools run locally (sandboxed to projectDir) and
|
|
325
325
|
* their result is POSTed to /tools/result so the backend continues the stream.
|
|
326
|
-
* Engine/GUI tools are out of scope
|
|
326
|
+
* Engine/GUI tools are out of scope: the SDK POSTs an is_error result (so the
|
|
327
|
+
* backend can finalize the turn) and continues — it does NOT throw, which would
|
|
328
|
+
* abandon the open stream.
|
|
327
329
|
*/
|
|
328
330
|
private _handleToolCall;
|
|
329
331
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -323,7 +323,9 @@ declare class Trace {
|
|
|
323
323
|
/**
|
|
324
324
|
* Execute one tool call. FILE tools run locally (sandboxed to projectDir) and
|
|
325
325
|
* their result is POSTed to /tools/result so the backend continues the stream.
|
|
326
|
-
* Engine/GUI tools are out of scope
|
|
326
|
+
* Engine/GUI tools are out of scope: the SDK POSTs an is_error result (so the
|
|
327
|
+
* backend can finalize the turn) and continues — it does NOT throw, which would
|
|
328
|
+
* abandon the open stream.
|
|
327
329
|
*/
|
|
328
330
|
private _handleToolCall;
|
|
329
331
|
/**
|
package/dist/index.js
CHANGED
|
@@ -574,12 +574,6 @@ function openBrowser(url) {
|
|
|
574
574
|
} catch {
|
|
575
575
|
}
|
|
576
576
|
}
|
|
577
|
-
var SUCCESS_HTML = `<!DOCTYPE html><html><head><meta charset="utf-8"><title>Trace</title></head>
|
|
578
|
-
<body style="font-family:system-ui,-apple-system,sans-serif;text-align:center;padding:64px;color:#2a2119">
|
|
579
|
-
<h1 style="font-weight:600">✓ Authentication successful</h1>
|
|
580
|
-
<p>You can close this window and return to your terminal.</p>
|
|
581
|
-
<script>setTimeout(function(){window.close();},500)</script>
|
|
582
|
-
</body></html>`;
|
|
583
577
|
var PENDING_HTML = `<!DOCTYPE html><html><head><meta charset="utf-8"><title>Trace</title></head>
|
|
584
578
|
<body style="font-family:system-ui,-apple-system,sans-serif;text-align:center;padding:64px;color:#2a2119">
|
|
585
579
|
<h1 style="font-weight:600">Waiting for authentication…</h1>
|
|
@@ -637,7 +631,13 @@ function browserLogin(opts = {}) {
|
|
|
637
631
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" }).end(PENDING_HTML);
|
|
638
632
|
return;
|
|
639
633
|
}
|
|
640
|
-
|
|
634
|
+
const successUrl = `${frontendUrl}/login?success=desktop`;
|
|
635
|
+
res.writeHead(302, {
|
|
636
|
+
Location: successUrl,
|
|
637
|
+
"Content-Type": "text/html; charset=utf-8"
|
|
638
|
+
}).end(
|
|
639
|
+
`<!DOCTYPE html><meta http-equiv="refresh" content="0;url=${successUrl}"><body style="font-family:system-ui;text-align:center;padding:60px"><p>Signed in. Returning to Trace… <a href="${successUrl}">continue</a></p></body>`
|
|
640
|
+
);
|
|
641
641
|
res.on("finish", shutdown);
|
|
642
642
|
res.on("close", shutdown);
|
|
643
643
|
settle(() => resolve3(result));
|
|
@@ -691,7 +691,7 @@ var import_posthog_node = require("posthog-node");
|
|
|
691
691
|
// src/_build_config.ts
|
|
692
692
|
var BUILD_POSTHOG_KEY = "phc_YbXW9ynLyGf9qHVxOY87InoZNSRikTCQ14GDJOZtSxX";
|
|
693
693
|
var BUILD_POSTHOG_HOST = "https://us.i.posthog.com";
|
|
694
|
-
var BUILD_SDK_VERSION = "0.1.
|
|
694
|
+
var BUILD_SDK_VERSION = "0.1.3";
|
|
695
695
|
|
|
696
696
|
// src/analytics.ts
|
|
697
697
|
var DEFAULT_HOST = "https://us.i.posthog.com";
|
|
@@ -854,6 +854,8 @@ function alias(distinctId, aliasId) {
|
|
|
854
854
|
// src/index.ts
|
|
855
855
|
var DEFAULT_API_URL2 = "https://api.buildwithtrace.com";
|
|
856
856
|
var API_VERSION = "latest";
|
|
857
|
+
var RETRYABLE_STREAM_STATUS = /* @__PURE__ */ new Set([429, 502, 503, 504]);
|
|
858
|
+
var MAX_STREAM_RETRIES = 3;
|
|
857
859
|
var TraceError = class extends Error {
|
|
858
860
|
constructor(message) {
|
|
859
861
|
super(message);
|
|
@@ -1184,21 +1186,35 @@ var Trace = class _Trace {
|
|
|
1184
1186
|
async _streamChat(message, opts) {
|
|
1185
1187
|
const sessionId = `sdk-${Date.now().toString(36)}`;
|
|
1186
1188
|
const body = this._buildChatBody(message, opts, sessionId);
|
|
1187
|
-
const
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
}
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1189
|
+
const controller = new AbortController();
|
|
1190
|
+
let idleTimer = setTimeout(
|
|
1191
|
+
() => controller.abort(),
|
|
1192
|
+
this.timeout
|
|
1193
|
+
);
|
|
1194
|
+
let resp;
|
|
1195
|
+
for (let attempt = 0; attempt < MAX_STREAM_RETRIES; attempt++) {
|
|
1196
|
+
resp = await fetch(`${this.baseUrl}/api/${API_VERSION}/chat/stream`, {
|
|
1197
|
+
method: "POST",
|
|
1198
|
+
headers: {
|
|
1199
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
1200
|
+
"Content-Type": "application/json",
|
|
1201
|
+
"Accept": "text/event-stream",
|
|
1202
|
+
"User-Agent": "buildwithtrace-node-sdk/0.1.0"
|
|
1203
|
+
},
|
|
1204
|
+
body: JSON.stringify(body),
|
|
1205
|
+
signal: controller.signal
|
|
1206
|
+
});
|
|
1207
|
+
if (resp.ok || !RETRYABLE_STREAM_STATUS.has(resp.status) || attempt === MAX_STREAM_RETRIES - 1)
|
|
1208
|
+
break;
|
|
1209
|
+
await new Promise((r) => setTimeout(r, 500 * 2 ** attempt));
|
|
1210
|
+
}
|
|
1211
|
+
if (!resp || !resp.ok) {
|
|
1212
|
+
clearTimeout(idleTimer);
|
|
1213
|
+
const errText = resp ? await resp.text().catch(() => "") : "";
|
|
1214
|
+
throw _Trace._httpError(resp ? resp.status : 0, errText, opts.mode);
|
|
1200
1215
|
}
|
|
1201
1216
|
if (!resp.body) {
|
|
1217
|
+
clearTimeout(idleTimer);
|
|
1202
1218
|
throw new TraceError("The backend returned an empty response stream.");
|
|
1203
1219
|
}
|
|
1204
1220
|
const projectDir = opts.projectDir ? (0, import_path2.resolve)(opts.projectDir) : process.cwd();
|
|
@@ -1233,6 +1249,8 @@ var Trace = class _Trace {
|
|
|
1233
1249
|
for (; ; ) {
|
|
1234
1250
|
const { done, value } = await reader.read();
|
|
1235
1251
|
if (done) break;
|
|
1252
|
+
clearTimeout(idleTimer);
|
|
1253
|
+
idleTimer = setTimeout(() => controller.abort(), this.timeout);
|
|
1236
1254
|
buffer += decoder.decode(value, { stream: true });
|
|
1237
1255
|
let nl;
|
|
1238
1256
|
while ((nl = buffer.indexOf("\n")) >= 0) {
|
|
@@ -1248,6 +1266,7 @@ var Trace = class _Trace {
|
|
|
1248
1266
|
if (ev) await handleEvent(ev);
|
|
1249
1267
|
}
|
|
1250
1268
|
} finally {
|
|
1269
|
+
clearTimeout(idleTimer);
|
|
1251
1270
|
reader.cancel().catch(() => {
|
|
1252
1271
|
});
|
|
1253
1272
|
}
|
|
@@ -1266,16 +1285,18 @@ var Trace = class _Trace {
|
|
|
1266
1285
|
/**
|
|
1267
1286
|
* Execute one tool call. FILE tools run locally (sandboxed to projectDir) and
|
|
1268
1287
|
* their result is POSTed to /tools/result so the backend continues the stream.
|
|
1269
|
-
* Engine/GUI tools are out of scope
|
|
1288
|
+
* Engine/GUI tools are out of scope: the SDK POSTs an is_error result (so the
|
|
1289
|
+
* backend can finalize the turn) and continues — it does NOT throw, which would
|
|
1290
|
+
* abandon the open stream.
|
|
1270
1291
|
*/
|
|
1271
1292
|
async _handleToolCall(event, sessionId, projectDir, defaultFile) {
|
|
1272
1293
|
const toolName = event.tool_name || "unknown";
|
|
1273
1294
|
const toolCallId = event.tool_call_id || "";
|
|
1274
1295
|
const toolArgs = event.tool_args || {};
|
|
1275
1296
|
if (!isFileTool(toolName)) {
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1297
|
+
const msg = `The agent requested '${toolName}', which the SDK does not execute. The SDK runs FILE tools only (read_file, write, search_replace, list_dir, grep, delete_trace_file); engine/GUI tools (ERC/DRC, gerber/export, take_snapshot, run_*, autoroute) require the \`buildwithtrace\` CLI or the desktop app.`;
|
|
1298
|
+
await this._postToolResult(sessionId, toolCallId, `Error: ${msg}`, true);
|
|
1299
|
+
return;
|
|
1279
1300
|
}
|
|
1280
1301
|
const result = executeFileTool(toolName, toolArgs, projectDir, defaultFile);
|
|
1281
1302
|
await this._postToolResult(sessionId, toolCallId, result.result, !result.success);
|
package/dist/index.mjs
CHANGED
|
@@ -537,12 +537,6 @@ function openBrowser(url) {
|
|
|
537
537
|
} catch {
|
|
538
538
|
}
|
|
539
539
|
}
|
|
540
|
-
var SUCCESS_HTML = `<!DOCTYPE html><html><head><meta charset="utf-8"><title>Trace</title></head>
|
|
541
|
-
<body style="font-family:system-ui,-apple-system,sans-serif;text-align:center;padding:64px;color:#2a2119">
|
|
542
|
-
<h1 style="font-weight:600">✓ Authentication successful</h1>
|
|
543
|
-
<p>You can close this window and return to your terminal.</p>
|
|
544
|
-
<script>setTimeout(function(){window.close();},500)</script>
|
|
545
|
-
</body></html>`;
|
|
546
540
|
var PENDING_HTML = `<!DOCTYPE html><html><head><meta charset="utf-8"><title>Trace</title></head>
|
|
547
541
|
<body style="font-family:system-ui,-apple-system,sans-serif;text-align:center;padding:64px;color:#2a2119">
|
|
548
542
|
<h1 style="font-weight:600">Waiting for authentication…</h1>
|
|
@@ -600,7 +594,13 @@ function browserLogin(opts = {}) {
|
|
|
600
594
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" }).end(PENDING_HTML);
|
|
601
595
|
return;
|
|
602
596
|
}
|
|
603
|
-
|
|
597
|
+
const successUrl = `${frontendUrl}/login?success=desktop`;
|
|
598
|
+
res.writeHead(302, {
|
|
599
|
+
Location: successUrl,
|
|
600
|
+
"Content-Type": "text/html; charset=utf-8"
|
|
601
|
+
}).end(
|
|
602
|
+
`<!DOCTYPE html><meta http-equiv="refresh" content="0;url=${successUrl}"><body style="font-family:system-ui;text-align:center;padding:60px"><p>Signed in. Returning to Trace… <a href="${successUrl}">continue</a></p></body>`
|
|
603
|
+
);
|
|
604
604
|
res.on("finish", shutdown);
|
|
605
605
|
res.on("close", shutdown);
|
|
606
606
|
settle(() => resolve3(result));
|
|
@@ -654,7 +654,7 @@ import { PostHog } from "posthog-node";
|
|
|
654
654
|
// src/_build_config.ts
|
|
655
655
|
var BUILD_POSTHOG_KEY = "phc_YbXW9ynLyGf9qHVxOY87InoZNSRikTCQ14GDJOZtSxX";
|
|
656
656
|
var BUILD_POSTHOG_HOST = "https://us.i.posthog.com";
|
|
657
|
-
var BUILD_SDK_VERSION = "0.1.
|
|
657
|
+
var BUILD_SDK_VERSION = "0.1.3";
|
|
658
658
|
|
|
659
659
|
// src/analytics.ts
|
|
660
660
|
var DEFAULT_HOST = "https://us.i.posthog.com";
|
|
@@ -817,6 +817,8 @@ function alias(distinctId, aliasId) {
|
|
|
817
817
|
// src/index.ts
|
|
818
818
|
var DEFAULT_API_URL2 = "https://api.buildwithtrace.com";
|
|
819
819
|
var API_VERSION = "latest";
|
|
820
|
+
var RETRYABLE_STREAM_STATUS = /* @__PURE__ */ new Set([429, 502, 503, 504]);
|
|
821
|
+
var MAX_STREAM_RETRIES = 3;
|
|
820
822
|
var TraceError = class extends Error {
|
|
821
823
|
constructor(message) {
|
|
822
824
|
super(message);
|
|
@@ -1147,21 +1149,35 @@ var Trace = class _Trace {
|
|
|
1147
1149
|
async _streamChat(message, opts) {
|
|
1148
1150
|
const sessionId = `sdk-${Date.now().toString(36)}`;
|
|
1149
1151
|
const body = this._buildChatBody(message, opts, sessionId);
|
|
1150
|
-
const
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
}
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1152
|
+
const controller = new AbortController();
|
|
1153
|
+
let idleTimer = setTimeout(
|
|
1154
|
+
() => controller.abort(),
|
|
1155
|
+
this.timeout
|
|
1156
|
+
);
|
|
1157
|
+
let resp;
|
|
1158
|
+
for (let attempt = 0; attempt < MAX_STREAM_RETRIES; attempt++) {
|
|
1159
|
+
resp = await fetch(`${this.baseUrl}/api/${API_VERSION}/chat/stream`, {
|
|
1160
|
+
method: "POST",
|
|
1161
|
+
headers: {
|
|
1162
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
1163
|
+
"Content-Type": "application/json",
|
|
1164
|
+
"Accept": "text/event-stream",
|
|
1165
|
+
"User-Agent": "buildwithtrace-node-sdk/0.1.0"
|
|
1166
|
+
},
|
|
1167
|
+
body: JSON.stringify(body),
|
|
1168
|
+
signal: controller.signal
|
|
1169
|
+
});
|
|
1170
|
+
if (resp.ok || !RETRYABLE_STREAM_STATUS.has(resp.status) || attempt === MAX_STREAM_RETRIES - 1)
|
|
1171
|
+
break;
|
|
1172
|
+
await new Promise((r) => setTimeout(r, 500 * 2 ** attempt));
|
|
1173
|
+
}
|
|
1174
|
+
if (!resp || !resp.ok) {
|
|
1175
|
+
clearTimeout(idleTimer);
|
|
1176
|
+
const errText = resp ? await resp.text().catch(() => "") : "";
|
|
1177
|
+
throw _Trace._httpError(resp ? resp.status : 0, errText, opts.mode);
|
|
1163
1178
|
}
|
|
1164
1179
|
if (!resp.body) {
|
|
1180
|
+
clearTimeout(idleTimer);
|
|
1165
1181
|
throw new TraceError("The backend returned an empty response stream.");
|
|
1166
1182
|
}
|
|
1167
1183
|
const projectDir = opts.projectDir ? resolve2(opts.projectDir) : process.cwd();
|
|
@@ -1196,6 +1212,8 @@ var Trace = class _Trace {
|
|
|
1196
1212
|
for (; ; ) {
|
|
1197
1213
|
const { done, value } = await reader.read();
|
|
1198
1214
|
if (done) break;
|
|
1215
|
+
clearTimeout(idleTimer);
|
|
1216
|
+
idleTimer = setTimeout(() => controller.abort(), this.timeout);
|
|
1199
1217
|
buffer += decoder.decode(value, { stream: true });
|
|
1200
1218
|
let nl;
|
|
1201
1219
|
while ((nl = buffer.indexOf("\n")) >= 0) {
|
|
@@ -1211,6 +1229,7 @@ var Trace = class _Trace {
|
|
|
1211
1229
|
if (ev) await handleEvent(ev);
|
|
1212
1230
|
}
|
|
1213
1231
|
} finally {
|
|
1232
|
+
clearTimeout(idleTimer);
|
|
1214
1233
|
reader.cancel().catch(() => {
|
|
1215
1234
|
});
|
|
1216
1235
|
}
|
|
@@ -1229,16 +1248,18 @@ var Trace = class _Trace {
|
|
|
1229
1248
|
/**
|
|
1230
1249
|
* Execute one tool call. FILE tools run locally (sandboxed to projectDir) and
|
|
1231
1250
|
* their result is POSTed to /tools/result so the backend continues the stream.
|
|
1232
|
-
* Engine/GUI tools are out of scope
|
|
1251
|
+
* Engine/GUI tools are out of scope: the SDK POSTs an is_error result (so the
|
|
1252
|
+
* backend can finalize the turn) and continues — it does NOT throw, which would
|
|
1253
|
+
* abandon the open stream.
|
|
1233
1254
|
*/
|
|
1234
1255
|
async _handleToolCall(event, sessionId, projectDir, defaultFile) {
|
|
1235
1256
|
const toolName = event.tool_name || "unknown";
|
|
1236
1257
|
const toolCallId = event.tool_call_id || "";
|
|
1237
1258
|
const toolArgs = event.tool_args || {};
|
|
1238
1259
|
if (!isFileTool(toolName)) {
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1260
|
+
const msg = `The agent requested '${toolName}', which the SDK does not execute. The SDK runs FILE tools only (read_file, write, search_replace, list_dir, grep, delete_trace_file); engine/GUI tools (ERC/DRC, gerber/export, take_snapshot, run_*, autoroute) require the \`buildwithtrace\` CLI or the desktop app.`;
|
|
1261
|
+
await this._postToolResult(sessionId, toolCallId, `Error: ${msg}`, true);
|
|
1262
|
+
return;
|
|
1242
1263
|
}
|
|
1243
1264
|
const result = executeFileTool(toolName, toolArgs, projectDir, defaultFile);
|
|
1244
1265
|
await this._postToolResult(sessionId, toolCallId, result.result, !result.success);
|