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) }