@m8t-stack/cli 0.2.65 → 0.2.67
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/cli.js +343 -32
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1364,7 +1364,7 @@ var init_enable_hosted_brain = __esm({
|
|
|
1364
1364
|
import { Builtins, Cli } from "clipanion";
|
|
1365
1365
|
|
|
1366
1366
|
// src/lib/package-version.ts
|
|
1367
|
-
var CLI_VERSION = "0.2.
|
|
1367
|
+
var CLI_VERSION = "0.2.67";
|
|
1368
1368
|
|
|
1369
1369
|
// src/lib/render-error.ts
|
|
1370
1370
|
init_errors();
|
|
@@ -21295,6 +21295,7 @@ function resolveHeadlessContextFromEnv(env) {
|
|
|
21295
21295
|
|
|
21296
21296
|
// src/lib/apply-request-store.ts
|
|
21297
21297
|
import { TableClient as TableClient4 } from "@azure/data-tables";
|
|
21298
|
+
var MAX_LEASE_TAKEOVERS = 2;
|
|
21298
21299
|
async function openApplyTable(opts) {
|
|
21299
21300
|
const { tableEndpoint } = await discoverStampStorage(opts);
|
|
21300
21301
|
return new TableClient4(tableEndpoint, "Metadata", opts.credential);
|
|
@@ -21314,12 +21315,37 @@ async function readApplyRequest(client) {
|
|
|
21314
21315
|
async function claimApplyRequest(client, executionId, nowIso, leaseMs) {
|
|
21315
21316
|
const cur = await readApplyRequest(client);
|
|
21316
21317
|
if (!cur) return null;
|
|
21317
|
-
const leaseExpired = cur.status
|
|
21318
|
+
const leaseExpired = isInFlight(cur.status) && cur.leaseUntil !== null && Date.parse(cur.leaseUntil) < Date.parse(nowIso);
|
|
21318
21319
|
const claimable = cur.status === "pending" || cur.status === "awaiting-engine-update" || leaseExpired;
|
|
21319
21320
|
if (!claimable) return null;
|
|
21320
21321
|
const nowMs = Date.parse(nowIso);
|
|
21321
21322
|
const leaseUntil = new Date((Number.isNaN(nowMs) ? Date.now() : nowMs) + leaseMs).toISOString();
|
|
21322
|
-
|
|
21323
|
+
if (leaseExpired && cur.attempt >= MAX_LEASE_TAKEOVERS) {
|
|
21324
|
+
const held = {
|
|
21325
|
+
...cur,
|
|
21326
|
+
status: "held",
|
|
21327
|
+
breaker: "held",
|
|
21328
|
+
result: {
|
|
21329
|
+
appliedVersion: cur.result?.appliedVersion ?? null,
|
|
21330
|
+
error: `the converge was abandoned mid-apply ${(cur.attempt + 1).toString()} times (last owner ${cur.claimedBy ?? "(unknown)"}, phase "${cur.phase ?? "(none)"}"); the updater stopped retrying to avoid re-rolling infra behind a converge that cannot finish`
|
|
21331
|
+
},
|
|
21332
|
+
updatedAt: nowIso
|
|
21333
|
+
};
|
|
21334
|
+
try {
|
|
21335
|
+
await client.updateEntity({ ...applyRequestToEntity(held), etag: cur.etag }, "Merge", { etag: cur.etag });
|
|
21336
|
+
} catch (e) {
|
|
21337
|
+
if (!hasStatus(e, 412)) throw e;
|
|
21338
|
+
}
|
|
21339
|
+
return null;
|
|
21340
|
+
}
|
|
21341
|
+
const claimed = {
|
|
21342
|
+
...cur,
|
|
21343
|
+
status: "claimed",
|
|
21344
|
+
claimedBy: executionId,
|
|
21345
|
+
leaseUntil,
|
|
21346
|
+
...leaseExpired ? { attempt: cur.attempt + 1 } : {},
|
|
21347
|
+
updatedAt: nowIso
|
|
21348
|
+
};
|
|
21323
21349
|
try {
|
|
21324
21350
|
await client.updateEntity({ ...applyRequestToEntity(claimed), etag: cur.etag }, "Merge", { etag: cur.etag });
|
|
21325
21351
|
return claimed;
|
|
@@ -33147,6 +33173,10 @@ var COMPANION_REQUEST_ID_MAX_LENGTH = 128;
|
|
|
33147
33173
|
var COMPANION_AGENT_NAME_MAX_LENGTH = 256;
|
|
33148
33174
|
var COMPANION_DESKTOP_AFTER_MAX_LENGTH = 256;
|
|
33149
33175
|
var COMPANION_BRIDGE_LINE_MAX_LENGTH = 14e4;
|
|
33176
|
+
var COMPANION_HISTORY_LIMIT_MAX = 40;
|
|
33177
|
+
var COMPANION_TURN_TEXT_MAX_CODE_POINTS = 32768;
|
|
33178
|
+
var COMPANION_REPLY_DELTA_MAX_CODE_POINTS = 4096;
|
|
33179
|
+
var COMPANION_TURN_ID_MAX_LENGTH = 256;
|
|
33150
33180
|
var PERSONAS = /* @__PURE__ */ new Set([
|
|
33151
33181
|
"startup-advisor",
|
|
33152
33182
|
"azure-advisor"
|
|
@@ -33181,6 +33211,17 @@ function isBoundedPlainString(value, maxLength) {
|
|
|
33181
33211
|
function isRequestId(value) {
|
|
33182
33212
|
return isBoundedPlainString(value, COMPANION_REQUEST_ID_MAX_LENGTH);
|
|
33183
33213
|
}
|
|
33214
|
+
var FORBIDDEN_TEXT_CHARACTERS = /[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/u;
|
|
33215
|
+
function isBoundedMessageText(value, maxCodePoints) {
|
|
33216
|
+
return typeof value === "string" && value.length > 0 && !FORBIDDEN_TEXT_CHARACTERS.test(value) && [...value].length <= maxCodePoints;
|
|
33217
|
+
}
|
|
33218
|
+
var INSTANT_SHAPE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?Z$/;
|
|
33219
|
+
function isInstantOrNull(value) {
|
|
33220
|
+
return value === null || typeof value === "string" && INSTANT_SHAPE.test(value) && Number.isFinite(Date.parse(value));
|
|
33221
|
+
}
|
|
33222
|
+
function isCompanionTurn(value) {
|
|
33223
|
+
return isRecord2(value) && hasExactKeys(value, ["id", "role", "text", "at"]) && isBoundedPlainString(value.id, COMPANION_TURN_ID_MAX_LENGTH) && (value.role === "user" || value.role === "mate") && isBoundedMessageText(value.text, COMPANION_TURN_TEXT_MAX_CODE_POINTS) && isInstantOrNull(value.at);
|
|
33224
|
+
}
|
|
33184
33225
|
function isCanonicalInstant(value) {
|
|
33185
33226
|
if (typeof value !== "string") return false;
|
|
33186
33227
|
const time = Date.parse(value);
|
|
@@ -33244,7 +33285,18 @@ function parseRequest(value) {
|
|
|
33244
33285
|
if (!hasExactKeys(value, ["type"])) return requestError();
|
|
33245
33286
|
return { type: "update" };
|
|
33246
33287
|
}
|
|
33247
|
-
if (value.type
|
|
33288
|
+
if (value.type === "history") {
|
|
33289
|
+
if (!hasExactKeys(value, ["type", "requestId", "personaKey", "limit"]) || !isRequestId(value.requestId) || !isPersonaKey(value.personaKey) || !Number.isSafeInteger(value.limit) || value.limit < 1 || value.limit > COMPANION_HISTORY_LIMIT_MAX) {
|
|
33290
|
+
return requestError();
|
|
33291
|
+
}
|
|
33292
|
+
return {
|
|
33293
|
+
type: "history",
|
|
33294
|
+
requestId: value.requestId,
|
|
33295
|
+
personaKey: value.personaKey,
|
|
33296
|
+
limit: value.limit
|
|
33297
|
+
};
|
|
33298
|
+
}
|
|
33299
|
+
if (value.type !== "send" && value.type !== "converse" || !hasExactKeys(value, [
|
|
33248
33300
|
"type",
|
|
33249
33301
|
"requestId",
|
|
33250
33302
|
"personaKey",
|
|
@@ -33254,7 +33306,7 @@ function parseRequest(value) {
|
|
|
33254
33306
|
return requestError();
|
|
33255
33307
|
}
|
|
33256
33308
|
return {
|
|
33257
|
-
type:
|
|
33309
|
+
type: value.type,
|
|
33258
33310
|
requestId: value.requestId,
|
|
33259
33311
|
personaKey: value.personaKey,
|
|
33260
33312
|
draftRevision: value.draftRevision,
|
|
@@ -33339,6 +33391,41 @@ function parseEvent(value) {
|
|
|
33339
33391
|
}
|
|
33340
33392
|
return { type: "completed", requestId: value.requestId };
|
|
33341
33393
|
}
|
|
33394
|
+
if (value.type === "turn") {
|
|
33395
|
+
if (!hasExactKeys(value, ["type", "requestId", "turn"]) || !isRequestId(value.requestId) || !isCompanionTurn(value.turn)) {
|
|
33396
|
+
return eventError();
|
|
33397
|
+
}
|
|
33398
|
+
return {
|
|
33399
|
+
type: "turn",
|
|
33400
|
+
requestId: value.requestId,
|
|
33401
|
+
turn: {
|
|
33402
|
+
id: value.turn.id,
|
|
33403
|
+
role: value.turn.role,
|
|
33404
|
+
text: value.turn.text,
|
|
33405
|
+
at: value.turn.at
|
|
33406
|
+
}
|
|
33407
|
+
};
|
|
33408
|
+
}
|
|
33409
|
+
if (value.type === "history-end") {
|
|
33410
|
+
if (!hasExactKeys(value, ["type", "requestId", "count"]) || !isRequestId(value.requestId) || !Number.isSafeInteger(value.count) || value.count < 0 || value.count > COMPANION_HISTORY_LIMIT_MAX) {
|
|
33411
|
+
return eventError();
|
|
33412
|
+
}
|
|
33413
|
+
return {
|
|
33414
|
+
type: "history-end",
|
|
33415
|
+
requestId: value.requestId,
|
|
33416
|
+
count: value.count
|
|
33417
|
+
};
|
|
33418
|
+
}
|
|
33419
|
+
if (value.type === "reply-delta") {
|
|
33420
|
+
if (!hasExactKeys(value, ["type", "requestId", "text"]) || !isRequestId(value.requestId) || !isBoundedMessageText(value.text, COMPANION_REPLY_DELTA_MAX_CODE_POINTS)) {
|
|
33421
|
+
return eventError();
|
|
33422
|
+
}
|
|
33423
|
+
return {
|
|
33424
|
+
type: "reply-delta",
|
|
33425
|
+
requestId: value.requestId,
|
|
33426
|
+
text: value.text
|
|
33427
|
+
};
|
|
33428
|
+
}
|
|
33342
33429
|
if (value.type === "dispatching" || value.type === "accepted") {
|
|
33343
33430
|
if (!hasExactKeys(value, [
|
|
33344
33431
|
"type",
|
|
@@ -33496,6 +33583,77 @@ function decodeLastMessageId(data) {
|
|
|
33496
33583
|
}
|
|
33497
33584
|
return last.id;
|
|
33498
33585
|
}
|
|
33586
|
+
async function resolveConversationId(fetchImpl, origin, headers, agentName, signal) {
|
|
33587
|
+
let response;
|
|
33588
|
+
try {
|
|
33589
|
+
response = await fetchImpl(`${origin}/api/conversations`, {
|
|
33590
|
+
method: "POST",
|
|
33591
|
+
headers: { ...headers, "content-type": "application/json" },
|
|
33592
|
+
body: JSON.stringify({ agentName }),
|
|
33593
|
+
signal
|
|
33594
|
+
});
|
|
33595
|
+
} catch {
|
|
33596
|
+
throw new PredispatchFailure("not-connected");
|
|
33597
|
+
}
|
|
33598
|
+
return decodeConversationId(await readJsonEnvelope(response));
|
|
33599
|
+
}
|
|
33600
|
+
async function fetchConversationMessages(fetchImpl, origin, headers, conversationId, signal) {
|
|
33601
|
+
let response;
|
|
33602
|
+
try {
|
|
33603
|
+
response = await fetchImpl(
|
|
33604
|
+
`${origin}/api/conversations/${encodeURIComponent(conversationId)}/messages`,
|
|
33605
|
+
{ headers, signal }
|
|
33606
|
+
);
|
|
33607
|
+
} catch {
|
|
33608
|
+
throw new PredispatchFailure("not-connected");
|
|
33609
|
+
}
|
|
33610
|
+
return readJsonEnvelope(response);
|
|
33611
|
+
}
|
|
33612
|
+
var EPOCH_SECONDS_LIMIT = 1e11;
|
|
33613
|
+
function sanitizeMessageText(value) {
|
|
33614
|
+
let out = "";
|
|
33615
|
+
for (const character of value) {
|
|
33616
|
+
const code = character.codePointAt(0) ?? 0;
|
|
33617
|
+
const forbidden = code === 127 || code <= 31 && code !== 9 && code !== 10 && code !== 13;
|
|
33618
|
+
if (!forbidden) out += character;
|
|
33619
|
+
}
|
|
33620
|
+
return out;
|
|
33621
|
+
}
|
|
33622
|
+
function boundCodePoints(value, maxCodePoints) {
|
|
33623
|
+
let count = 0;
|
|
33624
|
+
let out = "";
|
|
33625
|
+
for (const character of value) {
|
|
33626
|
+
if (count >= maxCodePoints) return out;
|
|
33627
|
+
out += character;
|
|
33628
|
+
count += 1;
|
|
33629
|
+
}
|
|
33630
|
+
return value;
|
|
33631
|
+
}
|
|
33632
|
+
function decodeTurns(data, limit2) {
|
|
33633
|
+
if (!isRecord3(data) || !Array.isArray(data.messages)) {
|
|
33634
|
+
throw new PredispatchFailure("not-connected");
|
|
33635
|
+
}
|
|
33636
|
+
const turns = [];
|
|
33637
|
+
for (const entry of data.messages) {
|
|
33638
|
+
if (!isRecord3(entry)) continue;
|
|
33639
|
+
if (entry.role !== "user" && entry.role !== "assistant") continue;
|
|
33640
|
+
if (typeof entry.id !== "string" || !OPAQUE_ID.test(entry.id)) continue;
|
|
33641
|
+
if (typeof entry.content !== "string") continue;
|
|
33642
|
+
const text = boundCodePoints(
|
|
33643
|
+
sanitizeMessageText(entry.content),
|
|
33644
|
+
COMPANION_TURN_TEXT_MAX_CODE_POINTS
|
|
33645
|
+
);
|
|
33646
|
+
if (text.length === 0) continue;
|
|
33647
|
+
const at = typeof entry.createdAt === "number" && Number.isFinite(entry.createdAt) && entry.createdAt > 0 && entry.createdAt < EPOCH_SECONDS_LIMIT ? new Date(Math.round(entry.createdAt) * 1e3).toISOString() : null;
|
|
33648
|
+
turns.push({
|
|
33649
|
+
id: entry.id,
|
|
33650
|
+
role: entry.role === "user" ? "user" : "mate",
|
|
33651
|
+
text,
|
|
33652
|
+
at
|
|
33653
|
+
});
|
|
33654
|
+
}
|
|
33655
|
+
return turns.slice(-limit2);
|
|
33656
|
+
}
|
|
33499
33657
|
function mateRoute(personaKey, desktopAfter) {
|
|
33500
33658
|
const marker = desktopAfter === void 0 ? "" : `&desktopAfter=${desktopAfter}`;
|
|
33501
33659
|
return `/mates/${personaKey}?desktopPending=1${marker}`;
|
|
@@ -33618,7 +33776,93 @@ async function drainAcceptedSse(response) {
|
|
|
33618
33776
|
}
|
|
33619
33777
|
if (!sawDone) throw new Error("stream ended without terminal marker");
|
|
33620
33778
|
}
|
|
33621
|
-
|
|
33779
|
+
var REPLY_FLUSH_MIN_LENGTH = 64;
|
|
33780
|
+
var REPLY_FLUSH_MS = 150;
|
|
33781
|
+
function emitBoundedText(text, emit) {
|
|
33782
|
+
let slice = "";
|
|
33783
|
+
let count = 0;
|
|
33784
|
+
for (const character of text) {
|
|
33785
|
+
slice += character;
|
|
33786
|
+
count += 1;
|
|
33787
|
+
if (count === COMPANION_REPLY_DELTA_MAX_CODE_POINTS) {
|
|
33788
|
+
emit(slice);
|
|
33789
|
+
slice = "";
|
|
33790
|
+
count = 0;
|
|
33791
|
+
}
|
|
33792
|
+
}
|
|
33793
|
+
if (slice.length > 0) emit(slice);
|
|
33794
|
+
}
|
|
33795
|
+
async function streamAcceptedSse(response, now, onText) {
|
|
33796
|
+
if (!response.body) throw new Error("response body unavailable");
|
|
33797
|
+
const reader = response.body.getReader();
|
|
33798
|
+
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
33799
|
+
let buffered = "";
|
|
33800
|
+
let total = 0;
|
|
33801
|
+
const terminal = { sawDone: false };
|
|
33802
|
+
let pending = "";
|
|
33803
|
+
let lastFlush = now();
|
|
33804
|
+
const flush = () => {
|
|
33805
|
+
const text = sanitizeMessageText(pending);
|
|
33806
|
+
pending = "";
|
|
33807
|
+
lastFlush = now();
|
|
33808
|
+
if (text.length > 0) emitBoundedText(text, onText);
|
|
33809
|
+
};
|
|
33810
|
+
const handleFrame = (frame) => {
|
|
33811
|
+
if (frame.trim().length === 0) return;
|
|
33812
|
+
const dataLines = frame.split(/\r?\n/u).filter((line2) => line2.startsWith("data:")).map((line2) => line2.slice(5).trimStart());
|
|
33813
|
+
if (dataLines.length === 0) return;
|
|
33814
|
+
const data = dataLines.join("\n");
|
|
33815
|
+
if (terminal.sawDone) throw new Error("data after terminal stream marker");
|
|
33816
|
+
if (data === "[DONE]") {
|
|
33817
|
+
terminal.sawDone = true;
|
|
33818
|
+
return;
|
|
33819
|
+
}
|
|
33820
|
+
const parsed = JSON.parse(data);
|
|
33821
|
+
if (!isRecord3(parsed) || typeof parsed.type !== "string" || parsed.type === "error") {
|
|
33822
|
+
throw new Error("invalid stream event");
|
|
33823
|
+
}
|
|
33824
|
+
if (parsed.type === "text-delta" && typeof parsed.delta === "string" && parsed.delta.length > 0) {
|
|
33825
|
+
pending += parsed.delta;
|
|
33826
|
+
if (pending.length >= REPLY_FLUSH_MIN_LENGTH || now() - lastFlush >= REPLY_FLUSH_MS) {
|
|
33827
|
+
flush();
|
|
33828
|
+
}
|
|
33829
|
+
}
|
|
33830
|
+
};
|
|
33831
|
+
const drainFrames = () => {
|
|
33832
|
+
for (; ; ) {
|
|
33833
|
+
const boundary = /\r?\n\r?\n/u.exec(buffered);
|
|
33834
|
+
if (!boundary) return;
|
|
33835
|
+
const frame = buffered.slice(0, boundary.index);
|
|
33836
|
+
buffered = buffered.slice(boundary.index + boundary[0].length);
|
|
33837
|
+
handleFrame(frame);
|
|
33838
|
+
}
|
|
33839
|
+
};
|
|
33840
|
+
for (; ; ) {
|
|
33841
|
+
const part = await reader.read();
|
|
33842
|
+
if (part.done) break;
|
|
33843
|
+
total += part.value.byteLength;
|
|
33844
|
+
if (total > RESPONSE_MAX_BYTES) {
|
|
33845
|
+
await reader.cancel().catch(() => void 0);
|
|
33846
|
+
throw new Error("bounded response rejected");
|
|
33847
|
+
}
|
|
33848
|
+
buffered += decoder.decode(part.value, { stream: true });
|
|
33849
|
+
drainFrames();
|
|
33850
|
+
if (terminal.sawDone) {
|
|
33851
|
+
await reader.cancel().catch(() => void 0);
|
|
33852
|
+
break;
|
|
33853
|
+
}
|
|
33854
|
+
}
|
|
33855
|
+
if (!terminal.sawDone) {
|
|
33856
|
+
buffered += decoder.decode();
|
|
33857
|
+
drainFrames();
|
|
33858
|
+
if (buffered.trim().length > 0) handleFrame(buffered);
|
|
33859
|
+
}
|
|
33860
|
+
flush();
|
|
33861
|
+
if (!terminal.sawDone) {
|
|
33862
|
+
throw new Error("stream ended without terminal marker");
|
|
33863
|
+
}
|
|
33864
|
+
}
|
|
33865
|
+
async function dispatchConversation(request, sink, deps, consume, readDesktopMarker) {
|
|
33622
33866
|
const { controller, timer } = createDeadline(deps);
|
|
33623
33867
|
const fetchImpl = deps.fetch ?? fetch;
|
|
33624
33868
|
let route;
|
|
@@ -33634,32 +33878,22 @@ async function sendCompanionMessage(request, sink, deps = {}) {
|
|
|
33634
33878
|
controller.signal
|
|
33635
33879
|
);
|
|
33636
33880
|
const agentName = resolveAgentName(agents, request.personaKey);
|
|
33637
|
-
|
|
33638
|
-
|
|
33639
|
-
|
|
33640
|
-
|
|
33641
|
-
|
|
33642
|
-
|
|
33643
|
-
signal: controller.signal
|
|
33644
|
-
});
|
|
33645
|
-
} catch {
|
|
33646
|
-
throw new PredispatchFailure("not-connected");
|
|
33647
|
-
}
|
|
33648
|
-
const conversationId = decodeConversationId(
|
|
33649
|
-
await readJsonEnvelope(conversationResponse)
|
|
33650
|
-
);
|
|
33651
|
-
let messagesResponse;
|
|
33652
|
-
try {
|
|
33653
|
-
messagesResponse = await fetchImpl(
|
|
33654
|
-
`${origin}/api/conversations/${encodeURIComponent(conversationId)}/messages`,
|
|
33655
|
-
{ headers, signal: controller.signal }
|
|
33656
|
-
);
|
|
33657
|
-
} catch {
|
|
33658
|
-
throw new PredispatchFailure("not-connected");
|
|
33659
|
-
}
|
|
33660
|
-
const desktopAfter = decodeLastMessageId(
|
|
33661
|
-
await readJsonEnvelope(messagesResponse)
|
|
33881
|
+
const conversationId = await resolveConversationId(
|
|
33882
|
+
fetchImpl,
|
|
33883
|
+
origin,
|
|
33884
|
+
headers,
|
|
33885
|
+
agentName,
|
|
33886
|
+
controller.signal
|
|
33662
33887
|
);
|
|
33888
|
+
const desktopAfter = readDesktopMarker ? decodeLastMessageId(
|
|
33889
|
+
await fetchConversationMessages(
|
|
33890
|
+
fetchImpl,
|
|
33891
|
+
origin,
|
|
33892
|
+
headers,
|
|
33893
|
+
conversationId,
|
|
33894
|
+
controller.signal
|
|
33895
|
+
)
|
|
33896
|
+
) : void 0;
|
|
33663
33897
|
route = mateRoute(request.personaKey, desktopAfter);
|
|
33664
33898
|
const dispatching = parseEvent({
|
|
33665
33899
|
type: "dispatching",
|
|
@@ -33695,7 +33929,7 @@ async function sendCompanionMessage(request, sink, deps = {}) {
|
|
|
33695
33929
|
});
|
|
33696
33930
|
sink(acceptedEvent);
|
|
33697
33931
|
accepted = true;
|
|
33698
|
-
await
|
|
33932
|
+
await consume(chatResponse);
|
|
33699
33933
|
const completed = parseEvent({
|
|
33700
33934
|
type: "completed",
|
|
33701
33935
|
requestId: request.requestId
|
|
@@ -33722,6 +33956,76 @@ async function sendCompanionMessage(request, sink, deps = {}) {
|
|
|
33722
33956
|
clearTimeout(timer);
|
|
33723
33957
|
}
|
|
33724
33958
|
}
|
|
33959
|
+
async function sendCompanionMessage(request, sink, deps = {}) {
|
|
33960
|
+
return dispatchConversation(request, sink, deps, drainAcceptedSse, true);
|
|
33961
|
+
}
|
|
33962
|
+
async function converseCompanionMessage(request, sink, deps = {}) {
|
|
33963
|
+
return dispatchConversation(
|
|
33964
|
+
request,
|
|
33965
|
+
sink,
|
|
33966
|
+
deps,
|
|
33967
|
+
(response) => streamAcceptedSse(response, deps.now ?? Date.now, (text) => {
|
|
33968
|
+
sink(
|
|
33969
|
+
parseEvent({
|
|
33970
|
+
type: "reply-delta",
|
|
33971
|
+
requestId: request.requestId,
|
|
33972
|
+
text
|
|
33973
|
+
})
|
|
33974
|
+
);
|
|
33975
|
+
}),
|
|
33976
|
+
false
|
|
33977
|
+
);
|
|
33978
|
+
}
|
|
33979
|
+
async function historyCompanionMessages(request, sink, deps = {}) {
|
|
33980
|
+
const { controller, timer } = createDeadline(deps);
|
|
33981
|
+
const fetchImpl = deps.fetch ?? fetch;
|
|
33982
|
+
try {
|
|
33983
|
+
const { token, origin } = await acquireContext(deps);
|
|
33984
|
+
const headers = authenticatedHeaders(token);
|
|
33985
|
+
const agents = await fetchAgents(
|
|
33986
|
+
fetchImpl,
|
|
33987
|
+
origin,
|
|
33988
|
+
token,
|
|
33989
|
+
controller.signal
|
|
33990
|
+
);
|
|
33991
|
+
const agentName = resolveAgentName(agents, request.personaKey);
|
|
33992
|
+
const conversationId = await resolveConversationId(
|
|
33993
|
+
fetchImpl,
|
|
33994
|
+
origin,
|
|
33995
|
+
headers,
|
|
33996
|
+
agentName,
|
|
33997
|
+
controller.signal
|
|
33998
|
+
);
|
|
33999
|
+
const turns = decodeTurns(
|
|
34000
|
+
await fetchConversationMessages(
|
|
34001
|
+
fetchImpl,
|
|
34002
|
+
origin,
|
|
34003
|
+
headers,
|
|
34004
|
+
conversationId,
|
|
34005
|
+
controller.signal
|
|
34006
|
+
),
|
|
34007
|
+
request.limit
|
|
34008
|
+
);
|
|
34009
|
+
for (const turn of turns) {
|
|
34010
|
+
sink(parseEvent({ type: "turn", requestId: request.requestId, turn }));
|
|
34011
|
+
}
|
|
34012
|
+
const end = parseEvent({
|
|
34013
|
+
type: "history-end",
|
|
34014
|
+
requestId: request.requestId,
|
|
34015
|
+
count: turns.length
|
|
34016
|
+
});
|
|
34017
|
+
sink(end);
|
|
34018
|
+
return end;
|
|
34019
|
+
} catch (error) {
|
|
34020
|
+
return emitFailure(
|
|
34021
|
+
sink,
|
|
34022
|
+
classifyUnknownPredispatch(error),
|
|
34023
|
+
request.requestId
|
|
34024
|
+
);
|
|
34025
|
+
} finally {
|
|
34026
|
+
clearTimeout(timer);
|
|
34027
|
+
}
|
|
34028
|
+
}
|
|
33725
34029
|
|
|
33726
34030
|
// src/lib/companion-update-check.ts
|
|
33727
34031
|
async function checkCompanionUpdate(options, deps = {}) {
|
|
@@ -33742,6 +34046,8 @@ function companionUpdateAvailable(update) {
|
|
|
33742
34046
|
var defaultDeps3 = {
|
|
33743
34047
|
roster: rosterCompanions,
|
|
33744
34048
|
send: sendCompanionMessage,
|
|
34049
|
+
converse: converseCompanionMessage,
|
|
34050
|
+
history: historyCompanionMessages,
|
|
33745
34051
|
update: () => checkCompanionUpdate(defaultLocalCompanionInstallOptions())
|
|
33746
34052
|
};
|
|
33747
34053
|
async function readSingleRequest(stdin) {
|
|
@@ -33764,6 +34070,7 @@ async function readSingleRequest(stdin) {
|
|
|
33764
34070
|
}
|
|
33765
34071
|
function exitFor(terminal) {
|
|
33766
34072
|
if (terminal.type === "roster" || terminal.type === "completed") return 0;
|
|
34073
|
+
if (terminal.type === "history-end") return 0;
|
|
33767
34074
|
if (terminal.type === "update") return 0;
|
|
33768
34075
|
if (terminal.type === "indeterminate") return 4;
|
|
33769
34076
|
if (terminal.type === "failed" && terminal.reason !== "bad-request") {
|
|
@@ -33789,6 +34096,10 @@ async function runCompanionBridge(stdin, stdout, stderr, deps = defaultDeps3) {
|
|
|
33789
34096
|
else if (request.type === "update") {
|
|
33790
34097
|
terminal = await deps.update();
|
|
33791
34098
|
sink(terminal);
|
|
34099
|
+
} else if (request.type === "history") {
|
|
34100
|
+
terminal = await deps.history(request, sink);
|
|
34101
|
+
} else if (request.type === "converse") {
|
|
34102
|
+
terminal = await deps.converse(request, sink);
|
|
33792
34103
|
} else terminal = await deps.send(request, sink);
|
|
33793
34104
|
return exitFor(terminal);
|
|
33794
34105
|
} catch {
|