@agentvault/claude-bridge 0.3.2 → 0.3.3
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 +6 -2
- package/dist/index.js +32 -13
- package/dist/session.d.ts +14 -1
- package/package.json +1 -1
package/dist/bridge.d.ts
CHANGED
|
@@ -35,8 +35,12 @@ export declare class RoomHushState {
|
|
|
35
35
|
}
|
|
36
36
|
export interface RoomSession {
|
|
37
37
|
/** `reply` is the immutable reply sink captured for THIS message (see
|
|
38
|
-
* ActiveTarget.snapshotReply) — the session invokes it when Claude answers.
|
|
39
|
-
|
|
38
|
+
* ActiveTarget.snapshotReply) — the session invokes it when Claude answers.
|
|
39
|
+
* `opts.autoReplyOnText` (set for 1:1 DMs) makes the session fall back to
|
|
40
|
+
* sending plain assistant text when the model never calls the say tool (#416). */
|
|
41
|
+
push(text: string, reply?: (text: string) => Promise<void>, opts?: {
|
|
42
|
+
autoReplyOnText?: boolean;
|
|
43
|
+
}): void;
|
|
40
44
|
}
|
|
41
45
|
/** Where a reply should go: a room (sendToRoom) or a 1:1 DM (send). */
|
|
42
46
|
export type BridgeTarget = {
|
package/dist/index.js
CHANGED
|
@@ -131554,14 +131554,25 @@ var PersistentClaudeSession = class {
|
|
|
131554
131554
|
/** Reply sink bound to the message currently being processed. Set as each
|
|
131555
131555
|
* message is handed to the model so the say tool routes to the right place. */
|
|
131556
131556
|
activeReply;
|
|
131557
|
-
|
|
131557
|
+
/** Per-turn state for the #416 DM auto-reply fallback. */
|
|
131558
|
+
currentAutoReply = false;
|
|
131559
|
+
saidThisTurn = false;
|
|
131560
|
+
turnText = "";
|
|
131561
|
+
/**
|
|
131562
|
+
* Queue an inbound message for the model.
|
|
131563
|
+
* @param opts.autoReplyOnText — for 1:1 DMs (where the owner always expects a
|
|
131564
|
+
* reply): if the turn produces assistant text but never calls the say tool,
|
|
131565
|
+
* send that text as the reply instead of silently dropping it (#416). Rooms
|
|
131566
|
+
* omit this so the agent can still choose silence.
|
|
131567
|
+
*/
|
|
131568
|
+
push(text, reply, opts) {
|
|
131558
131569
|
const msg = {
|
|
131559
131570
|
type: "user",
|
|
131560
131571
|
message: { role: "user", content: text },
|
|
131561
131572
|
parent_tool_use_id: null,
|
|
131562
131573
|
session_id: ""
|
|
131563
131574
|
};
|
|
131564
|
-
const item = { msg, reply };
|
|
131575
|
+
const item = { msg, reply, autoReplyOnText: opts?.autoReplyOnText };
|
|
131565
131576
|
if (this.waiting) {
|
|
131566
131577
|
const w2 = this.waiting;
|
|
131567
131578
|
this.waiting = null;
|
|
@@ -131574,21 +131585,19 @@ var PersistentClaudeSession = class {
|
|
|
131574
131585
|
* back to opts.onSay. This is what closes the DM→room leak: the destination is
|
|
131575
131586
|
* the one captured for the message being answered, not a live global target. */
|
|
131576
131587
|
async deliver(text) {
|
|
131588
|
+
this.saidThisTurn = true;
|
|
131577
131589
|
if (this.activeReply) await this.activeReply(text);
|
|
131578
131590
|
else if (this.opts.onSay) await this.opts.onSay(text);
|
|
131579
131591
|
}
|
|
131580
131592
|
async *input() {
|
|
131581
131593
|
while (true) {
|
|
131582
|
-
|
|
131583
|
-
const item2 = this.pending.shift();
|
|
131584
|
-
this.activeReply = item2.reply;
|
|
131585
|
-
yield item2.msg;
|
|
131586
|
-
continue;
|
|
131587
|
-
}
|
|
131588
|
-
const item = await new Promise((resolve2) => {
|
|
131594
|
+
const item = this.pending.length > 0 ? this.pending.shift() : await new Promise((resolve2) => {
|
|
131589
131595
|
this.waiting = resolve2;
|
|
131590
131596
|
});
|
|
131591
131597
|
this.activeReply = item.reply;
|
|
131598
|
+
this.currentAutoReply = item.autoReplyOnText ?? false;
|
|
131599
|
+
this.saidThisTurn = false;
|
|
131600
|
+
this.turnText = "";
|
|
131592
131601
|
yield item.msg;
|
|
131593
131602
|
}
|
|
131594
131603
|
}
|
|
@@ -131635,7 +131644,15 @@ var PersistentClaudeSession = class {
|
|
|
131635
131644
|
if (m6.type === "assistant") {
|
|
131636
131645
|
const blocks = m6.message?.content ?? [];
|
|
131637
131646
|
const text = blocks.filter((b5) => b5.type === "text").map((b5) => b5.text ?? "").join("");
|
|
131638
|
-
if (text.trim())
|
|
131647
|
+
if (text.trim()) {
|
|
131648
|
+
this.turnText += text;
|
|
131649
|
+
this.opts.onObserve?.(text);
|
|
131650
|
+
}
|
|
131651
|
+
} else if (m6.type === "result") {
|
|
131652
|
+
const reply = this.activeReply;
|
|
131653
|
+
if (this.currentAutoReply && !this.saidThisTurn && this.turnText.trim() && reply) {
|
|
131654
|
+
void reply(this.turnText);
|
|
131655
|
+
}
|
|
131639
131656
|
}
|
|
131640
131657
|
}
|
|
131641
131658
|
}
|
|
@@ -131741,13 +131758,15 @@ function wireBridge(channel, session, target, opts = {}) {
|
|
|
131741
131758
|
}
|
|
131742
131759
|
log(`inbound from ${e7.senderName} in ${e7.roomId.slice(0, 8)}`);
|
|
131743
131760
|
target.setRoom(e7.roomId);
|
|
131744
|
-
session.push(`[${e7.senderName}]: ${e7.plaintext}`, target.snapshotReply(channel, log)
|
|
131761
|
+
session.push(`[${e7.senderName}]: ${e7.plaintext}`, target.snapshotReply(channel, log), {
|
|
131762
|
+
autoReplyOnText: false
|
|
131763
|
+
});
|
|
131745
131764
|
});
|
|
131746
131765
|
channel.on("message", (text, metadata) => {
|
|
131747
131766
|
if (metadata?.roomId) return;
|
|
131748
131767
|
log("inbound 1:1 DM from owner");
|
|
131749
131768
|
target.setDm();
|
|
131750
|
-
session.push(text, target.snapshotReply(channel, log));
|
|
131769
|
+
session.push(text, target.snapshotReply(channel, log), { autoReplyOnText: true });
|
|
131751
131770
|
});
|
|
131752
131771
|
}
|
|
131753
131772
|
|
|
@@ -131783,7 +131802,7 @@ async function main() {
|
|
|
131783
131802
|
});
|
|
131784
131803
|
wireBridge(
|
|
131785
131804
|
channel,
|
|
131786
|
-
{ push: (t7, reply) => session.push(t7, reply) },
|
|
131805
|
+
{ push: (t7, reply, opts) => session.push(t7, reply, opts) },
|
|
131787
131806
|
target,
|
|
131788
131807
|
{ roomFilter: cfg.roomFilter, log: (m6) => console.error("[bridge] " + m6) }
|
|
131789
131808
|
);
|
package/dist/session.d.ts
CHANGED
|
@@ -63,8 +63,21 @@ export declare class PersistentClaudeSession {
|
|
|
63
63
|
/** Reply sink bound to the message currently being processed. Set as each
|
|
64
64
|
* message is handed to the model so the say tool routes to the right place. */
|
|
65
65
|
private activeReply?;
|
|
66
|
+
/** Per-turn state for the #416 DM auto-reply fallback. */
|
|
67
|
+
private currentAutoReply;
|
|
68
|
+
private saidThisTurn;
|
|
69
|
+
private turnText;
|
|
66
70
|
constructor(opts: SessionOpts);
|
|
67
|
-
|
|
71
|
+
/**
|
|
72
|
+
* Queue an inbound message for the model.
|
|
73
|
+
* @param opts.autoReplyOnText — for 1:1 DMs (where the owner always expects a
|
|
74
|
+
* reply): if the turn produces assistant text but never calls the say tool,
|
|
75
|
+
* send that text as the reply instead of silently dropping it (#416). Rooms
|
|
76
|
+
* omit this so the agent can still choose silence.
|
|
77
|
+
*/
|
|
78
|
+
push(text: string, reply?: ReplySink, opts?: {
|
|
79
|
+
autoReplyOnText?: boolean;
|
|
80
|
+
}): void;
|
|
68
81
|
/** Route a say-tool message to the reply bound to the in-flight message, falling
|
|
69
82
|
* back to opts.onSay. This is what closes the DM→room leak: the destination is
|
|
70
83
|
* the one captured for the message being answered, not a live global target. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentvault/claude-bridge",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AgentVault Claude Bridge — daemon for bridging a Claude agent into secure E2E-encrypted AgentVault 1:1 direct messages and rooms.",
|
|
6
6
|
"main": "dist/index.js",
|