feat(sdk): pod-runtime L5 — multi-agent collaboration primitives#55
Merged
Conversation
Land the four high-priority L5 items from docs/sdk-pod-runtime-gaps.md
that close the remaining surface gaps in the multi-agent collaboration
layer. Each item was scoped down from the original RFC during review to
keep the change set incremental and avoid over-design.
kanban: Call(ctx, opts) sync sugar
- Subscribe to the board BEFORE Submit so a fast executor cannot race
past the watcher and miss the terminal transition.
- Returns CallResult{CardID, Status, Output, Error, ElapsedMs}; Done
→ nil, Failed → errdefs.Internal, Cancelled → errdefs.Aborted.
- ctx cancel triggers a best-effort Cancel via context.WithoutCancel
and returns ctx.Err() so callers retain standard ctx semantics.
kanban: Cancel + CardCancelled
- New terminal status distinct from CardFailed so failure-rate metrics
stay honest when a Pod controller stops in-flight work.
- Board.Cancel(id, reason) state machine: Pending/Claimed → Cancelled
only; emits EventTaskCancelled + TaskCancelledPayload on Bus().
- Kanban.Cancel(ctx, id, reason) wrapper with NotFound / Conflict
classifications and a kanban.tasks.cancelled.total counter.
- Eviction, callback rendering, and subject helpers updated to treat
Cancelled as a first-class terminal alongside Done / Failed.
history: LoadOptions filter
- New LoadOptions{Budget, Roles, SinceSeq, LimitN, IncludeTools};
SinceSeq is a position cutoff because model.Message has no
timestamp — callers needing a wall-clock anchor look up the
sequence index in their own audit log first.
- Optional FilterableHistory sub-interface keeps the History
interface non-breaking; LoadFiltered() helper picks the most
efficient path automatically.
- ApplyLoadOptions in-memory pass strips RoleTool messages and
PartToolCall / PartToolResult parts when IncludeTools=false (the
default for moderation / inspection use cases).
- buffer + compactor implement FilterableHistory via the shared
helper.
graph/runner: stream.delta SPI promotion
- engine.EmitStreamToken / EmitStreamToolCall / EmitStreamToolResult
/ EmitStreamDelta package the SubjectStreamDelta envelope
construction + header stamping + per-Type field validation so any
node — not just LLM nodes — can publish in-flight increments
without re-implementing the boilerplate.
- Malformed deltas are caught at emit time instead of silently
flowing to subscribers.
- engine and graph/runner package docs explain the two paths
(graph.StreamPublisher.Emit vs direct EmitStream*) and that both
land on the same SubjectStreamDelta channel.
Tests: 18 new cases across kanban / history / engine; full make vet +
make test pass on sdk, sdkx, voice, bench, examples, tools/conformance.
Made-with: Cursor
…board_test.go Restore the test-file consolidation that was accidentally reverted while amending the L5 commit. The concurrency and restore suites belong with the rest of the Board tests; keeping them in dedicated files added an extra layer of indirection without organisational benefit. No production-code changes. Made-with: Cursor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Lands the four high-priority L5 items from
docs/sdk-pod-runtime-gaps.mdthat close the remaining surface gaps in the multi-agent collaboration
layer. Each item was scoped down from the original RFC during review to
keep the change set incremental and avoid over-design.
kanban:Call(ctx, opts)synchronous sugarSubmitso a fast executor cannotrace past the watcher and miss the terminal transition.
CallResult{CardID, Status, Output, Error, ElapsedMs};CardDone → nil,CardFailed → errdefs.Internal,CardCancelled → errdefs.Aborted.ctxcancel triggers a best-effortCancelviacontext.WithoutCanceland returnsctx.Err(), preserving standardcontext semantics for callers.
kanban:Cancel+CardCancelledterminal statusCardFailedso failure-ratedashboards stay honest when a Pod controller stops in-flight work.
Board.Cancel(id, reason)state machine:Pending/Claimed → Cancelledonly; emitsEventTaskCancelled+TaskCancelledPayloadon
Bus().Kanban.Cancel(ctx, id, reason)wrapper withNotFound/Conflictclassifications and a new
kanban.tasks.cancelled.totalcounter.Cancelledas a first-class terminal alongsideDone/Failed.history:LoadOptionsfilterLoadOptions{Budget, Roles, SinceSeq, LimitN, IncludeTools}.SinceSeqis a position cutoff becausemodel.Messagecarries nowall-clock timestamp — callers needing a time anchor look up the
sequence index in their own audit log first.
FilterableHistorysub-interface keeps theHistoryinterface non-breaking;
LoadFiltered()helper picks the mostefficient path automatically.
ApplyLoadOptionsin-memory pass stripsRoleToolmessages andPartToolCall/PartToolResultparts whenIncludeTools=false(the default for moderation / inspection use cases). Pure tool-call
assistant turns become empty after stripping and are dropped.
buffer+compactorboth implementFilterableHistoryvia theshared helper.
graph/runner:stream.deltaSPI promotionengine.EmitStreamToken/EmitStreamToolCall/EmitStreamToolResult/EmitStreamDeltapackage theSubjectStreamDeltaenvelope construction + header stamping +per-
Typefield validation so any node — not just LLM nodes — canpublish in-flight increments without re-implementing the
boilerplate.
to subscribers.
engineandgraph/runnerpackage docs explain the two paths(
graph.StreamPublisher.Emitvs directEmitStream*) and that bothland on the same
SubjectStreamDeltachannel.Test plan
make vet— sdk, sdkx, voice, bench, examples, tools/conformancemake test— sdk, sdkx, voice, bench, examples, tools/conformancesdk/kanban/call_cancel_test.go:Callhappy path / failed /ctx-cancel;
Cancelstate machine;Board.Cancelevent publish.sdk/history/load_options_test.go: zero-opts no-op, role filter,SinceSeqcutoff,LimitNtail-bias, tool stripping behaviour,IncludeTools=true,FilterableHistoryfallback.sdk/engine/stream_emit_test.go: token happy path,tool_call/result required-field validation, nil-publisher no-op,
empty-
Typerejection, forward-compatibleTypeacceptance.Made with Cursor