opencode-claw 0.2.1 → 0.2.2
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/channels/router.js +7 -1
- package/dist/channels/slack.js +9 -5
- package/dist/channels/split-message.d.ts +6 -0
- package/dist/channels/split-message.js +45 -0
- package/dist/channels/telegram.js +9 -3
- package/dist/channels/whatsapp.js +5 -1
- package/dist/memory/plugin.js +5 -4
- package/package.json +1 -1
package/dist/channels/router.js
CHANGED
|
@@ -105,6 +105,12 @@ async function handleCommand(cmd, msg, deps, activeStreams) {
|
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
|
+
/** Turn raw MCP tool names like `websearch_web_search_exa` into `Web Search Exa`. */
|
|
109
|
+
function humanizeToolName(raw) {
|
|
110
|
+
if (raw.includes(" "))
|
|
111
|
+
return raw;
|
|
112
|
+
return raw.replace(/[-_]+/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
113
|
+
}
|
|
108
114
|
async function routeMessage(msg, deps, activeStreams, pendingQuestions) {
|
|
109
115
|
const adapter = deps.adapters.get(msg.channel);
|
|
110
116
|
if (!adapter) {
|
|
@@ -175,7 +181,7 @@ async function routeMessage(msg, deps, activeStreams, pendingQuestions) {
|
|
|
175
181
|
const progress = progressEnabled
|
|
176
182
|
? {
|
|
177
183
|
onToolRunning: (_tool, title) => adapter.send(msg.peerId, {
|
|
178
|
-
text: `🔧 ${title}...`,
|
|
184
|
+
text: `🔧 ${humanizeToolName(title)}...`,
|
|
179
185
|
replyToId: msg.replyToId,
|
|
180
186
|
}),
|
|
181
187
|
onHeartbeat: async () => {
|
package/dist/channels/slack.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { App } from "@slack/bolt";
|
|
2
2
|
import { createReconnector } from "../utils/reconnect.js";
|
|
3
|
+
import { splitMessage } from "./split-message.js";
|
|
3
4
|
export function createSlackAdapter(config, logger) {
|
|
4
5
|
const app = new App({
|
|
5
6
|
token: config.botToken,
|
|
@@ -74,11 +75,14 @@ export function createSlackAdapter(config, logger) {
|
|
|
74
75
|
logger.info("slack: app stopped");
|
|
75
76
|
},
|
|
76
77
|
async send(peerId, message) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
const chunks = splitMessage(message.text, 40000);
|
|
79
|
+
for (const chunk of chunks) {
|
|
80
|
+
await app.client.chat.postMessage({
|
|
81
|
+
channel: peerId,
|
|
82
|
+
text: chunk,
|
|
83
|
+
thread_ts: message.threadId,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
82
86
|
},
|
|
83
87
|
async sendTyping(_peerId) {
|
|
84
88
|
// Slack has no general bot typing indicator API
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Split a message into chunks that fit within the given max length.
|
|
3
|
+
* Prefers splitting at double newlines (paragraphs), then single newlines,
|
|
4
|
+
* then spaces, and finally hard-cuts as a last resort.
|
|
5
|
+
*/
|
|
6
|
+
export declare function splitMessage(text: string, maxLength: number): string[];
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Split a message into chunks that fit within the given max length.
|
|
3
|
+
* Prefers splitting at double newlines (paragraphs), then single newlines,
|
|
4
|
+
* then spaces, and finally hard-cuts as a last resort.
|
|
5
|
+
*/
|
|
6
|
+
export function splitMessage(text, maxLength) {
|
|
7
|
+
if (text.length <= maxLength)
|
|
8
|
+
return [text];
|
|
9
|
+
const chunks = [];
|
|
10
|
+
let remaining = text;
|
|
11
|
+
while (remaining.length > 0) {
|
|
12
|
+
if (remaining.length <= maxLength) {
|
|
13
|
+
chunks.push(remaining);
|
|
14
|
+
break;
|
|
15
|
+
}
|
|
16
|
+
const slice = remaining.slice(0, maxLength);
|
|
17
|
+
let splitAt = -1;
|
|
18
|
+
// Try splitting at last double newline (paragraph boundary)
|
|
19
|
+
const doubleNewline = slice.lastIndexOf("\n\n");
|
|
20
|
+
if (doubleNewline > maxLength * 0.3) {
|
|
21
|
+
splitAt = doubleNewline;
|
|
22
|
+
}
|
|
23
|
+
// Try splitting at last single newline
|
|
24
|
+
if (splitAt === -1) {
|
|
25
|
+
const singleNewline = slice.lastIndexOf("\n");
|
|
26
|
+
if (singleNewline > maxLength * 0.3) {
|
|
27
|
+
splitAt = singleNewline;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// Try splitting at last space
|
|
31
|
+
if (splitAt === -1) {
|
|
32
|
+
const space = slice.lastIndexOf(" ");
|
|
33
|
+
if (space > maxLength * 0.3) {
|
|
34
|
+
splitAt = space;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// Hard cut as last resort
|
|
38
|
+
if (splitAt === -1) {
|
|
39
|
+
splitAt = maxLength;
|
|
40
|
+
}
|
|
41
|
+
chunks.push(remaining.slice(0, splitAt));
|
|
42
|
+
remaining = remaining.slice(splitAt).replace(/^[\s]+/, "");
|
|
43
|
+
}
|
|
44
|
+
return chunks;
|
|
45
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Bot } from "grammy";
|
|
2
2
|
import { createReconnector } from "../utils/reconnect.js";
|
|
3
|
+
import { splitMessage } from "./split-message.js";
|
|
3
4
|
export function createTelegramAdapter(config, logger) {
|
|
4
5
|
const bot = new Bot(config.botToken);
|
|
5
6
|
let state = "disconnected";
|
|
@@ -68,9 +69,14 @@ export function createTelegramAdapter(config, logger) {
|
|
|
68
69
|
logger.info("telegram: bot stopped");
|
|
69
70
|
},
|
|
70
71
|
async send(peerId, message) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
const chunks = splitMessage(message.text, 4096);
|
|
73
|
+
for (const chunk of chunks) {
|
|
74
|
+
await bot.api.sendMessage(Number(peerId), chunk, {
|
|
75
|
+
reply_parameters: message.replyToId
|
|
76
|
+
? { message_id: Number(message.replyToId) }
|
|
77
|
+
: undefined,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
74
80
|
},
|
|
75
81
|
async sendTyping(peerId) {
|
|
76
82
|
await bot.api.sendChatAction(Number(peerId), "typing");
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { DisconnectReason, makeWASocket, useMultiFileAuthState, } from "@whiskeysockets/baileys";
|
|
2
|
+
import { splitMessage } from "./split-message.js";
|
|
2
3
|
export function createWhatsAppAdapter(config, logger) {
|
|
3
4
|
let state = "disconnected";
|
|
4
5
|
let handler;
|
|
@@ -127,7 +128,10 @@ export function createWhatsAppAdapter(config, logger) {
|
|
|
127
128
|
if (!sock)
|
|
128
129
|
throw new Error("WhatsApp socket not connected");
|
|
129
130
|
const jid = `${peerId}@s.whatsapp.net`;
|
|
130
|
-
|
|
131
|
+
const chunks = splitMessage(message.text, 65536);
|
|
132
|
+
for (const chunk of chunks) {
|
|
133
|
+
await sock.sendMessage(jid, { text: chunk });
|
|
134
|
+
}
|
|
131
135
|
},
|
|
132
136
|
async sendTyping(peerId) {
|
|
133
137
|
if (!sock)
|
package/dist/memory/plugin.js
CHANGED
|
@@ -53,10 +53,11 @@ function createMemoryPlugin(backend) {
|
|
|
53
53
|
limit: 5,
|
|
54
54
|
minRelevance: 0.05,
|
|
55
55
|
});
|
|
56
|
-
if (memories.length
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
56
|
+
if (memories.length > 0) {
|
|
57
|
+
const block = memories.map((m) => `- [${m.category}] ${m.content}`).join("\n");
|
|
58
|
+
output.system.push(`\n\n## Relevant Context from Memory\n${block}`);
|
|
59
|
+
}
|
|
60
|
+
output.system.push(`\n\n## Memory Instructions\nYou have access to persistent long-term memory across sessions via two tools:\n- **memory_search**: Look up stored facts about projects, workflows, and past experiences.\n- **memory_store**: Save important information so it persists across sessions.\n\n**When to search memory:**\n- At the start of any task involving a project — search for its location, build commands, test steps, and relationships to other projects.\n- When you are unsure about a project's structure or conventions.\n\n**When to store memory (do this proactively):**\n- Project facts: absolute path on disk, repo URL, language/stack, key entry points.\n- Dev workflows: how to build, run, lint, and format the project.\n- Test procedures: how to run tests locally, what test framework is used, any setup required.\n- Dependencies and relationships: which projects depend on each other, shared libraries, APIs consumed.\n- Architecture decisions: patterns used, notable design choices, known pitfalls.\n- Use category \`project\` for project-specific facts, \`knowledge\` for workflows and procedures, \`experience\` for lessons learned.\n\nStore facts at the granularity of one clear, self-contained statement per call.`);
|
|
60
61
|
},
|
|
61
62
|
});
|
|
62
63
|
}
|