Define the conversation
Use the installed runtime package in your own TypeScript file. The complete source below uses local functions for the writer and reviewer, so it needs no model account. It writes a temporary record, reopens it within the program and removes its temporary files before exit.initialTurn is false:
mentions
contains member IDs; the runtime does not look for names in the text:
writer,
which gives the writer another turn with that reply. The example checks
that the writer’s final answer contains the reply before it prints success.
Output
The saved messages, dispatch order and final answers come from the run’s record and result. The fresh executor adds no events when it reads the completed conversation. This is an offline demonstration that reopens storage within one program, not a command that leaves a record behind or resumes across separate invocations.Gotchas
- A message sends when the turn ends. It is saved with the member’s successful result, not while an engine is still speaking. A member that needs an answer ends its turn. The reply queues it again. A failed or unfinished turn sends nothing.
- A mention waits for active work. It requests a later turn; it never interrupts one already running. The active batch settles before another batch starts. Several pending mentions for the same member share one queued turn and keep their triggering messages.
- The conversation has limits. Set a turn cap for each member and a
message-tail limit for its input. A requested turn beyond the cap fails
with
TEAM_TURN_LIMIT, not a successful answer. The host’s ordinary input and output byte limits also apply. - Room membership is not a filesystem sandbox. It controls accepted posts and the input supplied to each member. The operator’s full record contains every room. Keep that record and the room-file directory outside member workspaces and use the host’s access controls. Processes sharing unrestricted filesystem access can read the same files.
- Choose the execution path explicitly.
team(config)is a callable job with its own workspace and review behavior. The compiledteamGraphTypeuses the stored graph executor and host bindings. It does not create or merge worktrees or run callable review functions for you. A team result is not proof that a merge or review happened. See the callable team contract.
Team fields
teamGraphType is the workflow shape passed to compileGraph.
TeamDefinition contains an id, a definitionVersion, team data,
member nodes and an empty edges array. Messages request turns; edges do
not connect members.
Team data
All three limits, including
tailMessages below, must be positive safe
integers. The member count multiplied by maxTurnsPerMember must also be a
safe integer.
Members
Each node’sid is the member’s address. Its data is a TeamNodeData value:
Rooms
TeamCommunication.rooms is a list of TeamRoom values. Each room has a
unique id and a members list of distinct node IDs. List every member for
a run-wide room, one team’s members for a team room, or two members for a
direct message. Membership is part of the saved definition; a member cannot
change it during the run.
TeamCommunication.tailMessages sets how many recent messages from each
permitted room enter a member’s next input. A pending message that requested
the turn is included even when it falls outside that tail. Messages present
in both groups appear once, in saved order. The tail limit is therefore not
a limit on all messages in an input; the input-byte budget still applies.
Turn results
Every successful member result is aTeamTurnResult:
A
TeamPost has roomId, text and mentions. The sender must belong to
the room, and every mentioned member must belong to that same room. Every
post is checked before any post from that turn is accepted.
Invalid result content fails the turn with RESULT_INVALID before a completion
is saved. The team returns TEAM_NODE_FAILED after active turns settle. If an
invalid completion is already in the record, replay retains that failure and
the earlier valid results and messages. It delivers none of the bad turn’s
posts, and room files can still be rebuilt from accepted messages. Malformed
event records and unsupported event versions are rejected. The example also
binds a result contract that reuses the compiled form’s membership check.
A saved TeamMessage retains those three fields and adds sender,
position and id. The runtime obtains the sender from the completed node.
The message ID combines the dispatch position with the post’s zero-based
index.
Each next-turn input contains task, role, brief, result and
messages. result is this member’s preceding result, or null on its
first turn. It is not the whole team’s result. A member receives messages
only from rooms it belongs to.
Final answers
Successful execution returns aTeamGraphResult in the executor outcome’s
output: the task and an agents list in member declaration order. Each
entry contains name, role and that member’s last result. A member that
never receives a turn has result: null.
After active turns settle, TEAM_NODE_FAILED reports any failed member,
even when another member is paused. Without a failed member, a paused member
keeps the run paused until the host uses the executor’s existing resume
contract. TEAM_TURN_LIMIT reports a queued member whose turn cap is exhausted.
Room files
projectTeamRooms reads a saved team run and rebuilds its room files.
Supply the run’s storage, its runId and the operator’s output
directory. The result contains the last read revision and a list of
{ roomId, path } entries. Use that list to find each file; do not construct
its filename from the room name.
Each file contains one readable line per accepted message: sender, message
ID, mentions, a colon and the text. An empty room has an empty file. A run
without communication returns no files. Newlines and terminal control
characters are printed as escapes. People and tools can tail these files
like an ordinary text chat.
The helper changes no stored events. A rebuild replaces its own files and
leaves unrelated files alone. Each file replacement is atomic; the set of
room files is not replaced as one operation. The returned revision says
what was read, not that the run stopped changing during the write. Deleting
a room file does not delete its messages from the record.
Source
Copy this complete file into a TypeScript project with@obversa/runtime installed.
Complete team-conversation.ts
Complete team-conversation.ts