first pass of merging in warp (doesn't build)

This commit is contained in:
Ryan Ward
2026-07-01 16:08:58 -05:00
parent 2f64909469
commit 4770ac06b5
3662 changed files with 414574 additions and 89772 deletions
+43
View File
@@ -0,0 +1,43 @@
# REMOTE-1453: Resolve service-account global skills at agent driver startup
## Summary
Service accounts can have a configured set of global skill specs that should be available in every Oz agent run. The client resolves those specs at agent-driver startup, clones any org-qualified source repos that are not already on disk, and loads skills before the first query runs.
Global skills are intentionally not treated as permission to load every skill in their source repos. Repos that are part of the run's environment still use normal environment behavior and autodiscover all skills. Repos cloned only because they contain global skills load only the explicitly requested global skills.
## Problem
Before this work, an `oz agent run` only saw skills that were already present on disk or explicitly requested with `--skill <SKILL>`. Service-account global skills exposed by `User.globalSkills` were not made available automatically, and a repo cloned only to satisfy one global skill could accidentally expose unrelated skills in that repo.
## Goals
- For service-account-authenticated Oz agent runs, make every explicitly requested global skill available before the agent processes its first query.
- Autodiscover all skills from repositories that are part of the configured environment.
- For repositories cloned solely as global-skill sources, load only the global skills explicitly listed in `User.globalSkills`.
- If the same `(owner, repo)` appears both in the environment and in `User.globalSkills`, environment behavior wins and all skills from that repo are autodiscovered.
- Reuse existing skill parsing, repository cloning, skill watching, and skill manager flows where possible.
- Keep behavior unchanged for user principals and runs with no global skills.
## Non-goals
- A general plugin or skill registry mechanism beyond startup-time resolution.
- A Warp-managed cache directory for cloned skill repositories.
- Periodic or background refresh of the global skill list during a run.
- Changing CLI `--skill` resolution semantics.
- Adding global-skill loading to non-Oz harnesses in this iteration.
## Behavior
1. When an Oz agent driver starts, it reads the cached `User.globalSkills` list. The list uses the same skill spec format accepted by `--skill`: `skill_name`, `repo:skill_name`, `org/repo:skill_name`, or full-path variants.
2. If `OzPlatformSkills` is disabled, the client treats `globalSkills` as empty and bypasses the flow.
3. Each raw global skill string is parsed with the existing `SkillSpec` parser. Parse failures are logged at warn level and skipped; the rest of the list still resolves.
4. Specs without an org-qualified repository are not cloneable, so they do not add any repository to the global-skill clone set. They may still resolve through normal on-disk skill discovery if the skill is already present.
5. Specs with an `org/repo` qualifier contribute `(org, repo)` to the global-skill repo set. Multiple specs for the same `(org, repo)` result in one clone attempt and retain the explicit specs for later filtering.
6. Global-skill repos are cloned best-effort into `working_dir/<repo>` using the same environment clone helper and partial-clone behavior as environment repos. If the target repo already exists, it is reused. If a clone fails, the run logs a warning and continues without those global-only skills.
7. Environment preparation still clones the environment's `github_repos`, runs setup commands, and performs its normal repo registration. If a global-skill repo and an environment repo share the same `(owner, repo)`, whichever clone path reaches disk first is reused by the other path.
8. Skill loading is classified by source:
- Environment repos: scan and load all discovered `SKILL.md` files.
- Global-only repos: scan the repo tree, then keep only skills whose parsed names or explicit paths match the global skill specs for that repo.
- Overlapping repos: treat the repo as an environment repo, so all skills are loaded.
9. For simple global skill names such as `org/repo:deploy`, filtering matches parsed skill names and mirrors normal provider precedence when multiple providers define the same name. For full-path specs, filtering matches the exact path relative to the repo root.
10. Once loaded, the selected skills participate in the existing `SkillManager` flow. There is no separate global-skill registry or global-skill badge.
11. The flow is Oz-only for now. Non-Oz harnesses keep their existing behavior.
12. Historical conversations are unaffected; they retain whatever skills were available when they ran.
## Edge cases
1. Duplicate global skill specs: cloning is deduped by `(org, repo)` and skill filtering dedupes by selected skill path.
2. Multiple global skills in one global-only repo: only those explicit skills load; unrelated skills in the same repo do not.
3. A repo appears both in the environment and in `globalSkills`: all skills from that repo load because the environment classification wins.
4. No environment configured: cloneable global-skill repos still clone into `working_dir`, but only explicitly requested global skills load from those repos.
5. A global skill references a missing or inaccessible repo: the clone warning is logged, and the run continues without that repo's global-only skills.
6. A non-cloneable global skill spec is present: no repo is cloned for it, and it only resolves if the skill is already discoverable on disk.
7. `working_dir` does not exist: the existing agent-driver working-directory check fails before this flow changes anything.
+58
View File
@@ -0,0 +1,58 @@
# REMOTE-1453: Tech Spec - Resolve service-account global skills at agent driver startup
## Context
The product behavior is defined in `specs/REMOTE-1453/PRODUCT.md`. This spec covers the client-side runtime implementation for resolving service-account `User.globalSkills` during Oz agent startup.
Relevant existing pieces:
- `crates/warp_cli/src/skill.rs`: `SkillSpec`, `SkillSpec::from_str`, `SkillSpec::is_full_path`.
- `app/src/ai/skills/file_watchers/skill_watcher.rs`: scans repository trees for `SKILL.md` files.
- `app/src/ai/skills/skill_manager.rs`: stores the loaded skills for the active run.
- `app/src/ai/agent_sdk/driver/environment.rs`: environment repository clone helper used by environment prep.
- `app/src/ai/cloud_environments/mod.rs`: `GithubRepo { owner, repo }` and `AmbientAgentEnvironment.github_repos`.
- `app/src/ai/agent_sdk/driver.rs`: agent startup sequence, environment prep, and Oz-only repo skill loading.
## Implemented approach
### 1. Global skill parsing helpers
`app/src/ai/skills/global_skills.rs` owns the reusable parsing and filtering helpers and is re-exported through `app/src/ai/skills/mod.rs`.
- `resolve_skill_repos(raw_specs: &[String]) -> (Vec<SkillSpec>, Vec<GithubRepo>)` parses raw server strings with the existing CLI parser, logs warn-level parse failures, skips invalid entries, and extracts org-qualified `(org, repo)` pairs from the parsed specs while preserving first-seen order.
- `filter_skills_by_spec(repo_path, skills, specs)` takes the full scan result for one global-only repo and returns only the parsed skills explicitly requested for that repo.
Filtering behavior:
- Full-path specs match `repo_path.join(spec.skill_identifier)` exactly.
- Simple-name specs match parsed `ParsedSkill::name` values and pick the first match by provider-directory precedence.
- Duplicate selected paths are collapsed.
### 2. Driver source classification
`app/src/ai/agent_sdk/driver.rs` separates global skill resolution from repository skill loading using two explicit async methods rather than a unified load-request type.
- `GlobalSkillResolution` carries parsed global specs and cloneable global skill repos.
- `load_environment_skills` handles all repos that are part of the configured environment: it waits for `RepoMetadataModel` indexing to complete, then scans with `SkillWatcher::read_skills_for_repos` and loads all discovered skills.
- `load_global_skills` handles global-only repos: it reads directly from the known provider directories on disk via `read_skills_from_directories` (no `RepoMetadataModel` dependency), then applies `filter_skills_by_spec` to keep only the explicitly requested skills.
Because global skill repos are cloned before environment prep and are not registered with `DetectedRepositories`, they are not picked up by `SkillWatcher`'s `RepositoryMetadataEvent` path; `load_global_skills` reads them directly from disk instead. If a repo appears in both the environment and the global skill set, `load_environment_skills` runs over it and loads all skills; `load_global_skills` may also process it and add the filtered subset, but `SkillManager` deduplicates by path so the effective result is all skills from that repo.
### 3. Driver startup sequence
For Oz harnesses, `AgentDriver::run_internal` now does the following after the session is shared and before environment prep:
1. Read cached `AuthStateProvider::get().global_skills()`.
2. Parse specs and resolve cloneable repos with `resolve_skill_repos`.
3. Clone those repos best-effort with `environment::clone_repo` (which clones the repo but does NOT register it with `DetectedRepositories`, so only the explicitly requested global skills are loaded from it).
4. Prepare the configured environment, if any, preserving the existing file-based MCP discovery and setup-command sequencing. Environment repos are cloned via `ensure_repo_cloned`, which both clones and registers with `DetectedRepositories`.
5. Call `load_environment_skills` with the environment's `github_repos`, then `load_global_skills` with the global specs and repos.
Global-skill cloning is performed for all harnesses (before the Oz-only guard) so that skills are on disk, but skill loading into `SkillManager` remains Oz-only because third-party harnesses have separate skill systems.
### 4. Repo skill loading
Skill loading is split into two separate functions instead of a single unified `load_skills_from_repos`:
- `load_environment_skills(foreground, repos)`: waits for `RepoMetadataModel` indexing on each repo, then scans with `SkillWatcher::read_skills_for_repos` and loads all discovered skills into `SkillManager`.
- `load_global_skills(foreground, specs, repos)`: reads skills directly from provider directories via `read_skills_from_directories` (using `SKILL_PROVIDER_DEFINITIONS`), applies `filter_skills_by_spec` to keep only explicitly requested skills, and loads the result into `SkillManager`. This path does not depend on `RepoMetadataModel` because global-skill repos are not registered with `DetectedRepositories`.
Both functions call `SkillManager::set_cloud_environment(true)` and `handle_skills_added`, preserving the existing in-scope behavior for repo-loaded skills.
## Behavior guarantees
- Environment repos continue to autodiscover all skills.
- Global-only repos do not expose unrelated skills from the same repo.
- Environment/global overlap is resolved in favor of environment autodiscovery.
- Clone failures for global-skill repos are warn-and-continue.
- Invalid global skill specs are warn-and-skip.
- Non-cloneable specs do not trigger clone attempts.
## Testing and validation
Unit coverage added or expected:
- `resolve_skill_repos` skips invalid specs and handles empty input, unqualified specs, org-qualified specs, and duplicate repos.
- `filter_skills_by_spec` loads only requested simple-name skills, respects provider precedence, and matches full-path specs.
Validation commands:
- `cargo fmt`
- Targeted `cargo nextest` for the `global_skills` and `driver` tests touched by this change.
- A targeted `cargo check` or package build if test compilation exposes broader type issues.
## Follow-ups
- Add integration coverage around a real service-account run once the test harness can inject `User.globalSkills` and cloned repo contents cheaply.
- Consider refreshing `User.globalSkills` at run start if cached user state can become stale for long-lived clients.
- Consider global-skill provenance in skill listing UI or logs if users need to debug why a skill was available.
- Revisit third-party harness behavior if those harnesses adopt the same runtime skill loading path.