micro/go-micro · error

agent: ResumeStreamAsk unsupported by implementation

Error message

agent: ResumeStreamAsk unsupported by implementation

What it means

ResumeStreamAsk resumes a checkpointed agent run with streaming, but only for the concrete *agentImpl type. Any other Agent implementation causes this sentinel error because resume-from-checkpoint logic is implemented solely on agentImpl.

Source

Thrown at agent/stream.go:66

func StreamAsk(ctx context.Context, ag Agent, message string) (AgentStream, error) {
	streamer, ok := ag.(interface {
		StreamAsk(context.Context, string) (AgentStream, error)
	})
	if !ok {
		return nil, errors.New("agent: StreamAsk unsupported by implementation")
	}
	return streamer.StreamAsk(ctx, message)
}

// ResumeStreamAsk resumes a checkpointed agent run and emits the same event
// shape as StreamAsk. Completed runs are streamed from the persisted response;
// unfinished runs continue from their checkpoint and emit tool events for any
// work that still needs to run. Tool calls already recorded as done in the
// checkpoint are reused by the agent checkpoint wrapper and are not re-executed.
func ResumeStreamAsk(ctx context.Context, ag Agent, runID string) (AgentStream, error) {
	a, ok := ag.(*agentImpl)
	if !ok {
		return nil, errors.New("agent: ResumeStreamAsk unsupported by implementation")
	}
	return a.resumeStreamAsk(ctx, runID)
}

// StreamAsk runs tools like Ask, emits ToolStart/ToolEnd events as they execute,
// then emits chunks of the final answer followed by a Done event.
func (a *agentImpl) StreamAsk(ctx context.Context, message string) (AgentStream, error) {
	streamCtx, cancel := context.WithCancel(ctx)
	events := make(chan *StreamEvent, 16)
	done := make(chan struct{})
	s := &agentStream{events: events, done: done, cancel: cancel}

	go func() {
		defer close(events)
		defer close(done)
		resp, err := a.askWithStreamEvents(streamCtx, message, events)
		if err != nil {
			s.setErr(err)

View on GitHub (pinned to 24529f1404)

Solutions

  1. Pass the original *agentImpl returned by the library's constructor (not a wrapper)
  2. Expose the underlying agent via a method like Unwrap() and resume on that
  3. Create the agent directly from the library so the concrete type is preserved

Example fix

// before
wrapped := loggingAgent{inner: ag}
stream, err := agent.ResumeStreamAsk(ctx, wrapped, runID) // fails
// after
stream, err := agent.ResumeStreamAsk(ctx, ag, runID) // pass the concrete *agentImpl
Defensive patterns

Strategy: type-guard

Validate before calling

if _, ok := ag.(*agent.AgentImpl); !ok { /* resume unsupported */ }

Type guard

func supportsResumeStream(ag agent.Agent) bool {
    _, ok := ag.(*agent.AgentImpl) // concrete implementation check
    return ok
}

Try / catch

stream, err := agent.ResumeStreamAsk(ctx, ag, runID)
if err != nil && strings.Contains(err.Error(), "unsupported by implementation") {
    return fmt.Errorf("resume requires the concrete agent implementation")
}

Prevention

When it happens

Trigger: Calling agent.ResumeStreamAsk(ctx, ag, runID) with an Agent that is not the library's *agentImpl concrete type (e.g. a wrapper, decorator, or custom implementation).

Common situations: Wrapping the agent in middleware/decorators that hide the concrete type; storing the agent behind a custom interface value; tests using mock agents.

Related errors


AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01). Data as JSON: /api/errors/9be4e0d6821e9e4d. Report an issue: GitHub.