sim 2.1.8-preview.98.1 → 2.1.8-preview.99.1
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.js +126 -55
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4460,6 +4460,22 @@ function toApiError(url, status, contentType, raw) {
|
|
|
4460
4460
|
function truncate(value, max) {
|
|
4461
4461
|
return value.length <= max ? value : `${value.slice(0, max)}…`;
|
|
4462
4462
|
}
|
|
4463
|
+
function transportErrorMessage(error) {
|
|
4464
|
+
const messages = [];
|
|
4465
|
+
const seen = new Set;
|
|
4466
|
+
let current = error;
|
|
4467
|
+
while (current && typeof current === "object" && messages.length < 4 && !seen.has(current)) {
|
|
4468
|
+
seen.add(current);
|
|
4469
|
+
const candidate = current;
|
|
4470
|
+
const message = typeof candidate.message === "string" ? truncate(candidate.message.replace(/\s+/g, " ").trim(), 300) : "";
|
|
4471
|
+
const code = typeof candidate.code === "string" ? candidate.code : "";
|
|
4472
|
+
const detail = `${message}${code && !message.includes(code) ? ` (${code})` : ""}`;
|
|
4473
|
+
if (detail && messages.at(-1) !== detail)
|
|
4474
|
+
messages.push(detail);
|
|
4475
|
+
current = candidate.cause;
|
|
4476
|
+
}
|
|
4477
|
+
return messages.join(": ") || "Unknown network error";
|
|
4478
|
+
}
|
|
4463
4479
|
function namesKeyScopeRefusal(error) {
|
|
4464
4480
|
if (typeof error.code === "string" && KEY_SCOPE_REFUSALS.has(error.code))
|
|
4465
4481
|
return true;
|
|
@@ -4683,7 +4699,7 @@ class SimClient {
|
|
|
4683
4699
|
if (timeout?.aborted) {
|
|
4684
4700
|
throw new SimApiError(`${url} did not answer within ${timeoutMs / 1000}s. ${RAISE_TIMEOUT_HINT}`, 0);
|
|
4685
4701
|
}
|
|
4686
|
-
throw new SimApiError(`Could not reach ${this.profile.endpoint}: ${cause
|
|
4702
|
+
throw new SimApiError(`Could not reach ${this.profile.endpoint}: ${transportErrorMessage(cause)}`, 0);
|
|
4687
4703
|
}
|
|
4688
4704
|
if (trace)
|
|
4689
4705
|
traceRequest(method, url, response.status, startedAt);
|
|
@@ -17239,6 +17255,47 @@ function attachCredentialCommands(program) {
|
|
|
17239
17255
|
credentials.command("reconnect").argument("<credentialId>", "Existing OAuth credential to re-authorize").description(describeOperation(V2_OPERATIONS.createCredentialConnection, "Create a short-lived link for reconnecting an OAuth credential")).action((credentialId, _options, command) => createConnectionLink(command, { credentialId }));
|
|
17240
17256
|
}
|
|
17241
17257
|
|
|
17258
|
+
// src/http/ndjson.ts
|
|
17259
|
+
async function* readNdjson(body, protocol) {
|
|
17260
|
+
if (!body) {
|
|
17261
|
+
throw new SimApiError(`${protocol} ended without a response body`, 0);
|
|
17262
|
+
}
|
|
17263
|
+
const reader = body.getReader();
|
|
17264
|
+
const decoder = new TextDecoder;
|
|
17265
|
+
let buffer = "";
|
|
17266
|
+
const parse = (line) => {
|
|
17267
|
+
const trimmed = line.trim();
|
|
17268
|
+
if (!trimmed)
|
|
17269
|
+
return;
|
|
17270
|
+
try {
|
|
17271
|
+
return JSON.parse(trimmed);
|
|
17272
|
+
} catch {
|
|
17273
|
+
throw new SimApiError(`${protocol} returned malformed data`, 0);
|
|
17274
|
+
}
|
|
17275
|
+
};
|
|
17276
|
+
try {
|
|
17277
|
+
while (true) {
|
|
17278
|
+
const { done, value } = await reader.read();
|
|
17279
|
+
buffer += done ? decoder.decode() : decoder.decode(value, { stream: true });
|
|
17280
|
+
const lines = buffer.split(`
|
|
17281
|
+
`);
|
|
17282
|
+
buffer = done ? "" : lines.pop() ?? "";
|
|
17283
|
+
for (const line of lines) {
|
|
17284
|
+
const event = parse(line);
|
|
17285
|
+
if (event !== undefined)
|
|
17286
|
+
yield event;
|
|
17287
|
+
}
|
|
17288
|
+
if (done)
|
|
17289
|
+
return;
|
|
17290
|
+
}
|
|
17291
|
+
} finally {
|
|
17292
|
+
reader.cancel().catch(() => {
|
|
17293
|
+
return;
|
|
17294
|
+
});
|
|
17295
|
+
reader.releaseLock();
|
|
17296
|
+
}
|
|
17297
|
+
}
|
|
17298
|
+
|
|
17242
17299
|
// src/commands/protocol/result.ts
|
|
17243
17300
|
function printProtocolResult(format, result) {
|
|
17244
17301
|
const fields = Object.entries(result).map(([key, value]) => [key, text(value)]);
|
|
@@ -17246,72 +17303,28 @@ function printProtocolResult(format, result) {
|
|
|
17246
17303
|
}
|
|
17247
17304
|
|
|
17248
17305
|
// src/commands/protocol/chat.ts
|
|
17249
|
-
function parseChatStreamLine(line) {
|
|
17250
|
-
const trimmed = line.trim();
|
|
17251
|
-
if (!trimmed)
|
|
17252
|
-
return;
|
|
17253
|
-
try {
|
|
17254
|
-
return JSON.parse(trimmed);
|
|
17255
|
-
} catch {
|
|
17256
|
-
throw new SimApiError("Chat stream returned malformed data", 0);
|
|
17257
|
-
}
|
|
17258
|
-
}
|
|
17259
17306
|
async function readChatStream(response, onChunk) {
|
|
17260
|
-
|
|
17261
|
-
|
|
17262
|
-
|
|
17263
|
-
|
|
17264
|
-
|
|
17265
|
-
|
|
17266
|
-
|
|
17267
|
-
const processLine = (line) => {
|
|
17268
|
-
const event = parseChatStreamLine(line);
|
|
17269
|
-
if (!event || event.type === "heartbeat")
|
|
17270
|
-
return false;
|
|
17307
|
+
for await (const value of readNdjson(response.body, "Chat stream")) {
|
|
17308
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
17309
|
+
throw new SimApiError("Chat stream returned an unknown event", 0);
|
|
17310
|
+
}
|
|
17311
|
+
const event = value;
|
|
17312
|
+
if (event.type === "heartbeat")
|
|
17313
|
+
continue;
|
|
17271
17314
|
if (event.type === "chunk") {
|
|
17272
17315
|
if (event.content)
|
|
17273
17316
|
onChunk(sanitize(event.content));
|
|
17274
|
-
|
|
17317
|
+
continue;
|
|
17275
17318
|
}
|
|
17276
17319
|
if (event.type === "error") {
|
|
17277
17320
|
throw new SimApiError(event.error || "Chat request failed", 0);
|
|
17278
17321
|
}
|
|
17279
17322
|
if (event.type === "final") {
|
|
17280
|
-
|
|
17281
|
-
return true;
|
|
17323
|
+
return event.data;
|
|
17282
17324
|
}
|
|
17283
17325
|
throw new SimApiError("Chat stream returned an unknown event", 0);
|
|
17284
|
-
};
|
|
17285
|
-
try {
|
|
17286
|
-
let ended = false;
|
|
17287
|
-
while (!ended) {
|
|
17288
|
-
const { done, value } = await reader.read();
|
|
17289
|
-
if (done)
|
|
17290
|
-
break;
|
|
17291
|
-
buffer += decoder.decode(value, { stream: true });
|
|
17292
|
-
const lines = buffer.split(`
|
|
17293
|
-
`);
|
|
17294
|
-
buffer = lines.pop() ?? "";
|
|
17295
|
-
for (const line of lines) {
|
|
17296
|
-
if (processLine(line)) {
|
|
17297
|
-
ended = true;
|
|
17298
|
-
break;
|
|
17299
|
-
}
|
|
17300
|
-
}
|
|
17301
|
-
}
|
|
17302
|
-
if (!ended) {
|
|
17303
|
-
buffer += decoder.decode();
|
|
17304
|
-
processLine(buffer);
|
|
17305
|
-
}
|
|
17306
|
-
if (!finalResult) {
|
|
17307
|
-
throw new SimApiError("Chat stream ended without a final result", 0);
|
|
17308
|
-
}
|
|
17309
|
-
return finalResult;
|
|
17310
|
-
} finally {
|
|
17311
|
-
reader.cancel().catch(() => {
|
|
17312
|
-
return;
|
|
17313
|
-
});
|
|
17314
17326
|
}
|
|
17327
|
+
throw new SimApiError("Chat stream ended without a final result", 0);
|
|
17315
17328
|
}
|
|
17316
17329
|
function ignoreBrokenPipe(stream) {
|
|
17317
17330
|
const onError = (error) => {
|
|
@@ -18302,6 +18315,7 @@ function attachTableImport(tables) {
|
|
|
18302
18315
|
// src/commands/protocol/workflow-run-follow.ts
|
|
18303
18316
|
var AGENT_STREAM_PROTOCOL_HEADER = "x-sim-stream-protocol";
|
|
18304
18317
|
var AGENT_STREAM_PROTOCOL_V1 = "agent-events-v1";
|
|
18318
|
+
var WORKFLOW_RESULT_STREAM_CONTENT_TYPE = "application/x-ndjson";
|
|
18305
18319
|
var DONE_SENTINEL = "[DONE]";
|
|
18306
18320
|
function resolveWorkflowRunSelection(flags) {
|
|
18307
18321
|
const manual = flags.manual === true;
|
|
@@ -18353,6 +18367,59 @@ function stringField(frame, key) {
|
|
|
18353
18367
|
const value = frame[key];
|
|
18354
18368
|
return typeof value === "string" ? value : null;
|
|
18355
18369
|
}
|
|
18370
|
+
async function readWorkflowResult(response) {
|
|
18371
|
+
const contentType = (response.headers.get("content-type") ?? "").toLowerCase();
|
|
18372
|
+
if (!contentType.includes(WORKFLOW_RESULT_STREAM_CONTENT_TYPE)) {
|
|
18373
|
+
let envelope;
|
|
18374
|
+
try {
|
|
18375
|
+
envelope = await response.json();
|
|
18376
|
+
} catch {
|
|
18377
|
+
throw new SimApiError(`Workflow run returned malformed JSON${contentType ? ` as ${contentType}` : ""}`, response.status);
|
|
18378
|
+
}
|
|
18379
|
+
if (!isRecord(envelope)) {
|
|
18380
|
+
throw new SimApiError("Workflow run returned an invalid result envelope", response.status);
|
|
18381
|
+
}
|
|
18382
|
+
return isRecord(envelope.data) ? envelope.data : envelope;
|
|
18383
|
+
}
|
|
18384
|
+
for await (const value of readNdjson(response.body, "Workflow result stream")) {
|
|
18385
|
+
if (!isRecord(value) || typeof value.type !== "string") {
|
|
18386
|
+
throw new SimApiError("Workflow result stream returned an unknown event", response.status);
|
|
18387
|
+
}
|
|
18388
|
+
if (value.type === "heartbeat")
|
|
18389
|
+
continue;
|
|
18390
|
+
if (value.type === "error") {
|
|
18391
|
+
throw new SimApiError(safeOneLine(typeof value.error === "string" ? value.error : "Workflow run failed"), typeof value.status === "number" ? value.status : 0, typeof value.code === "string" ? value.code : null);
|
|
18392
|
+
}
|
|
18393
|
+
if (value.type === "final" && isRecord(value.data))
|
|
18394
|
+
return value.data;
|
|
18395
|
+
throw new SimApiError("Workflow result stream returned an unknown event", response.status);
|
|
18396
|
+
}
|
|
18397
|
+
throw new SimApiError("Workflow result stream ended without a final result", response.status);
|
|
18398
|
+
}
|
|
18399
|
+
async function runWithResultStream(workflowId, command) {
|
|
18400
|
+
const flags = command.optsWithGlobals();
|
|
18401
|
+
const { client, profile } = clientFrom(command);
|
|
18402
|
+
const operation = V2_OPERATIONS.executeWorkflow;
|
|
18403
|
+
const commandSpec = CLI_CONTRACT.executeWorkflow ?? {};
|
|
18404
|
+
try {
|
|
18405
|
+
const request = buildRequest("executeWorkflow", [workflowId], flags, profile.workspaceId);
|
|
18406
|
+
const response = await client.requestRaw(request.path, {
|
|
18407
|
+
method: operation.method,
|
|
18408
|
+
query: request.query,
|
|
18409
|
+
body: request.body,
|
|
18410
|
+
headers: { ...request.headers, accept: WORKFLOW_RESULT_STREAM_CONTENT_TYPE }
|
|
18411
|
+
});
|
|
18412
|
+
const payload = await readWorkflowResult(response);
|
|
18413
|
+
renderResult("executeWorkflow", profile.output, payload, commandSpec, {
|
|
18414
|
+
expandedTrace: flags.trace === true
|
|
18415
|
+
});
|
|
18416
|
+
const failure = runFailureMessage("executeWorkflow", payload);
|
|
18417
|
+
if (failure)
|
|
18418
|
+
throw new SimApiError(failure, 0);
|
|
18419
|
+
} catch (error) {
|
|
18420
|
+
throw retypeApiError(error, "executeWorkflow", commandSpec, operation);
|
|
18421
|
+
}
|
|
18422
|
+
}
|
|
18356
18423
|
async function* sseData(body) {
|
|
18357
18424
|
const reader = body.getReader();
|
|
18358
18425
|
const decoder = new TextDecoder;
|
|
@@ -18524,6 +18591,10 @@ function followOrDelegate(previous) {
|
|
|
18524
18591
|
if (flags.includeThinking === true || flags.includeToolCalls === true) {
|
|
18525
18592
|
throw new SimApiError("--include-thinking and --include-tool-calls describe a stream; add --follow", 0);
|
|
18526
18593
|
}
|
|
18594
|
+
if (flags.async !== true) {
|
|
18595
|
+
await runWithResultStream(workflowId, command);
|
|
18596
|
+
return;
|
|
18597
|
+
}
|
|
18527
18598
|
if (previous) {
|
|
18528
18599
|
await previous(command.processedArgs);
|
|
18529
18600
|
return;
|