Why: the completion doc requires the client to recognize resultType, treat input_required as a protocol-level result whose answer retries the original tools/call, and expose tasks/get|update|cancel; today only a content-block special case existed and the advertised version was never checked against the server's. Evidence: GOWORK=off go vet + go test -count=1 ./... green; TestInputRequiredResultTypeRetriesOriginalCall (ask → tasks/update → retry, call order and final content), TestNegotiatedVersionFallbackKeepsLegacyPath (byte-level legacy behavior on 2024-11-05), TestTasksGetAndCancelRoundTrip, TestRunEndCancelsSeenTasks, TestDefaultSchemaDeclares202012; the acceptance-③ regression TestStdioSlowCancelThenEcho passes unchanged. Impact: advertise 2026-07-28 and branch on the negotiated version (older servers keep byte-identical behavior); synthesized default tool schemas now declare JSON Schema 2020-12; runs cancel the MCP tasks they saw via a per-run TaskTracker (other runs on the shared manager are unaffected). Refs: Agent-System-Documents#42 (N2 plan WP3)
39 lines
1.1 KiB
Go
39 lines
1.1 KiB
Go
package mcp
|
|
|
|
import "context"
|
|
|
|
type askKey struct{}
|
|
|
|
// WithAsk 把当前回合的 AskUser 放进上下文。MCP 返回 input_required 时使用它。
|
|
func WithAsk(ctx context.Context, fn func(context.Context, string) (string, error)) context.Context {
|
|
return context.WithValue(ctx, askKey{}, fn)
|
|
}
|
|
|
|
func askFrom(ctx context.Context) func(context.Context, string) (string, error) {
|
|
if ctx == nil {
|
|
return nil
|
|
}
|
|
fn, _ := ctx.Value(askKey{}).(func(context.Context, string) (string, error))
|
|
return fn
|
|
}
|
|
|
|
// inputQuestion 提取需要用户输入的问题。两条路径:
|
|
// 2026-07-28 协议级 resultType="input_required"(问题取文本块);
|
|
// 旧版服务端的内容块 input_required(向后兼容)。
|
|
func inputQuestion(res callToolResult, negotiated string) (string, bool) {
|
|
if res.ResultType == "input_required" && SupportsResultType(negotiated) {
|
|
for _, blk := range res.Content {
|
|
if blk.Type == "text" && blk.Text != "" {
|
|
return blk.Text, true
|
|
}
|
|
}
|
|
return "", true
|
|
}
|
|
for _, blk := range res.Content {
|
|
if blk.Type == "input_required" {
|
|
return blk.Text, true
|
|
}
|
|
}
|
|
return "", false
|
|
}
|