@agentvault/muse-bridge 0.1.32 → 0.1.33
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 +78 -6
- 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
|
@@ -11803,7 +11803,7 @@ function ownIdentity() {
|
|
|
11803
11803
|
return `${PACKAGE}@${v2}`;
|
|
11804
11804
|
}
|
|
11805
11805
|
function buildSha() {
|
|
11806
|
-
const raw = true ? "
|
|
11806
|
+
const raw = true ? "628e3ba" : "";
|
|
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);
|
|
@@ -103567,6 +103576,17 @@ import { chmodSync as chmodSync5, mkdirSync as mkdirSync6 } from "node:fs";
|
|
|
103567
103576
|
import { join as join17 } from "node:path";
|
|
103568
103577
|
|
|
103569
103578
|
// src/muse-session.ts
|
|
103579
|
+
var ERROR_TYPE = /\(([a-z][a-z_]{2,40})\)\s*$/;
|
|
103580
|
+
function describeTurnFailure(err) {
|
|
103581
|
+
const message = err instanceof Error ? err.message : "";
|
|
103582
|
+
if (message === "muse turn stopped") return null;
|
|
103583
|
+
const status = err?.upstreamStatus;
|
|
103584
|
+
const type = ERROR_TYPE.exec(message.slice(-200))?.[1];
|
|
103585
|
+
return {
|
|
103586
|
+
...typeof status === "number" && Number.isInteger(status) && status >= 400 && status <= 599 ? { upstreamStatus: status } : {},
|
|
103587
|
+
...type ? { errorType: type } : {}
|
|
103588
|
+
};
|
|
103589
|
+
}
|
|
103570
103590
|
var MuseSession = class {
|
|
103571
103591
|
constructor(driver, opts = {}) {
|
|
103572
103592
|
this.driver = driver;
|
|
@@ -103638,8 +103658,17 @@ var MuseSession = class {
|
|
|
103638
103658
|
${item.text}` : item.text;
|
|
103639
103659
|
const result = await this.driver.runTurn(prompt, { ownerTurn: item.ownerTurn });
|
|
103640
103660
|
await this.maybeFallback(item, result);
|
|
103641
|
-
} catch {
|
|
103642
|
-
|
|
103661
|
+
} catch (err) {
|
|
103662
|
+
const failure2 = describeTurnFailure(err);
|
|
103663
|
+
if (failure2) {
|
|
103664
|
+
this.log(`turn failed reason=driver${failure2.upstreamStatus ? ` upstream_status=${failure2.upstreamStatus}` : ""}${failure2.errorType ? ` error_type=${failure2.errorType}` : ""}`);
|
|
103665
|
+
try {
|
|
103666
|
+
this.opts.onTurnFailed?.(failure2);
|
|
103667
|
+
} catch {
|
|
103668
|
+
}
|
|
103669
|
+
} else {
|
|
103670
|
+
this.log("turn failed reason=stopped");
|
|
103671
|
+
}
|
|
103643
103672
|
await this.failureNotice(item);
|
|
103644
103673
|
} finally {
|
|
103645
103674
|
this.current = null;
|
|
@@ -103767,6 +103796,16 @@ var META_RESPONSES_URL = "https://api.meta.ai/v1/responses";
|
|
|
103767
103796
|
var BODY_LIMIT = 16 * 1024 * 1024;
|
|
103768
103797
|
var ERROR_LIMIT = 64 * 1024;
|
|
103769
103798
|
var HOP_HEADERS = ["connection", "keep-alive", "proxy-authenticate", "proxy-authorization", "te", "trailer", "transfer-encoding", "upgrade"];
|
|
103799
|
+
var LIMIT_HEADER = /^(?:retry-after|x-ratelimit-[a-z0-9-]{1,40}|ratelimit(?:-[a-z0-9-]{1,40})?)$/;
|
|
103800
|
+
var LIMIT_VALUE = /^[0-9][0-9.smh]{0,15}$/;
|
|
103801
|
+
function limitHeaderNote(headers) {
|
|
103802
|
+
const parts = [];
|
|
103803
|
+
headers.forEach((value, name) => {
|
|
103804
|
+
if (parts.length >= 8 || !LIMIT_HEADER.test(name)) return;
|
|
103805
|
+
parts.push(`${name}=${LIMIT_VALUE.test(value.trim()) ? value.trim() : "present"}`);
|
|
103806
|
+
});
|
|
103807
|
+
return parts.length ? ` ${parts.join(" ")}` : "";
|
|
103808
|
+
}
|
|
103770
103809
|
function record2(value) {
|
|
103771
103810
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
103772
103811
|
}
|
|
@@ -103885,6 +103924,7 @@ async function createMuseProviderAdapter(opts) {
|
|
|
103885
103924
|
} catch {
|
|
103886
103925
|
}
|
|
103887
103926
|
};
|
|
103927
|
+
let lastStatus;
|
|
103888
103928
|
const server = createServer2((req, res) => {
|
|
103889
103929
|
const abort = new AbortController();
|
|
103890
103930
|
const stop = () => abort.abort();
|
|
@@ -103963,6 +104003,10 @@ async function createMuseProviderAdapter(opts) {
|
|
|
103963
104003
|
}
|
|
103964
104004
|
}
|
|
103965
104005
|
}
|
|
104006
|
+
if (!response.ok) {
|
|
104007
|
+
lastStatus = response.status;
|
|
104008
|
+
log(`upstream_error status=${response.status}${limitHeaderNote(response.headers)}`);
|
|
104009
|
+
}
|
|
103966
104010
|
await forward(response, res, abort.signal, inspected);
|
|
103967
104011
|
})().catch(() => {
|
|
103968
104012
|
log("request_failed reason=transport");
|
|
@@ -104004,7 +104048,11 @@ async function createMuseProviderAdapter(opts) {
|
|
|
104004
104048
|
await close();
|
|
104005
104049
|
throw new Error("provider adapter unavailable");
|
|
104006
104050
|
}
|
|
104007
|
-
return {
|
|
104051
|
+
return {
|
|
104052
|
+
baseUrl: `http://127.0.0.1:${address.port}${route.slice(0, -"/responses".length)}`,
|
|
104053
|
+
close,
|
|
104054
|
+
upstreamStatus: () => lastStatus
|
|
104055
|
+
};
|
|
104008
104056
|
}
|
|
104009
104057
|
|
|
104010
104058
|
// src/muse-driver.ts
|
|
@@ -104101,6 +104149,12 @@ var MuseDriver = class {
|
|
|
104101
104149
|
if (this.current?.cancelled) throw new Error("muse turn stopped");
|
|
104102
104150
|
spawn2.args.splice(2, 0, "--base-url", adapter.baseUrl);
|
|
104103
104151
|
return await this.execJsonl(spawn2);
|
|
104152
|
+
} catch (err) {
|
|
104153
|
+
const status = adapter.upstreamStatus?.();
|
|
104154
|
+
if (typeof status === "number" && err instanceof Error) {
|
|
104155
|
+
err.upstreamStatus = status;
|
|
104156
|
+
}
|
|
104157
|
+
throw err;
|
|
104104
104158
|
} finally {
|
|
104105
104159
|
await adapter.close();
|
|
104106
104160
|
if (this.adapter === adapter) this.adapter = null;
|
|
@@ -104724,6 +104778,18 @@ var RoomHushState = class {
|
|
|
104724
104778
|
return t2 !== void 0 && now < t2;
|
|
104725
104779
|
}
|
|
104726
104780
|
};
|
|
104781
|
+
function reportTurnFailure(channel, failure2) {
|
|
104782
|
+
try {
|
|
104783
|
+
reportToolInvoke(channel?.telemetry, {
|
|
104784
|
+
toolName: "model_turn",
|
|
104785
|
+
outcome: "error",
|
|
104786
|
+
errorKind: failure2.upstreamStatus === 429 ? "model_rate_limited" : "model_error",
|
|
104787
|
+
durationMs: 0,
|
|
104788
|
+
conversation: { kind: "unknown" }
|
|
104789
|
+
});
|
|
104790
|
+
} catch {
|
|
104791
|
+
}
|
|
104792
|
+
}
|
|
104727
104793
|
function reportSay(channel, t2, startedAt, failure2) {
|
|
104728
104794
|
try {
|
|
104729
104795
|
reportToolInvoke(channel.telemetry, {
|
|
@@ -105004,7 +105070,7 @@ function mkdir700(path2) {
|
|
|
105004
105070
|
chmodSync5(path2, 448);
|
|
105005
105071
|
}
|
|
105006
105072
|
function packageVersion() {
|
|
105007
|
-
return true ? "0.1.
|
|
105073
|
+
return true ? "0.1.33" : void 0;
|
|
105008
105074
|
}
|
|
105009
105075
|
function helpText(version2) {
|
|
105010
105076
|
return [
|
|
@@ -105129,7 +105195,13 @@ async function main(opts = {}) {
|
|
|
105129
105195
|
spawnFn: opts.spawnFn
|
|
105130
105196
|
});
|
|
105131
105197
|
const identity = identityPrompt(cfg.agentName, SAY_TOOL_NAME);
|
|
105132
|
-
session = new MuseSession(driver, {
|
|
105198
|
+
session = new MuseSession(driver, {
|
|
105199
|
+
log: (m2) => logLine(m2),
|
|
105200
|
+
identity,
|
|
105201
|
+
// #1467: every failed turn reaches Recent problems (and Admin) — `channel`
|
|
105202
|
+
// is read when the failure happens, after it is connected.
|
|
105203
|
+
onTurnFailed: (failure2) => reportTurnFailure(channel, failure2)
|
|
105204
|
+
});
|
|
105133
105205
|
try {
|
|
105134
105206
|
await driver.start();
|
|
105135
105207
|
} 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