@ozaiya/openclaw-channel 0.10.51 → 0.10.53
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/src/actionConfirmation.d.ts +45 -0
- package/dist/src/actionConfirmation.js +117 -8
- package/dist/src/actionConfirmation.js.map +1 -1
- package/dist/src/botEmail.d.ts +32 -3
- package/dist/src/botEmail.js +388 -64
- package/dist/src/botEmail.js.map +1 -1
- package/dist/src/botMcp.d.ts +10 -3
- package/dist/src/botMcp.js +16 -4
- package/dist/src/botMcp.js.map +1 -1
- package/dist/src/channel.js +89 -11
- package/dist/src/channel.js.map +1 -1
- package/dist/src/mailDocuments.d.ts +3 -1
- package/dist/src/mailDocuments.js +72 -6
- package/dist/src/mailDocuments.js.map +1 -1
- package/dist/src/mailHtml.d.ts +8 -0
- package/dist/src/mailHtml.js +79 -0
- package/dist/src/mailHtml.js.map +1 -0
- package/dist/src/mailSchedule.d.ts +29 -0
- package/dist/src/mailSchedule.js +89 -0
- package/dist/src/mailSchedule.js.map +1 -0
- package/package.json +1 -1
|
@@ -15,6 +15,51 @@ export interface ConfirmationDeps {
|
|
|
15
15
|
}>;
|
|
16
16
|
editEncrypted: (groupId: string, messageId: string, content: OzaiyaMessageContent) => Promise<void>;
|
|
17
17
|
}
|
|
18
|
+
/** What a lasting card ends in: answered within the first wait, or still open ("later"). */
|
|
19
|
+
export type LastingAnswer = "approved" | "rejected" | "later";
|
|
20
|
+
/**
|
|
21
|
+
* An action whose card was not answered within the first wait: kept (on disk too, so a gateway
|
|
22
|
+
* restart keeps it) until the owner answers or it expires. On Approve, the tool named here runs
|
|
23
|
+
* it again with exactly these args, approval already given.
|
|
24
|
+
*/
|
|
25
|
+
export interface ParkedAction {
|
|
26
|
+
actionId: string;
|
|
27
|
+
accountId: string;
|
|
28
|
+
groupId: string;
|
|
29
|
+
messageId: string;
|
|
30
|
+
tool: "email" | "mcp";
|
|
31
|
+
args: unknown;
|
|
32
|
+
label: string;
|
|
33
|
+
card: ActionCardContent;
|
|
34
|
+
expiresAt: number;
|
|
35
|
+
}
|
|
36
|
+
export interface LastingDeps extends ConfirmationDeps {
|
|
37
|
+
accountId: string;
|
|
38
|
+
/** The gateway's state dir; parked actions live in <stateDir>/ozaiya-approvals. */
|
|
39
|
+
stateDir: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Like requestConfirmation, but the card doesn't die with the wait: when nobody answers within the
|
|
43
|
+
* first 5 minutes, the action is parked for 24 hours ("later") and runs when the owner taps
|
|
44
|
+
* Approve (takeParkedAction). For actions that can wait: sending mail, writing to a business system.
|
|
45
|
+
*/
|
|
46
|
+
export declare function requestLastingConfirmation(deps: LastingDeps, groupId: string, action: string, params: Record<string, unknown>, label: string, replay: {
|
|
47
|
+
tool: ParkedAction["tool"];
|
|
48
|
+
args: unknown;
|
|
49
|
+
}): Promise<LastingAnswer>;
|
|
50
|
+
/**
|
|
51
|
+
* The owner answered a card that was parked: take it out (so a double tap can't run it twice) and,
|
|
52
|
+
* when it was approved and is still valid, hand it back to be run (`run`). The card shows the answer
|
|
53
|
+
* either way. `found: false` when there is no such parked action (not a lasting card, or answered).
|
|
54
|
+
*/
|
|
55
|
+
export declare function takeParkedAction(deps: LastingDeps, actionId: string, approved: boolean): Promise<{
|
|
56
|
+
found: false;
|
|
57
|
+
} | {
|
|
58
|
+
found: true;
|
|
59
|
+
run: ParkedAction | null;
|
|
60
|
+
}>;
|
|
61
|
+
/** After a gateway (re)start: expire the account's parked actions on time again. */
|
|
62
|
+
export declare function restoreParkedActions(deps: LastingDeps): Promise<number>;
|
|
18
63
|
/**
|
|
19
64
|
* Send a confirmation card and block until the user approves, rejects, or timeout.
|
|
20
65
|
*
|
|
@@ -10,9 +10,13 @@
|
|
|
10
10
|
* callbacks processed by the agent.
|
|
11
11
|
*/
|
|
12
12
|
import { randomBytes } from "node:crypto";
|
|
13
|
+
import fs from "node:fs/promises";
|
|
14
|
+
import path from "node:path";
|
|
13
15
|
// ─── Constants ───────────────────────────────────────────────────────────────
|
|
14
16
|
const ACTION_CALLBACK_PREFIX = "oz_ac:";
|
|
15
17
|
const CONFIRMATION_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes
|
|
18
|
+
// A lasting card (mail, business-system writes) stays open this long after the first wait.
|
|
19
|
+
const LASTING_VALID_MS = 24 * 60 * 60 * 1000;
|
|
16
20
|
// ─── State ───────────────────────────────────────────────────────────────────
|
|
17
21
|
const pendingConfirmations = new Map();
|
|
18
22
|
// ─── Action label mapping (server-side fallback) ─────────────────────────────
|
|
@@ -22,6 +26,111 @@ const ACTION_LABELS = {
|
|
|
22
26
|
message_user: "Send Direct Message",
|
|
23
27
|
create_group: "Create Group",
|
|
24
28
|
};
|
|
29
|
+
const parked = new Map();
|
|
30
|
+
const expiryTimers = new Map();
|
|
31
|
+
const hasCjk = (text) => /[\u3400-\u9fff]/.test(text);
|
|
32
|
+
const parkedDir = (stateDir) => path.join(stateDir, "ozaiya-approvals");
|
|
33
|
+
const parkedFile = (stateDir, actionId) => path.join(parkedDir(stateDir), `${actionId.replace(/[^a-f0-9]/g, "")}.json`);
|
|
34
|
+
async function forgetParked(stateDir, actionId) {
|
|
35
|
+
parked.delete(actionId);
|
|
36
|
+
clearTimeout(expiryTimers.get(actionId));
|
|
37
|
+
expiryTimers.delete(actionId);
|
|
38
|
+
await fs.rm(parkedFile(stateDir, actionId), { force: true }).catch(() => { });
|
|
39
|
+
}
|
|
40
|
+
function scheduleExpiry(deps, action) {
|
|
41
|
+
clearTimeout(expiryTimers.get(action.actionId));
|
|
42
|
+
// setTimeout caps at ~24.8 days; a day is well inside.
|
|
43
|
+
const timer = setTimeout(() => {
|
|
44
|
+
void forgetParked(deps.stateDir, action.actionId).then(() => updateCardStatus(deps, action.groupId, action.messageId, action.card, "expired"));
|
|
45
|
+
}, Math.max(0, action.expiresAt - Date.now()));
|
|
46
|
+
timer.unref?.();
|
|
47
|
+
expiryTimers.set(action.actionId, timer);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Like requestConfirmation, but the card doesn't die with the wait: when nobody answers within the
|
|
51
|
+
* first 5 minutes, the action is parked for 24 hours ("later") and runs when the owner taps
|
|
52
|
+
* Approve (takeParkedAction). For actions that can wait: sending mail, writing to a business system.
|
|
53
|
+
*/
|
|
54
|
+
export async function requestLastingConfirmation(deps, groupId, action, params, label, replay) {
|
|
55
|
+
const actionId = randomBytes(8).toString("hex");
|
|
56
|
+
const zh = hasCjk(`${label} ${Object.values(params).join(" ")}`);
|
|
57
|
+
const actionCard = {
|
|
58
|
+
action,
|
|
59
|
+
actionId,
|
|
60
|
+
status: "pending",
|
|
61
|
+
params: { ...params, [zh ? "有效期" : "Valid for"]: zh ? "24 小时(期间随时点同意都会执行)" : "24 hours (approving any time before then runs it)" },
|
|
62
|
+
label,
|
|
63
|
+
};
|
|
64
|
+
const result = await deps.sendEncrypted(groupId, {
|
|
65
|
+
text: `⏳ ${label}`,
|
|
66
|
+
actionCard,
|
|
67
|
+
inlineKeyboard: {
|
|
68
|
+
rows: [[
|
|
69
|
+
{ text: zh ? "✅ 同意" : "✅ Approve", callbackData: `${ACTION_CALLBACK_PREFIX}approve:${actionId}` },
|
|
70
|
+
{ text: zh ? "❌ 拒绝" : "❌ Reject", callbackData: `${ACTION_CALLBACK_PREFIX}reject:${actionId}` },
|
|
71
|
+
]],
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
const messageId = result.message.id;
|
|
75
|
+
const answered = await new Promise((resolve) => {
|
|
76
|
+
const timer = setTimeout(() => {
|
|
77
|
+
if (pendingConfirmations.delete(actionId))
|
|
78
|
+
resolve(null);
|
|
79
|
+
}, CONFIRMATION_TIMEOUT_MS);
|
|
80
|
+
pendingConfirmations.set(actionId, { messageId, groupId, card: actionCard, resolve, timer });
|
|
81
|
+
});
|
|
82
|
+
if (answered !== null)
|
|
83
|
+
return answered ? "approved" : "rejected";
|
|
84
|
+
const parkedAction = {
|
|
85
|
+
actionId,
|
|
86
|
+
accountId: deps.accountId,
|
|
87
|
+
groupId,
|
|
88
|
+
messageId,
|
|
89
|
+
tool: replay.tool,
|
|
90
|
+
args: replay.args,
|
|
91
|
+
label,
|
|
92
|
+
card: actionCard,
|
|
93
|
+
expiresAt: Date.now() + LASTING_VALID_MS,
|
|
94
|
+
};
|
|
95
|
+
parked.set(actionId, parkedAction);
|
|
96
|
+
await fs.mkdir(parkedDir(deps.stateDir), { recursive: true }).catch(() => { });
|
|
97
|
+
await fs.writeFile(parkedFile(deps.stateDir, actionId), JSON.stringify(parkedAction), { mode: 0o600 }).catch(() => { });
|
|
98
|
+
scheduleExpiry(deps, parkedAction);
|
|
99
|
+
return "later";
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* The owner answered a card that was parked: take it out (so a double tap can't run it twice) and,
|
|
103
|
+
* when it was approved and is still valid, hand it back to be run (`run`). The card shows the answer
|
|
104
|
+
* either way. `found: false` when there is no such parked action (not a lasting card, or answered).
|
|
105
|
+
*/
|
|
106
|
+
export async function takeParkedAction(deps, actionId, approved) {
|
|
107
|
+
let action = parked.get(actionId);
|
|
108
|
+
if (!action) {
|
|
109
|
+
const raw = await fs.readFile(parkedFile(deps.stateDir, actionId), "utf8").catch(() => null);
|
|
110
|
+
action = raw ? JSON.parse(raw) : undefined;
|
|
111
|
+
}
|
|
112
|
+
if (!action || action.accountId !== deps.accountId)
|
|
113
|
+
return { found: false };
|
|
114
|
+
await forgetParked(deps.stateDir, actionId);
|
|
115
|
+
const expired = action.expiresAt < Date.now();
|
|
116
|
+
await updateCardStatus(deps, action.groupId, action.messageId, action.card, expired ? "expired" : approved ? "approved" : "rejected");
|
|
117
|
+
return { found: true, run: approved && !expired ? action : null };
|
|
118
|
+
}
|
|
119
|
+
/** After a gateway (re)start: expire the account's parked actions on time again. */
|
|
120
|
+
export async function restoreParkedActions(deps) {
|
|
121
|
+
const names = await fs.readdir(parkedDir(deps.stateDir)).catch(() => []);
|
|
122
|
+
let restored = 0;
|
|
123
|
+
for (const name of names.filter((n) => n.endsWith(".json"))) {
|
|
124
|
+
const raw = await fs.readFile(path.join(parkedDir(deps.stateDir), name), "utf8").catch(() => null);
|
|
125
|
+
const action = raw ? JSON.parse(raw) : null;
|
|
126
|
+
if (!action || action.accountId !== deps.accountId || parked.has(action.actionId))
|
|
127
|
+
continue;
|
|
128
|
+
parked.set(action.actionId, action);
|
|
129
|
+
scheduleExpiry(deps, action);
|
|
130
|
+
restored++;
|
|
131
|
+
}
|
|
132
|
+
return restored;
|
|
133
|
+
}
|
|
25
134
|
// ─── Public API ──────────────────────────────────────────────────────────────
|
|
26
135
|
/**
|
|
27
136
|
* Send a confirmation card and block until the user approves, rejects, or timeout.
|
|
@@ -62,6 +171,7 @@ export async function requestConfirmation(deps, groupId, action, params, label)
|
|
|
62
171
|
pendingConfirmations.set(actionId, {
|
|
63
172
|
messageId: result.message.id,
|
|
64
173
|
groupId,
|
|
174
|
+
card: actionCard,
|
|
65
175
|
resolve,
|
|
66
176
|
timer,
|
|
67
177
|
});
|
|
@@ -101,22 +211,21 @@ export async function resolveConfirmation(deps, actionId, approved) {
|
|
|
101
211
|
pendingConfirmations.delete(actionId);
|
|
102
212
|
// Update card to show final status and remove keyboard
|
|
103
213
|
const status = approved ? "approved" : "rejected";
|
|
104
|
-
await updateCardStatus(deps, entry.groupId, entry.messageId,
|
|
214
|
+
await updateCardStatus(deps, entry.groupId, entry.messageId, entry.card, status);
|
|
105
215
|
entry.resolve(approved);
|
|
106
216
|
return true;
|
|
107
217
|
}
|
|
108
218
|
// ─── Internal ────────────────────────────────────────────────────────────────
|
|
109
|
-
async function updateCardStatus(deps, groupId, messageId,
|
|
219
|
+
async function updateCardStatus(deps, groupId, messageId, card, newStatus) {
|
|
110
220
|
try {
|
|
111
221
|
const statusEmoji = newStatus === "approved" ? "✅" : newStatus === "rejected" ? "❌" : "⏰";
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
: { action: "", actionId: "", status: newStatus, params: {} };
|
|
222
|
+
const label = card.label ?? "";
|
|
223
|
+
// A card shown in Chinese says its outcome in Chinese.
|
|
224
|
+
const zh = hasCjk(label);
|
|
225
|
+
const statusLabel = newStatus === "approved" ? (zh ? "已同意" : "Approved") : newStatus === "rejected" ? (zh ? "已拒绝" : "Rejected") : (zh ? "已过期" : "Expired");
|
|
117
226
|
const updatedContent = {
|
|
118
227
|
text: `${statusEmoji} ${label} — ${statusLabel}`,
|
|
119
|
-
actionCard:
|
|
228
|
+
actionCard: { ...card, status: newStatus },
|
|
120
229
|
// No inlineKeyboard — removes the buttons
|
|
121
230
|
};
|
|
122
231
|
await deps.editEncrypted(groupId, messageId, updatedContent);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actionConfirmation.js","sourceRoot":"","sources":["../../src/actionConfirmation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"actionConfirmation.js","sourceRoot":"","sources":["../../src/actionConfirmation.ts"],"names":[],"mappings":"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"}
|
package/dist/src/botEmail.d.ts
CHANGED
|
@@ -75,8 +75,11 @@ export declare function attachmentParts(root: MailStructureNode | undefined): Ma
|
|
|
75
75
|
export interface BotEmailToolDeps {
|
|
76
76
|
/** True when this tool call (by its id) was made in the owner's own chat with the bot. */
|
|
77
77
|
inOwnerChat: (toolCallId?: string) => boolean;
|
|
78
|
-
/**
|
|
79
|
-
|
|
78
|
+
/**
|
|
79
|
+
* Show an approval card in the owner's chat. true / false when they answer within the first wait;
|
|
80
|
+
* "later" when the card stays open and the action (these args) runs on a later Approve.
|
|
81
|
+
*/
|
|
82
|
+
askOwner: (label: string, params: Record<string, string>, args: unknown) => Promise<boolean | "later">;
|
|
80
83
|
/** Where the files the owner sent in their chat with the bot are kept; outgoing attachments come only from there. */
|
|
81
84
|
ownerFiles?: () => string | null;
|
|
82
85
|
/** Post a file into the owner's chat with the bot. */
|
|
@@ -86,7 +89,28 @@ export interface BotEmailToolDeps {
|
|
|
86
89
|
data: Buffer;
|
|
87
90
|
caption?: string;
|
|
88
91
|
}) => Promise<void>;
|
|
92
|
+
/** Keep an approved mail to send later (the args to run then, without send_at); returns its id. */
|
|
93
|
+
schedule?: (entry: {
|
|
94
|
+
sendAt: number;
|
|
95
|
+
args: unknown;
|
|
96
|
+
to: string;
|
|
97
|
+
subject: string;
|
|
98
|
+
}) => Promise<string>;
|
|
99
|
+
/** This bot's mails waiting to be sent, and cancelling one. */
|
|
100
|
+
scheduledList?: () => Array<{
|
|
101
|
+
id: string;
|
|
102
|
+
sendAt: number;
|
|
103
|
+
to: string;
|
|
104
|
+
subject: string;
|
|
105
|
+
}>;
|
|
106
|
+
cancelScheduled?: (id: string) => Promise<boolean>;
|
|
89
107
|
}
|
|
108
|
+
/** Told to the model when the card stays open past the first wait. */
|
|
109
|
+
export declare const APPROVAL_LATER = "Your owner hasn't answered yet. The approval card stays open for 24 hours: when they tap Approve, it is done then and the result is posted in this chat. Tell your owner in one line that it waits for their approval, and don't do it again yourself.";
|
|
110
|
+
/** The email tool, plus the way back in for an action approved later (not a model-callable tool). */
|
|
111
|
+
export type BotEmailTool = ChannelAgentTool & {
|
|
112
|
+
runApproved: (args: unknown) => Promise<string>;
|
|
113
|
+
};
|
|
90
114
|
interface OutgoingFile {
|
|
91
115
|
filename: string;
|
|
92
116
|
content: Buffer;
|
|
@@ -101,7 +125,7 @@ export declare const STAGED_NAME_SUFFIX = ".name";
|
|
|
101
125
|
*/
|
|
102
126
|
export declare function ownerChatFiles(paths: string[], root: string | null): Promise<OutgoingFile[]>;
|
|
103
127
|
/** The `email` tool for a bot with the add-on: its own mailbox(es). */
|
|
104
|
-
export declare function createBotEmailTool(account: ResolvedOzaiyaAccount, config: EmailAddonConfig, deps: BotEmailToolDeps):
|
|
128
|
+
export declare function createBotEmailTool(account: ResolvedOzaiyaAccount, config: EmailAddonConfig, deps: BotEmailToolDeps): BotEmailTool;
|
|
105
129
|
export interface NewMail {
|
|
106
130
|
uid: number;
|
|
107
131
|
from: string;
|
|
@@ -115,6 +139,11 @@ export interface MailWatchDeps {
|
|
|
115
139
|
id: string;
|
|
116
140
|
email: string;
|
|
117
141
|
}, mails: NewMail[]) => Promise<void>;
|
|
142
|
+
/** The mail server refused the mailbox's login (told once until a login works again). */
|
|
143
|
+
onLoginRejected?: (mailbox: {
|
|
144
|
+
id: string;
|
|
145
|
+
email: string;
|
|
146
|
+
}, detail: string) => Promise<void>;
|
|
118
147
|
log: {
|
|
119
148
|
info: (msg: string) => void;
|
|
120
149
|
warn: (msg: string) => void;
|