mirror of
https://github.com/docker/docker-agent.git
synced 2026-11-04 10:02:15 +00:00
A harness agent has no docker-agent model, so the TUI got no title generator for it and its sessions stayed untitled. The Claude Code driver now implements an optional harness.Completer: a one-shot `claude` call in print mode on the haiku model, with no tools, no MCP servers and no saved session, the prompt passed on stdin and the JSON result parsed. sessiontitle.Generator accepts such completers after its models, and LocalRuntime.TitleGenerator uses the driver's completer for a harness agent. Other harness types still get no title. Signed-off-by: Sayt-0 <louis.dal-moro-compta@epita.fr>
67 lines
2.0 KiB
Go
67 lines
2.0 KiB
Go
package codingharness
|
|
|
|
import (
|
|
"context"
|
|
|
|
baseharness "github.com/rumpl/harness"
|
|
|
|
"github.com/docker/docker-agent/pkg/config/latest"
|
|
"github.com/docker/docker-agent/pkg/harness"
|
|
)
|
|
|
|
// Factory builds the runtime driver for a `harness:` configuration using this
|
|
// package's Claude Code, Codex, Pi and OpenCode implementations. Register it
|
|
// with runtime.RegisterHarness(codingharness.Factory); the CLI and
|
|
// loaderdefaults.Opts do so, embedders that build teams in code and use
|
|
// harness agents must do it themselves.
|
|
func Factory(cfg *latest.HarnessConfig) (harness.Provider, error) {
|
|
p, err := NewProvider(cfg)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if cfg.Type == TypeClaudeCode {
|
|
return claudeCodeProvider{provider{p}}, nil
|
|
}
|
|
return provider{p}, nil
|
|
}
|
|
|
|
// provider adapts a rumpl/harness Provider to harness.Provider.
|
|
type provider struct {
|
|
baseharness.Provider
|
|
}
|
|
|
|
func (p provider) Run(ctx context.Context, prompt string, handle func(harness.Event)) error {
|
|
return baseharness.Run(ctx, p.Provider, prompt, adapt(handle))
|
|
}
|
|
|
|
func (p provider) Resume(ctx context.Context, sessionID, prompt string, handle func(harness.Event)) error {
|
|
return baseharness.Resume(ctx, p.Provider, sessionID, prompt, adapt(handle))
|
|
}
|
|
|
|
func adapt(handle func(harness.Event)) func(baseharness.Event) {
|
|
return func(ev baseharness.Event) {
|
|
out := harness.Event{
|
|
Type: harness.EventType(ev.Type),
|
|
Text: ev.Text,
|
|
Result: ev.Result,
|
|
SessionID: ev.SessionID,
|
|
ToolID: ev.ToolID,
|
|
ToolName: ev.ToolName,
|
|
ToolArgs: ev.ToolArgs,
|
|
ToolOutput: ev.ToolOutput,
|
|
ToolError: ev.ToolError,
|
|
Reasoning: ev.Reasoning,
|
|
}
|
|
if ev.Usage != nil {
|
|
out.Usage = &harness.Usage{
|
|
InputTokens: ev.Usage.InputTokens,
|
|
OutputTokens: ev.Usage.OutputTokens,
|
|
CacheReadInputTokens: ev.Usage.CacheReadInputTokens,
|
|
CacheCreationInputTokens: ev.Usage.CacheCreationInputTokens,
|
|
TotalCostUSD: ev.Usage.TotalCostUSD,
|
|
}
|
|
}
|
|
handle(out)
|
|
}
|
|
}
|