Skip to content

Add Go M0 runtime provider contracts#50

Merged
Vasanthdev2004 merged 2 commits into
mainfrom
feat/go-m0-runtime-contracts
Jun 4, 2026
Merged

Add Go M0 runtime provider contracts#50
Vasanthdev2004 merged 2 commits into
mainfrom
feat/go-m0-runtime-contracts

Conversation

@anandh8x

@anandh8x anandh8x commented Jun 4, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • add a small Go runtime contract package for provider messages, tool calls, stream events, usage, and completion requests
  • define the first Provider interface for streaming completion events with context cancellation
  • add SeedMessages and CollectStream helpers plus mock-provider contract tests

Scope

This intentionally does not implement an OpenAI/Anthropic/Gemini provider, model registry, CLI behavior, or stream-json protocol. It is a narrow M0 contract skeleton for Gnanam to extend.

Testing

  • bun run test:go
  • bun run build:go
  • bun run smoke:go
  • bun run typecheck
  • bun test tests/foundation-tools.test.ts --timeout 15000
  • git diff --check

Local note

  • Full local bun run test still has 5 unrelated pre-existing local failures in headless-exec/MCP tests; Go contract tests pass and CI should verify the full matrix.

Summary by CodeRabbit

  • New Features

    • Real-time streaming completions with structured tool-call support and ordered tool-call reconstruction.
    • Message role system (system/user/assistant/tool) for clearer conversation context.
    • Token usage tracking with total token summaries.
    • Convenience helpers to seed requests with system+user turns and to collect streamed events.
  • Tests

    • Expanded tests covering message seeding, streaming accumulation, tool-call flushing, error and cancellation handling.

@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Zero automated PR review

Verdict: No blockers found

Blockers

  • None found.

Validation

  • [pass] Diff hygiene: git diff --check
  • [pass] Typecheck: bun run typecheck
  • [pass] Tests: bun run test
  • [pass] Build: bun run build
  • [pass] Smoke build: bun run smoke:build

Scope

Head: 48954cc5c263
Changed files (3): internal/zeroruntime/helpers.go, internal/zeroruntime/provider_test.go, internal/zeroruntime/types.go

This deterministic review checks validation status and basic diff hygiene. A human reviewer still owns product judgment and design quality.

@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

This PR establishes the foundational streaming API for Zero Runtime: core types (messages, tool calls, usage), the Provider interface contract, stream collection helpers, and tests validating the complete flow.

Changes

Zero Runtime Streaming Infrastructure

Layer / File(s) Summary
Core types and Provider interface
internal/zeroruntime/types.go
Defines MessageRole and StreamEventType enums, ToolCall, Message (with optional tool fields), ToolDefinition, Usage (with TotalTokens method), StreamEvent (carrying typed event content), CompletionRequest, and Provider interface exposing StreamCompletion(ctx, request) to stream completion events.
Stream collection and message seeding
internal/zeroruntime/helpers.go
Implements CollectedStream accumulator, SeedMessages(system,user) to initialize system+user messages, and CollectStream(ctx, events) to consume a StreamEvent channel, concatenate text fragments, rebuild tool-call arguments from start/delta/end events while preserving start order, accumulate token counts, and flush pending calls on done/error/ctx cancellation/channel close.
Provider mock and comprehensive tests
internal/zeroruntime/provider_test.go
Adds mockProvider test double that streams preset events and tests: SeedMessages ordering; CollectStream aggregation of text, tool-calls, and usage; flush-on-channel-close; flush-on-context-cancel; error surfacing while flushing open tool calls; and Provider interface conformance end-to-end.

🎯 3 (Moderate) | ⏱️ ~20 minutes

Sequence Diagram

sequenceDiagram
  participant Client
  participant Provider
  participant EventsChannel
  participant CollectStream
  Client->>Provider: StreamCompletion(ctx, CompletionRequest)
  Provider->>EventsChannel: send StreamEvent(s)
  CollectStream->>EventsChannel: read StreamEvent(s)
  CollectStream->>CollectStream: aggregate text, usage, tool-call fragments
  CollectStream->>Client: return CollectedStream
Loading

Suggested Reviewers

  • Vasanthdev2004
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding a Go M0 runtime provider contract package with core types and interfaces.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/go-m0-runtime-contracts

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
internal/zeroruntime/provider_test.go (1)

44-76: ⚡ Quick win

Add edge-case tests for non-happy stream termination.

Please add cases for: (1) channel close before StreamEventDone with an open tool call, (2) context cancellation with pending deltas, and (3) StreamEventError handling once surfaced by CollectStream.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/zeroruntime/provider_test.go` around lines 44 - 76, Add three new
tests alongside TestCollectStreamAccumulatesTextToolCallsAndUsage that exercise
CollectStream for non-happy paths: (1) "channel closed before StreamEventDone
with an open tool call" — create events that send StreamEventToolCallStart and
some ToolCallDelta fragments then close the events channel without sending
StreamEventToolCallEnd/StreamEventDone and assert CollectStream returns (does
not hang) and includes the accumulated tool call (ID ToolCallID "call_..." with
concatenated Arguments) in collected.ToolCalls; (2) "context cancellation with
pending deltas" — start a goroutine that emits a start and some ToolCallDelta
fragments, cancel the context before sending ToolCallEnd, call CollectStream
with that context and assert it returns promptly and either includes the partial
tool call or records no incomplete state per current CollectStream semantics
(assert whichever behavior is expected); (3) "StreamEventError is surfaced" —
send a StreamEvent{Type: StreamEventError, /* set error details */} and ensure
CollectStream surfaces/returns that error (or sets an error field) instead of
hanging; use the same StreamEvent constants (StreamEventToolCallStart,
StreamEventToolCallDelta, StreamEventToolCallEnd, StreamEventDone,
StreamEventError) and CollectStream to locate the code under test.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/zeroruntime/helpers.go`:
- Around line 25-30: The loop exits on ctx.Done() and when events is closed
without flushing partially collected tool calls; ensure any pending calls in the
local collected slice are finalized on all exit paths (ctx.Done, !ok from
events, and other returns) similar to how StreamEventDone is handled. Update the
event-processing function (the loop that reads from events and uses collected
and StreamEventDone) to call the same flush/finalize logic for collected before
returning in those branches so no open tool calls are dropped.
- Around line 32-57: The switch currently ignores StreamEventError events; add
an explicit case for StreamEventError in the same switch that records the event
error into the collected result (e.g., set a collected.Error or
collected.ErrorMessage field — add that field to the Collected type if it
doesn't exist), ensure any open tool calls are appended by calling
appendOpenToolCalls(&collected, toolCallOrder, pendingToolCalls), and then
return collected (so the caller can distinguish a failed stream from partial
success); reference symbols: StreamEventError, collected, appendOpenToolCalls,
pendingToolCalls, toolCallOrder, and the event variable in the switch.

---

Nitpick comments:
In `@internal/zeroruntime/provider_test.go`:
- Around line 44-76: Add three new tests alongside
TestCollectStreamAccumulatesTextToolCallsAndUsage that exercise CollectStream
for non-happy paths: (1) "channel closed before StreamEventDone with an open
tool call" — create events that send StreamEventToolCallStart and some
ToolCallDelta fragments then close the events channel without sending
StreamEventToolCallEnd/StreamEventDone and assert CollectStream returns (does
not hang) and includes the accumulated tool call (ID ToolCallID "call_..." with
concatenated Arguments) in collected.ToolCalls; (2) "context cancellation with
pending deltas" — start a goroutine that emits a start and some ToolCallDelta
fragments, cancel the context before sending ToolCallEnd, call CollectStream
with that context and assert it returns promptly and either includes the partial
tool call or records no incomplete state per current CollectStream semantics
(assert whichever behavior is expected); (3) "StreamEventError is surfaced" —
send a StreamEvent{Type: StreamEventError, /* set error details */} and ensure
CollectStream surfaces/returns that error (or sets an error field) instead of
hanging; use the same StreamEvent constants (StreamEventToolCallStart,
StreamEventToolCallDelta, StreamEventToolCallEnd, StreamEventDone,
StreamEventError) and CollectStream to locate the code under test.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 92f354d2-0801-4d8c-883e-0cacc8a944a1

📥 Commits

Reviewing files that changed from the base of the PR and between af1d292 and d7e11fb.

📒 Files selected for processing (3)
  • internal/zeroruntime/helpers.go
  • internal/zeroruntime/provider_test.go
  • internal/zeroruntime/types.go

Comment thread internal/zeroruntime/helpers.go
Comment thread internal/zeroruntime/helpers.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/zeroruntime/helpers.go (1)

52-54: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Tool-call ordering can violate start-order contract.

At Line 52-Line 54, completed calls are appended immediately, which yields end order when multiple calls finish out of order. That conflicts with the stated start-order contract.
Please defer final emission to a single ordered flush path (or maintain a unified ordered buffer for both open and closed calls).

Proposed direction
case StreamEventToolCallEnd:
-   if toolCall, ok := pendingToolCalls[event.ToolCallID]; ok {
-       collected.ToolCalls = append(collected.ToolCalls, *toolCall)
-       delete(pendingToolCalls, event.ToolCallID)
-   }
+   // Mark as closed if needed, but do not append here.
+   // Emit once via ordered flush to preserve start order.

Also applies to: 77-84

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/zeroruntime/helpers.go` around lines 52 - 54, The code currently
appends finished tool calls directly into collected.ToolCalls when found in
pendingToolCalls (symbols: pendingToolCalls, collected.ToolCalls), which emits
by end-order; instead, stop appending immediately — move the append into the
unified flush path (the single ordered flush function) or add an intermediate
closed-buffer (e.g., closedToolCalls slice/map) that stores completed calls
keyed by their start-order index, remove from pendingToolCalls but do not emit;
then have the existing flush/emit routine (the ordered flush you already use
elsewhere) merge pending and closed buffers and append to collected.ToolCalls in
start-order, ensuring start-order contract is preserved (apply same change for
the other similar block that uses pendingToolCalls).
🧹 Nitpick comments (1)
internal/zeroruntime/provider_test.go (1)

78-140: ⚡ Quick win

Add a regression test for out-of-order tool-call completion.

Current tests validate flushing and error surfacing, but not start-order stability across interleaved calls. Add one case with call_1 then call_2 starts, call_2 ends before call_1, and assert output order remains [call_1, call_2].

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/zeroruntime/provider_test.go` around lines 78 - 140, Add a
regression test that verifies CollectStream preserves start order when tool
calls complete out-of-order: create a new test (e.g.
TestCollectStreamPreservesStartOrderWithInterleavedCompletion) that sends
StreamEventToolCallStart for "call_1" then for "call_2", then emits deltas and
closes/completes "call_2" before "call_1" (use StreamEventToolCallEnd events or
close the channel as appropriate), call CollectStream(ctx, events) and assert
collected.ToolCalls has length 2 and the order is first toolCall.ID == "call_1"
then toolCall.ID == "call_2"; reference CollectStream, StreamEvent,
StreamEventToolCallStart, StreamEventToolCallEnd, and the existing
TestCollectStream* tests for structure and assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@internal/zeroruntime/helpers.go`:
- Around line 52-54: The code currently appends finished tool calls directly
into collected.ToolCalls when found in pendingToolCalls (symbols:
pendingToolCalls, collected.ToolCalls), which emits by end-order; instead, stop
appending immediately — move the append into the unified flush path (the single
ordered flush function) or add an intermediate closed-buffer (e.g.,
closedToolCalls slice/map) that stores completed calls keyed by their
start-order index, remove from pendingToolCalls but do not emit; then have the
existing flush/emit routine (the ordered flush you already use elsewhere) merge
pending and closed buffers and append to collected.ToolCalls in start-order,
ensuring start-order contract is preserved (apply same change for the other
similar block that uses pendingToolCalls).

---

Nitpick comments:
In `@internal/zeroruntime/provider_test.go`:
- Around line 78-140: Add a regression test that verifies CollectStream
preserves start order when tool calls complete out-of-order: create a new test
(e.g. TestCollectStreamPreservesStartOrderWithInterleavedCompletion) that sends
StreamEventToolCallStart for "call_1" then for "call_2", then emits deltas and
closes/completes "call_2" before "call_1" (use StreamEventToolCallEnd events or
close the channel as appropriate), call CollectStream(ctx, events) and assert
collected.ToolCalls has length 2 and the order is first toolCall.ID == "call_1"
then toolCall.ID == "call_2"; reference CollectStream, StreamEvent,
StreamEventToolCallStart, StreamEventToolCallEnd, and the existing
TestCollectStream* tests for structure and assertions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a5e31f0e-9968-46a5-89eb-acb59dce454e

📥 Commits

Reviewing files that changed from the base of the PR and between d7e11fb and 48954cc.

📒 Files selected for processing (3)
  • internal/zeroruntime/helpers.go
  • internal/zeroruntime/provider_test.go
  • internal/zeroruntime/types.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • internal/zeroruntime/types.go

@Vasanthdev2004

Copy link
Copy Markdown
Collaborator

Blockers
None.

Non-Blocking

  • Local review host still does not have Go installed, so bun run test:go fails locally with bun: command not found: go. I verified the Go-specific contract tests/build/smoke through GitHub CI instead; the CI smoke job shows Go test/build/smoke passing on ubuntu, macos, and windows for head 48954cc.
  • The branch merge-base was behind current origin/main, so I also created a latest-main test-merge worktree. The merge applied cleanly and the TS/Bun validation path passed there too.
  • This is intentionally just the normalized Go provider/runtime contract skeleton. It does not wire providers, command routing, model registry behavior, stream-json, or tool execution yet, so there is no runtime dispatch/safety surface to block on in this PR.

Looks Good

  • The new internal/zeroruntime package keeps the M0 boundary narrow: message roles, tool definitions/calls, usage accounting, stream event types, completion requests, and a context-aware Provider interface.
  • CollectStream preserves tool-call start order, accumulates argument fragments and usage, and flushes open tool calls on done, channel close, provider error, or context cancellation. The tests cover those boundary paths.
  • SeedMessages and Usage.TotalTokens() are simple and predictable, which is what we want before adding real providers/adapters.
  • PR-branch validation I ran:
    • bun install --frozen-lockfile PASS
    • bun run typecheck PASS
    • bun test ./tests --timeout 15000 PASS, 279 pass / 0 fail
    • bun run build PASS
    • bun run smoke:build PASS
    • git diff --check PASS
  • Latest-main test-merge validation I ran:
    • merge origin/pr/50 into current origin/main PASS
    • bun install --frozen-lockfile PASS
    • bun run typecheck PASS
    • bun test ./tests --timeout 15000 PASS, 279 pass / 0 fail
    • bun run build PASS
    • bun run smoke:build PASS
    • git diff --check --cached and git diff --check PASS
  • GitHub CI for 48954cc: Go test/build/smoke PASS on ubuntu/macos/windows, plus TS/Bun test/typecheck/build/smoke PASS.

@Vasanthdev2004 Vasanthdev2004 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved current head 48954cc after reviewing the Go runtime contract skeleton, checking CI Go validation, and validating both PR branch and latest-main test-merge TS/Bun paths.

@Vasanthdev2004 Vasanthdev2004 merged commit f58ccf1 into main Jun 4, 2026
6 checks passed
@Vasanthdev2004 Vasanthdev2004 deleted the feat/go-m0-runtime-contracts branch June 4, 2026 10:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants