@lucashca/claudecontrol 0.3.29 → 0.3.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/backend/agents/canUseTool.ts +1 -1
- package/backend/agents/lifecycle.ts +7 -6
- package/backend/routes/agents.ts +1 -0
- package/backend/types.ts +1 -0
- package/frontend/src/components/ChatPanel.tsx +17 -1
- package/frontend/src/types/index.ts +1 -0
- package/package.json +1 -1
- package/version.json +1 -1
|
@@ -43,7 +43,7 @@ export function createBypassCanUseTool(agentId: string, workspaceId: string) {
|
|
|
43
43
|
* Creates canUseTool for default (secure) mode.
|
|
44
44
|
* Shows permission prompt in the frontend and waits for user response.
|
|
45
45
|
*/
|
|
46
|
-
export function createCanUseTool(agentId: string, workspaceId: string) {
|
|
46
|
+
export function createCanUseTool(agentId: string, workspaceId: string, isOrchestrator = false) {
|
|
47
47
|
return (toolName: string, input: Record<string, unknown>, options: CanUseToolOptions) => {
|
|
48
48
|
const requestId = genId();
|
|
49
49
|
const session = agents.get(agentId);
|
|
@@ -252,12 +252,12 @@ export async function sendToAgent(id: string, message: string, attachments?: Att
|
|
|
252
252
|
}
|
|
253
253
|
broadcast({ type: 'agent_working', agentId: id, workspaceId: session.workspaceId, task: displayText });
|
|
254
254
|
|
|
255
|
+
// Only the orchestrator role gets native subagent tools; specialists just execute tasks
|
|
256
|
+
const isOrchestrator = session.isOrchestrator === true || session.role === getOrchestratorRole(session.workspaceId);
|
|
257
|
+
|
|
255
258
|
const permissionOpts = session.bypass
|
|
256
259
|
? { permissionMode: 'bypassPermissions' as const, allowDangerouslySkipPermissions: true, canUseTool: createBypassCanUseTool(id, session.workspaceId) }
|
|
257
|
-
: { permissionMode: 'default' as const, canUseTool: createCanUseTool(id, session.workspaceId) };
|
|
258
|
-
|
|
259
|
-
// Only the orchestrator role gets native subagent tools; specialists just execute tasks
|
|
260
|
-
const isOrchestrator = session.role === getOrchestratorRole(session.workspaceId);
|
|
260
|
+
: { permissionMode: 'default' as const, canUseTool: createCanUseTool(id, session.workspaceId, isOrchestrator) };
|
|
261
261
|
const subagents = (isOrchestrator && runtime.enableSubagents) ? buildSubagents(cwd, session.role) : {};
|
|
262
262
|
const hasAttachments = attachments && attachments.length > 0;
|
|
263
263
|
|
|
@@ -368,8 +368,9 @@ export async function runAgentQuery(session: AgentSession, task: string, bypass
|
|
|
368
368
|
const isOrchestrator = session.isOrchestrator === true || session.role === getOrchestratorRole(session.workspaceId);
|
|
369
369
|
const subagents = (isOrchestrator && runtime.enableSubagents) ? buildSubagents(cwd, session.role) : {};
|
|
370
370
|
const poolContext = (!runtime.enableSubagents && isOrchestrator) ? buildPoolContext(session.workspaceId, session.id) : '';
|
|
371
|
+
const specialistCtx = !isOrchestrator && !session.canSpawnSubagents ? '[INSTRUCAO] Voce e um especialista. Execute suas tarefas diretamente usando suas proprias ferramentas. Nao use o Agent tool nem inicie subagentes.' : '';
|
|
371
372
|
// poolContext first so the model sees the delegation rules before the role instructions
|
|
372
|
-
const systemAppend = [poolContext, customContext, context].filter(Boolean).join('\n\n');
|
|
373
|
+
const systemAppend = [poolContext, specialistCtx, customContext, context].filter(Boolean).join('\n\n');
|
|
373
374
|
const prompt = task;
|
|
374
375
|
|
|
375
376
|
const abortController = new AbortController();
|
|
@@ -389,7 +390,7 @@ export async function runAgentQuery(session: AgentSession, task: string, bypass
|
|
|
389
390
|
stderr: (text: string) => console.error(`[agent:${session.id}]`, text),
|
|
390
391
|
...(bypass
|
|
391
392
|
? { permissionMode: 'bypassPermissions' as const, allowDangerouslySkipPermissions: true, canUseTool: createBypassCanUseTool(session.id, session.workspaceId) }
|
|
392
|
-
: { permissionMode: 'default' as const, canUseTool: createCanUseTool(session.id, session.workspaceId) }),
|
|
393
|
+
: { permissionMode: 'default' as const, canUseTool: createCanUseTool(session.id, session.workspaceId, isOrchestrator) }),
|
|
393
394
|
};
|
|
394
395
|
|
|
395
396
|
try {
|
package/backend/routes/agents.ts
CHANGED
|
@@ -75,6 +75,7 @@ export async function handleAgentRoutes(
|
|
|
75
75
|
const body = await parseBody(req);
|
|
76
76
|
if (body.customName !== undefined) agent.customName = body.customName as string;
|
|
77
77
|
if (body.isOrchestrator !== undefined) agent.isOrchestrator = body.isOrchestrator as boolean;
|
|
78
|
+
if (body.canSpawnSubagents !== undefined) agent.canSpawnSubagents = body.canSpawnSubagents as boolean;
|
|
78
79
|
persistAgents();
|
|
79
80
|
broadcast({ type: 'agent_updated', agentId: agent.id, workspaceId: agent.workspaceId, agent });
|
|
80
81
|
json(res, agent);
|
package/backend/types.ts
CHANGED
|
@@ -92,4 +92,5 @@ export interface AgentSession {
|
|
|
92
92
|
lastContextTokens?: number; // cache_read_input_tokens from last turn = current context size
|
|
93
93
|
model?: string; // per-agent model override
|
|
94
94
|
isOrchestrator?: boolean; // only orchestrators can delegate to other agents
|
|
95
|
+
canSpawnSubagents?: boolean; // allows using Agent tool even for non-orchestrators
|
|
95
96
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { LucideIcon } from 'lucide-react';
|
|
2
|
-
import { Blocks, Code2, TestTube2, Cloud, Database, Layout, ChevronRight, Loader2, GitBranch, Square } from 'lucide-react';
|
|
2
|
+
import { Blocks, Code2, TestTube2, Cloud, Database, Layout, ChevronRight, Loader2, GitBranch, Square, Network } from 'lucide-react';
|
|
3
3
|
import { useAtomValue } from 'jotai';
|
|
4
4
|
import { useState } from 'react';
|
|
5
5
|
import { agentsMapAtom } from '@/atoms';
|
|
@@ -59,6 +59,10 @@ export function ChatPanel({ agentId, compact }: { agentId: string; compact?: boo
|
|
|
59
59
|
api.patchAgent(agentId, { isOrchestrator: !agent!.isOrchestrator }).catch(() => {});
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
function handleToggleSubagents() {
|
|
63
|
+
api.patchAgent(agentId, { canSpawnSubagents: !agent!.canSpawnSubagents }).catch(() => {});
|
|
64
|
+
}
|
|
65
|
+
|
|
62
66
|
return (
|
|
63
67
|
<div className="flex flex-1 flex-col min-w-0 min-h-0 h-full overflow-hidden bg-cc-panel">
|
|
64
68
|
{/* Header */}
|
|
@@ -79,6 +83,18 @@ export function ChatPanel({ agentId, compact }: { agentId: string; compact?: boo
|
|
|
79
83
|
</div>
|
|
80
84
|
</div>
|
|
81
85
|
<div className="flex items-center gap-2">
|
|
86
|
+
<Tooltip text={agent.canSpawnSubagents ? 'Subagentes ativados' : 'Ativar subagentes'} position="bottom">
|
|
87
|
+
<button
|
|
88
|
+
onClick={handleToggleSubagents}
|
|
89
|
+
className={`inline-flex items-center justify-center w-6 h-6 rounded-md border-none cursor-pointer transition-colors ${
|
|
90
|
+
agent.canSpawnSubagents
|
|
91
|
+
? 'text-cc-info bg-cc-info/15 hover:bg-cc-info/25'
|
|
92
|
+
: 'text-cc-muted hover:text-cc-text-secondary hover:bg-cc-surface'
|
|
93
|
+
}`}
|
|
94
|
+
>
|
|
95
|
+
<Network size={12} />
|
|
96
|
+
</button>
|
|
97
|
+
</Tooltip>
|
|
82
98
|
<Tooltip text={agent.isOrchestrator ? 'Orquestrador — pode delegar' : 'Marcar como orquestrador'} position="bottom">
|
|
83
99
|
<button
|
|
84
100
|
onClick={handleToggleOrchestrator}
|
package/package.json
CHANGED
package/version.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"0.3.
|
|
1
|
+
{"version":"0.3.31","build":"2026-04-04T00:03:24.295Z"}
|