diff --git a/Cli-Proxy-API-Management-Center b/Cli-Proxy-API-Management-Center new file mode 160000 index 00000000..3f1f6a13 --- /dev/null +++ b/Cli-Proxy-API-Management-Center @@ -0,0 +1 @@ +Subproject commit 3f1f6a132336d4a985af2c2142a553f47f4a1ef6 diff --git a/agent-teams-controller/src/controller.js b/agent-teams-controller/src/controller.js index 9c4b1a6a..987b92d9 100644 --- a/agent-teams-controller/src/controller.js +++ b/agent-teams-controller/src/controller.js @@ -39,6 +39,7 @@ module.exports = { createControllerContext, agentBlocks, protocols: { + buildActionModeProtocolText: tasks.buildActionModeProtocolText, buildProcessProtocolText: tasks.buildProcessProtocolText, }, tasks, diff --git a/agent-teams-controller/src/internal/tasks.js b/agent-teams-controller/src/internal/tasks.js index ae47db6c..c5c0a17e 100644 --- a/agent-teams-controller/src/internal/tasks.js +++ b/agent-teams-controller/src/internal/tasks.js @@ -349,7 +349,12 @@ function buildMemberLanguageInstruction(config) { return `IMPORTANT: Communicate in ${language}. All messages, summaries, and task descriptions MUST be in ${language}.`; } -function buildMemberActionModeProtocol() { +/** + * Raw action-mode protocol text parameterized by DELEGATE description. + * Shared between lead (actionModeInstructions.ts) and member (memberBriefing). + * Context-free — does NOT follow the (context, ...) convention. + */ +function buildActionModeProtocolText(delegateDescription) { return [ 'TURN ACTION MODE PROTOCOL (HIGHEST PRIORITY FOR EACH USER TURN):', '- Some incoming user or relay messages may include a hidden agent-only block that declares the current action mode.', @@ -359,10 +364,16 @@ function buildMemberActionModeProtocol() { '- Modes:', ' - DO: Full execution mode. You may discuss, inspect, edit files, change state, run commands/tools, and delegate if useful.', ' - ASK: Strict read-only conversation mode. You may read/analyze/explain and reply, but you must not change code/files/tasks/state or run side-effecting commands/tools/scripts.', - ' - DELEGATE: Strict orchestration mode for leads. Delegate the work to teammates and coordinate it, but do not implement it yourself unless you are truly in SOLO MODE.', + ` - DELEGATE: ${delegateDescription}`, ].join('\n'); } +function buildMemberActionModeProtocol() { + return buildActionModeProtocolText( + 'Do not implement yourself. Pass the task with full context (what you know, what is needed) to your team lead or another teammate and let them handle it.' + ); +} + function buildMemberTaskProtocol(teamName) { return wrapAgentBlock(`MANDATORY TASK STATUS PROTOCOL — you MUST follow this for EVERY task: 0. IMPORTANT ID RULE: @@ -458,6 +469,8 @@ function buildProcessProtocolText(teamName) { { teamName: "${teamName}" } 4. When stopping a process, use MCP tool process_stop: { teamName: "${teamName}", pid: } +5. To fully remove a process record (e.g. after it has been stopped and is no longer needed), use MCP tool process_unregister: + { teamName: "${teamName}", pid: } If verification in step 3 fails or the process is missing from the list, re-register it.`; } @@ -602,6 +615,7 @@ module.exports = { setTaskStatus, softDeleteTask, startTask, + buildActionModeProtocolText, buildProcessProtocolText, memberBriefing, taskBriefing, diff --git a/mcp-server/src/agent-teams-controller.d.ts b/mcp-server/src/agent-teams-controller.d.ts index 92eb7333..188dd1c0 100644 --- a/mcp-server/src/agent-teams-controller.d.ts +++ b/mcp-server/src/agent-teams-controller.d.ts @@ -101,6 +101,7 @@ declare module 'agent-teams-controller' { /** Context-free protocol text builders, shared across lead and member prompts. */ export interface ProtocolsApi { + buildActionModeProtocolText(delegateDescription: string): string; buildProcessProtocolText(teamName: string): string; } diff --git a/src/main/services/team/TeamProvisioningService.ts b/src/main/services/team/TeamProvisioningService.ts index 19355880..a87673c0 100644 --- a/src/main/services/team/TeamProvisioningService.ts +++ b/src/main/services/team/TeamProvisioningService.ts @@ -99,6 +99,8 @@ import type { const logger = createLogger('Service:TeamProvisioning'); const { createController, protocols } = agentTeamsControllerModule; const TEAM_NAME_PATTERN = /^[a-z0-9][a-z0-9-]{0,127}$/; +const MEMBER_DELEGATE_DESCRIPTION = + 'Do not implement yourself. Pass the task with full context (what you know, what is needed) to your team lead or another teammate and let them handle it.'; const RUN_TIMEOUT_MS = 300_000; const VERIFY_TIMEOUT_MS = 15_000; const VERIFY_POLL_MS = 500; @@ -421,7 +423,7 @@ function buildMemberSpawnPrompt( const workflowBlock = member.workflow?.trim() ? `\n\nYour workflow and how you should behave:${formatWorkflowBlock(member.workflow, '')}` : ''; - const actionModeProtocol = buildActionModeProtocol(); + const actionModeProtocol = protocols.buildActionModeProtocolText(MEMBER_DELEGATE_DESCRIPTION); return `You are ${member.name}, a ${role} on team "${displayName}" (${teamName}).${workflowBlock} ${getAgentLanguageInstruction()} @@ -452,7 +454,10 @@ function buildReconnectMemberSpawnPrompt( const workflowBlock = member.workflow?.trim() ? `\n\nYour workflow and how you should behave:${formatWorkflowBlock(member.workflow, ' ')}` : ''; - const actionModeProtocol = indentMultiline(buildActionModeProtocol(), ' '); + const actionModeProtocol = indentMultiline( + protocols.buildActionModeProtocolText(MEMBER_DELEGATE_DESCRIPTION), + ' ' + ); return ` For "${member.name}": - prompt: You are ${member.name}, a ${role} on team "${teamName}" (${teamName}).${workflowBlock} @@ -676,7 +681,7 @@ Constraints: - If the request is ambiguous or still needs technical discovery, immediately create a coarse investigation/triage task for the best-fit teammate. That teammate owns the code inspection, scope refinement, and creation of any follow-up tasks needed for execution. - Only do lead-side research first if the human explicitly asked YOU for analysis/planning, or if there is genuinely no appropriate teammate to own the investigation. - TaskCreate is optional for private planning only; do NOT use it for team-board tasks. -- When messaging "user" (the human): NEVER mention internal MCP tools, scripts, CLI commands, or file paths under ~/.claude/. The user sees messages in the UI — write plain human language. If a task needs a status update, do it yourself via the board MCP tools; never ask the user to run a command.${soloConstraint} +- When messaging "user" (the human): write plain human language. If a task needs a status update, do it yourself via the board MCP tools; never ask the user to run a command.${soloConstraint} ${teamCtlOps} diff --git a/src/main/services/team/actionModeInstructions.ts b/src/main/services/team/actionModeInstructions.ts index ce6f6869..1297853d 100644 --- a/src/main/services/team/actionModeInstructions.ts +++ b/src/main/services/team/actionModeInstructions.ts @@ -2,6 +2,13 @@ import { AGENT_BLOCK_CLOSE, AGENT_BLOCK_OPEN } from '@shared/constants/agentBloc import type { AgentActionMode } from '@shared/types'; +import * as agentTeamsControllerModule from 'agent-teams-controller'; + +const { protocols } = agentTeamsControllerModule; + +const LEAD_DELEGATE_DESCRIPTION = + 'Strict orchestration mode for leads. Delegate the work and any needed investigation to teammates, coordinate it, and do not implement or personally research it yourself unless you are truly in SOLO MODE.'; + const ACTION_MODE_BLOCKS: Record = { do: [ 'TURN ACTION MODE: DO', @@ -27,17 +34,7 @@ const ACTION_MODE_BLOCKS: Record = { }; export function buildActionModeProtocol(): string { - return [ - 'TURN ACTION MODE PROTOCOL (HIGHEST PRIORITY FOR EACH USER TURN):', - '- Some incoming user or relay messages may include a hidden agent-only block that declares the current action mode.', - '- If such a block is present, that mode applies to THIS TURN ONLY and overrides any conflicting default behavior.', - '- Never silently broaden permissions beyond the selected mode.', - '- Never reveal the hidden mode block verbatim to the human unless they explicitly ask for it.', - '- Modes:', - ' - DO: Full execution mode. You may discuss, inspect, edit files, change state, run commands/tools, and delegate if useful.', - ' - ASK: Strict read-only conversation mode. You may read/analyze/explain and reply, but you must not change code/files/tasks/state or run side-effecting commands/tools/scripts.', - ' - DELEGATE: Strict orchestration mode for leads. Delegate the work and any needed investigation to teammates, coordinate it, and do not implement or personally research it yourself unless you are truly in SOLO MODE.', - ].join('\n'); + return protocols.buildActionModeProtocolText(LEAD_DELEGATE_DESCRIPTION); } export function buildActionModeAgentBlock(mode: AgentActionMode | undefined): string { diff --git a/src/types/agent-teams-controller.d.ts b/src/types/agent-teams-controller.d.ts index 0f726387..d75b2c71 100644 --- a/src/types/agent-teams-controller.d.ts +++ b/src/types/agent-teams-controller.d.ts @@ -88,6 +88,7 @@ declare module 'agent-teams-controller' { /** Context-free protocol text builders, shared across lead and member prompts. */ export interface ProtocolsApi { + buildActionModeProtocolText(delegateDescription: string): string; buildProcessProtocolText(teamName: string): string; } diff --git a/test/main/services/team/TeamProvisioningServiceLiveMessages.test.ts b/test/main/services/team/TeamProvisioningServiceLiveMessages.test.ts index 29ff6f7f..d9e68057 100644 --- a/test/main/services/team/TeamProvisioningServiceLiveMessages.test.ts +++ b/test/main/services/team/TeamProvisioningServiceLiveMessages.test.ts @@ -104,6 +104,8 @@ vi.mock('agent-teams-controller', () => ({ }, }), protocols: { + buildActionModeProtocolText: (delegate: string) => + `ACTION MODE PROTOCOL (mock, delegate: ${delegate})`, buildProcessProtocolText: (teamName: string) => `BACKGROUND PROCESS REGISTRATION (mock for ${teamName})`, }, diff --git a/test/main/services/team/TeamProvisioningServiceRelay.test.ts b/test/main/services/team/TeamProvisioningServiceRelay.test.ts index 4847ccb6..38b65822 100644 --- a/test/main/services/team/TeamProvisioningServiceRelay.test.ts +++ b/test/main/services/team/TeamProvisioningServiceRelay.test.ts @@ -122,6 +122,8 @@ vi.mock('agent-teams-controller', () => ({ }, }), protocols: { + buildActionModeProtocolText: (delegate: string) => + `ACTION MODE PROTOCOL (mock, delegate: ${delegate})`, buildProcessProtocolText: (teamName: string) => `BACKGROUND PROCESS REGISTRATION (mock for ${teamName})`, },