diff --git a/src/tools/agent-teams/types.test.ts b/src/tools/agent-teams/types.test.ts
index ea9a1e4b..59467f67 100644
--- a/src/tools/agent-teams/types.test.ts
+++ b/src/tools/agent-teams/types.test.ts
@@ -1,10 +1,198 @@
-///
-import { describe, expect, test } from "bun:test"
-import { TeamTeammateMemberSchema } from "./types"
+import { describe, it, expect } from "bun:test"
+import { z } from "zod"
+import {
+ TeamConfigSchema,
+ TeamMemberSchema,
+ TeamTeammateMemberSchema,
+ MessageTypeSchema,
+ InboxMessageSchema,
+ TeamTaskSchema,
+ TeamCreateInputSchema,
+ TeamDeleteInputSchema,
+ SendMessageInputSchema,
+ ReadInboxInputSchema,
+ ReadConfigInputSchema,
+ TeamSpawnInputSchema,
+ ForceKillTeammateInputSchema,
+ ProcessShutdownApprovedInputSchema,
+} from "./types"
-describe("agent-teams types", () => {
- test("rejects reserved agentType for teammate schema", () => {
- //#given
+describe("TeamConfigSchema", () => {
+ it("validates a complete team config", () => {
+ // given
+ const validConfig = {
+ name: "my-team",
+ description: "A test team",
+ createdAt: "2026-02-11T10:00:00Z",
+ leadAgentId: "agent-123",
+ leadSessionId: "ses-456",
+ members: [
+ {
+ agentId: "agent-123",
+ name: "Lead Agent",
+ agentType: "lead",
+ color: "blue",
+ },
+ {
+ agentId: "agent-789",
+ name: "Worker 1",
+ agentType: "teammate",
+ color: "green",
+ category: "quick",
+ model: "claude-sonnet-4-5",
+ prompt: "You are a helpful assistant",
+ planModeRequired: false,
+ joinedAt: "2026-02-11T10:05:00Z",
+ cwd: "/tmp",
+ subscriptions: ["task-updates"],
+ backendType: "native" as const,
+ isActive: true,
+ sessionID: "ses-789",
+ backgroundTaskID: "task-123",
+ },
+ ],
+ }
+
+ // when
+ const result = TeamConfigSchema.safeParse(validConfig)
+
+ // then
+ expect(result.success).toBe(true)
+ })
+
+ it("rejects invalid team config", () => {
+ // given
+ const invalidConfig = {
+ name: "",
+ description: "A test team",
+ createdAt: "invalid-date",
+ leadAgentId: "",
+ leadSessionId: "ses-456",
+ members: [],
+ }
+
+ // when
+ const result = TeamConfigSchema.safeParse(invalidConfig)
+
+ // then
+ expect(result.success).toBe(false)
+ })
+})
+
+describe("TeamMemberSchema", () => {
+ it("validates a lead member", () => {
+ // given
+ const leadMember = {
+ agentId: "agent-123",
+ name: "Lead Agent",
+ agentType: "lead",
+ color: "blue",
+ }
+
+ // when
+ const result = TeamMemberSchema.safeParse(leadMember)
+
+ // then
+ expect(result.success).toBe(true)
+ })
+
+ it("rejects invalid member", () => {
+ // given
+ const invalidMember = {
+ agentId: "",
+ name: "",
+ agentType: "invalid",
+ color: "invalid",
+ }
+
+ // when
+ const result = TeamMemberSchema.safeParse(invalidMember)
+
+ // then
+ expect(result.success).toBe(false)
+ })
+})
+
+describe("TeamTeammateMemberSchema", () => {
+ it("validates a complete teammate member", () => {
+ // given
+ const teammateMember = {
+ agentId: "agent-789",
+ name: "Worker 1",
+ agentType: "teammate",
+ color: "green",
+ category: "quick",
+ model: "claude-sonnet-4-5",
+ prompt: "You are a helpful assistant",
+ planModeRequired: false,
+ joinedAt: "2026-02-11T10:05:00Z",
+ cwd: "/tmp",
+ subscriptions: ["task-updates"],
+ backendType: "native" as const,
+ isActive: true,
+ sessionID: "ses-789",
+ backgroundTaskID: "task-123",
+ }
+
+ // when
+ const result = TeamTeammateMemberSchema.safeParse(teammateMember)
+
+ // then
+ expect(result.success).toBe(true)
+ })
+
+ it("validates teammate member with optional fields missing", () => {
+ // given
+ const minimalTeammate = {
+ agentId: "agent-789",
+ name: "Worker 1",
+ agentType: "teammate",
+ color: "green",
+ category: "quick",
+ model: "claude-sonnet-4-5",
+ prompt: "You are a helpful assistant",
+ planModeRequired: false,
+ joinedAt: "2026-02-11T10:05:00Z",
+ cwd: "/tmp",
+ subscriptions: [],
+ backendType: "native" as const,
+ isActive: true,
+ }
+
+ // when
+ const result = TeamTeammateMemberSchema.safeParse(minimalTeammate)
+
+ // then
+ expect(result.success).toBe(true)
+ })
+
+ it("rejects invalid teammate member", () => {
+ // given
+ const invalidTeammate = {
+ agentId: "",
+ name: "Worker 1",
+ agentType: "teammate",
+ color: "green",
+ category: "quick",
+ model: "claude-sonnet-4-5",
+ prompt: "You are a helpful assistant",
+ planModeRequired: false,
+ joinedAt: "invalid-date",
+ cwd: "/tmp",
+ subscriptions: [],
+ backendType: "invalid" as const,
+ isActive: true,
+ }
+
+ // when
+ const result = TeamTeammateMemberSchema.safeParse(invalidTeammate)
+
+ // then
+ expect(result.success).toBe(false)
+ })
+
+ it("rejects reserved agentType for teammate schema", () => {
+ // given
const invalidTeammate = {
agentId: "worker@team",
name: "worker",
@@ -14,17 +202,520 @@ describe("agent-teams types", () => {
prompt: "do work",
color: "blue",
planModeRequired: false,
- joinedAt: Date.now(),
+ joinedAt: "2026-02-11T10:05:00Z",
cwd: "/tmp",
subscriptions: [],
backendType: "native",
isActive: false,
}
- //#when
+ // when
const result = TeamTeammateMemberSchema.safeParse(invalidTeammate)
- //#then
+ // then
+ expect(result.success).toBe(false)
+ })
+})
+
+describe("MessageTypeSchema", () => {
+ it("validates all 5 message types", () => {
+ // given
+ const types = ["message", "broadcast", "shutdown_request", "shutdown_response", "plan_approval_response"]
+
+ // when & then
+ types.forEach(type => {
+ const result = MessageTypeSchema.safeParse(type)
+ expect(result.success).toBe(true)
+ expect(result.data).toBe(type)
+ })
+ })
+
+ it("rejects invalid message type", () => {
+ // given
+ const invalidType = "invalid_type"
+
+ // when
+ const result = MessageTypeSchema.safeParse(invalidType)
+
+ // then
+ expect(result.success).toBe(false)
+ })
+})
+
+describe("InboxMessageSchema", () => {
+ it("validates a complete inbox message", () => {
+ // given
+ const message = {
+ id: "msg-123",
+ type: "message" as const,
+ sender: "agent-123",
+ recipient: "agent-456",
+ content: "Hello world",
+ summary: "Greeting",
+ timestamp: "2026-02-11T10:00:00Z",
+ read: false,
+ requestId: "req-123",
+ approve: true,
+ }
+
+ // when
+ const result = InboxMessageSchema.safeParse(message)
+
+ // then
+ expect(result.success).toBe(true)
+ })
+
+ it("validates message with optional fields missing", () => {
+ // given
+ const minimalMessage = {
+ id: "msg-123",
+ type: "broadcast" as const,
+ sender: "agent-123",
+ recipient: "agent-456",
+ content: "Hello world",
+ summary: "Greeting",
+ timestamp: "2026-02-11T10:00:00Z",
+ read: false,
+ }
+
+ // when
+ const result = InboxMessageSchema.safeParse(minimalMessage)
+
+ // then
+ expect(result.success).toBe(true)
+ })
+
+ it("rejects invalid inbox message", () => {
+ // given
+ const invalidMessage = {
+ id: "",
+ type: "invalid" as const,
+ sender: "",
+ recipient: "",
+ content: "",
+ summary: "",
+ timestamp: "invalid-date",
+ read: "not-boolean",
+ }
+
+ // when
+ const result = InboxMessageSchema.safeParse(invalidMessage)
+
+ // then
+ expect(result.success).toBe(false)
+ })
+})
+
+describe("TeamTaskSchema", () => {
+ it("validates a task object", () => {
+ // given
+ const task = {
+ id: "T-12345678-1234-1234-1234-123456789012",
+ subject: "Implement feature",
+ description: "Add new functionality",
+ status: "pending" as const,
+ activeForm: "Implementing feature",
+ blocks: [],
+ blockedBy: [],
+ owner: "agent-123",
+ metadata: { priority: "high" },
+ repoURL: "https://github.com/user/repo",
+ parentID: "T-parent",
+ threadID: "thread-123",
+ }
+
+ // when
+ const result = TeamTaskSchema.safeParse(task)
+
+ // then
+ expect(result.success).toBe(true)
+ })
+
+ it("rejects invalid task", () => {
+ // given
+ const invalidTask = {
+ id: "invalid-id",
+ subject: "",
+ description: "Add new functionality",
+ status: "invalid" as const,
+ activeForm: "Implementing feature",
+ blocks: [],
+ blockedBy: [],
+ }
+
+ // when
+ const result = TeamTaskSchema.safeParse(invalidTask)
+
+ // then
+ expect(result.success).toBe(false)
+ })
+})
+
+describe("TeamCreateInputSchema", () => {
+ it("validates create input with description", () => {
+ // given
+ const input = {
+ team_name: "my-team",
+ description: "A test team",
+ }
+
+ // when
+ const result = TeamCreateInputSchema.safeParse(input)
+
+ // then
+ expect(result.success).toBe(true)
+ })
+
+ it("validates create input without description", () => {
+ // given
+ const input = {
+ team_name: "my-team",
+ }
+
+ // when
+ const result = TeamCreateInputSchema.safeParse(input)
+
+ // then
+ expect(result.success).toBe(true)
+ })
+
+ it("rejects invalid create input", () => {
+ // given
+ const input = {
+ team_name: "invalid team name with spaces and special chars!",
+ }
+
+ // when
+ const result = TeamCreateInputSchema.safeParse(input)
+
+ // then
+ expect(result.success).toBe(false)
+ })
+})
+
+describe("TeamDeleteInputSchema", () => {
+ it("validates delete input", () => {
+ // given
+ const input = {
+ team_name: "my-team",
+ }
+
+ // when
+ const result = TeamDeleteInputSchema.safeParse(input)
+
+ // then
+ expect(result.success).toBe(true)
+ })
+
+ it("rejects invalid delete input", () => {
+ // given
+ const input = {
+ team_name: "",
+ }
+
+ // when
+ const result = TeamDeleteInputSchema.safeParse(input)
+
+ // then
+ expect(result.success).toBe(false)
+ })
+})
+
+describe("SendMessageInputSchema", () => {
+ it("validates message type input", () => {
+ // given
+ const input = {
+ team_name: "my-team",
+ type: "message" as const,
+ recipient: "agent-456",
+ content: "Hello world",
+ summary: "Greeting",
+ }
+
+ // when
+ const result = SendMessageInputSchema.safeParse(input)
+
+ // then
+ expect(result.success).toBe(true)
+ })
+
+ it("validates broadcast type input", () => {
+ // given
+ const input = {
+ team_name: "my-team",
+ type: "broadcast" as const,
+ content: "Team announcement",
+ summary: "Announcement",
+ }
+
+ // when
+ const result = SendMessageInputSchema.safeParse(input)
+
+ // then
+ expect(result.success).toBe(true)
+ })
+
+ it("validates shutdown_request type input", () => {
+ // given
+ const input = {
+ team_name: "my-team",
+ type: "shutdown_request" as const,
+ recipient: "agent-456",
+ content: "Please shutdown",
+ summary: "Shutdown request",
+ }
+
+ // when
+ const result = SendMessageInputSchema.safeParse(input)
+
+ // then
+ expect(result.success).toBe(true)
+ })
+
+ it("validates shutdown_response type input", () => {
+ // given
+ const input = {
+ team_name: "my-team",
+ type: "shutdown_response" as const,
+ request_id: "req-123",
+ approve: true,
+ }
+
+ // when
+ const result = SendMessageInputSchema.safeParse(input)
+
+ // then
+ expect(result.success).toBe(true)
+ })
+
+ it("validates plan_approval_response type input", () => {
+ // given
+ const input = {
+ team_name: "my-team",
+ type: "plan_approval_response" as const,
+ request_id: "req-456",
+ approve: false,
+ }
+
+ // when
+ const result = SendMessageInputSchema.safeParse(input)
+
+ // then
+ expect(result.success).toBe(true)
+ })
+
+ it("rejects message type without recipient", () => {
+ // given
+ const input = {
+ team_name: "my-team",
+ type: "message" as const,
+ content: "Hello world",
+ summary: "Greeting",
+ }
+
+ // when
+ const result = SendMessageInputSchema.safeParse(input)
+
+ // then
+ expect(result.success).toBe(false)
+ })
+
+ it("rejects shutdown_response without request_id", () => {
+ // given
+ const input = {
+ team_name: "my-team",
+ type: "shutdown_response" as const,
+ approve: true,
+ }
+
+ // when
+ const result = SendMessageInputSchema.safeParse(input)
+
+ // then
+ expect(result.success).toBe(false)
+ })
+
+ it("rejects invalid team_name", () => {
+ // given
+ const input = {
+ team_name: "invalid team name",
+ type: "broadcast" as const,
+ content: "Hello",
+ summary: "Greeting",
+ }
+
+ // when
+ const result = SendMessageInputSchema.safeParse(input)
+
+ // then
+ expect(result.success).toBe(false)
+ })
+})
+
+describe("ReadInboxInputSchema", () => {
+ it("validates read inbox input", () => {
+ // given
+ const input = {
+ team_name: "my-team",
+ agent_name: "worker-1",
+ unread_only: true,
+ mark_as_read: false,
+ }
+
+ // when
+ const result = ReadInboxInputSchema.safeParse(input)
+
+ // then
+ expect(result.success).toBe(true)
+ })
+
+ it("validates minimal read inbox input", () => {
+ // given
+ const input = {
+ team_name: "my-team",
+ agent_name: "worker-1",
+ }
+
+ // when
+ const result = ReadInboxInputSchema.safeParse(input)
+
+ // then
+ expect(result.success).toBe(true)
+ })
+
+ it("rejects invalid read inbox input", () => {
+ // given
+ const input = {
+ team_name: "",
+ agent_name: "",
+ }
+
+ // when
+ const result = ReadInboxInputSchema.safeParse(input)
+
+ // then
+ expect(result.success).toBe(false)
+ })
+})
+
+describe("ReadConfigInputSchema", () => {
+ it("validates read config input", () => {
+ // given
+ const input = {
+ team_name: "my-team",
+ }
+
+ // when
+ const result = ReadConfigInputSchema.safeParse(input)
+
+ // then
+ expect(result.success).toBe(true)
+ })
+
+ it("rejects invalid read config input", () => {
+ // given
+ const input = {
+ team_name: "",
+ }
+
+ // when
+ const result = ReadConfigInputSchema.safeParse(input)
+
+ // then
+ expect(result.success).toBe(false)
+ })
+})
+
+describe("TeamSpawnInputSchema", () => {
+ it("validates spawn input", () => {
+ // given
+ const input = {
+ team_name: "my-team",
+ name: "worker-1",
+ category: "quick",
+ prompt: "You are a helpful assistant",
+ }
+
+ // when
+ const result = TeamSpawnInputSchema.safeParse(input)
+
+ // then
+ expect(result.success).toBe(true)
+ })
+
+ it("rejects invalid spawn input", () => {
+ // given
+ const input = {
+ team_name: "invalid team",
+ name: "",
+ category: "quick",
+ prompt: "You are a helpful assistant",
+ }
+
+ // when
+ const result = TeamSpawnInputSchema.safeParse(input)
+
+ // then
+ expect(result.success).toBe(false)
+ })
+})
+
+describe("ForceKillTeammateInputSchema", () => {
+ it("validates force kill input", () => {
+ // given
+ const input = {
+ team_name: "my-team",
+ teammate_name: "worker-1",
+ }
+
+ // when
+ const result = ForceKillTeammateInputSchema.safeParse(input)
+
+ // then
+ expect(result.success).toBe(true)
+ })
+
+ it("rejects invalid force kill input", () => {
+ // given
+ const input = {
+ team_name: "",
+ teammate_name: "",
+ }
+
+ // when
+ const result = ForceKillTeammateInputSchema.safeParse(input)
+
+ // then
+ expect(result.success).toBe(false)
+ })
+})
+
+describe("ProcessShutdownApprovedInputSchema", () => {
+ it("validates shutdown approved input", () => {
+ // given
+ const input = {
+ team_name: "my-team",
+ teammate_name: "worker-1",
+ }
+
+ // when
+ const result = ProcessShutdownApprovedInputSchema.safeParse(input)
+
+ // then
+ expect(result.success).toBe(true)
+ })
+
+ it("rejects invalid shutdown approved input", () => {
+ // given
+ const input = {
+ team_name: "",
+ teammate_name: "",
+ }
+
+ // when
+ const result = ProcessShutdownApprovedInputSchema.safeParse(input)
+
+ // then
expect(result.success).toBe(false)
})
})
diff --git a/src/tools/agent-teams/types.ts b/src/tools/agent-teams/types.ts
index dad9126d..be52a4fa 100644
--- a/src/tools/agent-teams/types.ts
+++ b/src/tools/agent-teams/types.ts
@@ -1,82 +1,52 @@
import { z } from "zod"
+import { TaskObjectSchema } from "../task/types"
-export const TEAM_COLOR_PALETTE = [
- "blue",
- "green",
- "yellow",
- "purple",
- "orange",
- "pink",
- "cyan",
- "red",
-] as const
+// Team member schemas
+export const TeamMemberSchema = z.object({
+ agentId: z.string().min(1),
+ name: z.string().min(1),
+ agentType: z.enum(["lead", "teammate"]),
+ color: z.string().min(1),
+})
-export const TeamTaskStatusSchema = z.enum(["pending", "in_progress", "completed", "deleted"])
-export type TeamTaskStatus = z.infer
+export type TeamMember = z.infer
-export const TeamLeadMemberSchema = z.object({
- agentId: z.string(),
- name: z.literal("team-lead"),
- agentType: z.literal("team-lead"),
- model: z.string(),
- joinedAt: z.number(),
- cwd: z.string(),
- subscriptions: z.array(z.unknown()).default([]),
-}).strict()
-
-export const TeamTeammateMemberSchema = z.object({
- agentId: z.string(),
- name: z.string(),
- agentType: z.string().refine((value) => value !== "team-lead", {
- message: "agent_type_reserved",
- }),
- category: z.string(),
- model: z.string(),
- prompt: z.string(),
- color: z.string(),
- planModeRequired: z.boolean().default(false),
- joinedAt: z.number(),
- cwd: z.string(),
- subscriptions: z.array(z.unknown()).default([]),
- backendType: z.literal("native").default("native"),
- isActive: z.boolean().default(false),
+export const TeamTeammateMemberSchema = TeamMemberSchema.extend({
+ category: z.string().min(1),
+ model: z.string().min(1),
+ prompt: z.string().min(1),
+ planModeRequired: z.boolean(),
+ joinedAt: z.string().datetime(),
+ cwd: z.string().min(1),
+ subscriptions: z.array(z.string()),
+ backendType: z.literal("native"),
+ isActive: z.boolean(),
sessionID: z.string().optional(),
backgroundTaskID: z.string().optional(),
-}).strict()
+}).refine(
+ (data) => data.agentType === "teammate",
+ "TeamTeammateMemberSchema requires agentType to be 'teammate'"
+).refine(
+ (data) => data.agentType !== "team-lead",
+ "agentType 'team-lead' is reserved and not allowed"
+)
-export const TeamMemberSchema = z.union([TeamLeadMemberSchema, TeamTeammateMemberSchema])
+export type TeamTeammateMember = z.infer
+// Team config schema
export const TeamConfigSchema = z.object({
- name: z.string(),
- description: z.string().default(""),
- createdAt: z.number(),
- leadAgentId: z.string(),
- leadSessionId: z.string(),
- members: z.array(TeamMemberSchema),
-}).strict()
+ name: z.string().min(1),
+ description: z.string().optional(),
+ createdAt: z.string().datetime(),
+ leadAgentId: z.string().min(1),
+ leadSessionId: z.string().min(1),
+ members: z.array(z.union([TeamMemberSchema, TeamTeammateMemberSchema])),
+})
-export const TeamInboxMessageSchema = z.object({
- from: z.string(),
- text: z.string(),
- timestamp: z.string(),
- read: z.boolean().default(false),
- summary: z.string().optional(),
- color: z.string().optional(),
-}).strict()
+export type TeamConfig = z.infer
-export const TeamTaskSchema = z.object({
- id: z.string(),
- subject: z.string(),
- description: z.string(),
- activeForm: z.string().optional(),
- status: TeamTaskStatusSchema,
- blocks: z.array(z.string()).default([]),
- blockedBy: z.array(z.string()).default([]),
- owner: z.string().optional(),
- metadata: z.record(z.string(), z.unknown()).optional(),
-}).strict()
-
-export const TeamSendMessageTypeSchema = z.enum([
+// Message schemas
+export const MessageTypeSchema = z.enum([
"message",
"broadcast",
"shutdown_request",
@@ -84,118 +54,113 @@ export const TeamSendMessageTypeSchema = z.enum([
"plan_approval_response",
])
-export type TeamLeadMember = z.infer
-export type TeamTeammateMember = z.infer
-export type TeamMember = z.infer
-export type TeamConfig = z.infer
-export type TeamInboxMessage = z.infer
-export type TeamTask = z.infer
-export type TeamSendMessageType = z.infer
+export type MessageType = z.infer
+export const InboxMessageSchema = z.object({
+ id: z.string().min(1),
+ type: MessageTypeSchema,
+ sender: z.string().min(1),
+ recipient: z.string().min(1),
+ content: z.string().optional(),
+ summary: z.string().optional(),
+ timestamp: z.string().datetime(),
+ read: z.boolean(),
+ requestId: z.string().optional(),
+ approve: z.boolean().optional(),
+})
+
+export type InboxMessage = z.infer
+
+// Task schema (reuse from task/types.ts)
+export const TeamTaskSchema = TaskObjectSchema
+
+export type TeamTask = z.infer
+
+// Input schemas for tools
export const TeamCreateInputSchema = z.object({
- team_name: z.string(),
+ team_name: z.string().regex(/^[A-Za-z0-9_-]+$/, "Team name must contain only letters, numbers, hyphens, and underscores").max(64),
description: z.string().optional(),
})
+export type TeamCreateInput = z.infer
+
export const TeamDeleteInputSchema = z.object({
- team_name: z.string(),
+ team_name: z.string().regex(/^[A-Za-z0-9_-]+$/, "Team name must contain only letters, numbers, hyphens, and underscores").max(64),
})
-export const TeamReadConfigInputSchema = z.object({
- team_name: z.string(),
-})
+export type TeamDeleteInput = z.infer
-export const TeamSpawnInputSchema = z.object({
- team_name: z.string(),
- name: z.string(),
- prompt: z.string(),
- category: z.string(),
- subagent_type: z.string().optional(),
- model: z.string().optional(),
- plan_mode_required: z.boolean().optional(),
-})
-
-function normalizeTeamRecipient(recipient: string): string {
- const trimmed = recipient.trim()
- const atIndex = trimmed.indexOf("@")
- if (atIndex <= 0) {
- return trimmed
- }
-
- return trimmed.slice(0, atIndex)
-}
-
-export const TeamSendMessageInputSchema = z.object({
- team_name: z.string(),
- type: TeamSendMessageTypeSchema,
- recipient: z.string().optional().transform((value) => {
- if (value === undefined) {
- return undefined
- }
-
- return normalizeTeamRecipient(value)
+export const SendMessageInputSchema = z.discriminatedUnion("type", [
+ z.object({
+ team_name: z.string().regex(/^[A-Za-z0-9_-]+$/, "Team name must contain only letters, numbers, hyphens, and underscores").max(64),
+ type: z.literal("message"),
+ recipient: z.string().min(1),
+ content: z.string().optional(),
+ summary: z.string().optional(),
}),
- content: z.string().optional(),
- summary: z.string().optional(),
- request_id: z.string().optional(),
- approve: z.boolean().optional(),
- sender: z.string().optional(),
-})
+ z.object({
+ team_name: z.string().regex(/^[A-Za-z0-9_-]+$/, "Team name must contain only letters, numbers, hyphens, and underscores").max(64),
+ type: z.literal("broadcast"),
+ content: z.string().optional(),
+ summary: z.string().optional(),
+ }),
+ z.object({
+ team_name: z.string().regex(/^[A-Za-z0-9_-]+$/, "Team name must contain only letters, numbers, hyphens, and underscores").max(64),
+ type: z.literal("shutdown_request"),
+ recipient: z.string().min(1),
+ content: z.string().optional(),
+ summary: z.string().optional(),
+ }),
+ z.object({
+ team_name: z.string().regex(/^[A-Za-z0-9_-]+$/, "Team name must contain only letters, numbers, hyphens, and underscores").max(64),
+ type: z.literal("shutdown_response"),
+ request_id: z.string().min(1),
+ approve: z.boolean(),
+ }),
+ z.object({
+ team_name: z.string().regex(/^[A-Za-z0-9_-]+$/, "Team name must contain only letters, numbers, hyphens, and underscores").max(64),
+ type: z.literal("plan_approval_response"),
+ request_id: z.string().min(1),
+ approve: z.boolean(),
+ }),
+])
-export const TeamReadInboxInputSchema = z.object({
- team_name: z.string(),
- agent_name: z.string(),
+export type SendMessageInput = z.infer
+
+export const ReadInboxInputSchema = z.object({
+ team_name: z.string().regex(/^[A-Za-z0-9_-]+$/, "Team name must contain only letters, numbers, hyphens, and underscores").max(64),
+ agent_name: z.string().min(1),
unread_only: z.boolean().optional(),
mark_as_read: z.boolean().optional(),
})
-export const TeamTaskCreateInputSchema = z.object({
- team_name: z.string(),
- subject: z.string(),
- description: z.string(),
- active_form: z.string().optional(),
- metadata: z.record(z.string(), z.unknown()).optional(),
+export type ReadInboxInput = z.infer
+
+export const ReadConfigInputSchema = z.object({
+ team_name: z.string().regex(/^[A-Za-z0-9_-]+$/, "Team name must contain only letters, numbers, hyphens, and underscores").max(64),
})
-export const TeamTaskUpdateInputSchema = z.object({
- team_name: z.string(),
- task_id: z.string(),
- status: TeamTaskStatusSchema.optional(),
- owner: z.string().optional(),
- subject: z.string().optional(),
- description: z.string().optional(),
- active_form: z.string().optional(),
- add_blocks: z.array(z.string()).optional(),
- add_blocked_by: z.array(z.string()).optional(),
- metadata: z.record(z.string(), z.unknown()).optional(),
+export type ReadConfigInput = z.infer
+
+export const TeamSpawnInputSchema = z.object({
+ team_name: z.string().regex(/^[A-Za-z0-9_-]+$/, "Team name must contain only letters, numbers, hyphens, and underscores").max(64),
+ name: z.string().min(1),
+ category: z.string().min(1),
+ prompt: z.string().min(1),
})
-export const TeamTaskListInputSchema = z.object({
- team_name: z.string(),
+export type TeamSpawnInput = z.infer
+
+export const ForceKillTeammateInputSchema = z.object({
+ team_name: z.string().regex(/^[A-Za-z0-9_-]+$/, "Team name must contain only letters, numbers, hyphens, and underscores").max(64),
+ teammate_name: z.string().min(1),
})
-export const TeamTaskGetInputSchema = z.object({
- team_name: z.string(),
- task_id: z.string(),
+export type ForceKillTeammateInput = z.infer
+
+export const ProcessShutdownApprovedInputSchema = z.object({
+ team_name: z.string().regex(/^[A-Za-z0-9_-]+$/, "Team name must contain only letters, numbers, hyphens, and underscores").max(64),
+ teammate_name: z.string().min(1),
})
-export const TeamForceKillInputSchema = z.object({
- team_name: z.string(),
- agent_name: z.string(),
-})
-
-export const TeamProcessShutdownInputSchema = z.object({
- team_name: z.string(),
- agent_name: z.string(),
-})
-
-export interface TeamToolContext {
- sessionID: string
- messageID: string
- abort: AbortSignal
- agent?: string
-}
-
-export function isTeammateMember(member: TeamMember): member is TeamTeammateMember {
- return member.agentType !== "team-lead"
-}
+export type ProcessShutdownApprovedInput = z.infer