@@ -22,6 +22,9 @@ const (
2222 teamSendTargetCoordinator = "coordinator"
2323 teamSendTargetAll = "all"
2424
25+ teamAutoScheduleSourceDeterministic = "deterministic"
26+ teamAutoScheduleSourceCoordinatorPlan = "coordinator_plan"
27+
2528 scheduleCronActionCreate = "create"
2629 scheduleCronActionList = "list"
2730 scheduleCronActionDelete = "delete"
@@ -93,8 +96,9 @@ type teamScheduleInput struct {
9396}
9497
9598type teamAutoScheduleInput struct {
96- TeamID string `json:"team_id,omitempty"`
97- Objective string `json:"objective,omitempty"`
99+ TeamID string `json:"team_id,omitempty"`
100+ Objective string `json:"objective,omitempty"`
101+ Assignments []teamDispatchAssignmentInput `json:"assignments,omitempty"`
98102}
99103
100104type teamCoordinateInput struct {
@@ -461,8 +465,8 @@ func NewTeamAutoScheduleTool() tool.Tool {
461465 return tool.FuncTool {
462466 DefinitionValue : contracts.ToolDefinition {
463467 Name : "TeamAutoSchedule" ,
464- Description : "Send a team objective to the coordinator and deterministically schedule it across running task members." ,
465- SearchHint : "auto schedule objective team coordinator members assignments" ,
468+ Description : "Send a team objective to the coordinator and schedule it across running task members." ,
469+ SearchHint : "auto schedule objective team coordinator model plan members assignments" ,
466470 ConcurrencySafe : false ,
467471 Strict : true ,
468472 InputSchema : contracts.JSONSchema {
@@ -471,11 +475,23 @@ func NewTeamAutoScheduleTool() tool.Tool {
471475 "properties" : map [string ]any {
472476 "team_id" : map [string ]any {"type" : "string" },
473477 "objective" : map [string ]any {"type" : "string" },
478+ "assignments" : map [string ]any {
479+ "type" : "array" ,
480+ "description" : "Optional coordinator/model-produced member plan. When omitted, deterministic assignments are generated for every member." ,
481+ "items" : map [string ]any {
482+ "type" : "object" ,
483+ "required" : []any {"task_id" , "message" },
484+ "properties" : map [string ]any {
485+ "task_id" : map [string ]any {"type" : "string" },
486+ "message" : map [string ]any {"type" : "string" },
487+ },
488+ },
489+ },
474490 },
475491 },
476492 },
477493 PromptFunc : func (tool.PromptContext ) (string , error ) {
478- return "Combines coordinator briefing and deterministic member scheduling for a subagent team. If the team has a coordinator, the objective is first appended to the running coordinator with team status context; then every running member receives an assignment message." , nil
494+ return "Combines coordinator briefing and member scheduling for a subagent team. If the team has a coordinator, the objective is first appended to the running coordinator with team status context. Provide assignments when a coordinator/model has produced a concrete member plan; otherwise every running member receives a deterministic assignment message." , nil
479495 },
480496 NormalizeFunc : normalizeTeamAutoScheduleInput ,
481497 ValidateFunc : validateTeamAutoSchedule ,
@@ -1045,7 +1061,7 @@ func validateTeamAutoSchedule(ctx tool.Context, raw json.RawMessage) error {
10451061 if err != nil {
10461062 return err
10471063 }
1048- taskIDs , err := teamScheduleTaskIDs (team )
1064+ taskIDs , err := teamAutoScheduleTaskIDs (team , input )
10491065 if err != nil {
10501066 return err
10511067 }
@@ -1892,13 +1908,17 @@ func callTeamAutoSchedule(ctx tool.Context, raw json.RawMessage, sink tool.Progr
18921908 if err != nil {
18931909 return contracts.ToolResult {}, err
18941910 }
1895- taskIDs , err := teamScheduleTaskIDs (team )
1911+ taskIDs , err := teamAutoScheduleTaskIDs (team , input )
18961912 if err != nil {
18971913 return contracts.ToolResult {}, err
18981914 }
18991915 if err := validateTaskIDsRunning (manager , taskIDs ); err != nil {
19001916 return contracts.ToolResult {}, err
19011917 }
1918+ scheduleSource := teamAutoScheduleSourceDeterministic
1919+ if len (input .Assignments ) > 0 {
1920+ scheduleSource = teamAutoScheduleSourceCoordinatorPlan
1921+ }
19021922 var coordinator session.SidechainState
19031923 if team .CoordinatorTaskID != "" {
19041924 coordinator , err = runningTeamCoordinatorState (manager , team )
@@ -1912,9 +1932,10 @@ func callTeamAutoSchedule(ctx tool.Context, raw json.RawMessage, sink tool.Progr
19121932 structured ["type" ] = "team_auto_schedule"
19131933 structured ["objective" ] = input .Objective
19141934 structured ["objective_chars" ] = len (input .Objective )
1935+ structured ["schedule_source" ] = scheduleSource
19151936 structured ["tasks" ] = tasks
19161937 if coordinator .ID != "" {
1917- briefing := formatTeamCoordinateMessage (team , tasks , input .Objective )
1938+ briefing := formatTeamAutoCoordinateMessage (team , tasks , input .Objective , input . Assignments )
19181939 message , err := appendTaskUserMessage (manager , ctx .SessionID , coordinator .ID , briefing , now )
19191940 if err != nil {
19201941 return contracts.ToolResult {}, err
@@ -1933,20 +1954,39 @@ func callTeamAutoSchedule(ctx tool.Context, raw json.RawMessage, sink tool.Progr
19331954 }
19341955 }
19351956 assignments := make ([]map [string ]any , 0 , len (taskIDs ))
1936- for i , taskID := range taskIDs {
1937- scheduleMessage := formatTeamScheduleMessage (team , tasks , input .Objective , taskID , i + 1 , len (taskIDs ))
1938- message , err := appendTaskUserMessage (manager , ctx .SessionID , taskID , scheduleMessage , now )
1939- if err != nil {
1940- return contracts.ToolResult {}, err
1957+ if len (input .Assignments ) > 0 {
1958+ for _ , assignment := range input .Assignments {
1959+ plannedMessage := formatTeamPlannedAssignmentMessage (team , input .Objective , assignment )
1960+ message , err := appendTaskUserMessage (manager , ctx .SessionID , assignment .TaskID , plannedMessage , now )
1961+ if err != nil {
1962+ return contracts.ToolResult {}, err
1963+ }
1964+ assignments = append (assignments , map [string ]any {
1965+ "task_id" : assignment .TaskID ,
1966+ "sidechain_id" : assignment .TaskID ,
1967+ "message_uuid" : string (message .UUID ),
1968+ "message_chars" : len (assignment .Message ),
1969+ "planned_message_chars" : len (plannedMessage ),
1970+ "schedule_source" : scheduleSource ,
1971+ })
1972+ }
1973+ } else {
1974+ for i , taskID := range taskIDs {
1975+ scheduleMessage := formatTeamScheduleMessage (team , tasks , input .Objective , taskID , i + 1 , len (taskIDs ))
1976+ message , err := appendTaskUserMessage (manager , ctx .SessionID , taskID , scheduleMessage , now )
1977+ if err != nil {
1978+ return contracts.ToolResult {}, err
1979+ }
1980+ assignments = append (assignments , map [string ]any {
1981+ "task_id" : taskID ,
1982+ "sidechain_id" : taskID ,
1983+ "member_index" : i + 1 ,
1984+ "member_count" : len (taskIDs ),
1985+ "message_uuid" : string (message .UUID ),
1986+ "message_chars" : len (scheduleMessage ),
1987+ "schedule_source" : scheduleSource ,
1988+ })
19411989 }
1942- assignments = append (assignments , map [string ]any {
1943- "task_id" : taskID ,
1944- "sidechain_id" : taskID ,
1945- "member_index" : i + 1 ,
1946- "member_count" : len (taskIDs ),
1947- "message_uuid" : string (message .UUID ),
1948- "message_chars" : len (scheduleMessage ),
1949- })
19501990 }
19511991 structured ["assignment_count" ] = len (assignments )
19521992 structured ["assignments" ] = assignments
@@ -1957,9 +1997,10 @@ func callTeamAutoSchedule(ctx tool.Context, raw json.RawMessage, sink tool.Progr
19571997 "has_coordinator" : coordinator .ID != "" ,
19581998 "coordinator_task_id" : coordinator .ID ,
19591999 "objective_chars" : len (input .Objective ),
2000+ "schedule_source" : scheduleSource ,
19602001 })
19612002 return contracts.ToolResult {
1962- Content : fmt .Sprintf ("Auto-scheduled %d assignment(s) in team %s." , len (assignments ), team .ID ),
2003+ Content : fmt .Sprintf ("Auto-scheduled %d assignment(s) in team %s using %s ." , len (assignments ), team .ID , scheduleSource ),
19632004 StructuredContent : structured ,
19642005 }, nil
19652006}
@@ -2623,6 +2664,10 @@ func decodeTeamAutoScheduleInput(raw json.RawMessage) (teamAutoScheduleInput, er
26232664 }
26242665 input .TeamID = strings .TrimSpace (input .TeamID )
26252666 input .Objective = strings .TrimSpace (input .Objective )
2667+ for i := range input .Assignments {
2668+ input .Assignments [i ].TaskID = sanitizeTaskLikeID (input .Assignments [i ].TaskID )
2669+ input .Assignments [i ].Message = strings .TrimSpace (input .Assignments [i ].Message )
2670+ }
26262671 return input , nil
26272672}
26282673
@@ -2900,7 +2945,28 @@ func normalizeTeamScheduleInput(raw json.RawMessage) (json.RawMessage, error) {
29002945}
29012946
29022947func normalizeTeamAutoScheduleInput (raw json.RawMessage ) (json.RawMessage , error ) {
2903- return normalizeTeamScheduleInput (raw )
2948+ obj , err := decodeRawTaskObject (raw )
2949+ if err != nil {
2950+ return nil , err
2951+ }
2952+ for key := range obj {
2953+ switch key {
2954+ case "team_id" , "teamId" , "id" , "name" , "objective" , "message" , "text" , "content" , "prompt" , "input" , "instruction" , "request" , "goal" , "assignments" , "tasks" , "dispatches" , "plan" , "member_assignments" , "memberAssignments" , "messages" :
2955+ default :
2956+ return nil , fmt .Errorf ("input.%s is not allowed" , key )
2957+ }
2958+ }
2959+ normalized := map [string ]json.RawMessage {}
2960+ if value , ok := firstRawTaskField (obj , "team_id" , "teamId" , "id" , "name" ); ok {
2961+ normalized ["team_id" ] = value
2962+ }
2963+ if value , ok := firstRawTaskField (obj , "objective" , "message" , "text" , "content" , "prompt" , "input" , "instruction" , "request" , "goal" ); ok {
2964+ normalized ["objective" ] = value
2965+ }
2966+ if value , ok := firstRawTaskField (obj , "assignments" , "tasks" , "dispatches" , "plan" , "member_assignments" , "memberAssignments" , "messages" ); ok {
2967+ normalized ["assignments" ] = value
2968+ }
2969+ return json .Marshal (normalized )
29042970}
29052971
29062972func normalizeTeamCoordinateInput (raw json.RawMessage ) (json.RawMessage , error ) {
@@ -3393,6 +3459,16 @@ func teamDispatchTaskIDs(team session.TeamState, assignments []teamDispatchAssig
33933459 return taskIDs , nil
33943460}
33953461
3462+ func teamAutoScheduleTaskIDs (team session.TeamState , input teamAutoScheduleInput ) ([]string , error ) {
3463+ if len (input .Assignments ) == 0 {
3464+ return teamScheduleTaskIDs (team )
3465+ }
3466+ if len (input .Assignments ) > 32 {
3467+ return nil , fmt .Errorf ("assignments must include <= 32 items" )
3468+ }
3469+ return teamDispatchTaskIDs (team , input .Assignments )
3470+ }
3471+
33963472func teamScheduleTaskIDs (team session.TeamState ) ([]string , error ) {
33973473 if len (team .TaskIDs ) == 0 {
33983474 return nil , fmt .Errorf ("team %s has no tasks" , team .ID )
@@ -3681,6 +3757,20 @@ func formatTeamCoordinateMessage(team session.TeamState, tasks []map[string]any,
36813757 return builder .String ()
36823758}
36833759
3760+ func formatTeamAutoCoordinateMessage (team session.TeamState , tasks []map [string ]any , objective string , assignments []teamDispatchAssignmentInput ) string {
3761+ briefing := formatTeamCoordinateMessage (team , tasks , objective )
3762+ if len (assignments ) == 0 {
3763+ return briefing
3764+ }
3765+ var builder strings.Builder
3766+ builder .WriteString (briefing )
3767+ builder .WriteString ("\n Planned assignments:" )
3768+ for _ , assignment := range assignments {
3769+ fmt .Fprintf (& builder , "\n - %s: %s" , assignment .TaskID , assignment .Message )
3770+ }
3771+ return builder .String ()
3772+ }
3773+
36843774func formatTeamScheduleMessage (team session.TeamState , tasks []map [string ]any , objective string , taskID string , index int , total int ) string {
36853775 var builder strings.Builder
36863776 fmt .Fprintf (& builder , "Team scheduled assignment for %s." , team .ID )
@@ -3708,6 +3798,20 @@ func formatTeamScheduleMessage(team session.TeamState, tasks []map[string]any, o
37083798 return builder .String ()
37093799}
37103800
3801+ func formatTeamPlannedAssignmentMessage (team session.TeamState , objective string , assignment teamDispatchAssignmentInput ) string {
3802+ var builder strings.Builder
3803+ fmt .Fprintf (& builder , "Team planned assignment for %s." , team .ID )
3804+ if team .Description != "" {
3805+ fmt .Fprintf (& builder , "\n Description: %s" , team .Description )
3806+ }
3807+ builder .WriteString ("\n Objective:\n " )
3808+ builder .WriteString (objective )
3809+ builder .WriteString ("\n Assignment:\n " )
3810+ builder .WriteString (assignment .Message )
3811+ builder .WriteString ("\n Instruction:\n Execute this coordinator/model plan for your assigned scope. Use team communication tools when coordination is needed." )
3812+ return builder .String ()
3813+ }
3814+
37113815func formatTeamDispatchMessage (team session.TeamState , assignment teamDispatchAssignmentInput ) string {
37123816 var builder strings.Builder
37133817 fmt .Fprintf (& builder , "Team dispatch assignment for %s." , team .ID )
0 commit comments