first pass of merging in warp (doesn't build)
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
# Product Spec: Oz CLI Named-Agent CRUD
|
||||
|
||||
## Summary
|
||||
Add first-class Oz CLI commands for managing named agents. Developers can list, inspect, create, update, and delete named agents from the terminal with output modes that match existing Oz run commands.
|
||||
|
||||
## Problem
|
||||
Named agents are manageable through the public API and related Oz surfaces, but the Oz CLI does not expose the full CRUD surface. The existing `oz agent list` command lists repository-discovered agent skills, so the CLI needs a clear split between named agents and skills before adding CRUD commands.
|
||||
|
||||
## Goals
|
||||
- Make `oz agent list` mean "list named agents".
|
||||
- Preserve skill discovery by renaming the existing command to `oz agent skills`.
|
||||
- Provide terminal-friendly pretty output, script-friendly plain text, and JSON output with `--jq` filtering.
|
||||
- Preserve server patch semantics for updates so users only pass fields they want to modify.
|
||||
- Make list sorting predictable and client-side.
|
||||
|
||||
## Non-goals
|
||||
- Changing the public API behavior or authorization model for named agents.
|
||||
- Adding interactive prompts for create or update.
|
||||
- Managing API keys for named agents.
|
||||
- Changing `oz agent run` or `oz agent run-cloud` semantics beyond continuing to accept an agent UID where already supported.
|
||||
|
||||
## Behavior
|
||||
1. `oz agent skills` lists available agent skills using the current `oz agent list` behavior, including the existing `--repo` option and repository authorization flow.
|
||||
2. `oz agent list` lists named agents accessible to the authenticated user's team.
|
||||
3. `oz agent list` supports `--sort-by name` and `--sort-by created-at`.
|
||||
4. `oz agent list` supports `--sort-order asc` and `--sort-order desc`. If omitted, name sorting defaults to ascending, and timestamp sorting defaults to descending.
|
||||
5. Sorting is performed client-side after the API response is fetched and before rendering pretty, text, or ndjson output.
|
||||
6. `oz agent get <uid>` retrieves a single named agent by UID.
|
||||
7. `oz agent create` creates a named agent. `--name` is required. Optional fields are accepted for the fields supported by the API: description, secrets, skills, base model, and default environment.
|
||||
8. `oz agent update <uid>` partially updates a named agent. Users only pass fields they want to change.
|
||||
9. `oz agent update` preserves omitted fields. Passing an empty value through an explicit remove flag clears fields where the API supports clearing.
|
||||
10. `oz agent update` supports add/remove operations for list fields without requiring users to hand-write replacement arrays. Secrets use `--add-secret <NAME>`, `--remove-secret <NAME>`, and `--remove-all-secrets`; skills use `--add-skill <SKILL>`, `--remove-skill <SKILL>`, and `--remove-all-skills`.
|
||||
11. `oz agent delete <uid>` deletes a named agent and reports success. If the server rejects deletion, such as for the default agent, the CLI surfaces the server error.
|
||||
12. Pretty output for list uses a readable table with the core fields needed to identify and choose agents: UID, name, created time, description, secret names, skill specs, base model, and default environment when present. Disabled agents are hidden from pretty and text list output; when any are hidden, the CLI prints `N disabled agents hidden` to stderr after stdout output. JSON output still preserves the raw API response.
|
||||
13. Pretty output for `oz agent list` also includes a hint for users looking for the old skill-discovery behavior: `Looking for agent skills? Use <binary> agent skills instead.`
|
||||
14. Pretty output for get/create/update uses the same readable table shape for the single returned agent.
|
||||
15. Plain-text output is stable and script-friendly tabular text with headers for both list and single-agent output.
|
||||
16. JSON output for list/get/create/update preserves the API response shape so scripts can consume fields exactly as returned by the public API. List JSON is an object with an `agents` array.
|
||||
17. Sort flags are rejected for JSON output, including `--jq`, so raw API output remains raw.
|
||||
18. `--jq` implies JSON output even when the global output format is omitted or set to a human-readable format.
|
||||
19. `--jq` filters list/get/create/update JSON output using the same jq behavior as `oz run list` and `oz run get`, including unquoted scalar output.
|
||||
20. Delete has no JSON API response body. For JSON and ndjson output, the CLI emits a minimal operation result containing the deleted UID and `deleted: true`; pretty output reports the deleted UID in a sentence, text output prints the deleted UID, and delete does not support `--jq`.
|
||||
21. All named-agent CRUD commands require authentication and reuse the existing CLI authentication and API-key behavior.
|
||||
22. If the server returns authorization, validation, conflict, or not-found errors, the CLI prints the server-facing error through the existing fatal-error path.
|
||||
23. The command hierarchy remains backward-compatible except for the intentional rename: users who want the previous skill list behavior must use `oz agent skills`.
|
||||
@@ -0,0 +1,88 @@
|
||||
# Technical Spec: Oz CLI Named-Agent CRUD
|
||||
|
||||
## Context
|
||||
`specs/REMOTE-1696/PRODUCT.md` defines the user-visible behavior.
|
||||
|
||||
The CLI command definitions live in `crates/warp_cli/src/agent.rs`. The old skill-discovery command has moved to `AgentCommand::Skills(ListAgentSkillsArgs)` with an optional `--repo` flag. The app-side dispatcher in `app/src/ai/agent_sdk/mod.rs` sends that variant to `agent_config::list_skills`.
|
||||
|
||||
The existing skill-discovery implementation is in `app/src/ai/agent_sdk/agent_config.rs`. It calls `AIClient::list_skills(repo)` and renders repository-discovered `AgentSkillItem` values.
|
||||
|
||||
Run listing/getting in `app/src/ai/agent_sdk/ambient.rs (60-116)` is the output model to follow. It accepts `JsonOutput`, fetches raw API JSON for JSON or `--jq`, and uses `output::print_raw_json`. The reusable output helpers are in `app/src/ai/agent_sdk/output.rs (1-258)`.
|
||||
|
||||
The public API methods and types flow through `app/src/server/server_api/ai.rs`. The `AIClient` trait exposes skill listing as `list_skills(repo)` and named-agent CRUD as `list_agents`, `list_agents_raw`, `get_agent`, `get_agent_raw`, `create_agent`, `create_agent_raw`, `update_agent`, `update_agent_raw`, and `delete_agent`. The underlying `ServerApi` exposes authenticated GET/POST/PUT/DELETE helpers for public API commands.
|
||||
|
||||
The named-agent API reference is in `../warp-server/public_api/openapi.yaml`:
|
||||
- `POST /agent/identities` and `GET /agent/identities` at `../warp-server/public_api/openapi.yaml (2709-2781)`.
|
||||
- `GET /agent/identities/{uid}`, `PUT /agent/identities/{uid}`, and `DELETE /agent/identities/{uid}` at `../warp-server/public_api/openapi.yaml (2783-2917)`.
|
||||
- `CreateAgentRequest`, `UpdateAgentRequest`, `AgentResponse`, and `ListAgentsResponse` at `../warp-server/public_api/openapi.yaml (5399-5539)`.
|
||||
|
||||
Related named-agent environment work for `REMOTE-1695` adds an optional `environment_id` field to create/update/response models. The current checked-out OpenAPI schema may lag that server behavior, so the implementation keeps optional deserialization tolerant while still accepting `--environment` and `--remove-environment`.
|
||||
|
||||
## Implemented changes
|
||||
Add a new named-agent CLI surface and move the old skill-discovery command:
|
||||
- Rename the old skill-discovery command to `AgentCommand::Skills(ListAgentSkillsArgs)` with `#[command(name = "skills")]`.
|
||||
- Add `AgentCommand::List(AgentListArgs)`, `Get(AgentGetArgs)`, `Create(AgentCreateArgs)`, `Update(AgentUpdateArgs)`, and `Delete(AgentDeleteArgs)`.
|
||||
- Keep the old skill-discovery behavior and `--repo` intact under the renamed skills command.
|
||||
- Keep parser tests focused on custom conflict behavior rather than retesting clap's ordinary subcommand and repeated-flag parsing.
|
||||
|
||||
Command arguments:
|
||||
- `AgentListArgs`: `--sort-by <name|created-at>`, `--sort-order <asc|desc>`, and flattened `JsonOutput`.
|
||||
- `AgentGetArgs`: positional `uid` and flattened `JsonOutput`.
|
||||
- `AgentCreateArgs`: required `--name`; optional `--description`; repeatable `--secret <NAME>`; repeatable `--skill <SKILL>`; optional `--base-model <MODEL_ID>`; optional `--environment <ENVIRONMENT_ID>`; flattened `JsonOutput`.
|
||||
- `AgentUpdateArgs`: positional `uid`; optional `--name`; optional `--description` conflicting with `--remove-description`; repeatable `--add-secret`; repeatable `--remove-secret`; `--remove-all-secrets` conflicting with individual secret add/remove flags; repeatable `--add-skill`; repeatable `--remove-skill`; `--remove-all-skills` conflicting with individual skill add/remove flags; optional `--base-model` conflicting with `--remove-base-model`; optional `--environment` conflicting with `--remove-environment`; flattened `JsonOutput`.
|
||||
- `AgentDeleteArgs`: positional `uid`. It intentionally does not flatten `JsonOutput` because delete has no API response body to filter with `--jq`.
|
||||
|
||||
Add app-side named-agent command handling:
|
||||
- Create a new module such as `app/src/ai/agent_sdk/agent_management.rs` to avoid mixing named-agent CRUD with skill discovery.
|
||||
- Route the renamed skills command to the existing `agent_config::list_skills`.
|
||||
- Route named-agent CRUD commands from `run_agent` to the new module.
|
||||
- Update `command_requires_auth` so every named-agent command and the renamed skills command require authentication.
|
||||
- Add telemetry variants for `AgentSkills`, `AgentList`, `AgentGet`, `AgentCreate`, `AgentUpdate`, and `AgentDelete`, or at minimum preserve the existing `AgentList` telemetry for the renamed skills command and add distinct variants for new CRUD commands if the telemetry enum supports adding them.
|
||||
|
||||
Add API types and methods in `app/src/server/server_api/ai.rs`:
|
||||
- Define serde types for `SecretRef`, `CreateAgentRequest`, `UpdateAgentRequest`, `AgentResponse`, `ListAgentsResponse`, `AgentSkillItem`, and supporting skill response types.
|
||||
- Model `created_at` as `DateTime<Utc>`.
|
||||
- Model `environment_id` as an optional field to tolerate both the currently checked-in schema and the related server work.
|
||||
- For create requests, skip absent optional fields and omit empty lists.
|
||||
- For update requests, use nested `Option`/custom serde helpers as needed so omitted fields are not serialized, remove flags serialize empty string or empty array, and non-empty values serialize replacements.
|
||||
- Add `AIClient` trait methods for typed named-agent CRUD plus raw JSON list/get/create/update methods used by JSON output and `--jq`, using the names `list_agents`, `list_agents_raw`, `get_agent`, `get_agent_raw`, `create_agent`, `create_agent_raw`, `update_agent`, `update_agent_raw`, and `delete_agent`.
|
||||
- Implement the methods with `GET/POST/PUT/DELETE /api/v1/agent/identities`.
|
||||
- Add reusable `put_public_api`, `put_public_api_response`, and `delete_public_api_unit` helpers to `ServerApi` if no existing helper covers those verbs.
|
||||
|
||||
Output behavior:
|
||||
- Implement `TableFormat` for `AgentResponse`.
|
||||
- For list, fetch typed responses for pretty/text/ndjson and raw JSON for JSON/`--jq`. Apply client-side sorting before output for pretty/text/ndjson only.
|
||||
- Reject `--sort-by` or `--sort-order` when JSON output is requested or implied by `--jq`, because JSON mode should preserve raw API output rather than returning a client-mutated response.
|
||||
- In pretty list output, print `Looking for agent skills? Use <binary> agent skills instead.` after the named-agent list, where `<binary>` is resolved through the existing CLI binary-name helper.
|
||||
- List and single-agent pretty/text output share the same fields from `AgentResponse`: UID, name, created time, description, secret names, skill specs, base model, and environment.
|
||||
- Pretty/text list output filters out disabled agents. If any disabled agents are hidden, print `N disabled agents hidden` to stderr after stdout output. JSON output and `--jq` use the raw API response and do not filter or print this notice.
|
||||
- For get/create/update, pretty output renders a single-row table; text output renders stable tabular text with headers; JSON/`--jq` processes the raw API response.
|
||||
- List JSON is the raw public API response object with an `agents` array, so list `--jq` filters should address `.agents[]`.
|
||||
- For delete, pretty output says the agent was deleted, text output prints the deleted UID, and JSON/ndjson output prints `{ "uid": "<uid>", "deleted": true }`. Delete does not support `--jq`.
|
||||
|
||||
Update references and naming:
|
||||
- Update user-facing help strings so "agents" means named agents and "skills" means repository-discovered skills.
|
||||
- Update examples only if the CLI docs/examples mention `oz agent list` as skill discovery.
|
||||
|
||||
## Testing and validation
|
||||
- Keep CLI parse tests only for custom conflicts:
|
||||
- `agent update <uid> --description <value> --remove-description` is rejected.
|
||||
- `agent update <uid> --add-secret <NAME> --remove-all-secrets` is rejected.
|
||||
- Add unit tests for update request serialization to prove omitted fields are absent, remove flags serialize empty values, and replacement values serialize correctly.
|
||||
- Add unit tests for client-side secret and skill delta helpers.
|
||||
- Add unit tests for list sorting by name and created time.
|
||||
- Add unit tests that list sort flags are rejected for JSON and `--jq` output.
|
||||
- Add output tests for named-agent detail text/pretty helpers where they can be tested without a full app context.
|
||||
- Run `cargo fmt`.
|
||||
- Run targeted Rust tests for `warp_cli` and the new agent SDK module.
|
||||
- Run a focused clippy command if compile/test scope reveals warnings.
|
||||
- Manually validate against an authenticated staging server. On macOS, invoke the app runner with `WARP_CLI_MODE=1 ./script/run -- <cli args>` so the bundled app parses CLI subcommands rather than GUI URLs. For parallel manual validation, use the built binary with `WARP_CLI_MODE=1` to avoid concurrent `./script/run` rebundling and codesigning the same app path.
|
||||
- Manual validation should cover create/get/list/delete, update add/remove flags for skills and secrets, description/base-model/environment set and remove flags, invalid environment errors, nonexistent UID errors, update-with-no-flags errors, sort ordering by name and created time, JSON sort-flag rejection, pretty/text/ndjson/json output, and `--jq` scalar output.
|
||||
|
||||
## Parallelization
|
||||
Parallel child agents are not necessary for implementation. The change is medium-sized but tightly coupled across command definitions, SDK dispatch, API methods, and output tests; parallel edits would likely collide in `agent.rs`, `mod.rs`, and `ai.rs`. Manual validation can be parallelized after the implementation lands because validators only run CLI commands and use isolated disposable named-agent prefixes.
|
||||
|
||||
## Risks and mitigations
|
||||
- **Patch semantics are easy to break:** use serialization tests for omitted, remove, and replacement cases.
|
||||
- **The old `agent list` behavior is being renamed:** keep the renamed `agent skills` behavior otherwise unchanged and include the pretty-output hint for users looking for skills.
|
||||
- **Raw JSON sorting can diverge from "raw API" expectations:** reject sort flags when producing JSON output.
|
||||
Reference in New Issue
Block a user