diff options
Diffstat (limited to 'internal/executor')
| -rw-r--r-- | internal/executor/local.go | 46 |
1 files changed, 34 insertions, 12 deletions
diff --git a/internal/executor/local.go b/internal/executor/local.go index 09bfbfa..6a240a4 100644 --- a/internal/executor/local.go +++ b/internal/executor/local.go @@ -73,14 +73,6 @@ func (r *LocalRunner) Run(ctx context.Context, t *task.Task, e *storage.Executio } defer stdout.Close() - messages := []llm.Message{} - if sys := strings.TrimSpace(t.Agent.SystemPromptAppend); sys != "" { - messages = append(messages, llm.Message{Role: "system", Content: sys}) - } - // The agent tools are real here, so guide the model toward them with the - // same planning preamble the container runners use (unless skip_planning). - messages = append(messages, llm.Message{Role: "user", Content: buildAgentInstructions(t, true)}) - temperature := t.Agent.Temperature if temperature == nil && r.DefaultTemperature > 0 { v := r.DefaultTemperature @@ -97,22 +89,40 @@ func (r *LocalRunner) Run(ctx context.Context, t *task.Task, e *storage.Executio tools = agentToolDefs() } + // Build messages after tools are decided so the planning preamble is only + // included when the model actually supports the agent tools. + messages := []llm.Message{} + if sys := strings.TrimSpace(t.Agent.SystemPromptAppend); sys != "" { + messages = append(messages, llm.Message{Role: "system", Content: sys}) + } + messages = append(messages, llm.Message{Role: "user", Content: buildAgentInstructions(t, len(tools) > 0)}) + start := time.Now() var totalIn, totalOut int var lastModel, lastFinish string blocked := false + var fullText string for turn := 0; turn < maxLocalToolTurns; turn++ { - resp, chatErr := r.Client.Chat(ctx, llm.ChatRequest{ + req := llm.ChatRequest{ Model: t.Agent.Model, Messages: messages, Temperature: temperature, MaxTokens: t.Agent.MaxTokens, Tools: tools, - }) + } + resp, chatErr := r.Client.Chat(ctx, req) if chatErr != nil { - writeResultLine(stdout, "error", chatErr.Error(), totalIn, totalOut) - return fmt.Errorf("local runner: chat: %w", chatErr) + // If the model doesn't support tool-use, retry once without tools. + if tools != nil && strings.Contains(strings.ToLower(chatErr.Error()), "does not support tools") { + tools = nil + req.Tools = nil + resp, chatErr = r.Client.Chat(ctx, req) + } + if chatErr != nil { + writeResultLine(stdout, "error", chatErr.Error(), totalIn, totalOut) + return fmt.Errorf("local runner: chat: %w", chatErr) + } } totalIn += resp.PromptTokens totalOut += resp.OutputTokens @@ -120,6 +130,7 @@ func (r *LocalRunner) Run(ctx context.Context, t *task.Task, e *storage.Executio if resp.Content != "" { writeAssistantTextLine(stdout, resp.Content) + fullText += resp.Content } if len(resp.ToolCalls) == 0 { @@ -174,6 +185,17 @@ func (r *LocalRunner) Run(ctx context.Context, t *task.Task, e *storage.Executio return &BlockedError{QuestionJSON: q} } + // For tool-less models report_summary is never called, so synthesise a + // summary from the raw assistant output so handleRunResult has something to + // store. + if e.Summary == "" && fullText != "" { + s := strings.TrimSpace(fullText) + if len(s) > 500 { + s = s[:500] + } + e.Summary = s + } + writeResultLine(stdout, "success", "", totalIn, totalOut) return nil } |
