summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
Diffstat (limited to 'internal')
-rw-r--r--internal/executor/local.go46
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
}