piclaw 0.0.4 → 0.0.6
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/.output/nitro.json +1 -1
- package/.output/public/assets/dist-D51xeTP2.js +12 -0
- package/.output/public/assets/index-B3x2_en6.css +1 -0
- package/.output/public/assets/index-SfjxJZSD.js +38 -0
- package/.output/public/assets/md4x-CNLJ57xO.wasm +0 -0
- package/.output/public/assets/md4x-CyfQToGJ.js +1 -0
- package/.output/public/assets/wasm-Cm7RZrwg.js +1 -0
- package/.output/public/icon.svg +25 -0
- package/.output/public/index.html +3 -2
- package/.output/public/manifest.json +1 -1
- package/.output/server/_chunks/bun.mjs +49 -0
- package/.output/server/_chunks/commands.mjs +280 -0
- package/.output/server/_chunks/config.mjs +2 -4
- package/.output/server/_chunks/db.mjs +11 -5
- package/.output/server/_chunks/logger.mjs +1 -1
- package/.output/server/_chunks/node.mjs +31 -0
- package/.output/server/_chunks/ntfy.mjs +45 -0
- package/.output/server/_chunks/pi.mjs +33 -1
- package/.output/server/_chunks/renderer-template.mjs +1 -1
- package/.output/server/_chunks/{bootstrap.mjs → server.mjs} +203 -205
- package/.output/server/_chunks/session.mjs +249 -40
- package/.output/server/_chunks/settings.mjs +1 -1
- package/.output/server/_chunks/terminal.mjs +35 -20
- package/.output/server/_chunks/virtual.mjs +129 -0
- package/.output/server/_jid_.delete.mjs +2 -2
- package/.output/server/_jid_.patch.mjs +30 -3
- package/.output/server/_jid_2.delete.mjs +2 -2
- package/.output/server/_libs/@aws-sdk/client-bedrock-runtime+[...].mjs +13148 -13149
- package/.output/server/_libs/@aws-sdk/credential-provider-http+[...].mjs +1 -1
- package/.output/server/_libs/@aws-sdk/credential-provider-ini+[...].mjs +2 -2
- package/.output/server/_libs/@aws-sdk/credential-provider-process+[...].mjs +1 -1
- package/.output/server/_libs/@aws-sdk/credential-provider-sso+[...].mjs +1 -1
- package/.output/server/_libs/@aws-sdk/credential-provider-web-identity+[...].mjs +1 -1
- package/.output/server/_libs/@google/genai.mjs +2 -2
- package/.output/server/_libs/@mariozechner/pi-agent-core+[...].mjs +40 -74
- package/.output/server/_libs/@mariozechner/pi-coding-agent+[...].mjs +1315 -1210
- package/.output/server/_libs/@smithy/credential-provider-imds+[...].mjs +3 -3
- package/.output/server/_libs/_.mjs +3 -2
- package/.output/server/_libs/_100.mjs +3 -0
- package/.output/server/_libs/_101.mjs +2 -0
- package/.output/server/_libs/_102.mjs +3 -0
- package/.output/server/_libs/_103.mjs +2 -0
- package/.output/server/_libs/_16.mjs +2 -5
- package/.output/server/_libs/_17.mjs +2 -3
- package/.output/server/_libs/_18.mjs +2 -3
- package/.output/server/_libs/_19.mjs +2 -4
- package/.output/server/_libs/_2.mjs +2 -3
- package/.output/server/_libs/_20.mjs +2 -2
- package/.output/server/_libs/_21.mjs +2 -0
- package/.output/server/_libs/_22.mjs +2 -0
- package/.output/server/_libs/_23.mjs +2 -0
- package/.output/server/_libs/_24.mjs +2 -0
- package/.output/server/_libs/_25.mjs +2 -0
- package/.output/server/_libs/_26.mjs +2 -0
- package/.output/server/_libs/_27.mjs +2 -0
- package/.output/server/_libs/_28.mjs +2 -0
- package/.output/server/_libs/_29.mjs +2 -0
- package/.output/server/_libs/_30.mjs +2 -0
- package/.output/server/_libs/_31.mjs +2 -0
- package/.output/server/_libs/_32.mjs +2 -0
- package/.output/server/_libs/_33.mjs +2 -0
- package/.output/server/_libs/_34.mjs +2 -0
- package/.output/server/_libs/_35.mjs +2 -0
- package/.output/server/_libs/_36.mjs +2 -0
- package/.output/server/_libs/_37.mjs +2 -0
- package/.output/server/_libs/_38.mjs +2 -0
- package/.output/server/_libs/_39.mjs +2 -0
- package/.output/server/_libs/_40.mjs +2 -0
- package/.output/server/_libs/_41.mjs +2 -0
- package/.output/server/_libs/_42.mjs +2 -0
- package/.output/server/_libs/_43.mjs +2 -0
- package/.output/server/_libs/_44.mjs +2 -0
- package/.output/server/_libs/_45.mjs +2 -0
- package/.output/server/_libs/_46.mjs +2 -0
- package/.output/server/_libs/_47.mjs +2 -0
- package/.output/server/_libs/_48.mjs +2 -0
- package/.output/server/_libs/_49.mjs +2 -0
- package/.output/server/_libs/_50.mjs +2 -0
- package/.output/server/_libs/_51.mjs +2 -0
- package/.output/server/_libs/_52.mjs +2 -0
- package/.output/server/_libs/_53.mjs +2 -0
- package/.output/server/_libs/_54.mjs +2 -0
- package/.output/server/_libs/_55.mjs +2 -0
- package/.output/server/_libs/_56.mjs +2 -0
- package/.output/server/_libs/_57.mjs +2 -0
- package/.output/server/_libs/_58.mjs +2 -0
- package/.output/server/_libs/_59.mjs +2 -0
- package/.output/server/_libs/_60.mjs +2 -0
- package/.output/server/_libs/_61.mjs +2 -0
- package/.output/server/_libs/_62.mjs +2 -0
- package/.output/server/_libs/_63.mjs +2 -0
- package/.output/server/_libs/_64.mjs +2 -0
- package/.output/server/_libs/_65.mjs +2 -0
- package/.output/server/_libs/_66.mjs +2 -0
- package/.output/server/_libs/_67.mjs +2 -0
- package/.output/server/_libs/_68.mjs +2 -0
- package/.output/server/_libs/_69.mjs +2 -0
- package/.output/server/_libs/_70.mjs +2 -0
- package/.output/server/_libs/_71.mjs +2 -0
- package/.output/server/_libs/_72.mjs +2 -0
- package/.output/server/_libs/_73.mjs +2 -0
- package/.output/server/_libs/_74.mjs +2 -0
- package/.output/server/_libs/_75.mjs +2 -0
- package/.output/server/_libs/_76.mjs +2 -0
- package/.output/server/_libs/_77.mjs +2 -0
- package/.output/server/_libs/_78.mjs +2 -0
- package/.output/server/_libs/_79.mjs +2 -0
- package/.output/server/_libs/_80.mjs +2 -0
- package/.output/server/_libs/_81.mjs +2 -0
- package/.output/server/_libs/_82.mjs +2 -0
- package/.output/server/_libs/_83.mjs +2 -0
- package/.output/server/_libs/_84.mjs +2 -0
- package/.output/server/_libs/_85.mjs +2 -0
- package/.output/server/_libs/_86.mjs +2 -0
- package/.output/server/_libs/_87.mjs +2 -0
- package/.output/server/_libs/_88.mjs +2 -0
- package/.output/server/_libs/_89.mjs +2 -0
- package/.output/server/_libs/_90.mjs +2 -0
- package/.output/server/_libs/_91.mjs +2 -0
- package/.output/server/_libs/_92.mjs +2 -0
- package/.output/server/_libs/_93.mjs +2 -0
- package/.output/server/_libs/_94.mjs +2 -0
- package/.output/server/_libs/_95.mjs +2 -0
- package/.output/server/_libs/_96.mjs +2 -0
- package/.output/server/_libs/_97.mjs +2 -0
- package/.output/server/_libs/_98.mjs +2 -0
- package/.output/server/_libs/_99.mjs +5 -0
- package/.output/server/_libs/amdefine.mjs +188 -0
- package/.output/server/_libs/aws-sdk__nested-clients.mjs +1 -1
- package/.output/server/_libs/compressjs.mjs +50 -0
- package/.output/server/_libs/diff.mjs +137 -0
- package/.output/server/_libs/get-uri.mjs +1 -1
- package/.output/server/_libs/http-proxy-agent.mjs +1 -1
- package/.output/server/_libs/https-proxy-agent.mjs +1 -1
- package/.output/server/_libs/just-bash+[...].mjs +80359 -0
- package/.output/server/_libs/md4x.mjs +73 -0
- package/.output/server/_libs/mixmark-io__domino.mjs +14801 -0
- package/.output/server/_libs/node-fetch.mjs +1 -1
- package/.output/server/_libs/node-liblzma.mjs +1107 -0
- package/.output/server/_libs/pac-proxy-agent+[...].mjs +1 -1
- package/.output/server/_libs/proxy-agent+proxy-from-env.mjs +1 -1
- package/.output/server/_libs/smithy__core.mjs +1 -1
- package/.output/server/_routes/api/files/delete.mjs +2 -2
- package/.output/server/_routes/api/files/groups.mjs +14 -0
- package/.output/server/_routes/api/files/raw.mjs +1 -1
- package/.output/server/_routes/api/files/read.mjs +1 -1
- package/.output/server/_routes/api/files/watch.mjs +1 -1
- package/.output/server/_routes/api/files/write.mjs +3 -2
- package/.output/server/_routes/api/files.mjs +1 -1
- package/.output/server/_routes/api/groups.mjs +2 -2
- package/.output/server/_routes/api/groups2.mjs +3 -2
- package/.output/server/_routes/api/health.mjs +2 -2
- package/.output/server/_routes/api/logs.mjs +4 -2
- package/.output/server/_routes/api/ntfy/setup.mjs +54 -0
- package/.output/server/_routes/api/ntfy/status.mjs +12 -0
- package/.output/server/_routes/api/pi/apikey.mjs +1 -1
- package/.output/server/_routes/api/pi/apikey_providers.mjs +1 -1
- package/.output/server/_routes/api/pi/commands.mjs +6 -0
- package/.output/server/_routes/api/pi/login/events.mjs +1 -1
- package/.output/server/_routes/api/pi/login/respond.mjs +1 -1
- package/.output/server/_routes/api/pi/login.mjs +1 -1
- package/.output/server/_routes/api/pi/logout.mjs +1 -1
- package/.output/server/_routes/api/pi/models.mjs +1 -1
- package/.output/server/_routes/api/pi/status.mjs +1 -1
- package/.output/server/_routes/api/send.mjs +22 -3
- package/.output/server/_routes/api/status.mjs +9 -7
- package/.output/server/_routes/api/tasks2.mjs +2 -2
- package/.output/server/_routes/api/telegram/setup.mjs +2 -2
- package/.output/server/_routes/api/telegram/status.mjs +2 -2
- package/.output/server/_routes/api/terminal2.mjs +3 -2
- package/.output/server/_utils.mjs +12 -4
- package/.output/server/build/md4x.wasm +0 -0
- package/.output/server/index.mjs +223 -149
- package/.output/server/node_modules/@mongodb-js/zstd/lib/index.js +55 -0
- package/.output/server/node_modules/@mongodb-js/zstd/package.json +51 -0
- package/.output/server/package.json +1 -0
- package/README.md +118 -24
- package/bin/piclaw.mjs +39 -1
- package/package.json +16 -13
- package/.output/public/assets/client-TIs-Ghqj.js +0 -9
- package/.output/public/assets/dist-BVjfG3ok.js +0 -12
- package/.output/public/assets/dist-DJh8l6yS.js +0 -1
- package/.output/public/assets/index-BNNEMkNV.js +0 -39
- package/.output/public/assets/index-CdWBxO5V.css +0 -1
- package/.output/public/assets/react-DFP7nCmh.js +0 -1
|
@@ -1,160 +1,28 @@
|
|
|
1
1
|
import { a as MAX_CONCURRENT_AGENTS, c as POLL_INTERVAL$1, f as TELEGRAM_BOT_TOKEN, i as MAIN_GROUP_FOLDER, l as SCHEDULER_POLL_INTERVAL, m as TRIGGER_PATTERN, n as ASSISTANT_NAME, p as TIMEZONE, r as GROUPS_DIR, u as SESSIONS_DIR } from "./config.mjs";
|
|
2
2
|
import { t as createLogger } from "./logger.mjs";
|
|
3
3
|
import { t as streamBus } from "./stream.mjs";
|
|
4
|
-
import { i as
|
|
4
|
+
import { C as setSession, D as updateTaskAfterRun, S as setRouterState, T as storeMessage, _ as removeRegisteredGroup, b as setConfig, d as getMessagesSince, f as getNewMessages, g as logTaskRun, h as initDatabase, i as deleteConfig, l as getConfig, m as getTaskById, o as getAllRegisteredGroups, p as getRouterState, r as deleteChat, s as getAllSessions, u as getDueTasks, v as removeSession, w as storeChatMetadata, x as setRegisteredGroup, y as removeTasksByChat } from "./db.mjs";
|
|
5
5
|
import { n as pi_exports } from "./pi.mjs";
|
|
6
|
-
import {
|
|
6
|
+
import { i as tryPriorityCommand, n as tryBashCommand, r as tryCommand, t as commandDescriptions } from "./commands.mjs";
|
|
7
|
+
import { a as renderToAnsi, i as parseAST, r as init } from "../_libs/md4x.mjs";
|
|
7
8
|
import { t as terminalManager } from "./terminal.mjs";
|
|
8
9
|
import crypto from "node:crypto";
|
|
9
10
|
import fs from "node:fs";
|
|
10
11
|
import path from "node:path";
|
|
11
12
|
import path$1 from "path";
|
|
12
13
|
import fs$1 from "fs";
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
info: handleInfo,
|
|
16
|
-
new: handleNew,
|
|
17
|
-
model: handleModel
|
|
18
|
-
};
|
|
19
|
-
/**
|
|
20
|
-
* Try to handle a message as a `/command`. Returns true if handled.
|
|
21
|
-
*/
|
|
22
|
-
function tryCommand(ctx, text) {
|
|
23
|
-
if (!text.startsWith("/")) return false;
|
|
24
|
-
const spaceIdx = text.indexOf(" ");
|
|
25
|
-
const name = (spaceIdx > 0 ? text.slice(1, spaceIdx) : text.slice(1)).toLowerCase();
|
|
26
|
-
const arg = spaceIdx > 0 ? text.slice(spaceIdx + 1).trim() : "";
|
|
27
|
-
const handler = commands[name];
|
|
28
|
-
if (handler) {
|
|
29
|
-
handler(ctx, arg);
|
|
30
|
-
return true;
|
|
31
|
-
}
|
|
32
|
-
ctx.server.sendBotMessage(ctx.chatJid, `Unknown command \`/${name}\`. Use /help for available commands.`);
|
|
33
|
-
return true;
|
|
34
|
-
}
|
|
35
|
-
function handleHelp(ctx) {
|
|
36
|
-
ctx.server.sendBotMessage(ctx.chatJid, [
|
|
37
|
-
"Available commands:",
|
|
38
|
-
" /info — Show session info (model, context, status)",
|
|
39
|
-
" /new — Reset session and start a fresh conversation",
|
|
40
|
-
" /model — List available models and show current",
|
|
41
|
-
" /model <query> — Set model (fuzzy search)",
|
|
42
|
-
" /model default — Reset to global default model",
|
|
43
|
-
" /help — Show this help"
|
|
44
|
-
].join("\n"));
|
|
45
|
-
}
|
|
46
|
-
function handleInfo(ctx) {
|
|
47
|
-
const resolved = resolveGroupModel(ctx.group);
|
|
48
|
-
const modelLabel = resolved ? `${resolved.provider}/${resolved.id}` : "none";
|
|
49
|
-
const modelSource = ctx.group.model ? `group (${ctx.group.model})` : "default";
|
|
50
|
-
const managed = sessions.get(ctx.chatJid);
|
|
51
|
-
const lines = [
|
|
52
|
-
`Group: ${ctx.group.name} (${ctx.group.folder})`,
|
|
53
|
-
`Model: ${modelLabel} [${modelSource}]`,
|
|
54
|
-
`Trigger: ${ctx.group.requiresTrigger ? "required" : "not required"}`
|
|
55
|
-
];
|
|
56
|
-
if (managed) {
|
|
57
|
-
const s = managed.session;
|
|
58
|
-
const actualModel = s.model;
|
|
59
|
-
const actualLabel = actualModel ? `${actualModel.provider}/${actualModel.id}` : "none";
|
|
60
|
-
const ctx$ = s.getContextUsage();
|
|
61
|
-
lines.push("", `Session: ${s.sessionId}`, actualLabel !== modelLabel ? `Session model: ${actualLabel} (MISMATCH with resolved)` : `Session model: ${actualLabel}`, `Messages: ${s.messages.length}`, `Streaming: ${s.isStreaming ? "yes" : "no"}`, `Idle: ${formatDuration(Date.now() - managed.lastActivity)}`);
|
|
62
|
-
if (ctx$?.tokens != null && ctx$.percent != null) {
|
|
63
|
-
const pct = Math.round(ctx$.percent);
|
|
64
|
-
lines.push(`Context: ${ctx$.tokens.toLocaleString()} / ${ctx$.contextWindow.toLocaleString()} tokens (${pct}%)`);
|
|
65
|
-
}
|
|
66
|
-
} else lines.push("", "No active session");
|
|
67
|
-
ctx.server.sendBotMessage(ctx.chatJid, lines.join("\n"));
|
|
68
|
-
}
|
|
69
|
-
function formatDuration(ms) {
|
|
70
|
-
const s = Math.floor(ms / 1e3);
|
|
71
|
-
if (s < 60) return `${s}s`;
|
|
72
|
-
const m = Math.floor(s / 60);
|
|
73
|
-
if (m < 60) return `${m}m ${s % 60}s`;
|
|
74
|
-
return `${Math.floor(m / 60)}h ${m % 60}m`;
|
|
75
|
-
}
|
|
76
|
-
function handleNew(ctx) {
|
|
77
|
-
ctx.server.pi.kill(ctx.chatJid);
|
|
78
|
-
removeSession(ctx.group.folder);
|
|
79
|
-
clearMessages(ctx.chatJid);
|
|
80
|
-
ctx.server.sendBotMessage(ctx.chatJid, "Session reset. Next message starts a fresh conversation.");
|
|
81
|
-
}
|
|
82
|
-
function handleModel(ctx, arg) {
|
|
83
|
-
if (!arg) return listModels(ctx);
|
|
84
|
-
if (arg === "default" || arg === "reset") return resetModel(ctx);
|
|
85
|
-
return setModel(ctx, arg);
|
|
86
|
-
}
|
|
87
|
-
function listModels(ctx) {
|
|
88
|
-
const available = modelRegistry.getAvailable();
|
|
89
|
-
const resolved = resolveGroupModel(ctx.group);
|
|
90
|
-
const lines = [
|
|
91
|
-
`Current: ${ctx.group.model || "default (global)"} → ${resolved ? `${resolved.provider}/${resolved.id}` : "none"}`,
|
|
92
|
-
"",
|
|
93
|
-
"Available models:"
|
|
94
|
-
];
|
|
95
|
-
const byProvider = /* @__PURE__ */ new Map();
|
|
96
|
-
for (const m of available) {
|
|
97
|
-
let list = byProvider.get(m.provider);
|
|
98
|
-
if (!list) {
|
|
99
|
-
list = [];
|
|
100
|
-
byProvider.set(m.provider, list);
|
|
101
|
-
}
|
|
102
|
-
const marker = resolved && m.provider === resolved.provider && m.id === resolved.id ? " ←" : "";
|
|
103
|
-
list.push(` ${m.provider}/${m.id}${marker}`);
|
|
104
|
-
}
|
|
105
|
-
for (const [provider, models] of byProvider) {
|
|
106
|
-
lines.push(`[${provider}]`);
|
|
107
|
-
lines.push(...models);
|
|
108
|
-
}
|
|
109
|
-
lines.push("", "Usage: /model <query> | /model default");
|
|
110
|
-
ctx.server.sendBotMessage(ctx.chatJid, lines.join("\n"));
|
|
111
|
-
}
|
|
112
|
-
function resetModel(ctx) {
|
|
113
|
-
const had = ctx.group.model;
|
|
114
|
-
updateGroupModel(ctx, void 0);
|
|
115
|
-
ctx.server.sendBotMessage(ctx.chatJid, had ? `Model reset to default (was: ${had}).` : "Already using default model.");
|
|
116
|
-
}
|
|
117
|
-
function setModel(ctx, query) {
|
|
118
|
-
const match = findModel(query);
|
|
119
|
-
if (!match) {
|
|
120
|
-
ctx.server.sendBotMessage(ctx.chatJid, `No model matching "${query}". Use /model to list available models.`);
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
const modelStr = `${match.provider}/${match.id}`;
|
|
124
|
-
updateGroupModel(ctx, modelStr);
|
|
125
|
-
ctx.server.sendBotMessage(ctx.chatJid, `Model set to: ${modelStr}`);
|
|
126
|
-
}
|
|
127
|
-
function updateGroupModel(ctx, model) {
|
|
128
|
-
const old = ctx.group.model;
|
|
129
|
-
ctx.group.model = model;
|
|
130
|
-
ctx.server.setRegisteredGroup(ctx.chatJid, ctx.group);
|
|
131
|
-
if (old !== model) ctx.server.pi.kill(ctx.chatJid);
|
|
132
|
-
}
|
|
133
|
-
function findModel(query) {
|
|
134
|
-
const available = modelRegistry.getAvailable();
|
|
135
|
-
if (available.length === 0) return void 0;
|
|
136
|
-
const q = query.toLowerCase();
|
|
137
|
-
const exact = available.filter((m) => `${m.provider}/${m.id}`.toLowerCase() === q);
|
|
138
|
-
if (exact.length === 1) return exact[0];
|
|
139
|
-
const byId = available.filter((m) => m.id.toLowerCase() === q);
|
|
140
|
-
if (byId.length === 1) return byId[0];
|
|
141
|
-
const tokens = q.split(/[\s/]+/).filter(Boolean);
|
|
142
|
-
const fuzzy = available.filter((m) => {
|
|
143
|
-
const label = `${m.provider}/${m.id}`.toLowerCase();
|
|
144
|
-
return tokens.every((t) => label.includes(t));
|
|
145
|
-
});
|
|
146
|
-
const matches = exact.length > 1 ? exact : byId.length > 1 ? byId : fuzzy;
|
|
147
|
-
if (matches.length === 0) return void 0;
|
|
148
|
-
matches.sort((a, b) => a.id.length - b.id.length || b.id.localeCompare(a.id, void 0, { numeric: true }));
|
|
149
|
-
return matches[0];
|
|
150
|
-
}
|
|
14
|
+
await init();
|
|
15
|
+
console.log(renderToAnsi("`md4x` initialized for Telegram channel!"));
|
|
151
16
|
var logger$3 = createLogger("telegram");
|
|
152
17
|
var JID_PREFIX = "tg:";
|
|
153
18
|
var POLL_INTERVAL = 1e3;
|
|
154
19
|
var POLL_TIMEOUT = 30;
|
|
155
20
|
var API_BASE = "https://api.telegram.org/bot";
|
|
156
|
-
var
|
|
157
|
-
var
|
|
21
|
+
var STREAM_THROTTLE_MIN = 700;
|
|
22
|
+
var STREAM_THROTTLE_MAX = 1500;
|
|
23
|
+
var STREAM_THROTTLE_STEP = 200;
|
|
24
|
+
var STREAM_THROTTLE_JITTER = 120;
|
|
25
|
+
var STREAM_INITIAL_DELAY = 100;
|
|
158
26
|
var TG_MAX_TEXT = 4096;
|
|
159
27
|
var TelegramChannel = class {
|
|
160
28
|
name = "telegram";
|
|
@@ -178,6 +46,7 @@ var TelegramChannel = class {
|
|
|
178
46
|
this.botId = me.id;
|
|
179
47
|
this.botUsername = me.username || me.first_name;
|
|
180
48
|
await this.api("deleteWebhook", { drop_pending_updates: false });
|
|
49
|
+
await this.api("setMyCommands", { commands: commandDescriptions });
|
|
181
50
|
this.connected = true;
|
|
182
51
|
this.startPolling();
|
|
183
52
|
this.streamUnsub = streamBus.subscribeAll((e) => this.onStreamEvent(e));
|
|
@@ -189,6 +58,8 @@ var TelegramChannel = class {
|
|
|
189
58
|
async sendMessage(jid, text) {
|
|
190
59
|
const chatId = jid.slice(3);
|
|
191
60
|
const state = this.streamState.get(jid);
|
|
61
|
+
const { text: formatted, parse_mode } = formatForTelegram(text);
|
|
62
|
+
const parseMode = { parse_mode };
|
|
192
63
|
if (state) {
|
|
193
64
|
this.streamState.delete(jid);
|
|
194
65
|
if (state.editTimer) clearTimeout(state.editTimer);
|
|
@@ -197,14 +68,16 @@ var TelegramChannel = class {
|
|
|
197
68
|
await this.api("editMessageText", {
|
|
198
69
|
chat_id: chatId,
|
|
199
70
|
message_id: state.messageId,
|
|
200
|
-
text:
|
|
71
|
+
text: formatted.slice(0, TG_MAX_TEXT),
|
|
72
|
+
...parseMode
|
|
201
73
|
});
|
|
202
74
|
return;
|
|
203
75
|
} catch {}
|
|
204
76
|
}
|
|
205
77
|
await this.api("sendMessage", {
|
|
206
78
|
chat_id: chatId,
|
|
207
|
-
text
|
|
79
|
+
text: formatted,
|
|
80
|
+
...parseMode
|
|
208
81
|
});
|
|
209
82
|
}
|
|
210
83
|
isConnected() {
|
|
@@ -237,19 +110,14 @@ var TelegramChannel = class {
|
|
|
237
110
|
if (!this.ownsJid(event.chatJid)) return;
|
|
238
111
|
const jid = event.chatJid;
|
|
239
112
|
switch (event.type) {
|
|
113
|
+
case "thinking_delta": {
|
|
114
|
+
const state = this.getOrCreateStreamState(jid);
|
|
115
|
+
state.thinkingText += event.delta || "";
|
|
116
|
+
this.scheduleStreamEdit(jid, state);
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
240
119
|
case "text_delta": {
|
|
241
|
-
|
|
242
|
-
if (!state) {
|
|
243
|
-
state = {
|
|
244
|
-
chatId: jid.slice(3),
|
|
245
|
-
text: "",
|
|
246
|
-
messageId: null,
|
|
247
|
-
sendPromise: null,
|
|
248
|
-
lastEdit: 0,
|
|
249
|
-
editTimer: null
|
|
250
|
-
};
|
|
251
|
-
this.streamState.set(jid, state);
|
|
252
|
-
}
|
|
120
|
+
const state = this.getOrCreateStreamState(jid);
|
|
253
121
|
state.text += event.delta || "";
|
|
254
122
|
this.scheduleStreamEdit(jid, state);
|
|
255
123
|
break;
|
|
@@ -265,40 +133,70 @@ var TelegramChannel = class {
|
|
|
265
133
|
}
|
|
266
134
|
}
|
|
267
135
|
}
|
|
136
|
+
getOrCreateStreamState(jid) {
|
|
137
|
+
let state = this.streamState.get(jid);
|
|
138
|
+
if (!state) {
|
|
139
|
+
state = {
|
|
140
|
+
chatId: jid.slice(3),
|
|
141
|
+
text: "",
|
|
142
|
+
thinkingText: "",
|
|
143
|
+
messageId: null,
|
|
144
|
+
sendPromise: null,
|
|
145
|
+
lastEdit: 0,
|
|
146
|
+
editTimer: null,
|
|
147
|
+
throttleMs: STREAM_THROTTLE_MIN
|
|
148
|
+
};
|
|
149
|
+
this.streamState.set(jid, state);
|
|
150
|
+
}
|
|
151
|
+
return state;
|
|
152
|
+
}
|
|
268
153
|
scheduleStreamEdit(jid, state) {
|
|
269
154
|
if (state.editTimer) return;
|
|
270
155
|
const elapsed = Date.now() - state.lastEdit;
|
|
271
|
-
const
|
|
156
|
+
const jitter = randomJitter(STREAM_THROTTLE_JITTER);
|
|
157
|
+
const delay = state.messageId === null ? STREAM_INITIAL_DELAY : Math.max(0, state.throttleMs + jitter - elapsed);
|
|
272
158
|
state.editTimer = setTimeout(() => {
|
|
273
159
|
state.editTimer = null;
|
|
274
160
|
this.flushStreamEdit(jid, state);
|
|
275
161
|
}, delay);
|
|
276
162
|
}
|
|
277
|
-
async flushStreamEdit(
|
|
278
|
-
|
|
163
|
+
async flushStreamEdit(jid, state) {
|
|
164
|
+
if (state.sendPromise) {
|
|
165
|
+
await state.sendPromise.catch(() => {});
|
|
166
|
+
state.sendPromise = null;
|
|
167
|
+
}
|
|
168
|
+
const display = state.text.trim() || (state.thinkingText.trim() ? `💭 ${state.thinkingText.trim()}` : "");
|
|
279
169
|
if (!display) return;
|
|
280
|
-
const
|
|
170
|
+
const { text: formatted, parse_mode } = formatForTelegram(display.length > TG_MAX_TEXT ? display.slice(0, TG_MAX_TEXT - 1) + "…" : display);
|
|
171
|
+
const snapshotLen = display.length;
|
|
281
172
|
try {
|
|
282
|
-
if (state.messageId === null
|
|
173
|
+
if (state.messageId === null) {
|
|
283
174
|
state.sendPromise = this.api("sendMessage", {
|
|
284
175
|
chat_id: state.chatId,
|
|
285
|
-
text:
|
|
176
|
+
text: formatted,
|
|
177
|
+
parse_mode
|
|
286
178
|
}).then((msg) => {
|
|
287
179
|
state.messageId = msg.message_id;
|
|
288
|
-
state.
|
|
180
|
+
state.sendPromise = null;
|
|
289
181
|
});
|
|
290
182
|
await state.sendPromise;
|
|
291
|
-
} else
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
183
|
+
} else await this.api("editMessageText", {
|
|
184
|
+
chat_id: state.chatId,
|
|
185
|
+
message_id: state.messageId,
|
|
186
|
+
text: formatted,
|
|
187
|
+
parse_mode
|
|
188
|
+
});
|
|
189
|
+
state.lastEdit = Date.now();
|
|
190
|
+
state.throttleMs = Math.max(STREAM_THROTTLE_MIN, state.throttleMs - 50);
|
|
299
191
|
} catch (err) {
|
|
300
|
-
|
|
192
|
+
const retryAfterMs = getRetryAfterMs(err);
|
|
193
|
+
if (retryAfterMs > 0) state.throttleMs = Math.min(STREAM_THROTTLE_MAX, Math.max(state.throttleMs + STREAM_THROTTLE_STEP, retryAfterMs));
|
|
194
|
+
logger$3.debug({
|
|
195
|
+
err,
|
|
196
|
+
throttleMs: state.throttleMs
|
|
197
|
+
}, "Stream edit failed");
|
|
301
198
|
}
|
|
199
|
+
if ((state.text.trim() || (state.thinkingText.trim() ? `💭 ${state.thinkingText.trim()}` : "")).length > snapshotLen && this.streamState.has(jid)) this.scheduleStreamEdit(jid, state);
|
|
302
200
|
}
|
|
303
201
|
startPolling() {
|
|
304
202
|
this.stopPolling();
|
|
@@ -352,12 +250,13 @@ var TelegramChannel = class {
|
|
|
352
250
|
this.pollAbort = null;
|
|
353
251
|
}
|
|
354
252
|
async api(method, body) {
|
|
355
|
-
const
|
|
253
|
+
const res = await fetch(`${API_BASE}${this.config.botToken}/${method}`, {
|
|
356
254
|
method: "POST",
|
|
357
255
|
headers: { "content-type": "application/json" },
|
|
358
256
|
body: body ? JSON.stringify(body) : void 0
|
|
359
|
-
})
|
|
360
|
-
|
|
257
|
+
});
|
|
258
|
+
const data = await res.json();
|
|
259
|
+
if (!data.ok) throw new TelegramApiError(method, data.description || "unknown error", res.status, data);
|
|
361
260
|
return data.result;
|
|
362
261
|
}
|
|
363
262
|
handleUpdate(update) {
|
|
@@ -383,12 +282,101 @@ var TelegramChannel = class {
|
|
|
383
282
|
this.opts.onChatMetadata(jid, now, senderName, "telegram", isGroup);
|
|
384
283
|
}
|
|
385
284
|
};
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
285
|
+
var TelegramApiError = class extends Error {
|
|
286
|
+
constructor(method, message, status, response) {
|
|
287
|
+
super(`Telegram API ${method} failed: ${message}`);
|
|
288
|
+
this.method = method;
|
|
289
|
+
this.status = status;
|
|
290
|
+
this.response = response;
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
/** Format message text as Telegram MarkdownV2 — parse with md4x, render AST to TG format */
|
|
294
|
+
function formatForTelegram(text) {
|
|
295
|
+
let remaining = text.replace(/<\/?internal>/g, (t) => t.replace("internal", "thinking"));
|
|
296
|
+
const parts = [];
|
|
297
|
+
const thinkingRe = /<thinking>([\s\S]*?)<\/thinking>/g;
|
|
298
|
+
let lastIdx = 0;
|
|
299
|
+
let m;
|
|
300
|
+
while ((m = thinkingRe.exec(remaining)) !== null) {
|
|
301
|
+
if (m.index > lastIdx) parts.push(mdToTgV2(remaining.slice(lastIdx, m.index)));
|
|
302
|
+
const trimmed = (m[1] || "").trim();
|
|
303
|
+
if (trimmed) {
|
|
304
|
+
const quoted = escTgV2(trimmed).split("\n").map((l) => `>${l}`).join("\n");
|
|
305
|
+
parts.push(quoted);
|
|
306
|
+
}
|
|
307
|
+
lastIdx = m.index + m[0].length;
|
|
308
|
+
}
|
|
309
|
+
if (lastIdx < remaining.length) parts.push(mdToTgV2(remaining.slice(lastIdx)));
|
|
310
|
+
return {
|
|
311
|
+
text: parts.join("").replace(/\n{3,}/g, "\n\n").trim(),
|
|
312
|
+
parse_mode: "MarkdownV2"
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
/** Parse markdown with md4x and render AST nodes to Telegram MarkdownV2 */
|
|
316
|
+
function mdToTgV2(text) {
|
|
317
|
+
return parseAST(text).nodes.map((node) => renderNode(node, true)).join("\n\n");
|
|
318
|
+
}
|
|
319
|
+
/** Collect raw text from children (for code content that must not be escaped) */
|
|
320
|
+
function collectText(children) {
|
|
321
|
+
return children.map((c) => typeof c === "string" ? c : "").join("");
|
|
322
|
+
}
|
|
323
|
+
/** Render a single AST node to Telegram MarkdownV2 */
|
|
324
|
+
function renderNode(node, topLevel = false) {
|
|
325
|
+
if (typeof node === "string") return escTgV2(node);
|
|
326
|
+
const [tag, attrs, ...children] = node;
|
|
327
|
+
const inner = () => children.map((c) => renderNode(c)).join("");
|
|
328
|
+
switch (tag) {
|
|
329
|
+
case "p": return inner();
|
|
330
|
+
case "h1":
|
|
331
|
+
case "h2":
|
|
332
|
+
case "h3":
|
|
333
|
+
case "h4":
|
|
334
|
+
case "h5":
|
|
335
|
+
case "h6": return `*${inner()}*`;
|
|
336
|
+
case "strong": return `*${inner()}*`;
|
|
337
|
+
case "em": return `_${inner()}_`;
|
|
338
|
+
case "u": return `__${inner()}__`;
|
|
339
|
+
case "del": return `~${inner()}~`;
|
|
340
|
+
case "code":
|
|
341
|
+
if (!topLevel) return collectText(children);
|
|
342
|
+
return `\`${collectText(children)}\``;
|
|
343
|
+
case "pre": {
|
|
344
|
+
const codeNode = children.find((c) => typeof c !== "string" && c[0] === "code");
|
|
345
|
+
return `\`\`\`${String(attrs.language || "")}\n${(codeNode ? collectText(codeNode.slice(2)) : inner()).replace(/\n$/, "")}\n\`\`\``;
|
|
346
|
+
}
|
|
347
|
+
case "a": {
|
|
348
|
+
const href = String(attrs.href || "");
|
|
349
|
+
return `[${inner()}](${escTgUrl(href)})`;
|
|
350
|
+
}
|
|
351
|
+
case "img": return escTgV2(String(attrs.alt || "image"));
|
|
352
|
+
case "blockquote": return inner().split("\n").map((l) => `>${l}`).join("\n");
|
|
353
|
+
case "ul":
|
|
354
|
+
case "ol": return children.map((c, i) => {
|
|
355
|
+
if (typeof c === "string") return escTgV2(c);
|
|
356
|
+
return (tag === "ol" ? `${escTgV2(`${i + 1}.`)} ` : `${escTgV2("•")} `) + renderNode(c);
|
|
357
|
+
}).filter((l) => l.trim()).join("\n");
|
|
358
|
+
case "li": return inner();
|
|
359
|
+
case "hr": return escTgV2("---");
|
|
360
|
+
case "br": return "\n";
|
|
361
|
+
default: return inner();
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
/** Escape special characters for Telegram MarkdownV2 outside code spans */
|
|
365
|
+
function escTgV2(s) {
|
|
366
|
+
return s.replace(/([_*[\]()~`>#+=|{}.!\\-])/g, "\\$1");
|
|
367
|
+
}
|
|
368
|
+
/** Escape only ) and \ inside MarkdownV2 link URLs */
|
|
369
|
+
function escTgUrl(s) {
|
|
370
|
+
return s.replace(/([)\\])/g, "\\$1");
|
|
371
|
+
}
|
|
372
|
+
function getRetryAfterMs(err) {
|
|
373
|
+
if (!(err instanceof TelegramApiError)) return 0;
|
|
374
|
+
const retryAfterSec = Number(err.response?.parameters?.retry_after || 0);
|
|
375
|
+
if (!Number.isFinite(retryAfterSec) || retryAfterSec <= 0) return 0;
|
|
376
|
+
return retryAfterSec * 1e3;
|
|
377
|
+
}
|
|
378
|
+
function randomJitter(maxAbs) {
|
|
379
|
+
return Math.round((Math.random() * 2 - 1) * maxAbs);
|
|
392
380
|
}
|
|
393
381
|
function sleep(ms, signal) {
|
|
394
382
|
return new Promise((resolve) => {
|
|
@@ -424,8 +412,6 @@ function ensureGlobalMemory() {
|
|
|
424
412
|
function initGroupMemory(folder) {
|
|
425
413
|
ensureGlobalMemory();
|
|
426
414
|
ensureGroupMemory(folder);
|
|
427
|
-
const logsDir = path$1.join(GROUPS_DIR, folder, "logs");
|
|
428
|
-
fs$1.mkdirSync(logsDir, { recursive: true });
|
|
429
415
|
}
|
|
430
416
|
/** Initialize the main group */
|
|
431
417
|
function initMainMemory() {
|
|
@@ -515,13 +501,9 @@ function escapeXml(s) {
|
|
|
515
501
|
function formatMessages(messages) {
|
|
516
502
|
return `<messages>\n${messages.map((m) => `<message sender="${escapeXml(m.sender_name)}" time="${m.timestamp}">${escapeXml(m.content)}</message>`).join("\n")}\n</messages>`;
|
|
517
503
|
}
|
|
518
|
-
/**
|
|
519
|
-
function stripInternalTags(text) {
|
|
520
|
-
return text.replace(/<internal>[\s\S]*?<\/internal>/g, "").trim();
|
|
521
|
-
}
|
|
522
|
-
/** Format outbound text (strip internal reasoning) */
|
|
504
|
+
/** Format outbound text */
|
|
523
505
|
function formatOutbound(rawText) {
|
|
524
|
-
return
|
|
506
|
+
return rawText.trim();
|
|
525
507
|
}
|
|
526
508
|
/** Check if messages need a trigger and whether any message matches */
|
|
527
509
|
function needsProcessing(group, messages) {
|
|
@@ -689,8 +671,9 @@ var PiClawServer = class {
|
|
|
689
671
|
if (text) this.sendBotMessage(jid, text);
|
|
690
672
|
}
|
|
691
673
|
});
|
|
692
|
-
this.
|
|
674
|
+
await this.pi.warmUp(this.registeredGroups, this.sessions, ASSISTANT_NAME);
|
|
693
675
|
this.recoverPendingMessages();
|
|
676
|
+
this.queue.setProcessMessagesFn((chatJid) => this.processGroupMessages(chatJid));
|
|
694
677
|
this.startMessageLoop();
|
|
695
678
|
const elapsed = (performance.now() - startTime).toFixed(0);
|
|
696
679
|
logger.info(`PiClaw server started in ${elapsed}ms`);
|
|
@@ -783,7 +766,7 @@ var PiClawServer = class {
|
|
|
783
766
|
if (this.unregisteredNotified.has(jid)) return;
|
|
784
767
|
this.unregisteredNotified.add(jid);
|
|
785
768
|
setTimeout(() => this.unregisteredNotified.delete(jid), 3600 * 1e3);
|
|
786
|
-
this.sendBotMessage(jid, `This chat is not registered. Ask an admin to approve it (
|
|
769
|
+
this.sendBotMessage(jid, `This chat is not registered. Ask an admin to approve it from chats window (${jid}).`);
|
|
787
770
|
}
|
|
788
771
|
/** For DM chats, auto-disable trigger requirement so every message is processed */
|
|
789
772
|
autoSetTriggerForDM(jid, isGroup) {
|
|
@@ -864,11 +847,15 @@ var PiClawServer = class {
|
|
|
864
847
|
const group = this.registeredGroups[chatJid];
|
|
865
848
|
if (!group) return messages;
|
|
866
849
|
const remaining = [];
|
|
867
|
-
for (const msg of messages)
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
850
|
+
for (const msg of messages) {
|
|
851
|
+
const text = msg.content.trim();
|
|
852
|
+
const ctx = {
|
|
853
|
+
chatJid,
|
|
854
|
+
group,
|
|
855
|
+
server: this
|
|
856
|
+
};
|
|
857
|
+
if (!(tryBashCommand(ctx, text) || tryCommand(ctx, text))) remaining.push(msg);
|
|
858
|
+
}
|
|
872
859
|
return remaining;
|
|
873
860
|
}
|
|
874
861
|
async processGroupMessages(chatJid) {
|
|
@@ -885,9 +872,7 @@ var PiClawServer = class {
|
|
|
885
872
|
}
|
|
886
873
|
if (!needsProcessing(group, agentMessages)) return true;
|
|
887
874
|
const prompt = formatMessages(agentMessages);
|
|
888
|
-
const
|
|
889
|
-
this.lastAgentTimestamp[chatJid] = missedMessages[missedMessages.length - 1].timestamp;
|
|
890
|
-
this.saveState();
|
|
875
|
+
const lastMessageTimestamp = missedMessages[missedMessages.length - 1].timestamp;
|
|
891
876
|
logger.info({
|
|
892
877
|
group: group.name,
|
|
893
878
|
messageCount: missedMessages.length
|
|
@@ -919,6 +904,7 @@ var PiClawServer = class {
|
|
|
919
904
|
});
|
|
920
905
|
} catch (err) {
|
|
921
906
|
hadError = true;
|
|
907
|
+
console.error(err);
|
|
922
908
|
logger.error({
|
|
923
909
|
group: group.name,
|
|
924
910
|
err
|
|
@@ -926,11 +912,11 @@ var PiClawServer = class {
|
|
|
926
912
|
}
|
|
927
913
|
clearInterval(typingInterval);
|
|
928
914
|
if (hadError && !outputSentToUser) {
|
|
929
|
-
|
|
930
|
-
this.saveState();
|
|
931
|
-
logger.warn({ group: group.name }, "Agent error, rolled back cursor for retry");
|
|
915
|
+
logger.warn({ group: group.name }, "Agent error, cursor not advanced for retry");
|
|
932
916
|
return false;
|
|
933
917
|
}
|
|
918
|
+
this.lastAgentTimestamp[chatJid] = lastMessageTimestamp;
|
|
919
|
+
this.saveState();
|
|
934
920
|
return true;
|
|
935
921
|
}
|
|
936
922
|
/** Send repeating typing indicator to the channel owning the JID */
|
|
@@ -959,7 +945,17 @@ var PiClawServer = class {
|
|
|
959
945
|
}
|
|
960
946
|
for (const [chatJid, groupMessages] of byGroup) {
|
|
961
947
|
const group = this.registeredGroups[chatJid];
|
|
962
|
-
if (!group
|
|
948
|
+
if (!group) continue;
|
|
949
|
+
for (const msg of groupMessages) {
|
|
950
|
+
const ctx = {
|
|
951
|
+
chatJid,
|
|
952
|
+
group,
|
|
953
|
+
server: this
|
|
954
|
+
};
|
|
955
|
+
tryBashCommand(ctx, msg.content.trim());
|
|
956
|
+
tryPriorityCommand(ctx, msg.content.trim());
|
|
957
|
+
}
|
|
958
|
+
if (!needsProcessing(group, groupMessages)) continue;
|
|
963
959
|
this.queue.enqueueMessageCheck(chatJid);
|
|
964
960
|
}
|
|
965
961
|
}
|
|
@@ -999,6 +995,7 @@ var PiClawServer = class {
|
|
|
999
995
|
folder: MAIN_GROUP_FOLDER,
|
|
1000
996
|
trigger: `@${ASSISTANT_NAME}`,
|
|
1001
997
|
requiresTrigger: false,
|
|
998
|
+
thinkingLevel: "medium",
|
|
1002
999
|
added_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1003
1000
|
};
|
|
1004
1001
|
this.setRegisteredGroup(defaultJid, group, {
|
|
@@ -1011,7 +1008,8 @@ var PiClawServer = class {
|
|
|
1011
1008
|
/**
|
|
1012
1009
|
* Shared PiClawServer singleton — imported by route handlers.
|
|
1013
1010
|
*/
|
|
1014
|
-
const startTime =
|
|
1011
|
+
const startTime = globalThis.__piclaw_start_time__ || performance.now();
|
|
1015
1012
|
const server = new PiClawServer();
|
|
1016
1013
|
await server.start();
|
|
1017
|
-
|
|
1014
|
+
var server_default = () => {};
|
|
1015
|
+
export { server_default as n, startTime as r, server as t };
|