praxis-agent 0.35.0 → 0.37.0
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/README.md +20 -2
- package/dist/application/background-agent-manager.d.ts +16 -6
- package/dist/application/background-agent-manager.js +139 -97
- package/dist/application/context-engine.d.ts +56 -0
- package/dist/application/context-engine.js +129 -0
- package/dist/application/durable-follow-up.d.ts +14 -0
- package/dist/application/durable-follow-up.js +52 -0
- package/dist/application/native-session-transcript.d.ts +72 -0
- package/dist/application/native-session-transcript.js +351 -0
- package/dist/application/native-sidechain-transcript.d.ts +34 -0
- package/dist/application/native-sidechain-transcript.js +156 -0
- package/dist/application/session-service.d.ts +23 -4
- package/dist/application/session-service.js +1130 -494
- package/dist/application/subagent-service.d.ts +5 -1
- package/dist/application/subagent-service.js +749 -320
- package/dist/application/team-agent-runtime.d.ts +29 -0
- package/dist/application/team-agent-runtime.js +169 -0
- package/dist/application/team-capability.d.ts +27 -0
- package/dist/application/team-capability.js +41 -0
- package/dist/application/team-lead-operations.d.ts +38 -0
- package/dist/application/team-lead-operations.js +155 -0
- package/dist/application/team-mailbox.d.ts +54 -0
- package/dist/application/team-mailbox.js +196 -0
- package/dist/application/team-manager.d.ts +113 -0
- package/dist/application/team-manager.js +681 -0
- package/dist/application/team-workspace.d.ts +29 -0
- package/dist/application/team-workspace.js +197 -0
- package/dist/application/top-level-agent-manager.d.ts +1 -0
- package/dist/application/top-level-agent-manager.js +1025 -403
- package/dist/application/transcript-projection.d.ts +35 -0
- package/dist/application/transcript-projection.js +139 -0
- package/dist/application/turn-lifecycle.d.ts +2 -0
- package/dist/application/turn-memory-coordinator.d.ts +43 -0
- package/dist/application/turn-memory-coordinator.js +98 -0
- package/dist/cli/agents-dashboard.js +10 -5
- package/dist/cli/interactive.d.ts +7 -0
- package/dist/cli/interactive.js +645 -334
- package/dist/cli/tui/claude-style.d.ts +8 -25
- package/dist/cli/tui/claude-style.js +299 -277
- package/dist/cli/tui/decision-surface-model.d.ts +71 -0
- package/dist/cli/tui/decision-surface-model.js +131 -0
- package/dist/cli/tui/decision-surface.d.ts +7 -0
- package/dist/cli/tui/decision-surface.js +41 -0
- package/dist/cli/tui/help-surface-model.d.ts +68 -0
- package/dist/cli/tui/help-surface-model.js +131 -0
- package/dist/cli/tui/mcp-panel.js +1 -2
- package/dist/cli/tui/permission-surface-model.d.ts +195 -0
- package/dist/cli/tui/permission-surface-model.js +360 -0
- package/dist/cli/tui/permission-surface.d.ts +7 -0
- package/dist/cli/tui/permission-surface.js +69 -0
- package/dist/cli/tui/presentation-environment.d.ts +32 -0
- package/dist/cli/tui/presentation-environment.js +149 -0
- package/dist/cli/tui/task-panel.js +10 -1
- package/dist/cli/tui/theme.d.ts +46 -3
- package/dist/cli/tui/theme.js +414 -56
- package/dist/cli/tui/tool-permission.js +16 -8
- package/dist/cli/tui/transcript-presentation.d.ts +19 -1
- package/dist/cli/tui/transcript-presentation.js +26 -6
- package/dist/cli/tui/transcript-viewport.d.ts +18 -0
- package/dist/cli/tui/transcript-viewport.js +517 -111
- package/dist/cli/tui/transcript-window-model.d.ts +108 -0
- package/dist/cli/tui/transcript-window-model.js +772 -0
- package/dist/cli/tui/tui-interaction-router.d.ts +78 -0
- package/dist/cli/tui/tui-interaction-router.js +127 -0
- package/dist/cli/tui/tui-screen-model.d.ts +114 -0
- package/dist/cli/tui/tui-screen-model.js +210 -0
- package/dist/cli/tui/tui-view-model.d.ts +2 -49
- package/dist/cli/tui/tui-view-model.js +1 -68
- package/dist/cli-runtime.d.ts +4 -2
- package/dist/cli-runtime.js +397 -32
- package/dist/compatibility/claude/transcript-codec.js +6 -0
- package/dist/core/agent-orchestration.d.ts +31 -0
- package/dist/core/agent-orchestration.js +235 -0
- package/dist/core/permission-policy.d.ts +4 -0
- package/dist/core/permission-policy.js +21 -0
- package/dist/core/runtime.d.ts +6 -0
- package/dist/core/runtime.js +20 -2
- package/dist/core/team-mailbox.d.ts +54 -0
- package/dist/core/team-mailbox.js +212 -0
- package/dist/core/team-ownership.d.ts +84 -0
- package/dist/core/team-ownership.js +505 -0
- package/dist/core/tool-execution-scheduler.js +6 -1
- package/dist/core/transcript-event.d.ts +5 -1
- package/dist/core/transcript-event.js +12 -0
- package/dist/persistence/claude-job-store.d.ts +58 -0
- package/dist/persistence/claude-job-store.js +483 -1
- package/dist/persistence/claude-transcript-store.d.ts +2 -1
- package/dist/persistence/claude-transcript-store.js +2 -10
- package/dist/persistence/native-team-mailbox.d.ts +68 -0
- package/dist/persistence/native-team-mailbox.js +542 -0
- package/dist/persistence/native-team-store.d.ts +34 -0
- package/dist/persistence/native-team-store.js +257 -0
- package/dist/persistence/native-transcript-reader.d.ts +53 -0
- package/dist/persistence/native-transcript-reader.js +283 -0
- package/dist/persistence/native-transcript-store.d.ts +69 -0
- package/dist/persistence/native-transcript-store.js +321 -0
- package/dist/persistence/subagent-lifecycle-store.d.ts +41 -8
- package/dist/persistence/subagent-lifecycle-store.js +373 -146
- package/dist/persistence/transcript-file-append.d.ts +2 -0
- package/dist/persistence/transcript-file-append.js +10 -0
- package/dist/platform/exclusive-file-lease.d.ts +3 -0
- package/dist/platform/exclusive-file-lease.js +3 -0
- package/dist/tools/claude-capabilities.d.ts +4 -0
- package/dist/tools/claude-capabilities.js +18 -2
- package/dist/tools/team-lead-tools.d.ts +19 -0
- package/dist/tools/team-lead-tools.js +479 -0
- package/dist/tools/team-member-tools.d.ts +21 -0
- package/dist/tools/team-member-tools.js +259 -0
- package/package.json +1 -1
- package/dist/cli/tui/fullscreen-renderer.d.ts +0 -14
- package/dist/cli/tui/fullscreen-renderer.js +0 -13
|
@@ -25,6 +25,7 @@ export interface ClaudeToolCapabilityInput {
|
|
|
25
25
|
readonly agentTriggers?: boolean;
|
|
26
26
|
readonly backgroundAgents?: boolean;
|
|
27
27
|
readonly subagents?: boolean;
|
|
28
|
+
readonly teams?: boolean;
|
|
28
29
|
/** Explicit allow-list for capability-gated tools; never enables a gate. */
|
|
29
30
|
readonly tools?: readonly string[];
|
|
30
31
|
/** Always wins over the allow-list and the default rules. */
|
|
@@ -35,6 +36,7 @@ export interface ClaudeToolCapabilityInput {
|
|
|
35
36
|
export declare const CLAUDE_CODE_ENABLE_TASKS = "CLAUDE_CODE_ENABLE_TASKS";
|
|
36
37
|
export declare const CLAUDE_CODE_DISABLE_CRON = "CLAUDE_CODE_DISABLE_CRON";
|
|
37
38
|
export declare const PRAXIS_ENABLE_WORKFLOW_SCRIPTS = "PRAXIS_ENABLE_WORKFLOW_SCRIPTS";
|
|
39
|
+
export declare const PRAXIS_ENABLE_TEAMS = "PRAXIS_ENABLE_TEAMS";
|
|
38
40
|
/** task-v2 task-board tools, gated by the `tasks` capability. */
|
|
39
41
|
export declare const CLAUDE_TASK_V2_TOOLS: readonly ["TaskCreate", "TaskGet", "TaskList", "TaskUpdate"];
|
|
40
42
|
/** Workflow tool, gated by the `workflowScripts` capability. */
|
|
@@ -45,6 +47,8 @@ export declare const CLAUDE_AGENT_TRIGGER_TOOLS: readonly ["CronCreate", "CronDe
|
|
|
45
47
|
export declare const CLAUDE_AGENT_TOOLS: readonly ["Agent"];
|
|
46
48
|
/** Background task lifecycle tools, gated by the `backgroundAgents` capability. */
|
|
47
49
|
export declare const CLAUDE_BACKGROUND_TOOLS: readonly ["TaskOutput", "TaskStop"];
|
|
50
|
+
/** Experimental local Team lifecycle names, gated by `PRAXIS_ENABLE_TEAMS`. */
|
|
51
|
+
export declare const PRAXIS_TEAM_TOOLS: readonly ["TeamCreate", "TeamResume", "TeamList", "TeamAccept", "TeamStop", "TeamSend"];
|
|
48
52
|
/** Coordination tools advertised by a coordinator only when explicitly enabled. */
|
|
49
53
|
export declare const CLAUDE_COORDINATION_TOOLS: readonly ["AskUserQuestion", "SendMessage", "SendUserMessage", "Monitor", "PushNotification"];
|
|
50
54
|
/** Recursively suppressed for worker agents regardless of any allow-list. */
|
|
@@ -3,6 +3,7 @@ import { resolveToolSchedulingPolicy } from '../core/tool-scheduling-policy.js';
|
|
|
3
3
|
export const CLAUDE_CODE_ENABLE_TASKS = 'CLAUDE_CODE_ENABLE_TASKS';
|
|
4
4
|
export const CLAUDE_CODE_DISABLE_CRON = 'CLAUDE_CODE_DISABLE_CRON';
|
|
5
5
|
export const PRAXIS_ENABLE_WORKFLOW_SCRIPTS = 'PRAXIS_ENABLE_WORKFLOW_SCRIPTS';
|
|
6
|
+
export const PRAXIS_ENABLE_TEAMS = 'PRAXIS_ENABLE_TEAMS';
|
|
6
7
|
/** task-v2 task-board tools, gated by the `tasks` capability. */
|
|
7
8
|
export const CLAUDE_TASK_V2_TOOLS = [
|
|
8
9
|
'TaskCreate',
|
|
@@ -23,6 +24,15 @@ export const CLAUDE_AGENT_TRIGGER_TOOLS = [
|
|
|
23
24
|
export const CLAUDE_AGENT_TOOLS = ['Agent'];
|
|
24
25
|
/** Background task lifecycle tools, gated by the `backgroundAgents` capability. */
|
|
25
26
|
export const CLAUDE_BACKGROUND_TOOLS = ['TaskOutput', 'TaskStop'];
|
|
27
|
+
/** Experimental local Team lifecycle names, gated by `PRAXIS_ENABLE_TEAMS`. */
|
|
28
|
+
export const PRAXIS_TEAM_TOOLS = Object.freeze([
|
|
29
|
+
'TeamCreate',
|
|
30
|
+
'TeamResume',
|
|
31
|
+
'TeamList',
|
|
32
|
+
'TeamAccept',
|
|
33
|
+
'TeamStop',
|
|
34
|
+
'TeamSend',
|
|
35
|
+
]);
|
|
26
36
|
/** Coordination tools advertised by a coordinator only when explicitly enabled. */
|
|
27
37
|
export const CLAUDE_COORDINATION_TOOLS = [
|
|
28
38
|
'AskUserQuestion',
|
|
@@ -43,6 +53,7 @@ export const CLAUDE_CAPABILITY_GATED_TOOLS = new Set([
|
|
|
43
53
|
...CLAUDE_AGENT_TRIGGER_TOOLS,
|
|
44
54
|
...CLAUDE_AGENT_TOOLS,
|
|
45
55
|
...CLAUDE_BACKGROUND_TOOLS,
|
|
56
|
+
...PRAXIS_TEAM_TOOLS,
|
|
46
57
|
...CLAUDE_COORDINATION_TOOLS,
|
|
47
58
|
]);
|
|
48
59
|
const EMPTY_ENV = {};
|
|
@@ -91,6 +102,7 @@ export function resolveClaudeToolCapabilities(input) {
|
|
|
91
102
|
}
|
|
92
103
|
const backgroundAgents = input.backgroundAgents ?? false;
|
|
93
104
|
const subagents = input.subagents ?? false;
|
|
105
|
+
const teams = input.teams ?? envBoolean(env, PRAXIS_ENABLE_TEAMS) ?? false;
|
|
94
106
|
if (input.tools)
|
|
95
107
|
validateNames(input.tools, '--tools');
|
|
96
108
|
if (input.disallowedTools)
|
|
@@ -121,13 +133,17 @@ export function resolveClaudeToolCapabilities(input) {
|
|
|
121
133
|
for (const name of CLAUDE_BACKGROUND_TOOLS)
|
|
122
134
|
enabled.add(name);
|
|
123
135
|
}
|
|
136
|
+
if (teams) {
|
|
137
|
+
for (const name of PRAXIS_TEAM_TOOLS)
|
|
138
|
+
enabled.add(name);
|
|
139
|
+
}
|
|
124
140
|
if (input.role === 'worker') {
|
|
125
|
-
for (const name of CLAUDE_WORKER_RECURSIVE_TOOLS)
|
|
141
|
+
for (const name of [...CLAUDE_WORKER_RECURSIVE_TOOLS, ...PRAXIS_TEAM_TOOLS])
|
|
126
142
|
enabled.delete(name);
|
|
127
143
|
}
|
|
128
144
|
else if (input.role === 'coordinator') {
|
|
129
145
|
const explicit = new Set(input.tools ?? []);
|
|
130
|
-
for (const name of CLAUDE_COORDINATION_TOOLS) {
|
|
146
|
+
for (const name of [...CLAUDE_COORDINATION_TOOLS, ...PRAXIS_TEAM_TOOLS]) {
|
|
131
147
|
if (!explicit.has(name))
|
|
132
148
|
enabled.delete(name);
|
|
133
149
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ModelToolCall, ModelToolDefinition, ToolExecutionContext, ToolExecutionResult, ToolRegistry } from '../core/runtime.js';
|
|
2
|
+
import type { TeamLeadOperations } from '../application/team-lead-operations.js';
|
|
3
|
+
/** Tools a Coordinator Lead may use; all other base/MCP tools are denied. */
|
|
4
|
+
export declare const COORDINATOR_LEAD_ALLOWLIST: readonly ["Agent", "TaskOutput", "TaskStop", "TaskCreate", "TaskGet", "TaskList", "TaskUpdate", "AskUserQuestion", "EnterPlanMode", "ExitPlanMode", "SendMessage", "SendUserMessage", "Monitor", "PushNotification", "TeamCreate", "TeamResume", "TeamList", "TeamAccept", "TeamStop", "TeamSend"];
|
|
5
|
+
export declare class TeamLeadToolRegistry implements ToolRegistry {
|
|
6
|
+
private readonly base;
|
|
7
|
+
private readonly operations;
|
|
8
|
+
private readonly sessionId;
|
|
9
|
+
private readonly enabled;
|
|
10
|
+
constructor(base: ToolRegistry, operations: TeamLeadOperations, sessionId: string, toolNames: readonly string[]);
|
|
11
|
+
definitions(): readonly ModelToolDefinition[];
|
|
12
|
+
schedulingPolicy(call: ModelToolCall): import("../core/runtime.js").ToolSchedulingPolicy;
|
|
13
|
+
prepare(call: ModelToolCall, context: ToolExecutionContext): Promise<ModelToolCall>;
|
|
14
|
+
execute(call: ModelToolCall, context: ToolExecutionContext): Promise<ToolExecutionResult>;
|
|
15
|
+
private isAllowed;
|
|
16
|
+
private assertLeadPolicyAllows;
|
|
17
|
+
private result;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=team-lead-tools.d.ts.map
|
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
import { parseTeamMailboxPayload, } from '../core/team-mailbox.js';
|
|
2
|
+
import { parseTeamBudgetOverrides } from '../core/team-ownership.js';
|
|
3
|
+
const names = [
|
|
4
|
+
'TeamCreate',
|
|
5
|
+
'TeamResume',
|
|
6
|
+
'TeamList',
|
|
7
|
+
'TeamAccept',
|
|
8
|
+
'TeamStop',
|
|
9
|
+
'TeamSend',
|
|
10
|
+
];
|
|
11
|
+
/** Tools a Coordinator Lead may use; all other base/MCP tools are denied. */
|
|
12
|
+
export const COORDINATOR_LEAD_ALLOWLIST = Object.freeze([
|
|
13
|
+
'Agent',
|
|
14
|
+
'TaskOutput',
|
|
15
|
+
'TaskStop',
|
|
16
|
+
'TaskCreate',
|
|
17
|
+
'TaskGet',
|
|
18
|
+
'TaskList',
|
|
19
|
+
'TaskUpdate',
|
|
20
|
+
'AskUserQuestion',
|
|
21
|
+
'EnterPlanMode',
|
|
22
|
+
'ExitPlanMode',
|
|
23
|
+
'SendMessage',
|
|
24
|
+
'SendUserMessage',
|
|
25
|
+
'Monitor',
|
|
26
|
+
'PushNotification',
|
|
27
|
+
...names,
|
|
28
|
+
]);
|
|
29
|
+
const coordinatorAllowlist = new Set(COORDINATOR_LEAD_ALLOWLIST);
|
|
30
|
+
const teamPayloadSchema = {
|
|
31
|
+
oneOf: [
|
|
32
|
+
{
|
|
33
|
+
type: 'object',
|
|
34
|
+
additionalProperties: false,
|
|
35
|
+
required: ['kind', 'text'],
|
|
36
|
+
properties: {
|
|
37
|
+
kind: { const: 'text' },
|
|
38
|
+
text: { type: 'string', minLength: 1 },
|
|
39
|
+
summary: { type: 'string', minLength: 1 },
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
type: 'object',
|
|
44
|
+
additionalProperties: false,
|
|
45
|
+
required: ['kind', 'phase', 'requestId', 'taskId', 'text'],
|
|
46
|
+
properties: {
|
|
47
|
+
kind: { const: 'task' },
|
|
48
|
+
phase: { const: 'request' },
|
|
49
|
+
requestId: { type: 'string', minLength: 1 },
|
|
50
|
+
taskId: { type: 'string', minLength: 1 },
|
|
51
|
+
text: { type: 'string', minLength: 1 },
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
type: 'object',
|
|
56
|
+
additionalProperties: false,
|
|
57
|
+
required: ['kind', 'phase', 'requestId', 'taskId', 'status'],
|
|
58
|
+
properties: {
|
|
59
|
+
kind: { const: 'task' },
|
|
60
|
+
phase: { const: 'response' },
|
|
61
|
+
requestId: { type: 'string', minLength: 1 },
|
|
62
|
+
taskId: { type: 'string', minLength: 1 },
|
|
63
|
+
status: { enum: ['accepted', 'rejected', 'completed', 'failed'] },
|
|
64
|
+
text: { type: 'string', minLength: 1 },
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
type: 'object',
|
|
69
|
+
additionalProperties: false,
|
|
70
|
+
required: ['kind', 'phase', 'requestId'],
|
|
71
|
+
properties: {
|
|
72
|
+
kind: { const: 'shutdown' },
|
|
73
|
+
phase: { const: 'request' },
|
|
74
|
+
requestId: { type: 'string', minLength: 1 },
|
|
75
|
+
reason: { type: 'string', minLength: 1 },
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
type: 'object',
|
|
80
|
+
additionalProperties: false,
|
|
81
|
+
required: ['kind', 'phase', 'requestId', 'approved'],
|
|
82
|
+
properties: {
|
|
83
|
+
kind: { const: 'shutdown' },
|
|
84
|
+
phase: { const: 'response' },
|
|
85
|
+
requestId: { type: 'string', minLength: 1 },
|
|
86
|
+
approved: { type: 'boolean' },
|
|
87
|
+
reason: { type: 'string', minLength: 1 },
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
type: 'object',
|
|
92
|
+
additionalProperties: false,
|
|
93
|
+
required: ['kind', 'phase', 'requestId', 'plan'],
|
|
94
|
+
properties: {
|
|
95
|
+
kind: { const: 'plan' },
|
|
96
|
+
phase: { const: 'request' },
|
|
97
|
+
requestId: { type: 'string', minLength: 1 },
|
|
98
|
+
plan: { type: 'string', minLength: 1 },
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
type: 'object',
|
|
103
|
+
additionalProperties: false,
|
|
104
|
+
required: ['kind', 'phase', 'requestId', 'approved'],
|
|
105
|
+
properties: {
|
|
106
|
+
kind: { const: 'plan' },
|
|
107
|
+
phase: { const: 'response' },
|
|
108
|
+
requestId: { type: 'string', minLength: 1 },
|
|
109
|
+
approved: { type: 'boolean' },
|
|
110
|
+
feedback: { type: 'string', minLength: 1 },
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
};
|
|
115
|
+
const definitions = [
|
|
116
|
+
{
|
|
117
|
+
name: 'TeamCreate',
|
|
118
|
+
description: 'Create a local Team.',
|
|
119
|
+
inputSchema: {
|
|
120
|
+
type: 'object',
|
|
121
|
+
additionalProperties: false,
|
|
122
|
+
required: ['teamId', 'name', 'roster', 'tasks'],
|
|
123
|
+
properties: {
|
|
124
|
+
teamId: { type: 'string' },
|
|
125
|
+
name: { type: 'string' },
|
|
126
|
+
roster: {
|
|
127
|
+
type: 'array',
|
|
128
|
+
items: {
|
|
129
|
+
type: 'object',
|
|
130
|
+
additionalProperties: false,
|
|
131
|
+
required: ['name', 'agentType', 'access'],
|
|
132
|
+
properties: {
|
|
133
|
+
name: { type: 'string' },
|
|
134
|
+
agentType: { type: 'string' },
|
|
135
|
+
access: { enum: ['read-only', 'write'] },
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
tasks: {
|
|
140
|
+
type: 'array',
|
|
141
|
+
items: {
|
|
142
|
+
type: 'object',
|
|
143
|
+
additionalProperties: false,
|
|
144
|
+
required: ['id', 'description', 'assignee', 'blockedBy', 'claims'],
|
|
145
|
+
properties: {
|
|
146
|
+
id: { type: 'string' },
|
|
147
|
+
description: { type: 'string' },
|
|
148
|
+
assignee: { type: 'string' },
|
|
149
|
+
blockedBy: { type: 'array', items: { type: 'string' } },
|
|
150
|
+
claims: {
|
|
151
|
+
type: 'object',
|
|
152
|
+
additionalProperties: false,
|
|
153
|
+
required: [
|
|
154
|
+
'files',
|
|
155
|
+
'publicContracts',
|
|
156
|
+
'generatedArtifacts',
|
|
157
|
+
'migrations',
|
|
158
|
+
'mergeTargets',
|
|
159
|
+
],
|
|
160
|
+
properties: Object.fromEntries([
|
|
161
|
+
'files',
|
|
162
|
+
'publicContracts',
|
|
163
|
+
'generatedArtifacts',
|
|
164
|
+
'migrations',
|
|
165
|
+
'mergeTargets',
|
|
166
|
+
].map((key) => [
|
|
167
|
+
key,
|
|
168
|
+
{ type: 'array', items: { type: 'string' } },
|
|
169
|
+
])),
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
leadPolicy: { enum: ['hybrid', 'coordinator'] },
|
|
175
|
+
executionPolicy: { enum: ['sequential', 'swarm'] },
|
|
176
|
+
commitPolicy: { enum: ['lead'] },
|
|
177
|
+
budgets: {
|
|
178
|
+
type: 'object',
|
|
179
|
+
additionalProperties: false,
|
|
180
|
+
properties: {
|
|
181
|
+
maxAgents: { type: 'integer', minimum: 1 },
|
|
182
|
+
maxConcurrent: { type: 'integer', minimum: 1 },
|
|
183
|
+
maxTokens: { type: 'integer', minimum: 1 },
|
|
184
|
+
maxDurationMs: { type: 'integer', minimum: 1 },
|
|
185
|
+
shutdownDrainMs: { type: 'integer', minimum: 0, maximum: 600000 },
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
name: 'TeamResume',
|
|
193
|
+
description: 'Resume a local Team.',
|
|
194
|
+
inputSchema: {
|
|
195
|
+
type: 'object',
|
|
196
|
+
additionalProperties: false,
|
|
197
|
+
required: ['teamId'],
|
|
198
|
+
properties: { teamId: { type: 'string' } },
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
name: 'TeamList',
|
|
203
|
+
description: 'List local Teams.',
|
|
204
|
+
inputSchema: {
|
|
205
|
+
type: 'object',
|
|
206
|
+
additionalProperties: false,
|
|
207
|
+
properties: {},
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
name: 'TeamAccept',
|
|
212
|
+
description: 'Accept or reject a completed Team task.',
|
|
213
|
+
inputSchema: {
|
|
214
|
+
type: 'object',
|
|
215
|
+
additionalProperties: false,
|
|
216
|
+
required: ['teamId', 'taskId'],
|
|
217
|
+
properties: {
|
|
218
|
+
teamId: { type: 'string' },
|
|
219
|
+
taskId: { type: 'string' },
|
|
220
|
+
generation: { type: 'integer', minimum: 0 },
|
|
221
|
+
decision: { enum: ['accepted', 'rejected'], default: 'accepted' },
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
name: 'TeamStop',
|
|
227
|
+
description: 'Stop a local Team.',
|
|
228
|
+
inputSchema: {
|
|
229
|
+
type: 'object',
|
|
230
|
+
additionalProperties: false,
|
|
231
|
+
required: ['teamId'],
|
|
232
|
+
properties: {
|
|
233
|
+
teamId: { type: 'string' },
|
|
234
|
+
drainMs: { type: 'integer', minimum: 0, maximum: 600000 },
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
name: 'TeamSend',
|
|
240
|
+
description: 'Send a typed message through a local Team mailbox.',
|
|
241
|
+
inputSchema: {
|
|
242
|
+
type: 'object',
|
|
243
|
+
additionalProperties: false,
|
|
244
|
+
required: ['teamId', 'to', 'payload'],
|
|
245
|
+
properties: {
|
|
246
|
+
teamId: { type: 'string' },
|
|
247
|
+
to: {
|
|
248
|
+
anyOf: [
|
|
249
|
+
{ type: 'string' },
|
|
250
|
+
{ type: 'array', items: { type: 'string' }, minItems: 1 },
|
|
251
|
+
{ const: 'broadcast' },
|
|
252
|
+
],
|
|
253
|
+
},
|
|
254
|
+
payload: teamPayloadSchema,
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
];
|
|
259
|
+
function objectInput(input, allowed) {
|
|
260
|
+
if (!input || typeof input !== 'object' || Array.isArray(input))
|
|
261
|
+
throw new Error('Team tool input must be an object');
|
|
262
|
+
for (const key of Object.keys(input))
|
|
263
|
+
if (!allowed.includes(key))
|
|
264
|
+
throw new Error(`Unknown Team field: ${key}`);
|
|
265
|
+
}
|
|
266
|
+
function stringValue(input, key) {
|
|
267
|
+
const value = input[key];
|
|
268
|
+
if (typeof value !== 'string' || value.trim() === '')
|
|
269
|
+
throw new Error(`Invalid ${key}`);
|
|
270
|
+
return value;
|
|
271
|
+
}
|
|
272
|
+
function validate(input, name) {
|
|
273
|
+
if (name === 'TeamCreate') {
|
|
274
|
+
objectInput(input, [
|
|
275
|
+
'teamId',
|
|
276
|
+
'name',
|
|
277
|
+
'roster',
|
|
278
|
+
'tasks',
|
|
279
|
+
'leadPolicy',
|
|
280
|
+
'executionPolicy',
|
|
281
|
+
'commitPolicy',
|
|
282
|
+
'budgets',
|
|
283
|
+
]);
|
|
284
|
+
stringValue(input, 'teamId');
|
|
285
|
+
stringValue(input, 'name');
|
|
286
|
+
if (!Array.isArray(input.roster) || !Array.isArray(input.tasks))
|
|
287
|
+
throw new Error('Invalid Team roster or tasks');
|
|
288
|
+
if (input.leadPolicy !== undefined &&
|
|
289
|
+
input.leadPolicy !== 'hybrid' &&
|
|
290
|
+
input.leadPolicy !== 'coordinator')
|
|
291
|
+
throw new Error('Invalid leadPolicy');
|
|
292
|
+
if (input.executionPolicy !== undefined &&
|
|
293
|
+
input.executionPolicy !== 'sequential' &&
|
|
294
|
+
input.executionPolicy !== 'swarm')
|
|
295
|
+
throw new Error('Invalid executionPolicy');
|
|
296
|
+
if (input.commitPolicy !== undefined && input.commitPolicy !== 'lead')
|
|
297
|
+
throw new Error('Invalid commitPolicy');
|
|
298
|
+
if (input.budgets !== undefined) {
|
|
299
|
+
if (!input.budgets ||
|
|
300
|
+
typeof input.budgets !== 'object' ||
|
|
301
|
+
Array.isArray(input.budgets))
|
|
302
|
+
throw new Error('Invalid Team budgets');
|
|
303
|
+
parseTeamBudgetOverrides(input.budgets);
|
|
304
|
+
}
|
|
305
|
+
for (const member of input.roster) {
|
|
306
|
+
if (!member || typeof member !== 'object' || Array.isArray(member))
|
|
307
|
+
throw new Error('Invalid Team member');
|
|
308
|
+
objectInput(member, [
|
|
309
|
+
'name',
|
|
310
|
+
'agentType',
|
|
311
|
+
'access',
|
|
312
|
+
]);
|
|
313
|
+
}
|
|
314
|
+
for (const task of input.tasks) {
|
|
315
|
+
if (!task || typeof task !== 'object' || Array.isArray(task))
|
|
316
|
+
throw new Error('Invalid Team task');
|
|
317
|
+
const value = task;
|
|
318
|
+
objectInput(value, [
|
|
319
|
+
'id',
|
|
320
|
+
'description',
|
|
321
|
+
'assignee',
|
|
322
|
+
'blockedBy',
|
|
323
|
+
'claims',
|
|
324
|
+
]);
|
|
325
|
+
if (!value.claims ||
|
|
326
|
+
typeof value.claims !== 'object' ||
|
|
327
|
+
Array.isArray(value.claims))
|
|
328
|
+
throw new Error('Invalid Team claims');
|
|
329
|
+
objectInput(value.claims, [
|
|
330
|
+
'files',
|
|
331
|
+
'publicContracts',
|
|
332
|
+
'generatedArtifacts',
|
|
333
|
+
'migrations',
|
|
334
|
+
'mergeTargets',
|
|
335
|
+
]);
|
|
336
|
+
}
|
|
337
|
+
return input;
|
|
338
|
+
}
|
|
339
|
+
if (name === 'TeamList') {
|
|
340
|
+
objectInput(input, []);
|
|
341
|
+
return {};
|
|
342
|
+
}
|
|
343
|
+
if (name === 'TeamResume') {
|
|
344
|
+
objectInput(input, ['teamId']);
|
|
345
|
+
stringValue(input, 'teamId');
|
|
346
|
+
return input;
|
|
347
|
+
}
|
|
348
|
+
if (name === 'TeamAccept') {
|
|
349
|
+
objectInput(input, ['teamId', 'taskId', 'generation', 'decision']);
|
|
350
|
+
stringValue(input, 'teamId');
|
|
351
|
+
stringValue(input, 'taskId');
|
|
352
|
+
if (input.generation !== undefined &&
|
|
353
|
+
(!Number.isSafeInteger(input.generation) ||
|
|
354
|
+
input.generation < 0))
|
|
355
|
+
throw new Error('Invalid generation');
|
|
356
|
+
if (input.decision !== undefined &&
|
|
357
|
+
input.decision !== 'accepted' &&
|
|
358
|
+
input.decision !== 'rejected')
|
|
359
|
+
throw new Error('Invalid decision');
|
|
360
|
+
return {
|
|
361
|
+
...input,
|
|
362
|
+
...(input.decision === undefined ? { decision: 'accepted' } : {}),
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
if (name === 'TeamSend') {
|
|
366
|
+
objectInput(input, ['teamId', 'to', 'payload']);
|
|
367
|
+
stringValue(input, 'teamId');
|
|
368
|
+
if (input.to !== 'broadcast') {
|
|
369
|
+
if (typeof input.to === 'string') {
|
|
370
|
+
stringValue(input, 'to');
|
|
371
|
+
}
|
|
372
|
+
else if (Array.isArray(input.to)) {
|
|
373
|
+
if (input.to.length === 0 ||
|
|
374
|
+
input.to.some((value) => typeof value !== 'string' || value.trim() === ''))
|
|
375
|
+
throw new Error('Invalid Team recipients');
|
|
376
|
+
}
|
|
377
|
+
else
|
|
378
|
+
throw new Error('Invalid Team recipients');
|
|
379
|
+
}
|
|
380
|
+
return { ...input, payload: parseTeamMailboxPayload(input.payload) };
|
|
381
|
+
}
|
|
382
|
+
objectInput(input, ['teamId', 'drainMs']);
|
|
383
|
+
stringValue(input, 'teamId');
|
|
384
|
+
if (input.drainMs !== undefined &&
|
|
385
|
+
(typeof input.drainMs !== 'number' ||
|
|
386
|
+
!Number.isFinite(input.drainMs) ||
|
|
387
|
+
input.drainMs < 0 ||
|
|
388
|
+
input.drainMs > 600000))
|
|
389
|
+
throw new Error('Invalid drainMs');
|
|
390
|
+
if (input.drainMs !== undefined && !Number.isSafeInteger(input.drainMs))
|
|
391
|
+
throw new Error('Invalid drainMs');
|
|
392
|
+
return input;
|
|
393
|
+
}
|
|
394
|
+
export class TeamLeadToolRegistry {
|
|
395
|
+
base;
|
|
396
|
+
operations;
|
|
397
|
+
sessionId;
|
|
398
|
+
enabled;
|
|
399
|
+
constructor(base, operations, sessionId, toolNames) {
|
|
400
|
+
this.base = base;
|
|
401
|
+
this.operations = operations;
|
|
402
|
+
this.sessionId = sessionId;
|
|
403
|
+
this.enabled = new Set(toolNames.filter((name) => names.includes(name)));
|
|
404
|
+
}
|
|
405
|
+
definitions() {
|
|
406
|
+
return [
|
|
407
|
+
...this.base
|
|
408
|
+
.definitions()
|
|
409
|
+
.filter((definition) => this.isAllowed(definition.name)),
|
|
410
|
+
...definitions.filter((definition) => this.enabled.has(definition.name) && this.isAllowed(definition.name)),
|
|
411
|
+
];
|
|
412
|
+
}
|
|
413
|
+
schedulingPolicy(call) {
|
|
414
|
+
this.assertLeadPolicyAllows(call.name);
|
|
415
|
+
if (names.includes(call.name)) {
|
|
416
|
+
if (!this.enabled.has(call.name))
|
|
417
|
+
throw new Error(`Tool ${call.name} is unavailable`);
|
|
418
|
+
return { concurrency: 'exclusive', cancelOnInterrupt: true };
|
|
419
|
+
}
|
|
420
|
+
return (this.base.schedulingPolicy?.(call) ?? {
|
|
421
|
+
concurrency: 'concurrent',
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
async prepare(call, context) {
|
|
425
|
+
this.assertLeadPolicyAllows(call.name);
|
|
426
|
+
if (names.includes(call.name) && !this.enabled.has(call.name))
|
|
427
|
+
throw new Error(`Tool ${call.name} is unavailable`);
|
|
428
|
+
if (!this.enabled.has(call.name))
|
|
429
|
+
return this.base.prepare(call, context);
|
|
430
|
+
return { ...call, input: validate(call.input, call.name) };
|
|
431
|
+
}
|
|
432
|
+
async execute(call, context) {
|
|
433
|
+
this.assertLeadPolicyAllows(call.name);
|
|
434
|
+
if (names.includes(call.name) && !this.enabled.has(call.name))
|
|
435
|
+
throw new Error(`Tool ${call.name} is unavailable`);
|
|
436
|
+
if (!this.enabled.has(call.name))
|
|
437
|
+
return this.base.execute(call, context);
|
|
438
|
+
if (context.signal?.aborted)
|
|
439
|
+
throw new Error('Team tool interrupted');
|
|
440
|
+
const input = validate(call.input, call.name);
|
|
441
|
+
let value;
|
|
442
|
+
switch (call.name) {
|
|
443
|
+
case 'TeamCreate':
|
|
444
|
+
value = await this.operations.create(input, this.sessionId);
|
|
445
|
+
break;
|
|
446
|
+
case 'TeamResume':
|
|
447
|
+
value = await this.operations.resume(input.teamId, this.sessionId);
|
|
448
|
+
break;
|
|
449
|
+
case 'TeamList':
|
|
450
|
+
return this.result({ teams: await this.operations.list() });
|
|
451
|
+
case 'TeamAccept':
|
|
452
|
+
value = await this.operations.accept(input, this.sessionId);
|
|
453
|
+
break;
|
|
454
|
+
case 'TeamStop':
|
|
455
|
+
value = await this.operations.stop(input, this.sessionId);
|
|
456
|
+
break;
|
|
457
|
+
case 'TeamSend':
|
|
458
|
+
value = await this.operations.send(input, this.sessionId, call.id);
|
|
459
|
+
return this.result({ message: value });
|
|
460
|
+
}
|
|
461
|
+
return this.result({ team: value });
|
|
462
|
+
}
|
|
463
|
+
isAllowed(name) {
|
|
464
|
+
return (this.operations.activeLeadPolicy(this.sessionId) !== 'coordinator' ||
|
|
465
|
+
coordinatorAllowlist.has(name));
|
|
466
|
+
}
|
|
467
|
+
assertLeadPolicyAllows(name) {
|
|
468
|
+
if (!this.isAllowed(name))
|
|
469
|
+
throw new Error(`Tool ${name} is unavailable for Coordinator Lead`);
|
|
470
|
+
}
|
|
471
|
+
result(value) {
|
|
472
|
+
return {
|
|
473
|
+
content: JSON.stringify(value),
|
|
474
|
+
isError: false,
|
|
475
|
+
nativeToolUseResult: value,
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
//# sourceMappingURL=team-lead-tools.js.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ModelToolCall, ModelToolDefinition, ToolExecutionContext, ToolExecutionResult, ToolRegistry, ToolSchedulingPolicy } from '../core/runtime.js';
|
|
2
|
+
export interface TeamMemberToolRegistryOptions {
|
|
3
|
+
readonly base: ToolRegistry;
|
|
4
|
+
readonly access: 'read-only' | 'write';
|
|
5
|
+
readonly cwd: string;
|
|
6
|
+
}
|
|
7
|
+
export declare class TeamMemberToolRegistry implements ToolRegistry {
|
|
8
|
+
private readonly options;
|
|
9
|
+
private readonly allowed;
|
|
10
|
+
private readonly canonicalCwdPromise;
|
|
11
|
+
constructor(options: TeamMemberToolRegistryOptions);
|
|
12
|
+
definitions(): readonly ModelToolDefinition[];
|
|
13
|
+
schedulingPolicy(call: ModelToolCall): ToolSchedulingPolicy;
|
|
14
|
+
prepare(call: ModelToolCall, context: ToolExecutionContext): Promise<ModelToolCall>;
|
|
15
|
+
execute(call: ModelToolCall, context: ToolExecutionContext): Promise<ToolExecutionResult>;
|
|
16
|
+
private validateCallShape;
|
|
17
|
+
private validate;
|
|
18
|
+
private validateNormalizedCommand;
|
|
19
|
+
private hasInlineInterpreter;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=team-member-tools.d.ts.map
|