Add create_document tool to agent runtime

Agents can now create versioned company documents (PRD, spec, memo,
report, runbook, proposal, policy, guide) via the create_document tool.
Documents are persisted in the documents table and visible in the
Documents page.
This commit is contained in:
ZacharyZhang-NY committed 2026-06-07 17:51:12 -04:00
1 parent d50f0d8d1f
commit 7a36a12d08
2 files changed
+37 -1

No files matched your search

@@ -3,6 +3,7 @@ import { RISK_LEVEL, TASK_PRIORITY, TASK_STATUS, type RiskLevel } from "../../sh
import type { OrganizationService } from "./organization-service";
import type { ChatService } from "./chat-service";
import { writeDeliverable } from "./deliverable-writer";
import { DocumentService } from "./document-service";
import { recordWorkspaceFile } from "./files/file-object-store";
import type { JsonRecord } from "./provider-http";
import type { ToolCall, ToolDefinition } from "./provider-tool-turn";
@@ -103,6 +104,20 @@ export const AGENT_TOOLS: ToolDefinition[] = [
required: ["channel", "body"],
},
},
{
name: "create_document",
description: "Create a company document (PRD, spec, memo, report, runbook, proposal, policy, guide). Use this for structured deliverables that the company should keep versioned.",
parameters: {
type: "object",
additionalProperties: false,
properties: {
title: { type: "string" },
doc_type: { type: "string", enum: ["prd", "spec", "memo", "report", "runbook", "proposal", "policy", "guide"] },
content: { type: "string", description: "Full document content in markdown." },
},
required: ["title", "doc_type", "content"],
},
},
];
export function dispatchAgentTool(deps: AgentToolDeps, ctx: AgentToolContext, call: ToolCall): string {
@@ -118,6 +133,8 @@ export function dispatchAgentTool(deps: AgentToolDeps, ctx: AgentToolContext, ca
return writeDeliverableTool(deps, ctx, call.arguments);
case "send_message":
return sendMessageTool(deps, ctx, call.arguments);
case "create_document":
return createDocumentTool(deps, ctx, call.arguments);
default:
return `ERROR: unknown tool "${call.name}".`;
}
@@ -215,6 +232,25 @@ function sendMessageTool(deps: AgentToolDeps, ctx: AgentToolContext, args: JsonR
return `Posted to #${channel} (message_id=${messageId}, thread_id=${row.thread_id}).`;
}
function createDocumentTool(deps: AgentToolDeps, ctx: AgentToolContext, args: JsonRecord): string {
const title = requireString(args.title, "title");
const docType = requireString(args.doc_type, "doc_type");
const content = requireString(args.content, "content");
const documentService = new DocumentService(deps.db);
const docId = documentService.create({
orgId: ctx.orgId,
title,
docType,
content,
authorAgentId: ctx.agent.id,
reviewerAgentId: null,
projectId: ctx.taskProjectId,
goalId: ctx.taskGoalId,
taskId: null,
});
return `Created document "${title}" (doc_id=${docId}, type=${docType}, chars=${content.length}).`;
}
function resolveAgentByName(db: DatabaseSync, orgId: string, name: string): string | null {
const row = db.prepare("select id from agents where org_id = ? and lower(name) = lower(?) and lifecycle = 'active' limit 1")
.get(orgId, name.trim()) as { id: string } | undefined;
@@ -514,7 +514,7 @@ export class TaskExecutionService {
function buildAgentInstructions(agent: TaskExecutionAgentRow): string {
return [
`You are ${agent.name}, ${agent.title || agent.role} (${agent.department}, ${agent.role_level}) operating an autonomous AI company.`,
"You act by calling tools: hire_agent staffs your team, create_task delegates work and assigns it by agent name, update_task_status tracks progress, write_deliverable produces real files in the company workspace, and send_message posts coordination messages to a channel with optional file attachments.",
"You act by calling tools: hire_agent staffs your team, create_task delegates work and assigns it by agent name, update_task_status tracks progress, write_deliverable produces real files in the company workspace, create_document produces versioned company documents (PRDs, specs, memos, reports), and send_message posts coordination messages to a channel with optional file attachments.",
"Communicate like a real team. Post to the channel that matches the work — 'engineering' for engineering, 'product' for product or design, otherwise 'general'. Use @mentions when addressing a teammate. When you hand work or files to a teammate, use send_message with /handoff @Name and attachment_file_ids containing the file_id returned by write_deliverable. To keep a hand-off as one conversation, reply in the same thread by passing the thread_id a previous send_message returned.",
"Take concrete action with the tools and reserve narrative for brief summaries after coordination is posted.",
].join("\n");