Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion backend/internal/adapters/agent/pi/pi.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,25 @@ func (p *Plugin) Manifest() adapters.Manifest {
}
}

// GetConfigSpec reports the per-project agent config keys Pi understands.
func (p *Plugin) GetConfigSpec(ctx context.Context) (ports.ConfigSpec, error) {
if err := ctx.Err(); err != nil {
return ports.ConfigSpec{}, err
}
return ports.ConfigSpec{
Fields: []ports.ConfigField{
{
Key: "model",
Type: ports.ConfigFieldString,
Description: "Model override passed to `pi --model`.",
},
},
}, nil
}

// GetLaunchCommand builds the argv to start a new interactive Pi session:
//
// pi [--append-system-prompt <system prompt>] [<prompt>]
// pi [--append-system-prompt <system prompt>] [--model <model>] [<prompt>]
//
// The prompt is delivered in-command as a trailing positional message. Pi does
// not honor a `--` options terminator, so the prompt must not begin with "-".
Expand All @@ -97,6 +113,7 @@ func (p *Plugin) GetLaunchCommand(ctx context.Context, cfg ports.LaunchConfig) (
}
cmd = append(cmd, "--append-system-prompt", string(data))
}
appendModelFlag(&cmd, cfg.Config)
if cfg.Prompt != "" {
cmd = append(cmd, cfg.Prompt)
}
Expand Down Expand Up @@ -130,10 +147,17 @@ func (p *Plugin) GetRestoreCommand(ctx context.Context, cfg ports.RestoreConfig)
}
cmd = append(cmd, "--append-system-prompt", string(data))
}
appendModelFlag(&cmd, cfg.Config)
Comment thread
Hardik180704 marked this conversation as resolved.
cmd = append(cmd, "--session", agentSessionID)
return cmd, true, nil
}

func appendModelFlag(cmd *[]string, cfg ports.AgentConfig) {
if model := strings.TrimSpace(cfg.Model); model != "" {
*cmd = append(*cmd, "--model", model)
}
}

var piBinarySpec = binaryutil.BinarySpec{
Label: "pi",
Names: []string{"pi"},
Expand Down
67 changes: 64 additions & 3 deletions backend/internal/adapters/agent/pi/pi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,20 @@ func TestManifest(t *testing.T) {
}
}

func TestGetConfigSpecEmpty(t *testing.T) {
func TestGetConfigSpecReportsModelField(t *testing.T) {
spec, err := (&Plugin{}).GetConfigSpec(context.Background())
if err != nil {
t.Fatalf("err: %v", err)
}
if len(spec.Fields) != 0 {
t.Fatalf("expected no fields, got %d", len(spec.Fields))
want := []ports.ConfigField{
{
Key: "model",
Type: ports.ConfigFieldString,
Description: "Model override passed to `pi --model`.",
},
}
if !reflect.DeepEqual(spec.Fields, want) {
t.Fatalf("config fields\nwant: %#v\n got: %#v", want, spec.Fields)
}
}

Expand Down Expand Up @@ -68,6 +75,38 @@ func TestGetLaunchCommandWorkerWithPromptIsInteractive(t *testing.T) {
}
}

func TestGetLaunchCommandAppendsConfiguredModelBeforePrompt(t *testing.T) {
p := &Plugin{resolvedBinary: "pi"}
cmd, err := p.GetLaunchCommand(context.Background(), ports.LaunchConfig{
Config: ports.AgentConfig{Model: " openai/gpt-4o "},
SystemPrompt: "follow repo rules",
Prompt: "add a health check",
})
if err != nil {
t.Fatal(err)
}

want := []string{"pi", "--append-system-prompt", "follow repo rules", "--model", "openai/gpt-4o", "add a health check"}
if !reflect.DeepEqual(cmd, want) {
t.Fatalf("cmd = %#v, want %#v", cmd, want)
}
}

func TestGetLaunchCommandOmitsBlankConfiguredModel(t *testing.T) {
p := &Plugin{resolvedBinary: "pi"}
cmd, err := p.GetLaunchCommand(context.Background(), ports.LaunchConfig{
Config: ports.AgentConfig{Model: " \t "},
})
if err != nil {
t.Fatal(err)
}

want := []string{"pi"}
if !reflect.DeepEqual(cmd, want) {
t.Fatalf("cmd = %#v, want %#v", cmd, want)
}
}

func TestGetLaunchCommandOrchestratorAppendsSystemPromptInteractively(t *testing.T) {
p := &Plugin{resolvedBinary: "pi"}
cmd, err := p.GetLaunchCommand(context.Background(), ports.LaunchConfig{
Expand Down Expand Up @@ -187,6 +226,28 @@ func TestGetRestoreCommand(t *testing.T) {
}
}

func TestGetRestoreCommandAppendsConfiguredModelBeforeSession(t *testing.T) {
p := &Plugin{resolvedBinary: "pi"}
cmd, ok, err := p.GetRestoreCommand(context.Background(), ports.RestoreConfig{
Config: ports.AgentConfig{Model: " openai/gpt-4o "},
Session: ports.SessionRef{
Metadata: map[string]string{ports.MetadataKeyAgentSessionID: "019e950e-52e0-7411-961b-d380ca7e610f"},
},
SystemPrompt: "follow repo rules",
})
if err != nil {
t.Fatal(err)
}
if !ok {
t.Fatal("ok=false, want true")
}

want := []string{"pi", "--append-system-prompt", "follow repo rules", "--model", "openai/gpt-4o", "--session", "019e950e-52e0-7411-961b-d380ca7e610f"}
if !reflect.DeepEqual(cmd, want) {
t.Fatalf("cmd = %#v, want %#v", cmd, want)
}
}

func TestGetRestoreCommandReappendsSystemPromptInteractively(t *testing.T) {
p := &Plugin{resolvedBinary: "pi"}
cmd, ok, err := p.GetRestoreCommand(context.Background(), ports.RestoreConfig{
Expand Down
Loading