@agentvault/muse-bridge 0.1.32 → 0.1.34
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/bridge.d.ts +16 -0
- package/dist/index.js +154 -15
- package/dist/muse-provider.d.ts +3 -0
- package/dist/muse-session.d.ts +12 -0
- package/package.json +1 -1
package/dist/bridge.d.ts
CHANGED
|
@@ -92,6 +92,22 @@ export interface ReplyChannel {
|
|
|
92
92
|
groupId?: string;
|
|
93
93
|
}): Promise<T>;
|
|
94
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* "Recent problems" (2026-10-26): every say delivery is one
|
|
97
|
+
* `ai.agent.tool.invoke` span (tool `say`) on the channel's existing telemetry
|
|
98
|
+
* pipe. Only the outcome, a machine error code, the duration and the
|
|
99
|
+
* conversation it answers — never the text or the error message. Never throws.
|
|
100
|
+
*/
|
|
101
|
+
/**
|
|
102
|
+
* #1467: a Muse turn failed. One `ai.agent.tool.invoke` error span (tool
|
|
103
|
+
* `model_turn`): `model_rate_limited` when Meta answered 429, else
|
|
104
|
+
* `model_error`. No conversation and no text. Never throws.
|
|
105
|
+
*/
|
|
106
|
+
export declare function reportTurnFailure(channel: {
|
|
107
|
+
telemetry?: ToolSpanSink | null;
|
|
108
|
+
} | undefined, failure: {
|
|
109
|
+
upstreamStatus?: number;
|
|
110
|
+
}): void;
|
|
95
111
|
export declare class ActiveTarget {
|
|
96
112
|
private target;
|
|
97
113
|
setRoom(roomId: string): void;
|
package/dist/index.js
CHANGED
|
@@ -11799,11 +11799,11 @@ async function joinWithFirstMatchingKp(welcomeBytes, candidates) {
|
|
|
11799
11799
|
return null;
|
|
11800
11800
|
}
|
|
11801
11801
|
function ownIdentity() {
|
|
11802
|
-
const v2 = true ? "0.23.
|
|
11802
|
+
const v2 = true ? "0.23.61" : FALLBACK;
|
|
11803
11803
|
return `${PACKAGE}@${v2}`;
|
|
11804
11804
|
}
|
|
11805
11805
|
function buildSha() {
|
|
11806
|
-
const raw = true ? "
|
|
11806
|
+
const raw = true ? "129e537" : "";
|
|
11807
11807
|
const cleaned = (raw ?? "").trim();
|
|
11808
11808
|
return !cleaned || cleaned === "unknown" ? null : cleaned;
|
|
11809
11809
|
}
|
|
@@ -12658,6 +12658,10 @@ function buildToolInvokeSpan(report) {
|
|
|
12658
12658
|
"tool.duration_ms": durationMs
|
|
12659
12659
|
};
|
|
12660
12660
|
if (isError) attributes["tool.error_kind"] = safeErrorKind(report.errorKind);
|
|
12661
|
+
const resets = report.limitResetsAt;
|
|
12662
|
+
if (attributes["tool.error_kind"] === "plan_limit_reached" && typeof resets === "number" && Number.isInteger(resets) && resets > 0 && resets < 1e11) {
|
|
12663
|
+
attributes["av.limit_resets_at"] = resets;
|
|
12664
|
+
}
|
|
12661
12665
|
if (kind !== "unknown" && typeof conv.id === "string" && conv.id) {
|
|
12662
12666
|
attributes["av.conversation_id"] = conv.id.slice(0, 64);
|
|
12663
12667
|
}
|
|
@@ -71487,6 +71491,11 @@ var init_dist = __esm({
|
|
|
71487
71491
|
"ambiguous_target",
|
|
71488
71492
|
"no_receipt",
|
|
71489
71493
|
"invalid_request",
|
|
71494
|
+
// #1467: the owner's own AI plan refused the turn (a bridge on a subscription).
|
|
71495
|
+
"plan_limit_reached",
|
|
71496
|
+
// #1467: a Muse turn failed — Meta answered 429, or anything else.
|
|
71497
|
+
"model_rate_limited",
|
|
71498
|
+
"model_error",
|
|
71490
71499
|
UNCLASSIFIED_ERROR
|
|
71491
71500
|
];
|
|
71492
71501
|
KNOWN_CODES = new Set(KNOWN_TOOL_ERROR_CODES);
|
|
@@ -71698,6 +71707,17 @@ var init_dist = __esm({
|
|
|
71698
71707
|
* self-heal rather than be logged and dropped. */
|
|
71699
71708
|
_mlsCommitFailCounts = /* @__PURE__ */ new Map();
|
|
71700
71709
|
static MAX_MLS_DECRYPT_FAILS = 3;
|
|
71710
|
+
/**
|
|
71711
|
+
* #1518: ids of MLS application frames this process has already decrypted
|
|
71712
|
+
* (server-assigned `mls_messages.id`, the same on the live delivery pull and
|
|
71713
|
+
* on a `/sync` / reconnect replay). A replayed frame cannot be decrypted a
|
|
71714
|
+
* second time — forward secrecy deleted its key — so without this every
|
|
71715
|
+
* reconnect after a backend deploy fed already-read messages into the
|
|
71716
|
+
* decrypt-failure counter and re-admitted the agent (+2 epochs). Insertion
|
|
71717
|
+
* ordered; the oldest ids fall out past DECRYPTED_ID_CAP.
|
|
71718
|
+
*/
|
|
71719
|
+
_decryptedMessageIds = /* @__PURE__ */ new Map();
|
|
71720
|
+
static DECRYPTED_ID_CAP = 5e3;
|
|
71701
71721
|
/**
|
|
71702
71722
|
* #1084: consecutive resyncs that found NOTHING to apply, per group.
|
|
71703
71723
|
*
|
|
@@ -73903,7 +73923,7 @@ ${text}`,
|
|
|
73903
73923
|
*/
|
|
73904
73924
|
sendActivitySpan(spanData) {
|
|
73905
73925
|
if (!this._ws || this._ws.readyState !== WebSocket.OPEN) return;
|
|
73906
|
-
const pluginVersion = true ? "0.23.
|
|
73926
|
+
const pluginVersion = true ? "0.23.61" : "0.0.0-dev";
|
|
73907
73927
|
const agentName = this.config.agentName ?? "Agent";
|
|
73908
73928
|
const resource = {
|
|
73909
73929
|
"service.name": "agentvault-agent",
|
|
@@ -76113,7 +76133,7 @@ ${text}`,
|
|
|
76113
76133
|
agentVersion: this.config.agentVersion ?? "0.0.0",
|
|
76114
76134
|
// __AV_VERSION__ is injected by esbuild from package.json at build time.
|
|
76115
76135
|
// Falls back to "0.0.0-dev" in non-bundled contexts (tests).
|
|
76116
|
-
pluginVersion: true ? "0.23.
|
|
76136
|
+
pluginVersion: true ? "0.23.61" : "0.0.0-dev"
|
|
76117
76137
|
});
|
|
76118
76138
|
this._telemetryReporter.startAutoFlush(3e4);
|
|
76119
76139
|
}
|
|
@@ -76445,7 +76465,7 @@ ${text}`,
|
|
|
76445
76465
|
agentVersion: this.config.agentVersion ?? "0.0.0",
|
|
76446
76466
|
// __AV_VERSION__ is injected by esbuild from package.json at build time.
|
|
76447
76467
|
// Falls back to "0.0.0-dev" in non-bundled contexts (tests).
|
|
76448
|
-
pluginVersion: true ? "0.23.
|
|
76468
|
+
pluginVersion: true ? "0.23.61" : "0.0.0-dev"
|
|
76449
76469
|
});
|
|
76450
76470
|
this._telemetryReporter.startAutoFlush(3e4);
|
|
76451
76471
|
}
|
|
@@ -76881,9 +76901,14 @@ ${text}`,
|
|
|
76881
76901
|
if (groupId) void this._requestWelcomeSelfHeal(groupId);
|
|
76882
76902
|
return;
|
|
76883
76903
|
}
|
|
76904
|
+
if (this._alreadyDecrypted(data.message_id)) {
|
|
76905
|
+
console.debug(`[SecureChannel] MLS 1:1 frame ${String(data.message_id).slice(0, 8)} already read \u2014 replay skipped`);
|
|
76906
|
+
return;
|
|
76907
|
+
}
|
|
76884
76908
|
try {
|
|
76885
76909
|
const cipherBytes = new Uint8Array(Buffer.from(data.payload, "hex"));
|
|
76886
76910
|
const result = await mgr.decrypt(cipherBytes);
|
|
76911
|
+
this._rememberDecrypted(data.message_id);
|
|
76887
76912
|
if (mgrKey) this._mlsDecryptFailCounts.delete(mgrKey);
|
|
76888
76913
|
const mlsGroupId = (convGroupId ? this._persisted?.mlsGroups?.[convGroupId]?.mlsGroupId : null) ?? this._persisted?.mlsConversations?.[convId]?.mlsGroupId ?? groupId;
|
|
76889
76914
|
if (mlsGroupId) {
|
|
@@ -77906,9 +77931,14 @@ ${baseText}`;
|
|
|
77906
77931
|
}
|
|
77907
77932
|
return;
|
|
77908
77933
|
}
|
|
77934
|
+
if (this._alreadyDecrypted(data.message_id)) {
|
|
77935
|
+
console.debug(`[SecureChannel] MLS room frame ${String(data.message_id).slice(0, 8)} already read \u2014 replay skipped`);
|
|
77936
|
+
return;
|
|
77937
|
+
}
|
|
77909
77938
|
try {
|
|
77910
77939
|
const ciphertext = Buffer.from(data.payload, "hex");
|
|
77911
77940
|
const result = await mlsGroup.decrypt(new Uint8Array(ciphertext));
|
|
77941
|
+
this._rememberDecrypted(data.message_id);
|
|
77912
77942
|
this._mlsDecryptFailCounts.delete(resolvedRoomId);
|
|
77913
77943
|
await saveMlsState(this.config.dataDir, groupId, JSON.stringify(mlsGroup.exportState()));
|
|
77914
77944
|
if (result.isHandshake || !result.plaintext) {
|
|
@@ -79086,16 +79116,57 @@ ${baseText}`;
|
|
|
79086
79116
|
}
|
|
79087
79117
|
return await mlsGroup.encrypt(plaintextBytes);
|
|
79088
79118
|
}
|
|
79119
|
+
/** #1518: is the server answering at all? Bounded; any failure is "no". */
|
|
79120
|
+
async _serverReachable() {
|
|
79121
|
+
try {
|
|
79122
|
+
const res = await fetch(`${this.config.apiUrl}/health`, { signal: AbortSignal.timeout(5e3) });
|
|
79123
|
+
return res.ok;
|
|
79124
|
+
} catch {
|
|
79125
|
+
return false;
|
|
79126
|
+
}
|
|
79127
|
+
}
|
|
79128
|
+
/** #1518: the server is down — don't re-key (that needs the same server).
|
|
79129
|
+
* Clear the run so the next failures ask again. Reported as handled. */
|
|
79130
|
+
_deferResync(groupKey, groupId, why) {
|
|
79131
|
+
this._mlsDecryptFailCounts.delete(groupKey);
|
|
79132
|
+
console.warn(
|
|
79133
|
+
`[SecureChannel] Resync for ${groupId.slice(0, 8)}: server unreachable (${why}) \u2014 NOT re-keying; will retry (#1518)`
|
|
79134
|
+
);
|
|
79135
|
+
return true;
|
|
79136
|
+
}
|
|
79137
|
+
/** #1518: has this process already decrypted the frame with this id? */
|
|
79138
|
+
_alreadyDecrypted(messageId) {
|
|
79139
|
+
return typeof messageId === "string" && messageId !== "" && this._decryptedMessageIds.has(messageId);
|
|
79140
|
+
}
|
|
79141
|
+
/** #1518: remember a decrypted frame's id (bounded; oldest dropped). */
|
|
79142
|
+
_rememberDecrypted(messageId) {
|
|
79143
|
+
if (typeof messageId !== "string" || messageId === "") return;
|
|
79144
|
+
this._decryptedMessageIds.set(messageId, true);
|
|
79145
|
+
if (this._decryptedMessageIds.size > _SecureChannel.DECRYPTED_ID_CAP) {
|
|
79146
|
+
const oldest = this._decryptedMessageIds.keys().next().value;
|
|
79147
|
+
if (oldest !== void 0) this._decryptedMessageIds.delete(oldest);
|
|
79148
|
+
}
|
|
79149
|
+
}
|
|
79089
79150
|
async _resyncOnDivergence(groupKey, groupId) {
|
|
79090
79151
|
const mgr = this._mlsGroups.get(groupKey);
|
|
79091
79152
|
if (!mgr?.isInitialized) return false;
|
|
79092
79153
|
const fromEpoch = Number(mgr.epoch);
|
|
79093
79154
|
try {
|
|
79094
|
-
|
|
79095
|
-
|
|
79096
|
-
|
|
79097
|
-
|
|
79155
|
+
let res;
|
|
79156
|
+
try {
|
|
79157
|
+
res = await fetch(
|
|
79158
|
+
`${this.config.apiUrl}/api/v1/mls/groups/${groupId}/sync?last_epoch=${fromEpoch}`,
|
|
79159
|
+
{ headers: { Authorization: `Bearer ${this._deviceJwt}` } }
|
|
79160
|
+
);
|
|
79161
|
+
} catch (netErr) {
|
|
79162
|
+
if (!await this._serverReachable()) return this._deferResync(groupKey, groupId, String(netErr));
|
|
79163
|
+
console.warn(`[SecureChannel] Resync-on-divergence failed for ${groupId.slice(0, 8)}:`, netErr);
|
|
79164
|
+
return false;
|
|
79165
|
+
}
|
|
79098
79166
|
if (!res.ok) {
|
|
79167
|
+
if ((res.status >= 500 || res.status === 429) && !await this._serverReachable()) {
|
|
79168
|
+
return this._deferResync(groupKey, groupId, `HTTP ${res.status}`);
|
|
79169
|
+
}
|
|
79099
79170
|
console.warn(`[SecureChannel] Resync /sync failed for ${groupId.slice(0, 8)}: ${res.status}`);
|
|
79100
79171
|
return false;
|
|
79101
79172
|
}
|
|
@@ -80210,9 +80281,14 @@ ${baseText}`;
|
|
|
80210
80281
|
console.warn(`[SecureChannel] MLS group not loaded for A2A ${a2aChannelId.slice(0, 8)}`);
|
|
80211
80282
|
return;
|
|
80212
80283
|
}
|
|
80284
|
+
if (this._alreadyDecrypted(data.message_id)) {
|
|
80285
|
+
console.debug(`[SecureChannel] MLS A2A frame ${String(data.message_id).slice(0, 8)} already read \u2014 replay skipped`);
|
|
80286
|
+
return;
|
|
80287
|
+
}
|
|
80213
80288
|
try {
|
|
80214
80289
|
const ciphertext = new Uint8Array(Buffer.from(data.payload, "hex"));
|
|
80215
80290
|
const result = await mlsGroup.decrypt(ciphertext);
|
|
80291
|
+
this._rememberDecrypted(data.message_id);
|
|
80216
80292
|
this._mlsDecryptFailCounts.delete(`a2a:${a2aChannelId}`);
|
|
80217
80293
|
await saveMlsState(this.config.dataDir, groupId, JSON.stringify(mlsGroup.exportState()));
|
|
80218
80294
|
if (result.isHandshake || !result.plaintext) {
|
|
@@ -102863,7 +102939,7 @@ data:
|
|
|
102863
102939
|
await init_policy_enforcer();
|
|
102864
102940
|
init_room_protocol();
|
|
102865
102941
|
init_tool_telemetry();
|
|
102866
|
-
VERSION = true ? "0.23.
|
|
102942
|
+
VERSION = true ? "0.23.61" : "0.0.0-dev";
|
|
102867
102943
|
}
|
|
102868
102944
|
});
|
|
102869
102945
|
await init_index();
|
|
@@ -103567,6 +103643,17 @@ import { chmodSync as chmodSync5, mkdirSync as mkdirSync6 } from "node:fs";
|
|
|
103567
103643
|
import { join as join17 } from "node:path";
|
|
103568
103644
|
|
|
103569
103645
|
// src/muse-session.ts
|
|
103646
|
+
var ERROR_TYPE = /\(([a-z][a-z_]{2,40})\)\s*$/;
|
|
103647
|
+
function describeTurnFailure(err) {
|
|
103648
|
+
const message = err instanceof Error ? err.message : "";
|
|
103649
|
+
if (message === "muse turn stopped") return null;
|
|
103650
|
+
const status = err?.upstreamStatus;
|
|
103651
|
+
const type = ERROR_TYPE.exec(message.slice(-200))?.[1];
|
|
103652
|
+
return {
|
|
103653
|
+
...typeof status === "number" && Number.isInteger(status) && status >= 400 && status <= 599 ? { upstreamStatus: status } : {},
|
|
103654
|
+
...type ? { errorType: type } : {}
|
|
103655
|
+
};
|
|
103656
|
+
}
|
|
103570
103657
|
var MuseSession = class {
|
|
103571
103658
|
constructor(driver, opts = {}) {
|
|
103572
103659
|
this.driver = driver;
|
|
@@ -103638,8 +103725,17 @@ var MuseSession = class {
|
|
|
103638
103725
|
${item.text}` : item.text;
|
|
103639
103726
|
const result = await this.driver.runTurn(prompt, { ownerTurn: item.ownerTurn });
|
|
103640
103727
|
await this.maybeFallback(item, result);
|
|
103641
|
-
} catch {
|
|
103642
|
-
|
|
103728
|
+
} catch (err) {
|
|
103729
|
+
const failure2 = describeTurnFailure(err);
|
|
103730
|
+
if (failure2) {
|
|
103731
|
+
this.log(`turn failed reason=driver${failure2.upstreamStatus ? ` upstream_status=${failure2.upstreamStatus}` : ""}${failure2.errorType ? ` error_type=${failure2.errorType}` : ""}`);
|
|
103732
|
+
try {
|
|
103733
|
+
this.opts.onTurnFailed?.(failure2);
|
|
103734
|
+
} catch {
|
|
103735
|
+
}
|
|
103736
|
+
} else {
|
|
103737
|
+
this.log("turn failed reason=stopped");
|
|
103738
|
+
}
|
|
103643
103739
|
await this.failureNotice(item);
|
|
103644
103740
|
} finally {
|
|
103645
103741
|
this.current = null;
|
|
@@ -103767,6 +103863,16 @@ var META_RESPONSES_URL = "https://api.meta.ai/v1/responses";
|
|
|
103767
103863
|
var BODY_LIMIT = 16 * 1024 * 1024;
|
|
103768
103864
|
var ERROR_LIMIT = 64 * 1024;
|
|
103769
103865
|
var HOP_HEADERS = ["connection", "keep-alive", "proxy-authenticate", "proxy-authorization", "te", "trailer", "transfer-encoding", "upgrade"];
|
|
103866
|
+
var LIMIT_HEADER = /^(?:retry-after|x-ratelimit-[a-z0-9-]{1,40}|ratelimit(?:-[a-z0-9-]{1,40})?)$/;
|
|
103867
|
+
var LIMIT_VALUE = /^[0-9][0-9.smh]{0,15}$/;
|
|
103868
|
+
function limitHeaderNote(headers) {
|
|
103869
|
+
const parts = [];
|
|
103870
|
+
headers.forEach((value, name) => {
|
|
103871
|
+
if (parts.length >= 8 || !LIMIT_HEADER.test(name)) return;
|
|
103872
|
+
parts.push(`${name}=${LIMIT_VALUE.test(value.trim()) ? value.trim() : "present"}`);
|
|
103873
|
+
});
|
|
103874
|
+
return parts.length ? ` ${parts.join(" ")}` : "";
|
|
103875
|
+
}
|
|
103770
103876
|
function record2(value) {
|
|
103771
103877
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
103772
103878
|
}
|
|
@@ -103885,6 +103991,7 @@ async function createMuseProviderAdapter(opts) {
|
|
|
103885
103991
|
} catch {
|
|
103886
103992
|
}
|
|
103887
103993
|
};
|
|
103994
|
+
let lastStatus;
|
|
103888
103995
|
const server = createServer2((req, res) => {
|
|
103889
103996
|
const abort = new AbortController();
|
|
103890
103997
|
const stop = () => abort.abort();
|
|
@@ -103963,6 +104070,10 @@ async function createMuseProviderAdapter(opts) {
|
|
|
103963
104070
|
}
|
|
103964
104071
|
}
|
|
103965
104072
|
}
|
|
104073
|
+
if (!response.ok) {
|
|
104074
|
+
lastStatus = response.status;
|
|
104075
|
+
log(`upstream_error status=${response.status}${limitHeaderNote(response.headers)}`);
|
|
104076
|
+
}
|
|
103966
104077
|
await forward(response, res, abort.signal, inspected);
|
|
103967
104078
|
})().catch(() => {
|
|
103968
104079
|
log("request_failed reason=transport");
|
|
@@ -104004,7 +104115,11 @@ async function createMuseProviderAdapter(opts) {
|
|
|
104004
104115
|
await close();
|
|
104005
104116
|
throw new Error("provider adapter unavailable");
|
|
104006
104117
|
}
|
|
104007
|
-
return {
|
|
104118
|
+
return {
|
|
104119
|
+
baseUrl: `http://127.0.0.1:${address.port}${route.slice(0, -"/responses".length)}`,
|
|
104120
|
+
close,
|
|
104121
|
+
upstreamStatus: () => lastStatus
|
|
104122
|
+
};
|
|
104008
104123
|
}
|
|
104009
104124
|
|
|
104010
104125
|
// src/muse-driver.ts
|
|
@@ -104101,6 +104216,12 @@ var MuseDriver = class {
|
|
|
104101
104216
|
if (this.current?.cancelled) throw new Error("muse turn stopped");
|
|
104102
104217
|
spawn2.args.splice(2, 0, "--base-url", adapter.baseUrl);
|
|
104103
104218
|
return await this.execJsonl(spawn2);
|
|
104219
|
+
} catch (err) {
|
|
104220
|
+
const status = adapter.upstreamStatus?.();
|
|
104221
|
+
if (typeof status === "number" && err instanceof Error) {
|
|
104222
|
+
err.upstreamStatus = status;
|
|
104223
|
+
}
|
|
104224
|
+
throw err;
|
|
104104
104225
|
} finally {
|
|
104105
104226
|
await adapter.close();
|
|
104106
104227
|
if (this.adapter === adapter) this.adapter = null;
|
|
@@ -104724,6 +104845,18 @@ var RoomHushState = class {
|
|
|
104724
104845
|
return t2 !== void 0 && now < t2;
|
|
104725
104846
|
}
|
|
104726
104847
|
};
|
|
104848
|
+
function reportTurnFailure(channel, failure2) {
|
|
104849
|
+
try {
|
|
104850
|
+
reportToolInvoke(channel?.telemetry, {
|
|
104851
|
+
toolName: "model_turn",
|
|
104852
|
+
outcome: "error",
|
|
104853
|
+
errorKind: failure2.upstreamStatus === 429 ? "model_rate_limited" : "model_error",
|
|
104854
|
+
durationMs: 0,
|
|
104855
|
+
conversation: { kind: "unknown" }
|
|
104856
|
+
});
|
|
104857
|
+
} catch {
|
|
104858
|
+
}
|
|
104859
|
+
}
|
|
104727
104860
|
function reportSay(channel, t2, startedAt, failure2) {
|
|
104728
104861
|
try {
|
|
104729
104862
|
reportToolInvoke(channel.telemetry, {
|
|
@@ -105004,7 +105137,7 @@ function mkdir700(path2) {
|
|
|
105004
105137
|
chmodSync5(path2, 448);
|
|
105005
105138
|
}
|
|
105006
105139
|
function packageVersion() {
|
|
105007
|
-
return true ? "0.1.
|
|
105140
|
+
return true ? "0.1.34" : void 0;
|
|
105008
105141
|
}
|
|
105009
105142
|
function helpText(version2) {
|
|
105010
105143
|
return [
|
|
@@ -105129,7 +105262,13 @@ async function main(opts = {}) {
|
|
|
105129
105262
|
spawnFn: opts.spawnFn
|
|
105130
105263
|
});
|
|
105131
105264
|
const identity = identityPrompt(cfg.agentName, SAY_TOOL_NAME);
|
|
105132
|
-
session = new MuseSession(driver, {
|
|
105265
|
+
session = new MuseSession(driver, {
|
|
105266
|
+
log: (m2) => logLine(m2),
|
|
105267
|
+
identity,
|
|
105268
|
+
// #1467: every failed turn reaches Recent problems (and Admin) — `channel`
|
|
105269
|
+
// is read when the failure happens, after it is connected.
|
|
105270
|
+
onTurnFailed: (failure2) => reportTurnFailure(channel, failure2)
|
|
105271
|
+
});
|
|
105133
105272
|
try {
|
|
105134
105273
|
await driver.start();
|
|
105135
105274
|
} catch (err) {
|
package/dist/muse-provider.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
export interface MuseProviderAdapter {
|
|
2
2
|
baseUrl: string;
|
|
3
3
|
close(): Promise<void>;
|
|
4
|
+
/** #1467: the last error status Meta returned this turn; undefined if none. */
|
|
5
|
+
upstreamStatus?(): number | undefined;
|
|
4
6
|
}
|
|
7
|
+
export declare function limitHeaderNote(headers: Headers): string;
|
|
5
8
|
export interface MuseProviderAdapterOptions {
|
|
6
9
|
timeoutMs: number;
|
|
7
10
|
log?: (message: string) => void;
|
package/dist/muse-session.d.ts
CHANGED
|
@@ -20,6 +20,16 @@ export interface DriverLike {
|
|
|
20
20
|
* cannot redirect a private 1:1 reply, because the newer message only becomes
|
|
21
21
|
* current when its own turn starts.
|
|
22
22
|
*/
|
|
23
|
+
/** #1467: what is safe to keep about a failed turn — never its message text. */
|
|
24
|
+
export interface TurnFailure {
|
|
25
|
+
/** The error status Meta's API returned this turn, when it returned one. */
|
|
26
|
+
upstreamStatus?: number;
|
|
27
|
+
/** The provider's error type, e.g. "invalid_request_error" — only a short
|
|
28
|
+
* lower-case token in parentheses at the end of Muse's reason. */
|
|
29
|
+
errorType?: string;
|
|
30
|
+
}
|
|
31
|
+
/** A failed turn → what to report, or null when the turn was stopped on purpose. */
|
|
32
|
+
export declare function describeTurnFailure(err: unknown): TurnFailure | null;
|
|
23
33
|
export declare class MuseSession implements RoomSession {
|
|
24
34
|
private readonly driver;
|
|
25
35
|
private readonly opts;
|
|
@@ -32,6 +42,8 @@ export declare class MuseSession implements RoomSession {
|
|
|
32
42
|
onSay?: (text: string) => Promise<void>;
|
|
33
43
|
log?: (m: string) => void;
|
|
34
44
|
identity?: string;
|
|
45
|
+
/** #1467: a turn failed (not stopped). Fire-and-forget; a throw is swallowed. */
|
|
46
|
+
onTurnFailed?: (failure: TurnFailure) => void;
|
|
35
47
|
});
|
|
36
48
|
push(text: string, reply?: (text: string) => Promise<void>, opts?: {
|
|
37
49
|
autoReplyOnText?: boolean;
|
package/package.json
CHANGED