Add bots files handling logic

This commit is contained in:
2026-10-21 17:56:09 +01:00
parent b0af4db1bf
commit d17a4a7bdd
97 changed files with 5843 additions and 41 deletions
+1
View File
@@ -196,6 +196,7 @@ export default async function processBotJob({
result: outcome.result,
needs_you: outcome.needs_you,
silent: outcome.silent,
attachments: outcome.attachments,
});
await pushBotNotice({ bot_id, ...completion });
+20 -2
View File
@@ -2,6 +2,7 @@ import type { BUN_SQLITE_COBBLE_BOTS } from "@/db/types/db";
import { AppData } from "@/src/data/app-data";
import {
ActionCheckNote,
BotFilesNote,
ChatReplyNote,
CoordinatorReplyNote,
CoordinatorSoloNote,
@@ -12,6 +13,7 @@ import grabBotPrompt from "@/src/functions/backend/db/bots/grab-bot-prompt";
import grabBotComputers from "@/src/functions/backend/db/computers/grab-bot-computers";
import runTextLoop from "@/src/harness/text/run-text-loop";
import grabBotChatTools from "@/src/harness/tools/bot/grab-bot-chat-tools";
import grabBotFileTools from "@/src/harness/tools/storage/grab-bot-file-tools";
import openBotExtensions from "@/src/harness/tools/extensions/open-bot-extensions";
import botMessagesToHarness from "./bot-messages-to-harness";
import composeComputersNote from "./compose-computers-note";
@@ -76,6 +78,18 @@ export default async function runBotReply({
}).catch(() => "");
const take_overs: string[] = [];
/**
* Files the bot wrote and asked to send with its reply.
*/
const attachments: number[] = [];
const file_tools = await grabBotFileTools({
bot,
user_id,
workspace_id,
session_id,
onAttach: ({ media_id }) => attachments.push(media_id),
});
const tools = await grabBotChatTools({
bot,
@@ -111,6 +125,7 @@ export default async function runBotReply({
prompt,
carry_over,
ChatReplyNote,
BotFilesNote,
ActionCheckNote,
workspace_id ? WorkspaceLearningNote : "",
composeComputersNote({
@@ -132,7 +147,7 @@ export default async function runBotReply({
user_id,
}),
}),
tools: [...tools, ...extensions.tools],
tools: [...tools, ...file_tools, ...extensions.tools],
max_steps: AppData.BotReplyMaxToolSteps,
bot_id: bot.id,
workspace_id,
@@ -140,7 +155,10 @@ export default async function runBotReply({
onStep: report,
});
return withTakeOverRefs({ text: result.text, refs: take_overs });
return {
...withTakeOverRefs({ text: result.text, refs: take_overs }),
attachments: attachments.length ? attachments : undefined,
};
} finally {
await extensions.close();
}
+27 -5
View File
@@ -1,5 +1,11 @@
import type { BUN_SQLITE_COBBLE_BOTS } from "@/db/types/db";
import { ActionCheckNote, ScheduledRunNote, TaskRunNote, WorkspaceLearningNote } from "@/src/data/harness-prompts";
import {
ActionCheckNote,
BotFilesNote,
ScheduledRunNote,
TaskRunNote,
WorkspaceLearningNote,
} from "@/src/data/harness-prompts";
import grabBotComputers from "@/src/functions/backend/db/computers/grab-bot-computers";
import grabBotPrompt from "@/src/functions/backend/db/bots/grab-bot-prompt";
import grabUserWorkspaces from "@/src/functions/backend/db/workspaces/grab-user-workspaces";
@@ -11,6 +17,7 @@ import createWorkspaceTool from "@/src/harness/tools/bot/create-workspace-tool";
import updateWorkspaceTool from "@/src/harness/tools/bot/update-workspace-tool";
import askToTakeOverTool from "@/src/harness/tools/computer/ask-to-take-over-tool";
import searchComputersTool from "@/src/harness/tools/computer/search-computers-tool";
import grabBotFileTools from "@/src/harness/tools/storage/grab-bot-file-tools";
import reportRunFailedTool from "@/src/harness/tools/bot/report-run-failed-tool";
import computerRef from "@/src/utils/computer-ref";
import composeJobBrief from "./compose-job-brief";
@@ -81,6 +88,10 @@ export default async function runBotTask({
signal,
}).catch(() => "");
const take_overs: string[] = [];
/**
* Files the bot wrote and asked to send with its report.
*/
const attachments: number[] = [];
const scheduled = Boolean(params.schedule_id);
let failure = null as string | null;
@@ -120,6 +131,13 @@ export default async function runBotTask({
: []),
...(scheduled ? [reportRunFailedTool({ onFail: ({ reason }) => (failure = reason) })] : []),
...(computer?.tools || []),
...(await grabBotFileTools({
bot,
user_id,
workspace_id,
session_id,
onAttach: ({ media_id }) => attachments.push(media_id),
})),
];
extensions = await openBotExtensions({
@@ -136,6 +154,7 @@ export default async function runBotTask({
carry_over,
TaskRunNote,
scheduled ? ScheduledRunNote : "",
BotFilesNote,
ActionCheckNote,
workspace_id ? WorkspaceLearningNote : "",
bot.kind == "coordinator"
@@ -180,10 +199,13 @@ export default async function runBotTask({
throw new ScheduledRunFailedError(computer ? computer.redact(failure) : failure);
}
return withTakeOverRefs({
text: computer ? computer.redact(result.text) : result.text,
refs: take_overs,
});
return {
...withTakeOverRefs({
text: computer ? computer.redact(result.text) : result.text,
refs: take_overs,
}),
attachments: attachments.length ? attachments : undefined,
};
} finally {
await extensions?.close();
await computer?.close();
+5
View File
@@ -40,6 +40,11 @@ export type BotJobOutcome = {
* Finish without posting `result` (a reply with nothing left to answer).
*/
silent?: boolean;
/**
* Files the bot wrote and asked to send with its message (`media`
* ids), attached to the result message.
*/
attachments?: number[];
};
export type BotJobRunner = (context: BotJobContext) => Promise<BotJobOutcome>;