diff --git a/AgentCompany-New/src/main/services/agent-read-messages.ts b/AgentCompany-New/src/main/services/agent-read-messages.ts new file mode 100644 index 00000000..9814a21e --- /dev/null +++ b/AgentCompany-New/src/main/services/agent-read-messages.ts @@ -0,0 +1,45 @@ +import type { AgentToolContext, AgentToolDeps } from "./agent-tools"; +import type { JsonRecord } from "./provider-http"; + +export function readMessagesTool(deps: AgentToolDeps, ctx: AgentToolContext, args: JsonRecord): string { + const channel = optionalString(args.channel); + const limit = Math.min(Math.max(Number(args.limit) || 10, 1), 30); + if (channel) { + const space = deps.db.prepare( + "select id from chat_spaces where org_id = ? and lower(name) = lower(?) and space_type <> 'direct' limit 1", + ).get(ctx.orgId, channel) as { id: string } | undefined; + if (!space) throw new Error(`No channel named "${channel}".`); + const rows = deps.db.prepare(` + select m.body_md, + coalesce(a.name, e.display_name, m.sender_type) as sender_name, + m.thread_id + from chat_messages m + left join agents a on a.id = m.sender_id and m.sender_type = 'agent' + left join employees e on e.id = m.sender_id and m.sender_type = 'employee' + where m.space_id = ? and m.org_id = ? and m.deleted_at is null + order by m.created_at desc + limit ? + `).all(space.id, ctx.orgId, limit) as Array<{ body_md: string; sender_name: string; thread_id: string }>; + if (rows.length === 0) return `No recent messages in #${channel}.`; + return rows.reverse().map((m) => `[${m.sender_name}] (thread=${m.thread_id}): ${m.body_md}`).join("\n"); + } + const rows = deps.db.prepare(` + select m.body_md, + coalesce(a.name, e.display_name, m.sender_type) as sender_name, + m.thread_id, s.name as channel_name + from chat_mentions cm + join chat_messages m on m.id = cm.message_id + join chat_spaces s on s.id = m.space_id + left join agents a on a.id = m.sender_id and m.sender_type = 'agent' + left join employees e on e.id = m.sender_id and m.sender_type = 'employee' + where cm.target_type = 'agent' and cm.target_id = ? and m.org_id = ? and m.deleted_at is null + order by m.created_at desc + limit ? + `).all(ctx.agent.id, ctx.orgId, limit) as Array<{ body_md: string; sender_name: string; thread_id: string; channel_name: string }>; + if (rows.length === 0) return "No recent mentions."; + return rows.reverse().map((m) => `[${m.sender_name} in #${m.channel_name}] (thread=${m.thread_id}): ${m.body_md}`).join("\n"); +} + +function optionalString(value: unknown): string | null { + return typeof value === "string" && value.trim() ? value.trim() : null; +} diff --git a/AgentCompany-New/src/main/services/agent-tools.ts b/AgentCompany-New/src/main/services/agent-tools.ts index 2f6d084a..83bb2b2a 100644 --- a/AgentCompany-New/src/main/services/agent-tools.ts +++ b/AgentCompany-New/src/main/services/agent-tools.ts @@ -7,6 +7,7 @@ import { writeDeliverable } from "./deliverable-writer"; import { DocumentService } from "./document-service"; import { recordWorkspaceFile } from "./files/file-object-store"; import { canonicalMentionHandle } from "../../shared/mention-handles"; +import { readMessagesTool } from "./agent-read-messages"; import type { JsonRecord } from "./provider-http"; import type { ToolCall, ToolDefinition } from "./provider-tool-turn"; @@ -349,45 +350,6 @@ function joinNames(names: string[]): string { return `${names.slice(0, -1).join(", ")}, and ${names[names.length - 1]}`; } -function readMessagesTool(deps: AgentToolDeps, ctx: AgentToolContext, args: JsonRecord): string { - const channel = optionalString(args.channel); - const limit = Math.min(Math.max(Number(args.limit) || 10, 1), 30); - if (channel) { - const space = deps.db.prepare( - "select id from chat_spaces where org_id = ? and lower(name) = lower(?) and space_type <> 'direct' limit 1", - ).get(ctx.orgId, channel) as { id: string } | undefined; - if (!space) throw new Error(`No channel named "${channel}".`); - const rows = deps.db.prepare(` - select m.body_md, - coalesce(a.name, e.display_name, m.sender_type) as sender_name, - m.thread_id - from chat_messages m - left join agents a on a.id = m.sender_id and m.sender_type = 'agent' - left join employees e on e.id = m.sender_id and m.sender_type = 'employee' - where m.space_id = ? and m.org_id = ? and m.deleted_at is null - order by m.created_at desc - limit ? - `).all(space.id, ctx.orgId, limit) as Array<{ body_md: string; sender_name: string; thread_id: string }>; - if (rows.length === 0) return `No recent messages in #${channel}.`; - return rows.reverse().map((m) => `[${m.sender_name}] (thread=${m.thread_id}): ${m.body_md}`).join("\n"); - } - const rows = deps.db.prepare(` - select m.body_md, - coalesce(a.name, e.display_name, m.sender_type) as sender_name, - m.thread_id, s.name as channel_name - from chat_mentions cm - join chat_messages m on m.id = cm.message_id - join chat_spaces s on s.id = m.space_id - left join agents a on a.id = m.sender_id and m.sender_type = 'agent' - left join employees e on e.id = m.sender_id and m.sender_type = 'employee' - where cm.target_type = 'agent' and cm.target_id = ? and m.org_id = ? and m.deleted_at is null - order by m.created_at desc - limit ? - `).all(ctx.agent.id, ctx.orgId, limit) as Array<{ body_md: string; sender_name: string; thread_id: string; channel_name: string }>; - if (rows.length === 0) return "No recent mentions."; - return rows.reverse().map((m) => `[${m.sender_name} in #${m.channel_name}] (thread=${m.thread_id}): ${m.body_md}`).join("\n"); -} - function createDocumentTool(deps: AgentToolDeps, ctx: AgentToolContext, args: JsonRecord): string { const title = requireString(args.title, "title"); const docType = requireString(args.doc_type, "doc_type");