@odience-network/paperclip-plugin-telegram-enhanced 0.2.0
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/LICENSE +21 -0
- package/README.md +215 -0
- package/dist/acp-bridge.d.ts +35 -0
- package/dist/acp-bridge.js +891 -0
- package/dist/acp-bridge.js.map +1 -0
- package/dist/adapter.d.ts +35 -0
- package/dist/adapter.js +75 -0
- package/dist/adapter.js.map +1 -0
- package/dist/agent-labels.d.ts +12 -0
- package/dist/agent-labels.js +96 -0
- package/dist/agent-labels.js.map +1 -0
- package/dist/allowlist.d.ts +27 -0
- package/dist/allowlist.js +34 -0
- package/dist/allowlist.js.map +1 -0
- package/dist/approval-routing.d.ts +2 -0
- package/dist/approval-routing.js +7 -0
- package/dist/approval-routing.js.map +1 -0
- package/dist/command-registry.d.ts +3 -0
- package/dist/command-registry.js +268 -0
- package/dist/command-registry.js.map +1 -0
- package/dist/commands.d.ts +11 -0
- package/dist/commands.js +516 -0
- package/dist/commands.js.map +1 -0
- package/dist/constants.d.ts +76 -0
- package/dist/constants.js +71 -0
- package/dist/constants.js.map +1 -0
- package/dist/escalation.d.ts +42 -0
- package/dist/escalation.js +252 -0
- package/dist/escalation.js.map +1 -0
- package/dist/file-routing.d.ts +51 -0
- package/dist/file-routing.js +212 -0
- package/dist/file-routing.js.map +1 -0
- package/dist/formatters.d.ts +31 -0
- package/dist/formatters.js +336 -0
- package/dist/formatters.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/interaction-delivery.d.ts +90 -0
- package/dist/interaction-delivery.js +142 -0
- package/dist/interaction-delivery.js.map +1 -0
- package/dist/manifest.d.ts +3 -0
- package/dist/manifest.js +111 -0
- package/dist/manifest.js.map +1 -0
- package/dist/media-pipeline.d.ts +47 -0
- package/dist/media-pipeline.js +162 -0
- package/dist/media-pipeline.js.map +1 -0
- package/dist/notification-filters.d.ts +23 -0
- package/dist/notification-filters.js +93 -0
- package/dist/notification-filters.js.map +1 -0
- package/dist/paperclip-api.d.ts +25 -0
- package/dist/paperclip-api.js +69 -0
- package/dist/paperclip-api.js.map +1 -0
- package/dist/polling-offset.d.ts +22 -0
- package/dist/polling-offset.js +68 -0
- package/dist/polling-offset.js.map +1 -0
- package/dist/secret-ref-validation.d.ts +7 -0
- package/dist/secret-ref-validation.js +49 -0
- package/dist/secret-ref-validation.js.map +1 -0
- package/dist/telegram-api.d.ts +40 -0
- package/dist/telegram-api.js +251 -0
- package/dist/telegram-api.js.map +1 -0
- package/dist/topic-projects.d.ts +2 -0
- package/dist/topic-projects.js +45 -0
- package/dist/topic-projects.js.map +1 -0
- package/dist/ui/index.d.ts +2 -0
- package/dist/ui/index.js +1446 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/watch-registry.d.ts +9 -0
- package/dist/watch-registry.js +272 -0
- package/dist/watch-registry.js.map +1 -0
- package/dist/worker.d.ts +162 -0
- package/dist/worker.js +1520 -0
- package/dist/worker.js.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-routing.js","sourceRoot":"","sources":["../src/file-routing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { PluginEvent } from "@paperclipai/plugin-sdk";
|
|
2
|
+
import type { SendMessageOptions } from "./telegram-api.js";
|
|
3
|
+
type FormattedMessage = {
|
|
4
|
+
text: string;
|
|
5
|
+
options: SendMessageOptions;
|
|
6
|
+
};
|
|
7
|
+
export type IssueLinksOpts = {
|
|
8
|
+
baseUrl?: string;
|
|
9
|
+
issuePrefix?: string;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Build the text for a resolved approval/decision card.
|
|
13
|
+
*
|
|
14
|
+
* Ported from the tue-Jonas fork (TWX-619): rather than collapsing the card to
|
|
15
|
+
* a bare status line, preserve the original card context (issue identifier,
|
|
16
|
+
* title, description) and append a resolution footer so the message stays
|
|
17
|
+
* legible after the buttons are removed. Falls back to just the footer when no
|
|
18
|
+
* original text is available. The original text from Telegram is plain (entity
|
|
19
|
+
* formatting stripped), so it is MarkdownV2-escaped before being re-sent.
|
|
20
|
+
*/
|
|
21
|
+
export declare function formatResolvedDecision(originalText: string | undefined | null, decision: "approved" | "rejected", actor: string): string;
|
|
22
|
+
export declare function formatIssueCreated(event: PluginEvent, opts?: IssueLinksOpts): FormattedMessage;
|
|
23
|
+
export declare function formatIssueAssigned(event: PluginEvent, opts?: IssueLinksOpts): FormattedMessage;
|
|
24
|
+
export declare function formatIssueDone(event: PluginEvent, opts?: IssueLinksOpts): FormattedMessage;
|
|
25
|
+
export declare function formatIssueBlocked(event: PluginEvent, opts?: IssueLinksOpts): FormattedMessage;
|
|
26
|
+
export declare function formatBoardMention(event: PluginEvent, opts?: IssueLinksOpts): FormattedMessage;
|
|
27
|
+
export declare function formatApprovalCreated(event: PluginEvent, opts?: IssueLinksOpts): FormattedMessage;
|
|
28
|
+
export declare function formatAgentError(event: PluginEvent, opts?: IssueLinksOpts): FormattedMessage;
|
|
29
|
+
export declare function formatAgentRunStarted(event: PluginEvent, opts?: IssueLinksOpts): FormattedMessage;
|
|
30
|
+
export declare function formatAgentRunFinished(event: PluginEvent, opts?: IssueLinksOpts): FormattedMessage;
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import { escapeMarkdownV2, truncateAtWord } from "./telegram-api.js";
|
|
2
|
+
function esc(s) {
|
|
3
|
+
return escapeMarkdownV2(s);
|
|
4
|
+
}
|
|
5
|
+
function bold(s) {
|
|
6
|
+
return `*${esc(s)}*`;
|
|
7
|
+
}
|
|
8
|
+
function code(s) {
|
|
9
|
+
return `\`${esc(s)}\``;
|
|
10
|
+
}
|
|
11
|
+
function isExternalUrl(url) {
|
|
12
|
+
return !!url && url.startsWith("https://");
|
|
13
|
+
}
|
|
14
|
+
function issueLink(identifier, opts) {
|
|
15
|
+
if (opts?.baseUrl && opts?.issuePrefix) {
|
|
16
|
+
const url = `${opts.baseUrl}/${opts.issuePrefix}/issues/${identifier}`;
|
|
17
|
+
return `[${esc(identifier)}](${url})`;
|
|
18
|
+
}
|
|
19
|
+
return bold(identifier);
|
|
20
|
+
}
|
|
21
|
+
function issueButton(identifier, opts) {
|
|
22
|
+
if (opts?.baseUrl && opts?.issuePrefix && isExternalUrl(opts.baseUrl)) {
|
|
23
|
+
return { text: `Open ${identifier} ↗`, url: `${opts.baseUrl}/${opts.issuePrefix}/issues/${identifier}` };
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
function agentButton(agentId, label, publicUrl) {
|
|
28
|
+
if (publicUrl && isExternalUrl(publicUrl)) {
|
|
29
|
+
return { text: label, url: `${publicUrl}/agents/${agentId}` };
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
function runButton(agentId, runId, publicUrl) {
|
|
34
|
+
if (publicUrl && isExternalUrl(publicUrl) && runId) {
|
|
35
|
+
return { text: "View Run ↗", url: `${publicUrl}/agents/${agentId}/runs/${runId}` };
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Build the text for a resolved approval/decision card.
|
|
41
|
+
*
|
|
42
|
+
* Ported from the tue-Jonas fork (TWX-619): rather than collapsing the card to
|
|
43
|
+
* a bare status line, preserve the original card context (issue identifier,
|
|
44
|
+
* title, description) and append a resolution footer so the message stays
|
|
45
|
+
* legible after the buttons are removed. Falls back to just the footer when no
|
|
46
|
+
* original text is available. The original text from Telegram is plain (entity
|
|
47
|
+
* formatting stripped), so it is MarkdownV2-escaped before being re-sent.
|
|
48
|
+
*/
|
|
49
|
+
export function formatResolvedDecision(originalText, decision, actor) {
|
|
50
|
+
const icon = decision === "approved" ? "✅" : "❌";
|
|
51
|
+
const label = decision === "approved" ? "Approved" : "Rejected";
|
|
52
|
+
const footer = `${esc(icon)} ${bold(label)} by ${esc(actor)}`;
|
|
53
|
+
const trimmed = (originalText ?? "").trim();
|
|
54
|
+
if (!trimmed)
|
|
55
|
+
return footer;
|
|
56
|
+
return `${esc(trimmed)}\n\n${footer}`;
|
|
57
|
+
}
|
|
58
|
+
function classifyAgentError(errorMessage) {
|
|
59
|
+
if (/timed?\s*out|timeout/i.test(errorMessage))
|
|
60
|
+
return "Agent Timeout";
|
|
61
|
+
if (/limit|rate.?limit|quota/i.test(errorMessage))
|
|
62
|
+
return "Agent Rate Limit";
|
|
63
|
+
return "Agent Error";
|
|
64
|
+
}
|
|
65
|
+
export function formatIssueCreated(event, opts) {
|
|
66
|
+
const p = event.payload;
|
|
67
|
+
const identifier = String(p.identifier ?? event.entityId);
|
|
68
|
+
const title = String(p.title ?? "Untitled");
|
|
69
|
+
const status = p.status ? String(p.status) : null;
|
|
70
|
+
const priority = p.priority ? String(p.priority) : null;
|
|
71
|
+
const assigneeName = p.assigneeName ? String(p.assigneeName) : null;
|
|
72
|
+
const projectName = p.projectName ? String(p.projectName) : null;
|
|
73
|
+
const lines = [
|
|
74
|
+
`${esc("📋")} ${bold("Issue Created")}: ${issueLink(identifier, opts)}`,
|
|
75
|
+
bold(title),
|
|
76
|
+
];
|
|
77
|
+
const meta = [];
|
|
78
|
+
if (status)
|
|
79
|
+
meta.push(`Status: ${code(status)}`);
|
|
80
|
+
if (priority)
|
|
81
|
+
meta.push(`Priority: ${code(priority)}`);
|
|
82
|
+
if (assigneeName)
|
|
83
|
+
meta.push(`Assignee: ${esc(assigneeName)}`);
|
|
84
|
+
if (projectName)
|
|
85
|
+
meta.push(`Project: ${esc(projectName)}`);
|
|
86
|
+
if (meta.length > 0)
|
|
87
|
+
lines.push(meta.join(" \\| "));
|
|
88
|
+
if (p.description) {
|
|
89
|
+
const desc = truncateAtWord(String(p.description), 200);
|
|
90
|
+
lines.push(`\n${esc(">")} ${esc(desc)}`);
|
|
91
|
+
}
|
|
92
|
+
const button = issueButton(identifier, opts);
|
|
93
|
+
return {
|
|
94
|
+
text: lines.join("\n"),
|
|
95
|
+
options: {
|
|
96
|
+
parseMode: "MarkdownV2",
|
|
97
|
+
...(button ? { inlineKeyboard: [[button]] } : {}),
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
export function formatIssueAssigned(event, opts) {
|
|
102
|
+
const p = event.payload;
|
|
103
|
+
const prev = p._previous ?? {};
|
|
104
|
+
const identifier = String(p.identifier ?? event.entityId);
|
|
105
|
+
const title = String(p.title ?? "Untitled");
|
|
106
|
+
const assigneeName = p.assigneeName ? String(p.assigneeName) : null;
|
|
107
|
+
const prevAssigneeName = prev.assigneeName ? String(prev.assigneeName) : null;
|
|
108
|
+
const lines = [
|
|
109
|
+
`${esc("🎯")} ${bold("Issue Assigned")}: ${issueLink(identifier, opts)}`,
|
|
110
|
+
bold(title),
|
|
111
|
+
];
|
|
112
|
+
if (assigneeName) {
|
|
113
|
+
lines.push(prevAssigneeName
|
|
114
|
+
? `Assignee: ${esc(prevAssigneeName)} ${esc("→")} ${esc(assigneeName)}`
|
|
115
|
+
: `Assignee: ${esc(assigneeName)}`);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
lines.push(esc("Unassigned"));
|
|
119
|
+
}
|
|
120
|
+
const button = issueButton(identifier, opts);
|
|
121
|
+
return {
|
|
122
|
+
text: lines.join("\n"),
|
|
123
|
+
options: {
|
|
124
|
+
parseMode: "MarkdownV2",
|
|
125
|
+
...(button ? { inlineKeyboard: [[button]] } : {}),
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
export function formatIssueDone(event, opts) {
|
|
130
|
+
const p = event.payload;
|
|
131
|
+
const identifier = String(p.identifier ?? event.entityId);
|
|
132
|
+
const title = String(p.title ?? "");
|
|
133
|
+
const comment = p.comment ? String(p.comment) : null;
|
|
134
|
+
const lines = [
|
|
135
|
+
`${esc("✅")} ${bold("Issue Completed")}: ${issueLink(identifier, opts)}`,
|
|
136
|
+
`${bold(title)} ${esc("is now done.")}`,
|
|
137
|
+
];
|
|
138
|
+
if (comment) {
|
|
139
|
+
const truncated = truncateAtWord(comment, 300);
|
|
140
|
+
lines.push(`\n${esc(">")} ${esc(truncated)}`);
|
|
141
|
+
}
|
|
142
|
+
const button = issueButton(identifier, opts);
|
|
143
|
+
return {
|
|
144
|
+
text: lines.join("\n"),
|
|
145
|
+
options: {
|
|
146
|
+
parseMode: "MarkdownV2",
|
|
147
|
+
...(button ? { inlineKeyboard: [[button]] } : {}),
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
export function formatIssueBlocked(event, opts) {
|
|
152
|
+
const p = event.payload;
|
|
153
|
+
const identifier = String(p.identifier ?? event.entityId);
|
|
154
|
+
const title = String(p.title ?? "Untitled");
|
|
155
|
+
const assigneeName = p.assigneeName ? String(p.assigneeName) : null;
|
|
156
|
+
const reason = p.comment ? String(p.comment) : null;
|
|
157
|
+
const lines = [
|
|
158
|
+
`${esc("🚫")} ${bold("Issue Blocked")}: ${issueLink(identifier, opts)}`,
|
|
159
|
+
bold(title),
|
|
160
|
+
];
|
|
161
|
+
if (assigneeName)
|
|
162
|
+
lines.push(`Assignee: ${esc(assigneeName)}`);
|
|
163
|
+
if (reason) {
|
|
164
|
+
const truncated = truncateAtWord(reason, 300);
|
|
165
|
+
lines.push(`\n${esc(">")} ${esc(truncated)}`);
|
|
166
|
+
}
|
|
167
|
+
const button = issueButton(identifier, opts);
|
|
168
|
+
return {
|
|
169
|
+
text: lines.join("\n"),
|
|
170
|
+
options: {
|
|
171
|
+
parseMode: "MarkdownV2",
|
|
172
|
+
...(button ? { inlineKeyboard: [[button]] } : {}),
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
export function formatBoardMention(event, opts) {
|
|
177
|
+
const p = event.payload;
|
|
178
|
+
const identifier = String(p.identifier ?? p.issueIdentifier ?? p.issueId ?? event.entityId);
|
|
179
|
+
const title = p.title ?? p.issueTitle ? String(p.title ?? p.issueTitle) : null;
|
|
180
|
+
const author = p.authorName ?? p.author ?? p.userName ?? p.agentName;
|
|
181
|
+
const authorName = author ? String(author) : null;
|
|
182
|
+
const body = String(p.body ?? p.comment ?? p.text ?? "");
|
|
183
|
+
const lines = [
|
|
184
|
+
`${esc("📣")} ${bold("Board Mention")}: ${issueLink(identifier, opts)}`,
|
|
185
|
+
];
|
|
186
|
+
if (title)
|
|
187
|
+
lines.push(bold(title));
|
|
188
|
+
if (authorName)
|
|
189
|
+
lines.push(`From: ${esc(authorName)}`);
|
|
190
|
+
if (body) {
|
|
191
|
+
const truncated = truncateAtWord(body, 300);
|
|
192
|
+
lines.push(`\n${esc(">")} ${esc(truncated)}`);
|
|
193
|
+
}
|
|
194
|
+
const button = issueButton(identifier, opts);
|
|
195
|
+
return {
|
|
196
|
+
text: lines.join("\n"),
|
|
197
|
+
options: {
|
|
198
|
+
parseMode: "MarkdownV2",
|
|
199
|
+
...(button ? { inlineKeyboard: [[button]] } : {}),
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
export function formatApprovalCreated(event, opts) {
|
|
204
|
+
const p = event.payload;
|
|
205
|
+
const approvalType = String(p.type ?? "unknown");
|
|
206
|
+
const approvalId = String(p.approvalId ?? event.entityId);
|
|
207
|
+
const title = String(p.title ?? "Approval Requested");
|
|
208
|
+
const description = p.description ? String(p.description) : null;
|
|
209
|
+
const agentName = p.agentName ? String(p.agentName) : null;
|
|
210
|
+
const lines = [
|
|
211
|
+
`${esc("🔔")} ${bold("Approval Requested")}`,
|
|
212
|
+
bold(title),
|
|
213
|
+
];
|
|
214
|
+
if (agentName)
|
|
215
|
+
lines.push(`Agent: ${esc(agentName)} \\| Type: ${code(approvalType)}`);
|
|
216
|
+
if (description)
|
|
217
|
+
lines.push(`\n${esc(truncateAtWord(description, 300))}`);
|
|
218
|
+
// Add linked issues if present
|
|
219
|
+
const linkedIssues = Array.isArray(p.linkedIssues) ? p.linkedIssues : [];
|
|
220
|
+
if (linkedIssues.length > 0) {
|
|
221
|
+
lines.push(`\n${bold(`Linked Issues (${String(linkedIssues.length)})`)}`);
|
|
222
|
+
for (const issue of linkedIssues.slice(0, 5)) {
|
|
223
|
+
const issueId = String(issue.identifier ?? "?");
|
|
224
|
+
const issueParts = [`${issueLink(issueId, opts)} ${esc(String(issue.title ?? ""))}`];
|
|
225
|
+
const issueMeta = [];
|
|
226
|
+
if (issue.status)
|
|
227
|
+
issueMeta.push(String(issue.status));
|
|
228
|
+
if (issue.priority)
|
|
229
|
+
issueMeta.push(String(issue.priority));
|
|
230
|
+
if (issue.assignee)
|
|
231
|
+
issueMeta.push(`-> ${String(issue.assignee)}`);
|
|
232
|
+
if (issueMeta.length > 0)
|
|
233
|
+
issueParts.push(`\\(${esc(issueMeta.join(" | "))}\\)`);
|
|
234
|
+
lines.push(issueParts.join(" "));
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
const keyboard = [
|
|
238
|
+
[
|
|
239
|
+
{ text: "Approve", callback_data: `approve_${approvalId}` },
|
|
240
|
+
{ text: "Reject", callback_data: `reject_${approvalId}` },
|
|
241
|
+
],
|
|
242
|
+
];
|
|
243
|
+
// Add deep link to the first linked issue if available
|
|
244
|
+
if (linkedIssues.length > 0) {
|
|
245
|
+
const firstIssueId = String(linkedIssues[0].identifier ?? "");
|
|
246
|
+
if (firstIssueId) {
|
|
247
|
+
const btn = issueButton(firstIssueId, opts);
|
|
248
|
+
if (btn)
|
|
249
|
+
keyboard.push([btn]);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return {
|
|
253
|
+
text: lines.join("\n"),
|
|
254
|
+
options: {
|
|
255
|
+
parseMode: "MarkdownV2",
|
|
256
|
+
inlineKeyboard: keyboard,
|
|
257
|
+
},
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
export function formatAgentError(event, opts) {
|
|
261
|
+
const p = event.payload;
|
|
262
|
+
const agentId = String(p.agentId ?? event.entityId);
|
|
263
|
+
const agentName = String(p.agentName ?? p.name ?? agentId);
|
|
264
|
+
const errorMessage = String(p.error ?? p.message ?? "Unknown error");
|
|
265
|
+
const runId = p.runId ? String(p.runId) : null;
|
|
266
|
+
const companyName = p.companyName ? String(p.companyName) : null;
|
|
267
|
+
const issueIdentifier = p.issueIdentifier ? String(p.issueIdentifier) : null;
|
|
268
|
+
const issueTitle = p.issueTitle ? String(p.issueTitle) : null;
|
|
269
|
+
const lines = [
|
|
270
|
+
`${esc("❌")} ${bold(classifyAgentError(errorMessage))}`,
|
|
271
|
+
`Agent: ${bold(agentName)}`,
|
|
272
|
+
];
|
|
273
|
+
if (companyName)
|
|
274
|
+
lines.push(`Company: ${esc(companyName)}`);
|
|
275
|
+
if (issueIdentifier) {
|
|
276
|
+
lines.push(issueTitle
|
|
277
|
+
? `Issue: ${issueLink(issueIdentifier, opts)} ${esc("—")} ${esc(issueTitle)}`
|
|
278
|
+
: `Issue: ${issueLink(issueIdentifier, opts)}`);
|
|
279
|
+
}
|
|
280
|
+
lines.push(`\n${code(truncateAtWord(errorMessage, 500))}`);
|
|
281
|
+
const buttons = [
|
|
282
|
+
runButton(agentId, runId, opts?.baseUrl),
|
|
283
|
+
issueIdentifier ? issueButton(issueIdentifier, opts) : null,
|
|
284
|
+
agentButton(agentId, "View Agent ↗", opts?.baseUrl),
|
|
285
|
+
].filter((button) => Boolean(button));
|
|
286
|
+
return {
|
|
287
|
+
text: lines.join("\n"),
|
|
288
|
+
options: {
|
|
289
|
+
parseMode: "MarkdownV2",
|
|
290
|
+
...(buttons.length > 0 ? { inlineKeyboard: [buttons] } : {}),
|
|
291
|
+
},
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
export function formatAgentRunStarted(event, opts) {
|
|
295
|
+
const p = event.payload;
|
|
296
|
+
const agentId = String(p.agentId ?? event.entityId);
|
|
297
|
+
const agentName = String(p.agentName ?? agentId);
|
|
298
|
+
const runId = p.runId ? String(p.runId) : null;
|
|
299
|
+
const buttons = [];
|
|
300
|
+
if (opts?.baseUrl && isExternalUrl(opts.baseUrl)) {
|
|
301
|
+
const url = runId
|
|
302
|
+
? `${opts.baseUrl}/agents/${agentId}/runs/${runId}`
|
|
303
|
+
: `${opts.baseUrl}/agents/${agentId}`;
|
|
304
|
+
buttons.push({ text: "View Run ↗", url });
|
|
305
|
+
}
|
|
306
|
+
return {
|
|
307
|
+
text: `${esc("▶️")} ${bold(agentName)} ${esc("started a new run")}`,
|
|
308
|
+
options: {
|
|
309
|
+
parseMode: "MarkdownV2",
|
|
310
|
+
disableNotification: true,
|
|
311
|
+
...(buttons.length > 0 ? { inlineKeyboard: [buttons] } : {}),
|
|
312
|
+
},
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
export function formatAgentRunFinished(event, opts) {
|
|
316
|
+
const p = event.payload;
|
|
317
|
+
const agentId = String(p.agentId ?? event.entityId);
|
|
318
|
+
const agentName = String(p.agentName ?? agentId);
|
|
319
|
+
const runId = p.runId ? String(p.runId) : null;
|
|
320
|
+
const buttons = [];
|
|
321
|
+
if (opts?.baseUrl && isExternalUrl(opts.baseUrl)) {
|
|
322
|
+
const url = runId
|
|
323
|
+
? `${opts.baseUrl}/agents/${agentId}/runs/${runId}`
|
|
324
|
+
: `${opts.baseUrl}/agents/${agentId}`;
|
|
325
|
+
buttons.push({ text: "View Run ↗", url });
|
|
326
|
+
}
|
|
327
|
+
return {
|
|
328
|
+
text: `${esc("⏹️")} ${bold(agentName)} ${esc("completed successfully")}`,
|
|
329
|
+
options: {
|
|
330
|
+
parseMode: "MarkdownV2",
|
|
331
|
+
disableNotification: true,
|
|
332
|
+
...(buttons.length > 0 ? { inlineKeyboard: [buttons] } : {}),
|
|
333
|
+
},
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
//# sourceMappingURL=formatters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatters.js","sourceRoot":"","sources":["../src/formatters.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { default as manifest } from "./manifest.js";
|
|
2
|
+
export { TelegramAdapter } from "./adapter.js";
|
|
3
|
+
export type { PlatformAdapter, MessageRef, ActionButton, SendOpts } from "./adapter.js";
|
|
4
|
+
export { EscalationManager } from "./escalation.js";
|
|
5
|
+
export type { EscalationEvent, EscalationResponse, EscalationReason } from "./escalation.js";
|
|
6
|
+
export type { ChatSession } from "./acp-bridge.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interaction-notification dedupe + idempotency guard.
|
|
3
|
+
*
|
|
4
|
+
* Ported (logic only) from the tue-Jonas fork — `paperclip-plugin-telegram`
|
|
5
|
+
* TWX-136 (commits 8d1f0a2, 32caca9, 17ad4c6, 7bcbab0). The upstream change
|
|
6
|
+
* tracked deliveries in a host DB migration (`001_interaction_deliveries.sql`).
|
|
7
|
+
* We re-implement against our module layout and back the delivery-tracking
|
|
8
|
+
* state with the SDK key/value store (`ctx.state`) so the plugin does not take
|
|
9
|
+
* on a host migration dependency.
|
|
10
|
+
*
|
|
11
|
+
* Why this exists: Paperclip's core can re-emit the same plugin event for a
|
|
12
|
+
* single underlying change (route logging + heartbeat reconciliation), and a
|
|
13
|
+
* worker can crash or be retried mid-send. Both produce duplicate Telegram
|
|
14
|
+
* notifications. This guard claims a durable delivery slot before sending,
|
|
15
|
+
* skips work when a slot is already delivered (idempotency), and releases the
|
|
16
|
+
* claim when a send fails so a later retry can re-attempt (no lost messages).
|
|
17
|
+
*
|
|
18
|
+
* The in-memory sliding-window dedupe in `worker.ts` remains as a cheap
|
|
19
|
+
* fast-path for the burst case; this guard is the durable backstop that
|
|
20
|
+
* survives worker restarts and guarantees at-most-once delivery per key.
|
|
21
|
+
*/
|
|
22
|
+
import type { PluginContext } from "@paperclipai/plugin-sdk";
|
|
23
|
+
/** Default window after which a still-`pending` claim is treated as abandoned. */
|
|
24
|
+
export declare const DEFAULT_CLAIM_STALE_MS = 60000;
|
|
25
|
+
export type DeliveryStatus = "pending" | "delivered";
|
|
26
|
+
export interface DeliveryRecord {
|
|
27
|
+
status: DeliveryStatus;
|
|
28
|
+
/** ISO timestamp the most recent claim was taken. */
|
|
29
|
+
claimedAt: string;
|
|
30
|
+
/** ISO timestamp the notification was confirmed sent. */
|
|
31
|
+
deliveredAt?: string;
|
|
32
|
+
/** Telegram message id of the delivered notification, when known. */
|
|
33
|
+
messageId?: number;
|
|
34
|
+
/** Number of times a claim has been taken for this key (best-effort). */
|
|
35
|
+
attempts: number;
|
|
36
|
+
}
|
|
37
|
+
export type ClaimOutcome = "claimed" | "already_delivered" | "in_flight";
|
|
38
|
+
export interface ClaimResult {
|
|
39
|
+
outcome: ClaimOutcome;
|
|
40
|
+
record: DeliveryRecord;
|
|
41
|
+
}
|
|
42
|
+
export interface DeliveryGuardOptions {
|
|
43
|
+
/**
|
|
44
|
+
* How long a `pending` (claimed-but-unsent) slot is honored before it is
|
|
45
|
+
* considered abandoned and may be re-claimed. Guards against a worker that
|
|
46
|
+
* crashed between claim and send leaving a permanently stuck slot.
|
|
47
|
+
*/
|
|
48
|
+
staleMs?: number;
|
|
49
|
+
/** Injectable clock for deterministic tests. Defaults to `Date.now`. */
|
|
50
|
+
now?: () => number;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Build a deterministic, collision-resistant state key for a delivery slot.
|
|
54
|
+
*
|
|
55
|
+
* Callers pass the logically-significant parts of the notification (chat,
|
|
56
|
+
* topic, entity, event, and any handler-specific discriminator). The same
|
|
57
|
+
* logical notification must always produce the same key; distinct
|
|
58
|
+
* notifications must not collide.
|
|
59
|
+
*/
|
|
60
|
+
export declare function buildDeliveryKey(...parts: Array<string | number | null | undefined>): string;
|
|
61
|
+
/**
|
|
62
|
+
* Attempt to claim a delivery slot.
|
|
63
|
+
*
|
|
64
|
+
* - `already_delivered` — a prior attempt completed; skip the send (idempotent).
|
|
65
|
+
* - `in_flight` — another attempt holds a fresh `pending` claim; skip to avoid a
|
|
66
|
+
* duplicate. (Stale `pending` claims are reclaimed and return `claimed`.)
|
|
67
|
+
* - `claimed` — caller owns the slot and must send, then call
|
|
68
|
+
* {@link markDelivered} on success or {@link releaseDelivery} on failure.
|
|
69
|
+
*/
|
|
70
|
+
export declare function claimDelivery(ctx: PluginContext, key: string, options?: DeliveryGuardOptions): Promise<ClaimResult>;
|
|
71
|
+
/** Mark a previously-claimed slot as delivered (idempotent terminal state). */
|
|
72
|
+
export declare function markDelivered(ctx: PluginContext, key: string, messageId?: number, options?: DeliveryGuardOptions): Promise<void>;
|
|
73
|
+
/**
|
|
74
|
+
* Release an unsent claim so a future retry can re-attempt delivery.
|
|
75
|
+
*
|
|
76
|
+
* Only releases slots that are still `pending` — a `delivered` slot is a
|
|
77
|
+
* terminal success and must never be cleared, or duplicates would resume.
|
|
78
|
+
*/
|
|
79
|
+
export declare function releaseDelivery(ctx: PluginContext, key: string): Promise<void>;
|
|
80
|
+
/**
|
|
81
|
+
* Run `send` under the idempotency guard.
|
|
82
|
+
*
|
|
83
|
+
* Claims the slot, and on `claimed` invokes `send`. A truthy/`number` result is
|
|
84
|
+
* recorded as delivered (and returned); a falsy result or a thrown error
|
|
85
|
+
* releases the claim so a retry can re-send. When the slot is already delivered
|
|
86
|
+
* or another attempt is in-flight, `send` is not invoked and `null` is returned.
|
|
87
|
+
*
|
|
88
|
+
* @returns the value from `send` on a fresh successful delivery, otherwise `null`.
|
|
89
|
+
*/
|
|
90
|
+
export declare function withIdempotentDelivery<T extends number | undefined | null>(ctx: PluginContext, key: string, send: () => Promise<T>, options?: DeliveryGuardOptions): Promise<T | null>;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interaction-notification dedupe + idempotency guard.
|
|
3
|
+
*
|
|
4
|
+
* Ported (logic only) from the tue-Jonas fork — `paperclip-plugin-telegram`
|
|
5
|
+
* TWX-136 (commits 8d1f0a2, 32caca9, 17ad4c6, 7bcbab0). The upstream change
|
|
6
|
+
* tracked deliveries in a host DB migration (`001_interaction_deliveries.sql`).
|
|
7
|
+
* We re-implement against our module layout and back the delivery-tracking
|
|
8
|
+
* state with the SDK key/value store (`ctx.state`) so the plugin does not take
|
|
9
|
+
* on a host migration dependency.
|
|
10
|
+
*
|
|
11
|
+
* Why this exists: Paperclip's core can re-emit the same plugin event for a
|
|
12
|
+
* single underlying change (route logging + heartbeat reconciliation), and a
|
|
13
|
+
* worker can crash or be retried mid-send. Both produce duplicate Telegram
|
|
14
|
+
* notifications. This guard claims a durable delivery slot before sending,
|
|
15
|
+
* skips work when a slot is already delivered (idempotency), and releases the
|
|
16
|
+
* claim when a send fails so a later retry can re-attempt (no lost messages).
|
|
17
|
+
*
|
|
18
|
+
* The in-memory sliding-window dedupe in `worker.ts` remains as a cheap
|
|
19
|
+
* fast-path for the burst case; this guard is the durable backstop that
|
|
20
|
+
* survives worker restarts and guarantees at-most-once delivery per key.
|
|
21
|
+
*/
|
|
22
|
+
/** Default window after which a still-`pending` claim is treated as abandoned. */
|
|
23
|
+
export const DEFAULT_CLAIM_STALE_MS = 60_000;
|
|
24
|
+
const STATE_KEY_PREFIX = "interaction_delivery_";
|
|
25
|
+
/**
|
|
26
|
+
* Build a deterministic, collision-resistant state key for a delivery slot.
|
|
27
|
+
*
|
|
28
|
+
* Callers pass the logically-significant parts of the notification (chat,
|
|
29
|
+
* topic, entity, event, and any handler-specific discriminator). The same
|
|
30
|
+
* logical notification must always produce the same key; distinct
|
|
31
|
+
* notifications must not collide.
|
|
32
|
+
*/
|
|
33
|
+
export function buildDeliveryKey(...parts) {
|
|
34
|
+
const joined = parts
|
|
35
|
+
.map((p) => (p === null || p === undefined ? "" : String(p)))
|
|
36
|
+
.join("|");
|
|
37
|
+
// Sanitize to keep the composite state key readable and storage-safe.
|
|
38
|
+
return joined.replace(/[^A-Za-z0-9._:|-]/g, "_");
|
|
39
|
+
}
|
|
40
|
+
function stateScope(key) {
|
|
41
|
+
return { scopeKind: "instance", stateKey: `${STATE_KEY_PREFIX}${key}` };
|
|
42
|
+
}
|
|
43
|
+
async function readRecord(ctx, key) {
|
|
44
|
+
const raw = (await ctx.state.get(stateScope(key)));
|
|
45
|
+
if (!raw || typeof raw !== "object")
|
|
46
|
+
return null;
|
|
47
|
+
if (raw.status !== "pending" && raw.status !== "delivered")
|
|
48
|
+
return null;
|
|
49
|
+
return raw;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Attempt to claim a delivery slot.
|
|
53
|
+
*
|
|
54
|
+
* - `already_delivered` — a prior attempt completed; skip the send (idempotent).
|
|
55
|
+
* - `in_flight` — another attempt holds a fresh `pending` claim; skip to avoid a
|
|
56
|
+
* duplicate. (Stale `pending` claims are reclaimed and return `claimed`.)
|
|
57
|
+
* - `claimed` — caller owns the slot and must send, then call
|
|
58
|
+
* {@link markDelivered} on success or {@link releaseDelivery} on failure.
|
|
59
|
+
*/
|
|
60
|
+
export async function claimDelivery(ctx, key, options = {}) {
|
|
61
|
+
const now = options.now ?? Date.now;
|
|
62
|
+
const staleMs = options.staleMs ?? DEFAULT_CLAIM_STALE_MS;
|
|
63
|
+
const existing = await readRecord(ctx, key);
|
|
64
|
+
if (existing?.status === "delivered") {
|
|
65
|
+
return { outcome: "already_delivered", record: existing };
|
|
66
|
+
}
|
|
67
|
+
if (existing?.status === "pending") {
|
|
68
|
+
const age = now() - Date.parse(existing.claimedAt);
|
|
69
|
+
if (Number.isFinite(age) && age < staleMs) {
|
|
70
|
+
return { outcome: "in_flight", record: existing };
|
|
71
|
+
}
|
|
72
|
+
// Stale claim — reclaim it (previous attempt likely crashed mid-send).
|
|
73
|
+
}
|
|
74
|
+
const record = {
|
|
75
|
+
status: "pending",
|
|
76
|
+
claimedAt: new Date(now()).toISOString(),
|
|
77
|
+
attempts: (existing?.attempts ?? 0) + 1,
|
|
78
|
+
};
|
|
79
|
+
await ctx.state.set(stateScope(key), record);
|
|
80
|
+
return { outcome: "claimed", record };
|
|
81
|
+
}
|
|
82
|
+
/** Mark a previously-claimed slot as delivered (idempotent terminal state). */
|
|
83
|
+
export async function markDelivered(ctx, key, messageId, options = {}) {
|
|
84
|
+
const now = options.now ?? Date.now;
|
|
85
|
+
const existing = await readRecord(ctx, key);
|
|
86
|
+
const record = {
|
|
87
|
+
status: "delivered",
|
|
88
|
+
claimedAt: existing?.claimedAt ?? new Date(now()).toISOString(),
|
|
89
|
+
deliveredAt: new Date(now()).toISOString(),
|
|
90
|
+
attempts: existing?.attempts ?? 1,
|
|
91
|
+
...(messageId !== undefined ? { messageId } : {}),
|
|
92
|
+
};
|
|
93
|
+
await ctx.state.set(stateScope(key), record);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Release an unsent claim so a future retry can re-attempt delivery.
|
|
97
|
+
*
|
|
98
|
+
* Only releases slots that are still `pending` — a `delivered` slot is a
|
|
99
|
+
* terminal success and must never be cleared, or duplicates would resume.
|
|
100
|
+
*/
|
|
101
|
+
export async function releaseDelivery(ctx, key) {
|
|
102
|
+
const existing = await readRecord(ctx, key);
|
|
103
|
+
if (!existing || existing.status === "delivered")
|
|
104
|
+
return;
|
|
105
|
+
if (typeof ctx.state.delete === "function") {
|
|
106
|
+
await ctx.state.delete(stateScope(key));
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
// Fallback for hosts/mocks without delete: null out the slot.
|
|
110
|
+
await ctx.state.set(stateScope(key), null);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Run `send` under the idempotency guard.
|
|
115
|
+
*
|
|
116
|
+
* Claims the slot, and on `claimed` invokes `send`. A truthy/`number` result is
|
|
117
|
+
* recorded as delivered (and returned); a falsy result or a thrown error
|
|
118
|
+
* releases the claim so a retry can re-send. When the slot is already delivered
|
|
119
|
+
* or another attempt is in-flight, `send` is not invoked and `null` is returned.
|
|
120
|
+
*
|
|
121
|
+
* @returns the value from `send` on a fresh successful delivery, otherwise `null`.
|
|
122
|
+
*/
|
|
123
|
+
export async function withIdempotentDelivery(ctx, key, send, options = {}) {
|
|
124
|
+
const claim = await claimDelivery(ctx, key, options);
|
|
125
|
+
if (claim.outcome !== "claimed")
|
|
126
|
+
return null;
|
|
127
|
+
let result;
|
|
128
|
+
try {
|
|
129
|
+
result = await send();
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
await releaseDelivery(ctx, key);
|
|
133
|
+
throw err;
|
|
134
|
+
}
|
|
135
|
+
if (result === null || result === undefined) {
|
|
136
|
+
await releaseDelivery(ctx, key);
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
await markDelivered(ctx, key, typeof result === "number" ? result : undefined, options);
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=interaction-delivery.js.map
|