Skip to content

Commit 7405428

Browse files
committed
chore: refine slack reactions and status
1 parent 717a081 commit 7405428

File tree

5 files changed

+62
-31
lines changed

5 files changed

+62
-31
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ode",
3-
"version": "0.0.12",
3+
"version": "0.0.13",
44
"description": "Ode - OpenCode chat controller for Slack",
55
"module": "packages/core/index.ts",
66
"type": "module",

packages/agents/shared.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ export function buildSlackSystemPrompt(slack?: SlackContext): string {
4242
lines.push("- Payload: {\"action\":\"post_message\",\"channelId\":\"...\",\"threadId\":\"...\",\"messageId\":\"...\",\"text\":\"...\"}");
4343
}
4444
lines.push("- Supported actions: post_message, add_reaction, get_thread_messages, ask_user, get_user_info, upload_file.");
45-
lines.push("- Required fields: channelId; threadId for thread actions; messageId for reactions; userId for get_user_info.");
45+
lines.push("- Required fields: channelId; threadId for thread actions; messageId + emoji for reactions; userId for get_user_info.");
46+
lines.push("- add_reaction schema: { action: \"add_reaction\", channelId: string, messageId: string, emoji: \"thumbsup\" | \"eyes\" | \"ok_hand\" }");
4647
lines.push("- You can use any tool available via bash, curl");
4748
lines.push("");
4849
lines.push("IMPORTANT: Your text output is automatically posted to Slack.");

packages/ims/slack/api.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,24 @@ function requireString(value: unknown, label: string): string {
3939
return value;
4040
}
4141

42+
const ALLOWED_REACTIONS = new Set(["thumbsup", "eyes", "ok_hand"]);
43+
const REACTION_ALIASES: Record<string, string> = {
44+
thumbup: "thumbsup",
45+
ok: "ok_hand",
46+
};
47+
4248
function normalizeEmojiName(emoji: string): string {
4349
const trimmed = emoji.trim();
4450
if (!trimmed) {
4551
throw new Error("emoji is required");
4652
}
4753
const stripped = trimmed.replace(/^:+|:+$/g, "").replace(/:/g, "");
48-
return stripped || trimmed;
54+
const normalized = stripped || trimmed;
55+
const alias = REACTION_ALIASES[normalized] ?? normalized;
56+
if (!ALLOWED_REACTIONS.has(alias)) {
57+
throw new Error("emoji must be one of: thumbsup, eyes, ok_hand");
58+
}
59+
return alias;
4960
}
5061

5162
function normalizeOptionLabel(option: unknown): string {

packages/ims/slack/client.ts

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@ import { markdownToSlack, splitForSlack, truncateForSlack } from "./formatter";
1919
import {
2020
markThreadActive,
2121
isThreadActive,
22-
getChannelSettings,
2322
getOpenCodeSession,
24-
setOpenCodeSession,
2523
getGitHubAuthRecordForUser,
2624
getGitHubUserConfigDir,
2725
getPendingRestartMessages,
@@ -145,6 +143,26 @@ function getOdeSlackApiUrl(): string | undefined {
145143
return getSlackActionApiUrl();
146144
}
147145

146+
async function buildSlackContext(
147+
cwd: string,
148+
channelId: string,
149+
threadId: string,
150+
userId: string,
151+
threadHistory?: string | null
152+
): Promise<OpenCodeMessageContext> {
153+
return {
154+
threadHistory: threadHistory || undefined,
155+
slack: {
156+
channelId,
157+
threadId,
158+
userId,
159+
threadHistory: threadHistory || undefined,
160+
hasCustomSlackTool: await hasOdeSlackTool(cwd),
161+
odeSlackApiUrl: getOdeSlackApiUrl(),
162+
},
163+
};
164+
}
165+
148166
function buildGitEnvironmentForUser(userId: string): Record<string, string> {
149167
const env: Record<string, string> = {};
150168
const authRecord = getGitHubAuthRecordForUser(userId);
@@ -668,6 +686,13 @@ function buildToolDetails(tool: SessionMessageState["tools"][number], workingPat
668686
return title ? trimToolPath(title, workingPath) : "";
669687
}
670688

689+
const TOOL_DETAIL_LIMIT = 30;
690+
691+
function truncateToolDetail(detail: string): string {
692+
if (detail.length <= TOOL_DETAIL_LIMIT) return detail;
693+
return `${detail.slice(0, TOOL_DETAIL_LIMIT)}...`;
694+
}
695+
671696
function buildToolLines(state: SessionMessageState, workingPath: string): string[] {
672697
const tools = state.tools || [];
673698
if (tools.length === 0) return [];
@@ -680,7 +705,8 @@ function buildToolLines(state: SessionMessageState, workingPath: string): string
680705
const lines = [header];
681706
for (const tool of items) {
682707
const details = buildToolDetails(tool, workingPath);
683-
const suffix = details ? ` — ${details}` : "";
708+
const truncated = details ? truncateToolDetail(details) : "";
709+
const suffix = truncated ? ` — ${truncated}` : "";
684710
lines.push(`${getToolIcon(tool.status)} ${tool.name}${suffix}`);
685711
}
686712

@@ -1410,17 +1436,13 @@ async function handleUserMessageInternal(
14101436
? await fetchThreadHistory(client, channelId, threadId, messageId)
14111437
: null;
14121438

1413-
const messageContext: OpenCodeMessageContext = {
1414-
threadHistory: threadHistory || undefined,
1415-
slack: {
1416-
channelId,
1417-
threadId,
1418-
userId: threadOwnerUserId,
1419-
threadHistory: threadHistory || undefined,
1420-
hasCustomSlackTool: await hasOdeSlackTool(cwd),
1421-
odeSlackApiUrl: getOdeSlackApiUrl(),
1422-
},
1423-
};
1439+
const messageContext = await buildSlackContext(
1440+
cwd,
1441+
channelId,
1442+
threadId,
1443+
threadOwnerUserId,
1444+
threadHistory
1445+
);
14241446

14251447
const onTodosUpdated = async (todos: TrackedTodo[]) => {
14261448
await upsertPlanMessage(session, channelId, threadId, todos);
@@ -1721,15 +1743,12 @@ export async function handleButtonSelection(
17211743

17221744
try {
17231745
// Build context - the selection is the user's response
1724-
const messageContext = {
1725-
slack: {
1726-
channelId,
1727-
threadId,
1728-
userId: threadOwnerUserId,
1729-
hasCustomSlackTool: await hasOdeSlackTool(cwd),
1730-
odeSlackApiUrl: getOdeSlackApiUrl(),
1731-
},
1732-
};
1746+
const messageContext = await buildSlackContext(
1747+
cwd,
1748+
channelId,
1749+
threadId,
1750+
threadOwnerUserId
1751+
);
17331752

17341753
// Send to OpenCode - the selection as the user's message
17351754
const responses = await sendOpenCodeMessage(
@@ -1896,9 +1915,6 @@ export function setupMessageHandlers(): void {
18961915
return;
18971916
}
18981917
}
1899-
if (!localMode) {
1900-
}
1901-
19021918
if (localMode && !channelServerUrl) {
19031919
await say({
19041920
text: "OpenCode server URL missing for this channel. Set it in ~/.config/ode/ode.json.",

packages/utils/session-inspector.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,11 @@ export function buildSessionMessageState(
7777

7878
if (type === "session.updated") {
7979
const title = eventData?.properties?.info?.title;
80-
if (typeof title === "string" && title.trim()) {
81-
state.sessionTitle = title.trim();
80+
if (typeof title === "string") {
81+
const trimmedTitle = title.trim();
82+
if (trimmedTitle && !trimmedTitle.startsWith("New session")) {
83+
state.sessionTitle = trimmedTitle;
84+
}
8285
}
8386
}
8487

0 commit comments

Comments
 (0)