Files
Agent-System/internal/agent/backend.go
T
weichen 265616e997 feat(stream): 打通小队过程事件到持久化 detail 帧
pi-native 与 runner NDJSON 把推理和工具调用投影为 detail,任务流始终落库;非 200 的流式尝试回落到一次性 /v1/run,避免改变既有错误分类。
2026-09-28 10:30:52 +00:00

75 lines
2.5 KiB
Go

package agent
import (
"context"
"time"
"chat-agent-system/internal/config"
)
type Request struct {
WorkDir string `json:"work_dir"`
Prompt string `json:"prompt"`
Instructions string `json:"instructions"`
Targets []string `json:"targets"`
Timeout time.Duration `json:"timeout"`
// ToolProfile is workspace (default, document tools) or reasoning (no tools).
ToolProfile string `json:"tool_profile,omitempty"`
// OnEvent 可选过程事件回调(nil = 调用方不需要过程,后端行为与现状完全一致)。
// 实现方必须保证:回调在 Execute 返回前完成(同步调用或等待收尾),无泄漏 goroutine;
// 回调内不得阻塞(消费方自行节流/异步入队)。
OnEvent func(ev ProcessEvent)
}
// ProcessEvent 对 agentx 事件与远程 runner NDJSON 过程帧的统一投影,
// 供小队过程流式展示消费(见 .doc/system-design/2026-09-28-agent-process-streaming-and-subagent-view-design.md)。
type ProcessEvent struct {
Type string // text_delta | reasoning_delta | tool_call_delta | tool_execution_start | tool_execution_end | message_end | ...
Text string // delta 文本(Type 为 *_delta 时)
Tool string // 工具名(tool_* 时)
Detail string // 工具参数/结果摘要(tool_execution_* 时)
}
const (
ToolProfileWorkspace = "workspace"
ToolProfileReasoning = "reasoning"
)
type Result struct {
Success bool `json:"success"`
Patches map[string][]byte `json:"patches"`
Logs string `json:"logs"`
ErrorReason string `json:"error_reason"`
// Retryable marks a provider-transient failure that may receive a
// fresh step invocation. Permanent missing deliverables stay false.
Retryable bool `json:"retryable,omitempty"`
// PromptTokens and CompletionTokens are set by pi-native when the provider reports usage.
PromptTokens int `json:"prompt_tokens,omitempty"`
CompletionTokens int `json:"completion_tokens,omitempty"`
}
type Backend interface {
Name() string
Execute(ctx context.Context, req Request) (*Result, error)
}
func NewBackend(name string, cfg *config.Config) Backend {
var inner Backend
switch name {
case "pi-agent":
inner = &PiAgentBackend{cfg: cfg}
case "pi-native":
inner = &fallbackBackend{
primary: NewPiNativeBackend(cfg),
fallback: &PiAgentBackend{cfg: cfg},
}
default:
inner = &StubBackend{}
}
max := 8
if cfg != nil && cfg.MaxConcurrentAgents > 0 {
max = cfg.MaxConcurrentAgents
}
return WrapWithConcurrencyLimit(inner, max)
}