samplingHandler is the MCP-toolset-side hook that satisfies an inbound sampling/createMessage request from a server by driving the host agent's own model and returning the resulting message. The host always remains in control: the request is mapped to the agent's configured model (server-supplied M
(ctx context.Context, req *mcp.CreateMessageParams)
| 43 | // nested agent runs. Per-block size and per-request message-count limits |
| 44 | // keep an unbounded server response from pinning host memory. |
| 45 | func (r *LocalRuntime) samplingHandler(ctx context.Context, req *mcp.CreateMessageParams) (*mcp.CreateMessageResult, error) { |
| 46 | if req == nil { |
| 47 | return nil, errors.New("sampling request is nil") |
| 48 | } |
| 49 | |
| 50 | slog.InfoContext(ctx, "Sampling request received from MCP server", |
| 51 | "messages", len(req.Messages), |
| 52 | "max_tokens", req.MaxTokens, |
| 53 | "system_prompt", req.SystemPrompt != "", |
| 54 | ) |
| 55 | |
| 56 | a := r.CurrentAgent() |
| 57 | if a == nil { |
| 58 | return nil, errors.New("no current agent available to handle sampling request") |
| 59 | } |
| 60 | |
| 61 | messages, err := samplingMessagesToChat(req) |
| 62 | if err != nil { |
| 63 | return nil, fmt.Errorf("converting sampling messages: %w", err) |
| 64 | } |
| 65 | |
| 66 | baseModel := a.Model(ctx) |
| 67 | if baseModel == nil { |
| 68 | return nil, errors.New("current agent has no model configured") |
| 69 | } |
| 70 | |
| 71 | model := provider.CloneWithOptions(ctx, baseModel, samplingModelOptions(req)...) |
| 72 | |
| 73 | stream, err := model.CreateChatCompletionStream(ctx, messages, nil) |
| 74 | if err != nil { |
| 75 | return nil, fmt.Errorf("creating sampling completion stream: %w", err) |
| 76 | } |
| 77 | |
| 78 | content, finishReason, err := drainSamplingStream(stream) |
| 79 | if err != nil { |
| 80 | return nil, fmt.Errorf("reading sampling completion stream: %w", err) |
| 81 | } |
| 82 | |
| 83 | slog.DebugContext(ctx, "Sampling request completed", |
| 84 | "agent", a.Name(), |
| 85 | "model", model.ID().String(), |
| 86 | "finish_reason", finishReason, |
| 87 | "content_bytes", len(content), |
| 88 | ) |
| 89 | |
| 90 | return &mcp.CreateMessageResult{ |
| 91 | Role: mcp.Role("assistant"), |
| 92 | Model: model.ID().String(), |
| 93 | Content: &mcp.TextContent{Text: content}, |
| 94 | StopReason: stopReason(finishReason), |
| 95 | }, nil |
| 96 | } |
| 97 | |
| 98 | // samplingMessagesToChat converts an MCP CreateMessageParams into the |
| 99 | // host's chat.Message slice. The optional system prompt is prepended; |
nothing calls this directly
no test coverage detected