Replace Go example server with Dojo implementation#2047
Conversation
|
@mattsp1290 is attempting to deploy a commit to the CopilotKit Team on Vercel. A member of the Team first needs to authorize it. |
Python Preview PackagesVersion
Install with uvAdd the TestPyPI index to your [[tool.uv.index]]
name = "testpypi"
url = "https://test.pypi.org/simple/"
explicit = trueThen install the packages you need: # Core SDK
uv add 'ag-ui-protocol==0.0.0.dev1784169442' --index testpypi
# Integrations (each already depends on the matching ag-ui-protocol preview)
uv add 'ag-ui-langgraph==0.0.0.dev1784169442' --index testpypi
uv add 'ag-ui-crewai==0.0.0.dev1784169442' --index testpypi
# NOTE: ag-ui-agent-spec depends on pyagentspec (git-only, not on PyPI).
# You will need to install pyagentspec separately from its git repo.
uv add 'ag-ui-agent-spec==0.0.0.dev1784169442' --index testpypi
uv add 'ag_ui_adk==0.0.0.dev1784169442' --index testpypi
uv add 'ag_ui_strands==0.0.0.dev1784169442' --index testpypiInstall with pippip install \
--index-url https://test.pypi.org/simple/ \
--extra-index-url https://pypi.org/simple/ \
ag-ui-protocol==0.0.0.dev1784169442
Commit: 849f1f5 |
@ag-ui/a2a-middleware
@ag-ui/a2ui-middleware
@ag-ui/event-throttle-middleware
@ag-ui/mcp-apps-middleware
@ag-ui/mcp-middleware
@ag-ui/a2a
@ag-ui/adk
@ag-ui/ag2
@ag-ui/agno
@ag-ui/aws-strands
@ag-ui/claude-agent-sdk
@ag-ui/crewai
@ag-ui/langchain
@ag-ui/langgraph
@ag-ui/llamaindex
@ag-ui/mastra
@ag-ui/pydantic-ai
@ag-ui/vercel-ai-sdk
@ag-ui/watsonx
@ag-ui/a2ui-toolkit
create-ag-ui-app
@ag-ui/client
@ag-ui/core
@ag-ui/encoder
@ag-ui/proto
commit: |
|
@NathanTarbert could I request a review on this? |
contextablemark
left a comment
There was a problem hiding this comment.
Looks good overall : the event mapping is thorough and the interrupt/resume handling in loop.go is well done. One correctness issue in the predictive route that's worth fixing before merge.
In sdks/community/go/example/server/internal/agent/predictive.go, Run closes the llm step unconditionally after the stream helper returns:
emit.StepStarted("llm")
full, ok := p.streamPredictive(ctx, emit, doc, messages)
emit.StepFinished("llm") // <-- runs even when streamPredictive already emitted RUN_ERROR
if !ok {
return
}But unlike streamTurn (which returns an error and lets the caller close the step before emitting RUN_ERROR), streamPredictive emits RUN_ERROR itself on a model/stream failure — the initial Stream(...) error and the mid-stream Recv error both call emit.RunError(...) and return ok=false. So when the model backend fails (rate limit, API error, mid-stream drop — anything that isn't a client disconnect), the wire sequence becomes:
RUN_STARTED, STATE_SNAPSHOT, STEP_STARTED(llm), RUN_ERROR, STEP_FINISHED(llm)
That STEP_FINISHED after RUN_ERROR is rejected by the SDK's own sequence validator. verifyEvents runs in the default TS/Dojo client pipeline (sdks/typescript/packages/client/src/agent/agent.ts:218), and once it sees RUN_ERROR it throws on any subsequent event (verify/verify.ts:43-50). So instead of surfacing a clean RUN_ERROR, the client's run pipeline throws AGUIError: Cannot send event type 'STEP_FINISHED': The run has already errored.
The other streaming routes are fine because they go through streamTurn's return-the-error contract (loop.go, sharedstate.go close the step before emit.RunError), and agentic_generative_ui's error path emits RUN_ERROR while a step is open but then returns without a STEP_FINISHED (which the validator allows — it only checks active-step state on RUN_FINISHED). Predictive is the sole outlier because its bespoke stream loop emits the terminal event inline.
Suggested fix — align streamPredictive with the streamTurn contract (return the error, let Run close the step first):
emit.StepStarted("llm")
full, err := p.streamPredictive(ctx, emit, doc, messages)
emit.StepFinished("llm")
if err != nil {
if !errors.Is(err, context.Canceled) && !errors.Is(err, context.DeadlineExceeded) && emit.Err() == nil {
emit.RunError("the agent failed to generate a response")
}
return
}with streamPredictive returning (string, error) and no longer calling emit.RunError itself. (A minimal alternative is to reorder so StepFinished fires before any RunError, but matching streamTurn keeps all four streaming paths on one error-emission discipline, which is what prevents this class of bug from recurring.)
Also worth adding: predictive_test.go currently doesn't exercise the model-error path, which is why this slipped through — a test that stubs a failing stream and asserts no event follows RUN_ERROR would lock it in.
Please let me know if my analysis got this wrong, but this seems like an edge case worth addressing before a merge.
Nice catch! Refactored predictive streaming to close STEP_FINISHED before emitting RUN_ERROR and added regression tests for initial, mid-stream, cancellation, and deadline failures |
contextablemark
left a comment
There was a problem hiding this comment.
Looks great... even better than I suggested!
Replaces the existing Go example server with an example I made that implements the full AG-UI spec.