Give agents hands: workspace read/list/exec tools so engineers build instead of describing
Every "engineering" deliverable the company ever produced was a markdown skeleton, because documentation was the ceiling of the toolset: write_deliverable and create_document were the only artifact tools. An engineer could not see the files that exist, read a line of code, or run a single command — and create_task hardcoded requires_filesystem to false, so the entire approval-gated read_write mount plumbing was dead code. New workspace capability (agent-workspace-tools.ts): - list_files / read_file: explore the bound workspace, traversal-guarded by the same resolveWorkspacePath used for writes, size- and count-capped. - run_command: real shell execution with the workspace as cwd, 120s timeout, 16k output cap. Gated on the task's approved filesystem grant — the same requires_filesystem flag that flips the mount to read_write and routes the task through operator approval (auto-approved only in AI-CEO mode, which is that mode's explicit contract). - create_task now takes requires_filesystem, so the CEO and officers can delegate engineering work that is allowed to change code and run tests. - Prompts brief every agent on the tools, and filesystem tasks state the bar directly: real output is code that builds and tests that pass — a document describing the work does not close an engineering task. Tests: tool registry, dependency-folder-skipping listing, traversal refusal, the run_command access gate plus exit-code reporting, and the create_task approval path for filesystem work.
This commit is contained in:
1 parent
9c85b5ee3c
commit
291816aa06
8 files changed
+285
-8
No files matched your search
@@ -1,5 +1,6 @@
|
||||
import type { ProviderService } from "./provider-service";
|
||||
import { AGENT_TOOLS, dispatchAgentTool, type AgentToolContext, type AgentToolDeps } from "./agent-tools";
|
||||
import { executeWorkspaceTool, isWorkspaceTool, WORKSPACE_TOOLS } from "./agent-workspace-tools";
|
||||
import { canonicalMentionHandle } from "../../shared/mention-handles";
|
||||
import type { AgentTurnMessage, ToolDefinition } from "./provider-tool-turn";
|
||||
import { isComposioTool, executeComposioTool } from "./composio/composio-tool-bridge";
|
||||
@@ -37,7 +38,7 @@ export interface AgentRunLoopDeps {
|
||||
* iteration cap is hit (which throws rather than silently truncating).
|
||||
*/
|
||||
export async function runAgentLoop(deps: AgentRunLoopDeps, input: AgentRunLoopInput): Promise<AgentRunLoopResult> {
|
||||
const allTools = input.externalTools ? [...AGENT_TOOLS, ...input.externalTools] : AGENT_TOOLS;
|
||||
const allTools = [...AGENT_TOOLS, ...WORKSPACE_TOOLS, ...(input.externalTools ?? [])];
|
||||
const messages: AgentTurnMessage[] = [{ role: "user", text: input.initialUserTurn }];
|
||||
let toolCallCount = 0;
|
||||
let lastRequestId = "";
|
||||
@@ -70,6 +71,8 @@ export async function runAgentLoop(deps: AgentRunLoopDeps, input: AgentRunLoopIn
|
||||
let output: string;
|
||||
if (isComposioTool(call.name)) {
|
||||
output = await executeComposioTool(deps.tools.db, input.orgId, input.toolContext.agent.id, call);
|
||||
} else if (isWorkspaceTool(call.name)) {
|
||||
output = await executeWorkspaceTool(input.toolContext, call);
|
||||
} else {
|
||||
output = dispatchAgentTool(deps.tools, input.toolContext, call, {
|
||||
announceTaskAssignments: shouldAnnounceTaskAssignment(call, turn.toolCalls),
|
||||
|
||||
Reference in new issue
Block a user