@evo-dev/core 0.0.1-alpha.1 → 0.0.1-alpha.2

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/src/team/mcp.ts CHANGED
@@ -38,7 +38,8 @@ export function getTeamsMcpTools(): McpToolDefinition[] {
38
38
  {
39
39
  name: "list_agents",
40
40
  title: "List EvoDev Team Agents",
41
- description: "List role agents in the current EvoDev team run.",
41
+ description:
42
+ "List role agents in the current EvoDev team run for one-time roster discovery. Do not use this as a progress polling loop.",
42
43
  inputSchema: {
43
44
  type: "object",
44
45
  additionalProperties: false,
@@ -61,7 +62,8 @@ export function getTeamsMcpTools(): McpToolDefinition[] {
61
62
  {
62
63
  name: "send_message",
63
64
  title: "Send EvoDev Team Message",
64
- description: "Send a structured message to another EvoDev role agent.",
65
+ description:
66
+ "Queue a structured message to another EvoDev role agent. Delivery happens through hook safe points; callers should not wait or poll for immediate progress.",
65
67
  inputSchema: {
66
68
  type: "object",
67
69
  additionalProperties: false,
@@ -96,7 +98,8 @@ export function getTeamsMcpTools(): McpToolDefinition[] {
96
98
  properties: {
97
99
  ok: { type: "boolean" },
98
100
  messageId: { type: "string" },
99
- deliveredTo: { type: "string" },
101
+ delivery: { type: "string", enum: ["queued"] },
102
+ queuedFor: { type: "string" },
100
103
  cc: { type: "array" },
101
104
  },
102
105
  required: ["ok"],
@@ -105,7 +108,8 @@ export function getTeamsMcpTools(): McpToolDefinition[] {
105
108
  {
106
109
  name: "spawn_role",
107
110
  title: "Spawn EvoDev Role Agent",
108
- description: "Create or reuse one EvoDev role agent.",
111
+ description:
112
+ "Create or reuse one EvoDev role agent. For main, spawn needed roles, send their task messages, then finish the current turn unless new input or hook-delivered messages require coordination.",
109
113
  inputSchema: {
110
114
  type: "object",
111
115
  additionalProperties: false,
@@ -257,7 +261,7 @@ function initializeResult(request: ParsedRequest): Record<string, unknown> {
257
261
  version: "0.0.1-alpha",
258
262
  },
259
263
  instructions:
260
- "Use list_agents to discover EvoDev role agents, spawn_role to create or reuse role agents in the current EvoDev team run, send_message to communicate through the EvoDev broker, and stop_role to stop roles. Role lifecycle is tracked by EvoDev Teams MCP/CLI (`evodev team ...`), not direct tmux orchestration.",
264
+ "Use list_agents only for one-time roster discovery, spawn_role to create or reuse role agents in the current EvoDev team run, send_message to queue brokered role messages, and stop_role to stop roles. send_message does not paste into live prompts; pending messages surface through hook safe points. Main should delegate runnable role tasks, then finish the current turn instead of sleeping, waiting, or polling list_agents/status for progress. Role lifecycle is tracked by EvoDev Teams MCP/CLI (`evodev team ...`), not direct tmux orchestration.",
261
265
  };
262
266
  }
263
267
 
@@ -0,0 +1,141 @@
1
+ export interface TeamStartupPromptRole {
2
+ roleId: string;
3
+ roleName: string;
4
+ runtime: string;
5
+ model: string | null;
6
+ thinkingLevel: string | null;
7
+ prompt: string;
8
+ permissions: {
9
+ writeMode: string;
10
+ };
11
+ teamPolicy: {
12
+ recordTranscript: boolean;
13
+ };
14
+ nativeAgent: {
15
+ target: string;
16
+ agentName: string;
17
+ scope: string;
18
+ } | null;
19
+ }
20
+
21
+ export interface TeamStartupPromptRosterAgent {
22
+ roleId: string;
23
+ status: string;
24
+ roleName: string;
25
+ }
26
+
27
+ export interface RenderTeamRoleStartupPromptInput {
28
+ runId: string;
29
+ repoRoot: string;
30
+ role: TeamStartupPromptRole;
31
+ roster: TeamStartupPromptRosterAgent[];
32
+ scopedContext?: string | null;
33
+ }
34
+
35
+ const TEAM_ROLE_STARTUP_PROMPT_TEMPLATE = [
36
+ "You are an EvoDev managed role agent.",
37
+ "Team run: {{runId}}",
38
+ "Repository: {{repoRoot}}",
39
+ "Role id: {{roleId}}",
40
+ "Role name: {{roleName}}",
41
+ "Runtime: {{runtime}}",
42
+ "Native Code Agent binding: {{nativeAgentBinding}}",
43
+ "Model: {{model}}",
44
+ "Thinking level: {{thinkingLevel}}",
45
+ "Write mode: {{writeMode}}",
46
+ "Transcript recording: {{transcriptRecording}}",
47
+ "",
48
+ "Current known agents:",
49
+ "{{roster}}",
50
+ "",
51
+ "EvoDev team runtime control contract:",
52
+ "This run is already inside the EvoDev-managed team runtime.",
53
+ "For EvoDev role-agent lifecycle, use the current EvoDev run control plane.",
54
+ "Unprefixed user requests such as 'start the team', 'execute team', 'create agents', or 'spawn roles' mean: use the current EvoDev run control plane.",
55
+ "Do not answer those requests with only a role plan when a role agent should be created.",
56
+ "",
57
+ "Use Teams MCP as the primary control plane:",
58
+ "- list_agents: discover current EvoDev role agents.",
59
+ "- spawn_role: create or reuse exactly one EvoDev role agent.",
60
+ "- send_message: communicate through the EvoDev broker.",
61
+ "- stop_role: stop a role agent when allowed.",
62
+ "If Teams MCP is unavailable, fall back to the EvoDev CLI from this repository:",
63
+ "- evodev team spawn --role <roleId>",
64
+ "- evodev team send --to <roleId> --message <text>",
65
+ "- evodev team status",
66
+ "Teams MCP defaults are inherited from the environment:",
67
+ "EVODEV_TEAM_RUN_ID={{runId}}",
68
+ "EVODEV_TEAM_ROLE_ID={{roleId}}",
69
+ "When calling Teams MCP tools, let the MCP server-bound environment identify this run and role.",
70
+ "Do not operate tmux directly for role lifecycle; let EvoDev create and track panes.",
71
+ "Any server-bound role may request role lifecycle changes; EvoDev records and tracks panes but does not use role policy to stop execution.",
72
+ "{{roleGuidance}}",
73
+ "{{nativeAgentInstruction}}",
74
+ "Team messages are durably queued and delivered at hook safe points, not pasted into a live prompt. cc values are audit context; they are not an instruction for main to immediately forward or act.",
75
+ "{{scopedContext}}",
76
+ "",
77
+ "{{rolePrompt}}",
78
+ ].join("\n");
79
+
80
+ const MAIN_ROLE_GUIDANCE = [
81
+ "As main, you are the planner and delegator for complex work, not a standby worker.",
82
+ "On each user prompt or hook-delivered inbox message, decide whether to answer directly, ask for clarification, or use team execution.",
83
+ "Use team execution only when role separation improves correctness, coverage, safety, or latency.",
84
+ "When team execution is needed, create an upfront task plan with required role ids, role-specific assignments, dependencies, and runnable batches.",
85
+ "Spawn or reuse all roles needed for the first runnable batch and send each role a self-contained task message.",
86
+ "After all currently runnable tasks are delegated, finish your current turn immediately; do not call sleep, wait idly, poll list_agents/status, or keep the turn alive to watch progress.",
87
+ "Use list_agents only for one-time roster discovery when the current roster is genuinely unknown, never as a progress check.",
88
+ "Resume coordination only when the user sends new input or a role message is delivered by hooks; then decide whether to adjust tasks, send supplemental instructions, spawn dependent roles, synthesize completed results, or ask the user.",
89
+ "While delegated role work is pending, do not perform concrete implementation, testing, package research, or review work yourself.",
90
+ ].join(" ");
91
+
92
+ const NON_MAIN_ROLE_GUIDANCE =
93
+ "As a non-main role, send results or issues to the role that needs to act next. Coordinate with main only when the decision affects scope, assignment, user-facing synthesis, or unresolved tradeoffs.";
94
+
95
+ const PLACEHOLDER_PATTERN = /\{\{([A-Za-z][A-Za-z0-9]*)\}\}/g;
96
+
97
+ export function renderTeamRoleStartupPrompt(input: RenderTeamRoleStartupPromptInput): string {
98
+ const values: Record<string, string> = {
99
+ runId: input.runId,
100
+ repoRoot: input.repoRoot,
101
+ roleId: input.role.roleId,
102
+ roleName: input.role.roleName,
103
+ runtime: input.role.runtime,
104
+ nativeAgentBinding: formatNativeAgentBinding(input.role),
105
+ model: input.role.model ?? "default",
106
+ thinkingLevel: input.role.thinkingLevel ?? "default",
107
+ writeMode: input.role.permissions.writeMode,
108
+ transcriptRecording: input.role.teamPolicy.recordTranscript ? "enabled" : "disabled",
109
+ roster: formatStartupPromptRoster(input.roster),
110
+ roleGuidance: input.role.roleId === "main" ? MAIN_ROLE_GUIDANCE : NON_MAIN_ROLE_GUIDANCE,
111
+ nativeAgentInstruction: formatNativeAgentInstruction(input.role),
112
+ scopedContext: input.scopedContext ?? "",
113
+ rolePrompt: input.role.prompt,
114
+ };
115
+
116
+ return renderPromptTemplate(TEAM_ROLE_STARTUP_PROMPT_TEMPLATE, values);
117
+ }
118
+
119
+ function renderPromptTemplate(template: string, values: Record<string, string>): string {
120
+ return template.replace(PLACEHOLDER_PATTERN, (_placeholder, key: string) => {
121
+ if (!Object.hasOwn(values, key)) {
122
+ throw new Error(`Missing team startup prompt template value: ${key}`);
123
+ }
124
+ return values[key];
125
+ });
126
+ }
127
+
128
+ function formatStartupPromptRoster(roster: TeamStartupPromptRosterAgent[]): string {
129
+ if (roster.length === 0) return "- main: starting";
130
+ return roster.map((agent) => `- ${agent.roleId}: ${agent.status} (${agent.roleName})`).join("\n");
131
+ }
132
+
133
+ function formatNativeAgentBinding(role: TeamStartupPromptRole): string {
134
+ if (role.nativeAgent === null) return "none";
135
+ return `${role.nativeAgent.target}/${role.nativeAgent.agentName} (${role.nativeAgent.scope})`;
136
+ }
137
+
138
+ function formatNativeAgentInstruction(role: TeamStartupPromptRole): string {
139
+ if (role.nativeAgent === null) return "No native Code Agent agent is bound to this role.";
140
+ return `Use the bound native Code Agent agent name '${role.nativeAgent.agentName}' as role context when the runtime supports named agents; EvoDev does not load or transform the native agent file.`;
141
+ }