Skip to content

feat(team-mode): team_read_messages pull tool + top-level team_create args#5463

Open
harshav167 wants to merge 2 commits into
code-yeongyu:devfrom
harshav167:feat/team-mode-messaging
Open

feat(team-mode): team_read_messages pull tool + top-level team_create args#5463
harshav167 wants to merge 2 commits into
code-yeongyu:devfrom
harshav167:feat/team-mode-messaging

Conversation

@harshav167

@harshav167 harshav167 commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds team_read_messages so a team lead can pull its own inbox bodies on demand — the biggest team-mode blocker was that team_status exposes only unread COUNTS and the injector only surfaces messages passively on the lead's next turn (and consumes them).
  • Makes team_create accept the natural top-level { name, members } shape (folded into inline_spec), so agents stop hitting "exactly one of teamName or inline_spec" on the obvious call.

Changes

  • team_read_messages({ teamRunId, sinceId?, mark_read? }) (new team tool, gated on team_mode.enabled): resolves the caller's member identity via resolveTeamRuntimeDetails (same path as team_send_message), reads its inbox via the existing listUnreadMessages oldest-first, optional sinceId returns only messages after that id, and by default acks read messages via ackMessages so they are not re-injected (mark_read:false to peek). Registered in tool-registry-team-tools.ts, tool-registry-factories.ts, and the tools barrel. The injector path is untouched.
  • team_create top-level coercion: fold top-level spec fields (name/members/…) into inline_spec during arg preprocess when neither teamName nor inline_spec is supplied (leadSessionId preserved). Tool description + usage string updated to advertise all three shapes.

Testing

bun run typecheck   # 0 errors (tsgo, all packages)
bun test            # touched suites green; the 22 failing are pre-existing env failures
                    # (codex-installer / dist-bundle node-load) unrelated to this change
  • read-messages.test.ts (4): bodies oldest-first + ack, sinceId filter, mark_read:false peek, empty inbox.
  • lifecycle-top-level-args.test.ts (5): top-level coercion, leadSessionId preserved, inline_spec untouched, teamName path, empty still errors.
  • Team-mode tool regression: 80/80. Registration verified by direct record build — createTeamModeToolsRecord returns 13 tools including team_read_messages.
  • Isolated-XDG opencode boot; real ~/.local/share/opencode/opencode.db session count unchanged.

Related Issues

Team-mode tooling friction observed in a real hyperplan run:

Scoped to follow-up PRs (not here): #8/#2 (broadcast wakes idle members) and #5 (idle-wake determinism) touch the prompt-async-gate / live-delivery path and need their own PR with the mandatory duplicate-injection regression tests; #7 (list_models cold-cache) belongs on the per-call-model-override branch where list_models lives; #6 (filename ambiguity) is a hyperplan-skill prompt tweak.


Summary by cubic

Adds a team_read_messages tool for on-demand inbox reads, and lets team_create accept top-level name and members. This gives leads access to message bodies and removes a common arg mismatch.

  • New Features
    • team_read_messages({ teamRunId, sinceId?, mark_read? }): returns the caller’s unread messages oldest-first, optionally after sinceId. Marks them read by default; set mark_read:false to peek. Gated by team mode; injector path unchanged.
    • team_create: accepts top-level name and members and folds them into inline_spec automatically. Preserves leadSessionId. Tool description and usage updated.

Written for commit 7c71765. Summary will update on new commits.

Review in cubic

The lead could only see unread COUNTS via team_status; message BODIES were
only surfaced passively by the mailbox injector on the lead's next turn (and
consumed there). When the lead was busy or timing was off, member reports
piled up unread with no way to drain them, forcing a file side-channel.

Add team_read_messages({ teamRunId, sinceId?, mark_read? }): resolves the
caller's member identity (same path as team_send_message), reads its inbox
bodies via listUnreadMessages oldest-first, optionally filters after sinceId,
and by default acks them via ackMessages so they are not re-injected
(mark_read:false to peek). Additive and gated on team_mode.enabled; the
injector path is untouched.

Tests: read-messages.test.ts (bodies+ack, sinceId, peek, empty). Team record
now exposes 13 tools including team_read_messages; typecheck clean.
…-yeongyu#1)

The team_create tool advertises the inline member shape, so agents routinely
call it with the spec fields (name + members) at the top level and get
rejected with "exactly one of teamName or inline_spec", costing a failed call
every run. Fold top-level spec fields into inline_spec during arg preprocess
(leadSessionId preserved), and document the accepted shape in the tool
description and usage string. The documented teamName / inline_spec envelopes
are unchanged.

Test: lifecycle-top-level-args.test.ts (top-level coercion, leadSessionId
preserved, inline_spec untouched, teamName path, empty still errors).
@github-actions github-actions Bot added the opencode OpenCode edition: packages/omo-opencode label Jun 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

opencode OpenCode edition: packages/omo-opencode

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant