diff --git a/cmd/gateway_consumer_handlers.go b/cmd/gateway_consumer_handlers.go index a7af7db6..179e9f1e 100644 --- a/cmd/gateway_consumer_handlers.go +++ b/cmd/gateway_consumer_handlers.go @@ -661,7 +661,7 @@ func handleTeammateMessage( announceContent += "\n\nPresent this result to the user. Any media files are forwarded automatically. Do NOT search for files — the result above contains all relevant information." // Append team workspace path so lead can locate files without searching. if ws := inMeta["team_workspace"]; ws != "" { - announceContent += fmt.Sprintf("\n[Team workspace: %s — use workspace_read to read files, e.g. workspace_read(file_name=\"filename.md\")]", ws) + announceContent += fmt.Sprintf("\n[Team workspace: %s — use read_file/list_files to access shared files, e.g. list_files(path=\".\") then read_file(path=\"filename.md\")]", ws) } // Route to the lead's session on the original channel/chat. diff --git a/internal/store/pg/teams_tasks.go b/internal/store/pg/teams_tasks.go index 857db928..0854654a 100644 --- a/internal/store/pg/teams_tasks.go +++ b/internal/store/pg/teams_tasks.go @@ -32,7 +32,7 @@ const taskJoinClause = `FROM team_tasks t LEFT JOIN agents ca ON ca.id = t.created_by_agent_id` // maxListTasksRows caps ListTasks results to prevent unbounded queries. -const maxListTasksRows = 50 +const maxListTasksRows = 30 // ============================================================ // Scopes @@ -169,14 +169,15 @@ func (s *PGTeamStore) ListTasks(ctx context.Context, teamID uuid.UUID, orderBy s orderClause = "t.created_at DESC" } - statusWhere := "AND t.status NOT IN ('completed','cancelled')" // default: active only + statusWhere := "" // default: all statuses (no filter) switch statusFilter { - case store.TeamTaskFilterAll: - statusWhere = "" + case store.TeamTaskFilterActive: + statusWhere = "AND t.status NOT IN ('completed','cancelled')" case store.TeamTaskFilterInReview: statusWhere = "AND t.status = 'in_review'" case store.TeamTaskFilterCompleted: statusWhere = "AND t.status IN ('completed','cancelled')" + // "", store.TeamTaskFilterAll ("all") → no filter (all statuses) } // Scope filter: always bind $4/$5 but only enforce when non-empty. diff --git a/internal/store/team_store.go b/internal/store/team_store.go index e60746aa..53c9297d 100644 --- a/internal/store/team_store.go +++ b/internal/store/team_store.go @@ -42,10 +42,10 @@ const ( // Team task list filter constants (for ListTasks statusFilter parameter). const ( - TeamTaskFilterActive = "" // default: pending + in_progress + blocked + TeamTaskFilterActive = "active" // pending + in_progress + blocked TeamTaskFilterInReview = "in_review" // only in_review tasks TeamTaskFilterCompleted = "completed" // only completed tasks - TeamTaskFilterAll = "all" // all statuses + TeamTaskFilterAll = "all" // all statuses (default when "" passed) ) // Team message type constants. diff --git a/internal/tools/team_message_tool.go b/internal/tools/team_message_tool.go index e1e13f27..c1a28a06 100644 --- a/internal/tools/team_message_tool.go +++ b/internal/tools/team_message_tool.go @@ -337,7 +337,7 @@ func (t *TeamMessageTool) publishTeammateMessage(fromKey, toKey, text string, me teamMeta["team_task_id"] = teamTaskID.String() } // Pass team workspace so the receiving agent can access shared files. - if ws, err := workspaceDir(t.manager.dataDir, teamID, "", chatID); err == nil { + if ws, err := WorkspaceDir(t.manager.dataDir, teamID, chatID); err == nil { teamMeta["team_workspace"] = ws } // Propagate trace context so the receiving agent's trace links back. diff --git a/internal/tools/team_tasks_mutations.go b/internal/tools/team_tasks_mutations.go index aae16c7e..3b4aa477 100644 --- a/internal/tools/team_tasks_mutations.go +++ b/internal/tools/team_tasks_mutations.go @@ -109,9 +109,9 @@ func (t *TeamTasksTool) executeCreate(ctx context.Context, args map[string]any) // Compute the team workspace directory so member agents write files to the // shared team folder (teams/{teamID}/{chatID}/) instead of their own personal workspace. - // This aligns write_file/create_image with workspace_read/workspace_write paths. + // WorkspaceInterceptor redirects write_file/create_image to this path automatically. taskMeta := make(map[string]any) - if teamWsDir, err := workspaceDir(t.manager.dataDir, team.ID, "", chatID); err == nil { + if teamWsDir, err := WorkspaceDir(t.manager.dataDir, team.ID, chatID); err == nil { taskMeta["team_workspace"] = teamWsDir } // Preserve original blocked_by list for blocker-result forwarding when task unblocks. diff --git a/internal/tools/team_tasks_read.go b/internal/tools/team_tasks_read.go index 094e914f..626390a7 100644 --- a/internal/tools/team_tasks_read.go +++ b/internal/tools/team_tasks_read.go @@ -12,7 +12,7 @@ import ( "github.com/nextlevelbuilder/goclaw/internal/store" ) -const listPageSize = 50 +const listPageSize = 30 // blockerSummary is a compact view of a blocker task for blocked_by resolution. type blockerSummary struct { diff --git a/internal/tools/team_tasks_tool.go b/internal/tools/team_tasks_tool.go index afc0eea7..4abacc1d 100644 --- a/internal/tools/team_tasks_tool.go +++ b/internal/tools/team_tasks_tool.go @@ -54,7 +54,7 @@ func (t *TeamTasksTool) Parameters() map[string]any { }, "status": map[string]any{ "type": "string", - "description": "Filter for list: '' (active, default), 'completed', 'all'", + "description": "Filter for list: '' (all, default), 'active', 'completed', 'in_review'", }, "query": map[string]any{ "type": "string", @@ -87,7 +87,7 @@ func (t *TeamTasksTool) Parameters() map[string]any { }, "page": map[string]any{ "type": "number", - "description": "Page number for list/search (default 1, 50 per page)", + "description": "Page number for list/search (default 1, 30 per page)", }, }, "required": []string{"action"}, diff --git a/internal/tools/team_tool_dispatch.go b/internal/tools/team_tool_dispatch.go index b12ad8f2..9db763dd 100644 --- a/internal/tools/team_tool_dispatch.go +++ b/internal/tools/team_tool_dispatch.go @@ -67,7 +67,7 @@ func (m *TeamToolManager) dispatchTaskToAgent(ctx context.Context, task *store.T } // Hint: tell the agent it's on a team task and where the shared workspace is. if ws := taskTeamWorkspace(task); ws != "" { - content += fmt.Sprintf("\n\n[Team workspace: %s — all files you create will be saved here, accessible by the team lead and other members via workspace_read.]", ws) + content += fmt.Sprintf("\n\n[Team workspace: %s — use read_file/write_file/list_files to access shared files. All files you write are visible to the team lead and other members.]", ws) } // Use task's stored channel/chat as primary source for routing.