feat: enhance CoordinatorConfig with toolPreset and disallowedTools options

This commit is contained in:
MrAvalonApple 2026-04-08 12:34:25 +03:00
parent 30369b0597
commit 0b57ffe3e9
3 changed files with 37 additions and 2 deletions

View File

@ -885,7 +885,9 @@ export class OpenMultiAgent {
maxTurns: coordinatorOverrides?.maxTurns ?? 3, maxTurns: coordinatorOverrides?.maxTurns ?? 3,
maxTokens: coordinatorOverrides?.maxTokens, maxTokens: coordinatorOverrides?.maxTokens,
temperature: coordinatorOverrides?.temperature, temperature: coordinatorOverrides?.temperature,
toolPreset: coordinatorOverrides?.toolPreset,
tools: coordinatorOverrides?.tools, tools: coordinatorOverrides?.tools,
disallowedTools: coordinatorOverrides?.disallowedTools,
loopDetection: coordinatorOverrides?.loopDetection, loopDetection: coordinatorOverrides?.loopDetection,
timeoutMs: coordinatorOverrides?.timeoutMs, timeoutMs: coordinatorOverrides?.timeoutMs,
} }

View File

@ -449,8 +449,12 @@ export interface CoordinatorConfig {
readonly maxTurns?: number readonly maxTurns?: number
readonly maxTokens?: number readonly maxTokens?: number
readonly temperature?: number readonly temperature?: number
/** Predefined tool preset for common coordinator use cases. */
readonly toolPreset?: 'readonly' | 'readwrite' | 'full'
/** Tool names available to the coordinator. */ /** Tool names available to the coordinator. */
readonly tools?: readonly string[] readonly tools?: readonly string[]
/** Tool names explicitly denied to the coordinator. */
readonly disallowedTools?: readonly string[]
readonly loopDetection?: LoopDetectionConfig readonly loopDetection?: LoopDetectionConfig
readonly timeoutMs?: number readonly timeoutMs?: number
} }

View File

@ -323,7 +323,7 @@ describe('OpenMultiAgent', () => {
expect(coordinatorPrompt).not.toContain('You are a task coordinator responsible') expect(coordinatorPrompt).not.toContain('You are a task coordinator responsible')
}) })
it('applies advanced coordinator options (maxTokens, temperature, tools)', async () => { it('applies advanced coordinator options (maxTokens, temperature, tools, disallowedTools)', async () => {
mockAdapterResponses = [ mockAdapterResponses = [
'```json\n[{"title": "Inspect", "description": "Inspect", "assignee": "worker-a"}]\n```', '```json\n[{"title": "Inspect", "description": "Inspect", "assignee": "worker-a"}]\n```',
'worker output', 'worker output',
@ -343,7 +343,8 @@ describe('OpenMultiAgent', () => {
maxTurns: 5, maxTurns: 5,
maxTokens: 1234, maxTokens: 1234,
temperature: 0, temperature: 0,
tools: ['file_read'], tools: ['file_read', 'grep'],
disallowedTools: ['grep'],
timeoutMs: 1500, timeoutMs: 1500,
loopDetection: { maxRepetitions: 2, loopDetectionWindow: 3 }, loopDetection: { maxRepetitions: 2, loopDetectionWindow: 3 },
}, },
@ -353,6 +354,34 @@ describe('OpenMultiAgent', () => {
expect(capturedChatOptions[0]?.temperature).toBe(0) expect(capturedChatOptions[0]?.temperature).toBe(0)
expect(capturedChatOptions[0]?.tools).toBeDefined() expect(capturedChatOptions[0]?.tools).toBeDefined()
expect(capturedChatOptions[0]?.tools?.map((t) => t.name)).toContain('file_read') expect(capturedChatOptions[0]?.tools?.map((t) => t.name)).toContain('file_read')
expect(capturedChatOptions[0]?.tools?.map((t) => t.name)).not.toContain('grep')
})
it('supports coordinator.toolPreset and intersects with tools allowlist', async () => {
mockAdapterResponses = [
'```json\n[{"title": "Inspect", "description": "Inspect", "assignee": "worker-a"}]\n```',
'worker output',
'final synthesis',
]
const oma = new OpenMultiAgent({
defaultModel: 'mock-model',
defaultProvider: 'openai',
})
const team = oma.createTeam('t', teamCfg([
{ ...agentConfig('worker-a'), model: 'worker-model' },
]))
await oma.runTeam(team, 'First inspect project, then produce output', {
coordinator: {
toolPreset: 'readonly',
tools: ['file_read', 'bash'],
},
})
const coordinatorToolNames = capturedChatOptions[0]?.tools?.map((t) => t.name) ?? []
expect(coordinatorToolNames).toContain('file_read')
expect(coordinatorToolNames).not.toContain('bash')
}) })
}) })