@astralbeam/sdk 0.19.1 → 0.20.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/README.md +1 -1
- package/dist/{badge-B9WuChHI.js → badge-CCWjBUs7.js} +1 -1
- package/dist/client.js +1 -1
- package/dist/{core-CLWlvgYl.js → core-D53b-MKt.js} +231 -247
- package/dist/core.d.ts +2 -2
- package/dist/core.js +1 -1
- package/dist/{highlighter-Bd_oZUcA.js → highlighter-Dr600J9R.js} +1 -1
- package/dist/{index-DDfmeUeU.d.ts → index-Bgv7DalS.d.ts} +24 -8
- package/dist/{item-a9y_9nk7.js → item-BzAQVqAa.js} +1 -1
- package/dist/listings-BV-mV7FI.js +1 -0
- package/dist/{mcp-servers-ESbOt00F.js → mcp-servers-2HRu80la.js} +1 -1
- package/dist/react.d.ts +2 -1
- package/dist/react.js +2 -1
- package/dist/{styles.generated-D4k7izMB.js → styles.generated-DUb9y6Qp.js} +2 -2
- package/dist/{auth-lifecycle-B0BXyDr7.js → threads-3IgJTJaY.js} +6 -6
- package/dist/widget-CqoKBBPU.js +26 -0
- package/package.json +1 -1
- package/dist/listings-DzxJtGCD.js +0 -1
- package/dist/widget-QbGrB087.js +0 -24
|
@@ -10990,6 +10990,7 @@ function selectedThread(key, id) {
|
|
|
10990
10990
|
}
|
|
10991
10991
|
//#endregion
|
|
10992
10992
|
//#region src/core/session.ts
|
|
10993
|
+
const HISTORY_FAILED = "Reopen this conversation or start a new one before sending.";
|
|
10993
10994
|
const CORE_OPTION_KEYS = Object.keys({
|
|
10994
10995
|
agentId: true,
|
|
10995
10996
|
threadId: true,
|
|
@@ -11027,21 +11028,58 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
11027
11028
|
commands: []
|
|
11028
11029
|
},
|
|
11029
11030
|
thread: void 0,
|
|
11030
|
-
|
|
11031
|
-
threadLoadFailed: false,
|
|
11031
|
+
history: "idle",
|
|
11032
11032
|
messagesCursor: void 0,
|
|
11033
11033
|
olderMessagesLoading: false,
|
|
11034
|
-
|
|
11034
|
+
submission: void 0,
|
|
11035
11035
|
activeToolCallIds: [],
|
|
11036
11036
|
pendingInteractions: []
|
|
11037
11037
|
};
|
|
11038
|
+
let submission;
|
|
11039
|
+
const submissions = /* @__PURE__ */ new Map();
|
|
11040
|
+
let clientStatus = "ready";
|
|
11038
11041
|
const update = (next) => {
|
|
11042
|
+
const status = submission?.phase === "submitting" && clientStatus !== "streaming" ? "submitted" : clientStatus;
|
|
11039
11043
|
state = {
|
|
11040
11044
|
...state,
|
|
11041
|
-
...next
|
|
11045
|
+
...next,
|
|
11046
|
+
status
|
|
11042
11047
|
};
|
|
11043
11048
|
for (const listener of listeners) listener();
|
|
11044
11049
|
};
|
|
11050
|
+
const project = ({ id, content, phase, error }) => ({
|
|
11051
|
+
id,
|
|
11052
|
+
content,
|
|
11053
|
+
phase,
|
|
11054
|
+
...error ? { error } : {}
|
|
11055
|
+
});
|
|
11056
|
+
const nextPhases = {
|
|
11057
|
+
submitting: [
|
|
11058
|
+
"accepted",
|
|
11059
|
+
"failed",
|
|
11060
|
+
"refused"
|
|
11061
|
+
],
|
|
11062
|
+
failed: ["submitting"],
|
|
11063
|
+
accepted: [],
|
|
11064
|
+
refused: []
|
|
11065
|
+
};
|
|
11066
|
+
const settle = (sent, phase, error) => {
|
|
11067
|
+
if (!nextPhases[sent.phase].includes(phase)) return false;
|
|
11068
|
+
sent.phase = phase;
|
|
11069
|
+
sent.error = error;
|
|
11070
|
+
if (sent === submission) update({ submission: project(sent) });
|
|
11071
|
+
if (phase === "refused") sent.onRefused?.();
|
|
11072
|
+
return true;
|
|
11073
|
+
};
|
|
11074
|
+
const current = (sent, attempt) => sent === submission && sent.attempt === attempt;
|
|
11075
|
+
const owns = (sent, attempt) => current(sent, attempt) && sent.phase === "submitting";
|
|
11076
|
+
const endUnaccepted = (sent, error) => settle(sent, sent.tools ? "failed" : "refused", error ?? (sent.tools ? /* @__PURE__ */ new Error("This message may not have been sent. Retry to send it.") : void 0));
|
|
11077
|
+
const releaseSubmission = (reason) => {
|
|
11078
|
+
const released = submission;
|
|
11079
|
+
if (released?.phase === "submitting") endUnaccepted(released, released.tools ? void 0 : new Error(reason));
|
|
11080
|
+
submission = void 0;
|
|
11081
|
+
return released;
|
|
11082
|
+
};
|
|
11045
11083
|
const authentication = createChatAuthentication({
|
|
11046
11084
|
apiUrl: live.apiUrl,
|
|
11047
11085
|
scope: "tenant",
|
|
@@ -11052,7 +11090,6 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
11052
11090
|
let identity;
|
|
11053
11091
|
let started = false;
|
|
11054
11092
|
let selectionGeneration = 0;
|
|
11055
|
-
let navigationGeneration = 0;
|
|
11056
11093
|
let historyGeneration = 0;
|
|
11057
11094
|
let hydration = Promise.resolve();
|
|
11058
11095
|
let requestController = new AbortController();
|
|
@@ -11060,17 +11097,13 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
11060
11097
|
let startWithNewThread = false;
|
|
11061
11098
|
let threadRecords = [];
|
|
11062
11099
|
const clientId = newUuid();
|
|
11063
|
-
|
|
11064
|
-
|
|
11065
|
-
const pendingSends = /* @__PURE__ */ new Map();
|
|
11066
|
-
const acceptPendingSend = () => {
|
|
11067
|
-
if (!pendingSend || pendingSend.accepted) return;
|
|
11068
|
-
pendingSend.accepted = true;
|
|
11100
|
+
const acceptSubmission = () => {
|
|
11101
|
+
if (!submission || !settle(submission, "accepted")) return;
|
|
11069
11102
|
if (state.thread) update({ thread: {
|
|
11070
11103
|
...state.thread,
|
|
11071
11104
|
hasMessages: true
|
|
11072
11105
|
} });
|
|
11073
|
-
|
|
11106
|
+
submission.callbacks?.onAccepted?.();
|
|
11074
11107
|
};
|
|
11075
11108
|
const replaceAcceptedMessage = (record) => {
|
|
11076
11109
|
const messages = [...client.getMessages()];
|
|
@@ -11102,14 +11135,14 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
11102
11135
|
toolResults.clear();
|
|
11103
11136
|
for (const [id, result] of retained) toolResults.set(id, result);
|
|
11104
11137
|
};
|
|
11138
|
+
const notifyError = (error) => {
|
|
11139
|
+
if (state.auth.status !== "error" || state.auth.error !== error) live.streamCallbacks?.onError?.(error);
|
|
11140
|
+
};
|
|
11105
11141
|
const reportError = (error) => {
|
|
11106
11142
|
if (error instanceof Error && error.name === "AbortError") return;
|
|
11107
11143
|
const failure = error instanceof Error ? error : new Error(String(error));
|
|
11108
|
-
update({
|
|
11109
|
-
|
|
11110
|
-
status: "error"
|
|
11111
|
-
});
|
|
11112
|
-
if (state.auth.status !== "error" || state.auth.error !== failure) live.streamCallbacks?.onError?.(failure);
|
|
11144
|
+
update({ error: failure });
|
|
11145
|
+
notifyError(failure);
|
|
11113
11146
|
};
|
|
11114
11147
|
const clearUnavailableMcpConnection = (id) => {
|
|
11115
11148
|
update({ unavailableMcpConnections: state.unavailableMcpConnections?.filter((entry) => entry !== id) ?? [] });
|
|
@@ -11278,15 +11311,15 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
11278
11311
|
const body = JSON.parse(init.body);
|
|
11279
11312
|
let path = getRunChatUrl();
|
|
11280
11313
|
let payload;
|
|
11281
|
-
const
|
|
11282
|
-
const previouslyAttempted =
|
|
11283
|
-
if (
|
|
11314
|
+
const sent = body.messages.at(-1)?.role === "user" && submission?.phase === "submitting" ? submission : void 0;
|
|
11315
|
+
const previouslyAttempted = sent?.tools !== void 0;
|
|
11316
|
+
if (sent) payload = {
|
|
11284
11317
|
...body,
|
|
11285
11318
|
threadId: thread.id,
|
|
11286
11319
|
resume: void 0,
|
|
11287
11320
|
parentRunId: void 0,
|
|
11288
11321
|
messages: [body.messages.at(-1)],
|
|
11289
|
-
tools:
|
|
11322
|
+
tools: sent.tools ??= body.tools,
|
|
11290
11323
|
forwardedProps: {
|
|
11291
11324
|
...body.forwardedProps,
|
|
11292
11325
|
clientId
|
|
@@ -11321,7 +11354,7 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
11321
11354
|
liveToolCalls.clear();
|
|
11322
11355
|
update({ activeToolCallIds: [] });
|
|
11323
11356
|
const headers = new Headers(init.headers);
|
|
11324
|
-
if (
|
|
11357
|
+
if (sent) headers.set("Idempotency-Key", sent.key);
|
|
11325
11358
|
const response = await astralBeamChatFetch(path, {
|
|
11326
11359
|
...auth,
|
|
11327
11360
|
...init,
|
|
@@ -11333,7 +11366,7 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
11333
11366
|
name: limit.name,
|
|
11334
11367
|
resetsAt: limit.resets_at
|
|
11335
11368
|
} });
|
|
11336
|
-
if (
|
|
11369
|
+
if (sent && !previouslyAttempted && isAstralBeamApiError(error) && (error.status === 400 || error.status === 413 || error.status === 429)) delete sent.tools;
|
|
11337
11370
|
throw error;
|
|
11338
11371
|
});
|
|
11339
11372
|
if (generation !== selectionGeneration) throw new DOMException("Conversation changed", "AbortError");
|
|
@@ -11350,12 +11383,12 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
11350
11383
|
resetsAt: receipt.usage_limit.resets_at
|
|
11351
11384
|
} } : {}
|
|
11352
11385
|
});
|
|
11353
|
-
if (
|
|
11386
|
+
if (sent) {
|
|
11354
11387
|
const history = await loadThreadMessages(thread.id, auth, void 0, liveToolMessageIds);
|
|
11355
11388
|
if (generation !== selectionGeneration) throw new DOMException("Conversation changed", "AbortError");
|
|
11356
11389
|
const accepted = history.messages.find((message) => message.id === receipt.accepted_message_id);
|
|
11357
11390
|
if (accepted) replaceAcceptedMessage(accepted);
|
|
11358
|
-
|
|
11391
|
+
acceptSubmission();
|
|
11359
11392
|
}
|
|
11360
11393
|
return new Response("", { headers: { "Content-Type": "text/event-stream" } });
|
|
11361
11394
|
}
|
|
@@ -11416,70 +11449,76 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
11416
11449
|
throw error instanceof Error && isAstralBeamApiError(error.cause) ? error.cause : error;
|
|
11417
11450
|
}
|
|
11418
11451
|
};
|
|
11419
|
-
const createClient = (
|
|
11420
|
-
const generation = selectionGeneration;
|
|
11421
|
-
const adapter = { ...connection };
|
|
11422
|
-
delete adapter.hydrate;
|
|
11423
|
-
if (threadId) adapter.hydrate = (_id, options) => {
|
|
11424
|
-
const readGeneration = ++historyGeneration;
|
|
11425
|
-
if (!options?.before) update({ threadLoading: true });
|
|
11426
|
-
const read = (async () => {
|
|
11427
|
-
let history = await loadThreadMessages(threadId, await requestOptions(), options?.before, liveToolMessageIds);
|
|
11428
|
-
while (options?.before && history.messages.every((message) => message.role === "tool") && history.page_after) {
|
|
11429
|
-
const earlier = await loadThreadMessages(threadId, await requestOptions(), history.page_after, liveToolMessageIds);
|
|
11430
|
-
history = {
|
|
11431
|
-
...earlier,
|
|
11432
|
-
messages: [...earlier.messages, ...history.messages]
|
|
11433
|
-
};
|
|
11434
|
-
}
|
|
11435
|
-
if (generation !== selectionGeneration || readGeneration !== historyGeneration) throw new DOMException("Conversation changed", "AbortError");
|
|
11436
|
-
retainToolResults(history);
|
|
11437
|
-
threadRecords = options?.before ? [...history.messages, ...threadRecords] : history.messages;
|
|
11438
|
-
const pageIds = new Set(history.messages.map((message) => message.id));
|
|
11439
|
-
const messages = projectThreadMessages(threadRecords, history.pendingInteractions, liveToolMessageIds).filter((message) => pageIds.has(message.id));
|
|
11440
|
-
if (history.thread.role === "viewer") disposeRenders();
|
|
11441
|
-
const agentChanged = state.thread?.agentId !== history.thread.agent_id;
|
|
11442
|
-
update({
|
|
11443
|
-
thread: threadFromRecord(history.thread, history.messages.length > 0),
|
|
11444
|
-
messagesCursor: history.page_after ?? void 0,
|
|
11445
|
-
pendingInteractions: history.pendingInteractions,
|
|
11446
|
-
threadLoadFailed: false
|
|
11447
|
-
});
|
|
11448
|
-
restoreCompletedWidgets(messages);
|
|
11449
|
-
if (!options?.before && agentChanged) resolveCapabilities();
|
|
11450
|
-
if (!options?.before && messages.length === 0) next.setMessagesManually([]);
|
|
11451
|
-
return {
|
|
11452
|
-
messages,
|
|
11453
|
-
activeRun: null,
|
|
11454
|
-
interrupts: null,
|
|
11455
|
-
page: history.page_after ? {
|
|
11456
|
-
truncated: true,
|
|
11457
|
-
cursor: history.page_after
|
|
11458
|
-
} : { truncated: false }
|
|
11459
|
-
};
|
|
11460
|
-
})();
|
|
11461
|
-
if (!options?.before) {
|
|
11462
|
-
hydration = read;
|
|
11463
|
-
const settled = (failed) => queueMicrotask(() => {
|
|
11464
|
-
if (generation === selectionGeneration && readGeneration === historyGeneration) update({
|
|
11465
|
-
threadLoading: false,
|
|
11466
|
-
threadLoadFailed: failed
|
|
11467
|
-
});
|
|
11468
|
-
});
|
|
11469
|
-
read.then(() => settled(false), () => settled(true));
|
|
11470
|
-
}
|
|
11471
|
-
return read;
|
|
11472
|
-
};
|
|
11452
|
+
const createClient = () => {
|
|
11473
11453
|
const next = new ChatClient({
|
|
11474
|
-
connection:
|
|
11475
|
-
|
|
11454
|
+
connection: {
|
|
11455
|
+
...connection,
|
|
11456
|
+
hydrate: (_id, options) => {
|
|
11457
|
+
const threadId = selectedId;
|
|
11458
|
+
if (!threadId) return Promise.resolve({
|
|
11459
|
+
messages: [],
|
|
11460
|
+
activeRun: null,
|
|
11461
|
+
interrupts: null,
|
|
11462
|
+
page: { truncated: false }
|
|
11463
|
+
});
|
|
11464
|
+
const older = options?.before !== void 0;
|
|
11465
|
+
const readGeneration = older ? historyGeneration : ++historyGeneration;
|
|
11466
|
+
if (!options?.before) update({ history: state.messages.length > 0 || state.thread?.hasMessages === false ? "refreshing" : "loading" });
|
|
11467
|
+
const read = (async () => {
|
|
11468
|
+
let history = await loadThreadMessages(threadId, await requestOptions(), options?.before, liveToolMessageIds);
|
|
11469
|
+
while (options?.before && history.messages.every((message) => message.role === "tool") && history.page_after) {
|
|
11470
|
+
const earlier = await loadThreadMessages(threadId, await requestOptions(), history.page_after, liveToolMessageIds);
|
|
11471
|
+
history = {
|
|
11472
|
+
...earlier,
|
|
11473
|
+
messages: [...earlier.messages, ...history.messages]
|
|
11474
|
+
};
|
|
11475
|
+
}
|
|
11476
|
+
if (client !== next || readGeneration !== historyGeneration) throw new DOMException("Conversation changed", "AbortError");
|
|
11477
|
+
if (!older) retainToolResults(history);
|
|
11478
|
+
threadRecords = older ? [...history.messages, ...threadRecords] : history.messages;
|
|
11479
|
+
const pageIds = new Set(history.messages.map((message) => message.id));
|
|
11480
|
+
const messages = projectThreadMessages(threadRecords, older ? state.pendingInteractions : history.pendingInteractions, liveToolMessageIds).filter((message) => pageIds.has(message.id));
|
|
11481
|
+
if (older) update({ messagesCursor: history.page_after ?? void 0 });
|
|
11482
|
+
else {
|
|
11483
|
+
if (history.thread.role === "viewer") disposeRenders();
|
|
11484
|
+
const agentChanged = state.thread?.agentId !== history.thread.agent_id;
|
|
11485
|
+
update({
|
|
11486
|
+
thread: threadFromRecord(history.thread, history.messages.length > 0),
|
|
11487
|
+
messagesCursor: history.page_after ?? void 0,
|
|
11488
|
+
pendingInteractions: history.pendingInteractions
|
|
11489
|
+
});
|
|
11490
|
+
if (agentChanged) resolveCapabilities();
|
|
11491
|
+
if (messages.length === 0) next.setMessagesManually([]);
|
|
11492
|
+
}
|
|
11493
|
+
restoreCompletedWidgets(messages);
|
|
11494
|
+
return {
|
|
11495
|
+
messages,
|
|
11496
|
+
activeRun: null,
|
|
11497
|
+
interrupts: null,
|
|
11498
|
+
page: history.page_after ? {
|
|
11499
|
+
truncated: true,
|
|
11500
|
+
cursor: history.page_after
|
|
11501
|
+
} : { truncated: false }
|
|
11502
|
+
};
|
|
11503
|
+
})();
|
|
11504
|
+
if (!older) {
|
|
11505
|
+
hydration = read.then(() => "idle", () => "failed").then((history) => new Promise((resolve) => queueMicrotask(() => {
|
|
11506
|
+
if (client === next && readGeneration === historyGeneration) update({ history });
|
|
11507
|
+
resolve();
|
|
11508
|
+
}))).then(() => read);
|
|
11509
|
+
hydration.catch(() => void 0);
|
|
11510
|
+
}
|
|
11511
|
+
return read;
|
|
11512
|
+
}
|
|
11513
|
+
},
|
|
11514
|
+
threadId: selectedId ?? clientId,
|
|
11476
11515
|
persistence: true,
|
|
11477
11516
|
history: { pageSize: 100 },
|
|
11478
11517
|
queue: "drop",
|
|
11479
11518
|
tools: declareTools(),
|
|
11480
11519
|
forwardedProps: forwardedProps(),
|
|
11481
11520
|
onMessagesChange: (messages) => {
|
|
11482
|
-
if (client !== next
|
|
11521
|
+
if (client !== next) return;
|
|
11483
11522
|
restoreCompletedWidgets(messages);
|
|
11484
11523
|
for (const message of messages) {
|
|
11485
11524
|
if (message.role !== "user") continue;
|
|
@@ -11488,16 +11527,13 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
11488
11527
|
}
|
|
11489
11528
|
update({
|
|
11490
11529
|
messages,
|
|
11491
|
-
sandbox: collectSandboxActivity(messages)
|
|
11492
|
-
error: next.getError()
|
|
11530
|
+
sandbox: collectSandboxActivity(messages)
|
|
11493
11531
|
});
|
|
11494
11532
|
},
|
|
11495
11533
|
onStatusChange: (status) => {
|
|
11496
|
-
if (client
|
|
11497
|
-
|
|
11498
|
-
|
|
11499
|
-
...status === "submitted" ? { usageLimitReached: void 0 } : {}
|
|
11500
|
-
});
|
|
11534
|
+
if (client !== next) return;
|
|
11535
|
+
clientStatus = status;
|
|
11536
|
+
update(status === "submitted" ? { usageLimitReached: void 0 } : {});
|
|
11501
11537
|
},
|
|
11502
11538
|
onInterruptStateChange: (interrupts) => {
|
|
11503
11539
|
if (client === next) debug?.("tool", "interrupt state changed", interrupts);
|
|
@@ -11507,8 +11543,8 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
11507
11543
|
if (eventType === "astralbeam_thread") {
|
|
11508
11544
|
const event = data;
|
|
11509
11545
|
if (state.thread?.id === event.threadId) {
|
|
11510
|
-
if (event.acceptedMessage &&
|
|
11511
|
-
if (event.acceptedMessageId)
|
|
11546
|
+
if (event.acceptedMessage && submission?.phase === "submitting") replaceAcceptedMessage(event.acceptedMessage);
|
|
11547
|
+
if (event.acceptedMessageId) acceptSubmission();
|
|
11512
11548
|
if (event.saved) for (const id of event.executableToolCallIds ?? []) {
|
|
11513
11549
|
if (!liveToolCalls.has(id)) toolResults.delete(toolResultKey(id));
|
|
11514
11550
|
liveToolCalls.add(id);
|
|
@@ -11518,8 +11554,7 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
11518
11554
|
...state.thread,
|
|
11519
11555
|
version: event.version
|
|
11520
11556
|
},
|
|
11521
|
-
activeToolCallIds: [...liveToolCalls]
|
|
11522
|
-
...event.acceptedMessageId ? { unsentMessage: void 0 } : {}
|
|
11557
|
+
activeToolCallIds: [...liveToolCalls]
|
|
11523
11558
|
});
|
|
11524
11559
|
}
|
|
11525
11560
|
return;
|
|
@@ -11565,20 +11600,24 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
11565
11600
|
if (client === next) live.streamCallbacks?.onFinish?.(message);
|
|
11566
11601
|
},
|
|
11567
11602
|
onError: (error) => {
|
|
11568
|
-
if (client
|
|
11603
|
+
if (client !== next) return;
|
|
11604
|
+
if (submission?.phase !== "submitting" && error.name !== "AbortError") update({ error });
|
|
11605
|
+
notifyError(error);
|
|
11569
11606
|
}
|
|
11570
11607
|
});
|
|
11571
11608
|
return next;
|
|
11572
11609
|
};
|
|
11610
|
+
let selectedId;
|
|
11573
11611
|
let client = createClient();
|
|
11574
|
-
const replaceClient = (
|
|
11575
|
-
client.stop();
|
|
11612
|
+
const replaceClient = () => {
|
|
11576
11613
|
const previous = client;
|
|
11614
|
+
client = createClient();
|
|
11615
|
+
clientStatus = "ready";
|
|
11616
|
+
previous.stop();
|
|
11577
11617
|
previous.detach();
|
|
11578
11618
|
liveToolCalls.clear();
|
|
11579
11619
|
liveToolMessageIds.clear();
|
|
11580
11620
|
update({ activeToolCallIds: [] });
|
|
11581
|
-
client = createClient(threadId);
|
|
11582
11621
|
if (started) client.attach();
|
|
11583
11622
|
previous.dispose();
|
|
11584
11623
|
};
|
|
@@ -11609,17 +11648,16 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
11609
11648
|
};
|
|
11610
11649
|
const changeSelection = (threadId) => {
|
|
11611
11650
|
const previousId = state.thread?.id;
|
|
11651
|
+
const released = releaseSubmission("The conversation changed before this was sent.");
|
|
11612
11652
|
if (previousId) {
|
|
11613
|
-
if (
|
|
11614
|
-
else
|
|
11653
|
+
if (released?.phase === "failed") submissions.set(previousId, released);
|
|
11654
|
+
else submissions.delete(previousId);
|
|
11615
11655
|
threadToolResults.set(previousId, toolResults);
|
|
11616
11656
|
}
|
|
11617
11657
|
selectionGeneration++;
|
|
11618
|
-
|
|
11619
|
-
sending = false;
|
|
11658
|
+
selectedId = threadId;
|
|
11620
11659
|
requestController.abort();
|
|
11621
11660
|
requestController = new AbortController();
|
|
11622
|
-
pendingSend = void 0;
|
|
11623
11661
|
toolResults = threadToolResults.get(threadId ?? "") ?? /* @__PURE__ */ new Map();
|
|
11624
11662
|
historicalToolIds.clear();
|
|
11625
11663
|
threadRecords = [];
|
|
@@ -11627,9 +11665,8 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
11627
11665
|
update({
|
|
11628
11666
|
thread: void 0,
|
|
11629
11667
|
messages: [],
|
|
11630
|
-
|
|
11668
|
+
submission: void 0,
|
|
11631
11669
|
error: void 0,
|
|
11632
|
-
status: "ready",
|
|
11633
11670
|
sandbox: {
|
|
11634
11671
|
files: [],
|
|
11635
11672
|
commands: []
|
|
@@ -11639,41 +11676,30 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
11639
11676
|
pendingInteractions: [],
|
|
11640
11677
|
serverToolTitles: {},
|
|
11641
11678
|
unavailableMcpConnections: [],
|
|
11642
|
-
|
|
11679
|
+
history: "idle",
|
|
11643
11680
|
messagesCursor: void 0,
|
|
11644
11681
|
olderMessagesLoading: false
|
|
11645
11682
|
});
|
|
11646
|
-
replaceClient(
|
|
11683
|
+
replaceClient();
|
|
11647
11684
|
};
|
|
11648
11685
|
const openThread = async (id, restoring = false) => {
|
|
11649
|
-
if (!restoring) navigationGeneration++;
|
|
11650
11686
|
changeSelection(id);
|
|
11651
11687
|
const generation = selectionGeneration;
|
|
11652
|
-
|
|
11688
|
+
submission = submissions.get(id);
|
|
11689
|
+
if (submission) update({ submission: project(submission) });
|
|
11653
11690
|
try {
|
|
11654
|
-
pendingSend = pendingSends.get(id);
|
|
11655
|
-
update({ unsentMessage: pendingSend?.content });
|
|
11656
11691
|
if (!started) client.attach();
|
|
11657
11692
|
await hydration;
|
|
11658
11693
|
if (generation !== selectionGeneration) return;
|
|
11659
11694
|
if (threadKey) selectedThread(threadKey, id);
|
|
11660
11695
|
} catch (error) {
|
|
11661
|
-
if (generation
|
|
11662
|
-
|
|
11663
|
-
|
|
11664
|
-
return;
|
|
11665
|
-
}
|
|
11666
|
-
update({ threadLoadFailed: true });
|
|
11667
|
-
reportError(error);
|
|
11668
|
-
}
|
|
11669
|
-
} finally {
|
|
11670
|
-
if (generation === selectionGeneration) update({ threadLoading: false });
|
|
11696
|
+
if (generation !== selectionGeneration) return;
|
|
11697
|
+
if (restoring && (live.threadId === void 0 || live.threadId === "auto") && isAstralBeamApiError(error) && error.status === 404) newThread();
|
|
11698
|
+
else reportError(error);
|
|
11671
11699
|
}
|
|
11672
11700
|
};
|
|
11673
11701
|
const newThread = () => {
|
|
11674
|
-
navigationGeneration++;
|
|
11675
11702
|
changeSelection();
|
|
11676
|
-
update({ threadLoading: false });
|
|
11677
11703
|
if (started) resolveCapabilities();
|
|
11678
11704
|
if (threadKey) selectedThread(threadKey, null);
|
|
11679
11705
|
else startWithNewThread = true;
|
|
@@ -11687,53 +11713,33 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
11687
11713
|
if (selected && selected !== "new") openThread(selected, restoring);
|
|
11688
11714
|
else if (!restoring) newThread();
|
|
11689
11715
|
};
|
|
11690
|
-
const ensureThread = async () => {
|
|
11716
|
+
const ensureThread = async (sent, attempt) => {
|
|
11691
11717
|
if (state.thread) return;
|
|
11692
|
-
const generation = selectionGeneration;
|
|
11693
11718
|
const options = await requestOptions();
|
|
11694
11719
|
const record = await createChatThread(live.agentId ? { agent_id: live.agentId } : {}, options);
|
|
11695
|
-
if (
|
|
11696
|
-
|
|
11697
|
-
update({ thread });
|
|
11698
|
-
replaceClient();
|
|
11699
|
-
await hydration;
|
|
11720
|
+
if (!owns(sent, attempt)) throw new DOMException("Send cancelled", "AbortError");
|
|
11721
|
+
selectedId = record.id;
|
|
11722
|
+
update({ thread: threadFromRecord(record, false) });
|
|
11700
11723
|
resolveCapabilities();
|
|
11701
|
-
if (threadKey) selectedThread(threadKey,
|
|
11724
|
+
if (threadKey) selectedThread(threadKey, record.id);
|
|
11702
11725
|
};
|
|
11703
|
-
const refreshThread = async (
|
|
11704
|
-
if (!state.thread
|
|
11726
|
+
const refreshThread = async (explicit = true) => {
|
|
11727
|
+
if (!state.thread) return;
|
|
11705
11728
|
const generation = selectionGeneration;
|
|
11706
|
-
|
|
11707
|
-
update({
|
|
11708
|
-
threadLoading: true,
|
|
11709
|
-
olderMessagesLoading: false
|
|
11710
|
-
});
|
|
11729
|
+
update({ olderMessagesLoading: false });
|
|
11711
11730
|
try {
|
|
11712
|
-
|
|
11713
|
-
|
|
11714
|
-
client.detach();
|
|
11715
|
-
client.attach();
|
|
11716
|
-
}
|
|
11731
|
+
client.detach();
|
|
11732
|
+
client.attach();
|
|
11717
11733
|
await hydration;
|
|
11718
|
-
if (generation
|
|
11719
|
-
if (preserveError && previousError) update({
|
|
11720
|
-
error: previousError,
|
|
11721
|
-
status: "error"
|
|
11722
|
-
});
|
|
11734
|
+
if (explicit && generation === selectionGeneration) update({ error: void 0 });
|
|
11723
11735
|
} catch (error) {
|
|
11724
|
-
if (generation
|
|
11725
|
-
|
|
11726
|
-
|
|
11727
|
-
return;
|
|
11728
|
-
}
|
|
11729
|
-
reportError(error);
|
|
11730
|
-
}
|
|
11731
|
-
} finally {
|
|
11732
|
-
if (generation === selectionGeneration) update({ threadLoading: false });
|
|
11736
|
+
if (generation !== selectionGeneration) return;
|
|
11737
|
+
if (isAstralBeamApiError(error) && error.status === 404) newThread();
|
|
11738
|
+
else reportError(error);
|
|
11733
11739
|
}
|
|
11734
11740
|
};
|
|
11735
11741
|
const loadOlderMessages = async () => {
|
|
11736
|
-
if (!client.getHasOlderMessages() || state.olderMessagesLoading || state.
|
|
11742
|
+
if (!client.getHasOlderMessages() || state.olderMessagesLoading || state.history !== "idle" || submission?.phase === "submitting") return;
|
|
11737
11743
|
const generation = selectionGeneration;
|
|
11738
11744
|
update({ olderMessagesLoading: true });
|
|
11739
11745
|
try {
|
|
@@ -11755,11 +11761,7 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
11755
11761
|
}, await requestOptions());
|
|
11756
11762
|
if (generation !== selectionGeneration) return false;
|
|
11757
11763
|
const renamed = threadFromRecord(record, thread.hasMessages);
|
|
11758
|
-
update({
|
|
11759
|
-
thread: renamed,
|
|
11760
|
-
error: client.getError(),
|
|
11761
|
-
status: client.getStatus()
|
|
11762
|
-
});
|
|
11764
|
+
update({ thread: renamed });
|
|
11763
11765
|
return true;
|
|
11764
11766
|
} catch (error) {
|
|
11765
11767
|
if (generation === selectionGeneration) reportError(error);
|
|
@@ -11780,7 +11782,7 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
11780
11782
|
};
|
|
11781
11783
|
const addToolResult = async (result) => {
|
|
11782
11784
|
const generation = selectionGeneration;
|
|
11783
|
-
if (
|
|
11785
|
+
if (submission?.phase === "submitting" || client.getIsLoading()) {
|
|
11784
11786
|
reportError(/* @__PURE__ */ new Error("Wait for this client's current request to finish before responding."));
|
|
11785
11787
|
return;
|
|
11786
11788
|
}
|
|
@@ -11805,96 +11807,76 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
11805
11807
|
}
|
|
11806
11808
|
scopeCompletedToolCalls();
|
|
11807
11809
|
if (pending) {
|
|
11808
|
-
|
|
11809
|
-
await
|
|
11810
|
+
client.stop();
|
|
11811
|
+
await refreshThread(false);
|
|
11810
11812
|
if (generation !== selectionGeneration) return;
|
|
11811
|
-
update({ threadLoading: false });
|
|
11812
11813
|
await client.append({
|
|
11813
11814
|
role: "tool",
|
|
11814
11815
|
toolCallId: result.toolCallId,
|
|
11815
11816
|
content: JSON.stringify(toolResults.get(toolResultKey(result.toolCallId)))
|
|
11816
11817
|
});
|
|
11817
11818
|
} else if ("tool" in result) await client.addToolResult(result);
|
|
11818
|
-
if (generation === selectionGeneration) await refreshThread(
|
|
11819
|
+
if (generation === selectionGeneration) await refreshThread(false);
|
|
11819
11820
|
};
|
|
11820
11821
|
const abandonToolCall = (toolCallId) => addToolResult({ toolCallId });
|
|
11821
|
-
const
|
|
11822
|
-
const
|
|
11822
|
+
const deliver = async (sent) => {
|
|
11823
|
+
const attempt = ++sent.attempt;
|
|
11823
11824
|
try {
|
|
11824
11825
|
await getValidChatAuthToken(authentication);
|
|
11825
|
-
|
|
11826
|
-
if (
|
|
11827
|
-
|
|
11828
|
-
|
|
11829
|
-
return;
|
|
11830
|
-
|
|
11831
|
-
|
|
11832
|
-
if (sending || state.threadLoading || state.status === "streaming") {
|
|
11833
|
-
reportError(/* @__PURE__ */ new Error("Wait for this client's current request to finish before sending."));
|
|
11834
|
-
return;
|
|
11835
|
-
}
|
|
11836
|
-
if (state.threadLoadFailed) {
|
|
11837
|
-
reportError(/* @__PURE__ */ new Error("Reopen this conversation or start a new one before sending."));
|
|
11838
|
-
return;
|
|
11839
|
-
}
|
|
11840
|
-
const samePendingContent = pendingSend !== void 0 && JSON.stringify(pendingSend.content) === JSON.stringify(content);
|
|
11841
|
-
const uncertainSend = pendingSend?.tools !== void 0 && !pendingSend.accepted ? pendingSend : void 0;
|
|
11842
|
-
const retrying = uncertainSend !== void 0 && samePendingContent;
|
|
11843
|
-
if (state.thread?.agentId === null && !retrying) {
|
|
11844
|
-
reportError(/* @__PURE__ */ new Error("This conversation’s agent is unavailable. Start a new conversation to continue."));
|
|
11845
|
-
return;
|
|
11846
|
-
}
|
|
11847
|
-
if (state.thread?.role === "viewer" && !retrying) {
|
|
11848
|
-
reportError(/* @__PURE__ */ new Error("You have read-only access to this conversation."));
|
|
11849
|
-
return;
|
|
11850
|
-
}
|
|
11851
|
-
if (uncertainSend && !samePendingContent) {
|
|
11852
|
-
update({ unsentMessage: uncertainSend.content });
|
|
11853
|
-
reportError(/* @__PURE__ */ new Error("The previous message’s acceptance is unconfirmed. Retry that message before sending different text, or start a new conversation."));
|
|
11854
|
-
return;
|
|
11855
|
-
}
|
|
11856
|
-
const generation = selectionGeneration;
|
|
11857
|
-
historyGeneration++;
|
|
11858
|
-
update({ olderMessagesLoading: false });
|
|
11859
|
-
sending = true;
|
|
11860
|
-
if (!pendingSend || pendingSend.accepted || !samePendingContent) {
|
|
11861
|
-
pendingSend = {
|
|
11862
|
-
content,
|
|
11863
|
-
accepted: false,
|
|
11864
|
-
key: newUuid(),
|
|
11865
|
-
callbacks
|
|
11866
|
-
};
|
|
11867
|
-
client.stop();
|
|
11868
|
-
liveToolCalls.clear();
|
|
11826
|
+
await hydration.catch(() => void 0);
|
|
11827
|
+
if (!owns(sent, attempt)) return project(sent);
|
|
11828
|
+
if (state.history === "failed") throw new Error(HISTORY_FAILED);
|
|
11829
|
+
await ensureThread(sent, attempt);
|
|
11830
|
+
if (!owns(sent, attempt)) return project(sent);
|
|
11831
|
+
sent.callbacks?.onThreadReady?.(state.thread.id);
|
|
11832
|
+
if (!owns(sent, attempt)) return project(sent);
|
|
11869
11833
|
scopeCompletedToolCalls();
|
|
11870
|
-
|
|
11871
|
-
|
|
11834
|
+
await client.sendMessage(sent.content);
|
|
11835
|
+
if (!current(sent, attempt)) return project(sent);
|
|
11836
|
+
endUnaccepted(sent, client.getError());
|
|
11837
|
+
await refreshThread(false);
|
|
11838
|
+
} catch (error) {
|
|
11839
|
+
if (!current(sent, attempt)) return project(sent);
|
|
11840
|
+
const failure = error instanceof Error ? error : new Error(String(error));
|
|
11841
|
+
if (failure.name === "AbortError") endUnaccepted(sent);
|
|
11842
|
+
else if (endUnaccepted(sent, failure)) notifyError(failure);
|
|
11872
11843
|
}
|
|
11873
|
-
|
|
11844
|
+
return project(sent);
|
|
11845
|
+
};
|
|
11846
|
+
const sendMessage = async (content, callbacks) => {
|
|
11847
|
+
const rejection = submission?.phase === "submitting" || state.status === "streaming" || client.getIsLoading() ? "Wait for this client's current request to finish before sending." : state.history === "loading" ? "Wait for this conversation to load before sending." : state.history === "failed" ? HISTORY_FAILED : state.thread?.agentId === null ? "This conversation’s agent is unavailable. Start a new conversation to continue." : state.thread?.role === "viewer" ? "You have read-only access to this conversation." : submission?.phase === "failed" ? "The previous message’s acceptance is unconfirmed. Retry that message before sending different text, or start a new conversation." : void 0;
|
|
11848
|
+
if (rejection) return {
|
|
11849
|
+
id: newUuid(),
|
|
11850
|
+
content,
|
|
11851
|
+
phase: "refused",
|
|
11852
|
+
error: new Error(rejection)
|
|
11853
|
+
};
|
|
11854
|
+
const sent = {
|
|
11855
|
+
id: newUuid(),
|
|
11856
|
+
content,
|
|
11857
|
+
phase: "submitting",
|
|
11858
|
+
key: newUuid(),
|
|
11859
|
+
callbacks,
|
|
11860
|
+
attempt: 0
|
|
11861
|
+
};
|
|
11862
|
+
submission = sent;
|
|
11874
11863
|
update({
|
|
11875
|
-
|
|
11864
|
+
submission: project(sent),
|
|
11876
11865
|
error: void 0,
|
|
11877
|
-
|
|
11866
|
+
olderMessagesLoading: false
|
|
11878
11867
|
});
|
|
11879
|
-
|
|
11880
|
-
|
|
11881
|
-
|
|
11882
|
-
|
|
11883
|
-
|
|
11884
|
-
|
|
11885
|
-
|
|
11886
|
-
|
|
11887
|
-
|
|
11888
|
-
|
|
11889
|
-
|
|
11890
|
-
|
|
11891
|
-
}
|
|
11892
|
-
await refreshThread(failed, false);
|
|
11893
|
-
} catch (error) {
|
|
11894
|
-
if (generation === selectionGeneration) reportError(error);
|
|
11895
|
-
} finally {
|
|
11896
|
-
if (generation === selectionGeneration) sending = false;
|
|
11897
|
-
}
|
|
11868
|
+
client.stop();
|
|
11869
|
+
liveToolCalls.clear();
|
|
11870
|
+
scopeCompletedToolCalls();
|
|
11871
|
+
liveToolMessageIds.clear();
|
|
11872
|
+
update({ activeToolCallIds: [] });
|
|
11873
|
+
const refused = new Promise((resolve) => sent.onRefused = resolve);
|
|
11874
|
+
return Promise.race([deliver(sent), refused.then(() => project(sent))]);
|
|
11875
|
+
};
|
|
11876
|
+
const retry = async () => {
|
|
11877
|
+
if (!submission || !settle(submission, "submitting")) return void 0;
|
|
11878
|
+
update({ error: void 0 });
|
|
11879
|
+
return deliver(submission);
|
|
11898
11880
|
};
|
|
11899
11881
|
const observeAuthentication = () => {
|
|
11900
11882
|
const auth = authenticationState(authentication);
|
|
@@ -11902,16 +11884,15 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
11902
11884
|
if (auth.status === "ready") {
|
|
11903
11885
|
const nextIdentity = authenticationIdentity(auth.currentUser);
|
|
11904
11886
|
if (identity !== void 0 && identity !== nextIdentity) {
|
|
11905
|
-
|
|
11906
|
-
|
|
11887
|
+
releaseSubmission("The account changed before this was sent.");
|
|
11888
|
+
submissions.clear();
|
|
11907
11889
|
threadToolResults.clear();
|
|
11908
11890
|
toolResults.clear();
|
|
11909
|
-
pendingSend = void 0;
|
|
11910
11891
|
}
|
|
11911
11892
|
identity = nextIdentity;
|
|
11912
11893
|
const nextThreadKey = `astralbeam:thread:${live.apiUrl ?? "https://astralbeam.ai/api"}:${nextIdentity}`;
|
|
11913
11894
|
if (threadKey !== nextThreadKey) {
|
|
11914
|
-
changeSelection();
|
|
11895
|
+
if (threadKey !== void 0) changeSelection();
|
|
11915
11896
|
threadKey = nextThreadKey;
|
|
11916
11897
|
if (startWithNewThread) {
|
|
11917
11898
|
selectedThread(nextThreadKey, null);
|
|
@@ -11963,22 +11944,24 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
11963
11944
|
forwardedProps: forwardedProps()
|
|
11964
11945
|
});
|
|
11965
11946
|
if (live.apiUrl !== apiUrl) {
|
|
11966
|
-
|
|
11967
|
-
|
|
11947
|
+
releaseSubmission("The chat service changed before this was sent.");
|
|
11948
|
+
submissions.clear();
|
|
11968
11949
|
threadToolResults.clear();
|
|
11969
11950
|
toolResults.clear();
|
|
11970
|
-
pendingSend = void 0;
|
|
11971
11951
|
changeSelection();
|
|
11972
11952
|
threadKey = void 0;
|
|
11973
|
-
update({ threadLoading: false });
|
|
11974
11953
|
observeAuthentication();
|
|
11975
11954
|
} else if (live.threadId !== selectedId) selectConfiguredThread();
|
|
11976
11955
|
if (widgets !== live.widgets || onRenderWidget !== live.onRenderWidget) restoreCompletedWidgets(state.messages);
|
|
11977
11956
|
if (started && (live.agentId !== agent || live.apiUrl !== apiUrl)) resolveCapabilities();
|
|
11978
11957
|
},
|
|
11979
11958
|
sendMessage,
|
|
11959
|
+
retry,
|
|
11980
11960
|
addToolResult,
|
|
11981
|
-
stop: () =>
|
|
11961
|
+
stop: () => {
|
|
11962
|
+
if (submission?.phase === "submitting") endUnaccepted(submission);
|
|
11963
|
+
client.stop();
|
|
11964
|
+
},
|
|
11982
11965
|
retryAuthentication: () => {
|
|
11983
11966
|
getValidChatAuthToken({
|
|
11984
11967
|
...authentication,
|
|
@@ -12016,7 +11999,7 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
12016
11999
|
openThread,
|
|
12017
12000
|
renameThread,
|
|
12018
12001
|
deleteThread,
|
|
12019
|
-
refreshThread,
|
|
12002
|
+
refreshThread: () => refreshThread(),
|
|
12020
12003
|
loadOlderMessages,
|
|
12021
12004
|
uploadAttachment: async ({ data, filename, mimeType }) => {
|
|
12022
12005
|
const agentId = state.thread ? state.thread.agentId : live.agentId;
|
|
@@ -12062,6 +12045,7 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
12062
12045
|
newThread();
|
|
12063
12046
|
},
|
|
12064
12047
|
dispose: () => {
|
|
12048
|
+
releaseSubmission("The chat closed before this was sent.");
|
|
12065
12049
|
client.detach();
|
|
12066
12050
|
disposeRenders();
|
|
12067
12051
|
client.stop();
|