Files
Agent-Native/runtime/mcp/tasks.go
T
weichen fcd2539b9e
ci / vet-and-test (pull_request) Successful in 52s
ci / docker-checkout-hostgateway (pull_request) Successful in 1s
Align the MCP client with 2026-07-28: resultType, input_required retry, tasks surface (N2 WP3)
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)
2026-10-07 13:38:51 +00:00

66 lines
1.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package mcp
import (
"context"
"sync"
)
// TaskTracker 记录一次 run 内 tools/call 结果里出现过的长任务(按服务端
// 客户端分组),供 run 结束时对这些任务发 tasks/cancel(2026-07-28 最小
// 产品映射:取消只覆盖本 run 自己的任务,不影响共享 Manager 上其他 run)。
type TaskTracker struct {
mu sync.Mutex
seen map[Client]map[string]struct{}
}
type trackerKey struct{}
// WithTaskTracker 把任务跟踪器放进上下文(bridgeTool 记录 TaskID)。
func WithTaskTracker(ctx context.Context) (context.Context, *TaskTracker) {
tr := &TaskTracker{seen: map[Client]map[string]struct{}{}}
return context.WithValue(ctx, trackerKey{}, tr), tr
}
func trackerFrom(ctx context.Context) *TaskTracker {
if ctx == nil {
return nil
}
tr, _ := ctx.Value(trackerKey{}).(*TaskTracker)
return tr
}
func (t *TaskTracker) note(c Client, taskID string) {
if t == nil || c == nil || taskID == "" {
return
}
t.mu.Lock()
set := t.seen[c]
if set == nil {
set = map[string]struct{}{}
t.seen[c] = set
}
set[taskID] = struct{}{}
t.mu.Unlock()
}
// CancelAll 对记录的任务逐一向其服务端发 tasks/cancel(尽力而为,
// 首个错误后继续)。返回实际发出取消的任务数。
func (t *TaskTracker) CancelAll(ctx context.Context) int {
if t == nil {
return 0
}
t.mu.Lock()
seen := t.seen
t.seen = map[Client]map[string]struct{}{}
t.mu.Unlock()
n := 0
for c, ids := range seen {
for id := range ids {
if err := c.TasksCancel(ctx, id); err == nil {
n++
}
}
}
return n
}