Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 20 additions & 10 deletions packages/codingcode/src/agent/agent.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Effect } from 'effect';
import { z } from 'zod';
import { appendFileSync } from 'fs';

Check warning on line 3 in packages/codingcode/src/agent/agent.ts

View workflow job for this annotation

GitHub Actions / lint

'appendFileSync' is defined but never used. Allowed unused vars must match /^_/u
import type { Message, ToolCall } from '../core/types.js';
import { AgentError } from '../core/error.js';
import { Result } from '../core/result.js';
Expand All @@ -20,7 +20,8 @@
import { McpService } from '../mcp/index.js';
import { loadMemoryForPrompt, flushSessionToMemory } from '../memory/index.js';
import { createLogger } from '@codingcode/infra';
import type { AgentProfile } from '../subagent/registry';

Check warning on line 23 in packages/codingcode/src/agent/agent.ts

View workflow job for this annotation

GitHub Actions / lint

'AgentProfile' is defined but never used. Allowed unused vars must match /^_/u
import { resolveSubagentEnabled, resolveAgentDisabled } from '../subagent/registry.js';
import type { ToolVisibilityPolicy } from '../tools/types';
import { ProjectRuntimeService } from '../runtime/project-runtime';
import { createDispatchAgentTool } from '../tools/domains/subagent/dispatch.js';
Expand Down Expand Up @@ -71,26 +72,29 @@

// Apply main agent profile: model override, maxSteps, readonly, hooks, MCP
let activeLlm = llm;
if (profile.model) {
if (profile?.model) {
const entry = findModel(profile.model);
if (entry) {
const clientResult = yield* Effect.promise(() => createClient(entry));
if (clientResult.ok) activeLlm = clientResult.value;
}
}
const effectiveMaxSteps = profile.maxSteps;
const effectiveApproval: any = profile.readonly
const effectiveMaxSteps = profile?.maxSteps;
const effectiveApproval: any = profile?.readonly
? { permissionMode: 'bypass' }
: options?.approvalOverride;

if (profile.hooks?.length) {
if (profile?.hooks?.length) {
yield* hooks.attachSessionHooks(sid, profile.hooks);
}

if (profile.mcpServers?.length) {
if (profile?.mcpServers?.length) {
yield* mcp.connectServers(normalizedCwd, sid, profile.mcpServers);
}

// Get MCP tools for injection into ReAct loop
const mcpTools = mcp.listProjectMcpTools(normalizedCwd);

const turnId = session.incrementTurn(state);
const [matchedSkill, actualInput] = yield* skill.extractSkill(state.cwd, input);

Expand All @@ -106,6 +110,7 @@
maxStepsOverride: effectiveMaxSteps,
approvalOverride: effectiveApproval,
dispatchTool,
mcpTools,
skillInstruction: matchedSkill?.instruction,
abortSignal: options?.signal,
});
Expand Down Expand Up @@ -174,6 +179,7 @@
coreAllowlist?: ReadonlySet<string>;
toolPolicy?: ToolVisibilityPolicy;
dispatchTool?: ToolDefinition;
mcpTools?: ToolDefinition[];
abortSignal?: AbortSignal;
parentSessionId?: string;
agentName?: string;
Expand Down Expand Up @@ -239,8 +245,11 @@
const sessionId = state.sessionId;
const projectPath = state.cwd;

// Build system prompt
const agentProfiles = deps.runtime.listAgentProfiles(projectPath);
// Build system prompt — filter agent profiles by global switch and per-agent disabled state
const allAgentProfiles = deps.runtime.listAgentProfiles(projectPath);
const agentProfiles = resolveSubagentEnabled(projectPath)
? allAgentProfiles.filter((p) => !resolveAgentDisabled(projectPath, p.name))
: [];
const basePrompt =
opts.systemOverride ??
buildSystemPrompt({
Expand Down Expand Up @@ -308,9 +317,10 @@
return Result.err(new AgentError('AGENT_ABORTED', 'cancelled'));
}

// Build tools from static builtin + dispatch
let allToolDefs: ToolDefinition[] = [...STATIC_BUILTIN_TOOLS];
if (opts.dispatchTool) allToolDefs = [...allToolDefs, opts.dispatchTool];
// Build tools from static builtin + MCP + dispatch
let allToolDefs: ToolDefinition[] = [...STATIC_BUILTIN_TOOLS, ...(opts.mcpTools ?? [])];
if (opts.dispatchTool && resolveSubagentEnabled(projectPath))
allToolDefs = [...allToolDefs, opts.dispatchTool];

// Apply policy filter (derived from AgentProfile.tools via getToolPolicy)
const allowedByPolicy = opts.toolPolicy?.allowedTools;
Expand Down
15 changes: 9 additions & 6 deletions packages/codingcode/src/agent/prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,15 @@ export function buildSystemPrompt(opts: SystemPromptOptions): string {
}

if (opts.agentProfiles && opts.agentProfiles.length > 0) {
prompt += '\n\n## Available Subagents\n';
prompt += `You can dispatch subagents using the dispatch_agent tool. Available profiles:\n`;
for (const p of opts.agentProfiles) {
prompt += `\n### ${p.name}\n${p.description}`;
if (p.tools && p.tools.length > 0) {
prompt += `\nTools: ${p.tools.join(', ')}`;
const enabledProfiles = opts.agentProfiles.filter((p) => !p.disabled);
if (enabledProfiles.length > 0) {
prompt += '\n\n## Available Subagents\n';
prompt += `You can dispatch subagents using the dispatch_agent tool. Available profiles:\n`;
for (const p of enabledProfiles) {
prompt += `\n### ${p.name}\n${p.description}`;
if (p.tools && p.tools.length > 0) {
prompt += `\nTools: ${p.tools.join(', ')}`;
}
}
}
}
Expand Down
42 changes: 29 additions & 13 deletions packages/codingcode/src/client/direct.ts
Original file line number Diff line number Diff line change
Expand Up @@ -396,23 +396,27 @@ export async function createDirectClient(llm: any): Promise<AgentClient> {
},

async getSubagentEnabled() {
return clients.settings.getSubagentEnabled();
return clients.settings.getSubagentEnabled({ cwd: cwd() });
},

async setSubagentEnabled(enabled: boolean) {
await clients.settings.setSubagentEnabled(enabled);
async setSubagentEnabled(body: { enabled: boolean; cwd: string }) {
await clients.settings.setSubagentEnabled(body);
},

async resetSubagentEnabled(body: { cwd: string }) {
await clients.settings.resetSubagentEnabled(body);
},

async getMcpStatus() {
return clients.settings.getMcpStatus();
},

async disableMcp(name: string) {
await clients.settings.setMcpDisabled(name, true);
async setMcpDisabled(body: { name: string; disabled: boolean; cwd: string }) {
await clients.settings.setMcpDisabled(body);
},

async enableMcp(name: string) {
await clients.settings.setMcpDisabled(name, false);
async resetMcpDisabled(body: { name: string; cwd: string }) {
await clients.settings.resetMcpDisabled(body);
},

async createMcpServer(server: any): Promise<void> {
Expand All @@ -431,8 +435,8 @@ export async function createDirectClient(llm: any): Promise<AgentClient> {
return clients.settings.listSkills();
},

async toggleSkill(name: string, enabled: boolean) {
await clients.settings.toggleSkill(name, enabled);
async toggleSkill(body: { name: string; enabled: boolean; cwd: string }) {
await clients.settings.toggleSkill(body);
},

async listAgents() {
Expand All @@ -451,16 +455,28 @@ export async function createDirectClient(llm: any): Promise<AgentClient> {
await clients.settings.deleteAgent({ cwd: cwd(), name });
},

async setAgentDisabled(name: string, disabled: boolean): Promise<void> {
await clients.settings.setAgentDisabled(name, disabled);
async setAgentDisabled(body: { name: string; disabled: boolean; cwd: string }): Promise<void> {
await clients.settings.setAgentDisabled(body);
},

async resetAgentDisabled(body: { name: string; cwd: string }): Promise<void> {
await clients.settings.resetAgentDisabled(body);
},

async listHooks() {
return clients.settings.listHooks({ cwd: cwd() });
},

async setHookDisabled(name: string, disabled: boolean): Promise<void> {
await clients.settings.setHookDisabled({ cwd: cwd(), name, disabled });
async setHookDisabled(body: { name: string; disabled: boolean; cwd: string }): Promise<void> {
await clients.settings.setHookDisabled({
cwd: cwd(),
name: body.name,
disabled: body.disabled,
});
},

async resetHookDisabled(body: { name: string; cwd: string }): Promise<void> {
await clients.settings.resetHookDisabled(body);
},

async createHook(hook: any): Promise<void> {
Expand Down
Loading
Loading