diff --git a/.agents/skills/sync-openapi-spec/scripts/sync_openapi.py b/.agents/skills/sync-openapi-spec/scripts/sync_openapi.py index deb1170fd..8d637f0a9 100644 --- a/.agents/skills/sync-openapi-spec/scripts/sync_openapi.py +++ b/.agents/skills/sync-openapi-spec/scripts/sync_openapi.py @@ -465,13 +465,11 @@ def transform(source: dict[str, Any]) -> dict[str, Any]: out["info"] = {**out["info"], **DOCS_INFO_OVERRIDES} src_tags = source.get("tags") or [] - out_tags = [ + candidate_tags = [ t for t in src_tags if isinstance(t, dict) and t.get("name") not in EXCLUDED_TAGS ] - if out_tags: - out["tags"] = out_tags src_paths = source.get("paths") or {} kept_paths = { @@ -479,6 +477,34 @@ def transform(source: dict[str, Any]) -> dict[str, Any]: for path, item in src_paths.items() if isinstance(item, dict) and _should_keep_path(path, item) } + + tag_by_name = { + tag["name"]: tag + for tag in candidate_tags + if isinstance(tag.get("name"), str) + } + kept_tag_names = { + tag + for path_item in kept_paths.values() + for tag in _path_tags(path_item) + } + pending_parents = list(kept_tag_names) + while pending_parents: + tag_name = pending_parents.pop() + tag = tag_by_name.get(tag_name) + parent = tag.get("parent") if tag else None + if ( + isinstance(parent, str) + and parent in tag_by_name + and parent not in kept_tag_names + ): + kept_tag_names.add(parent) + pending_parents.append(parent) + out_tags = [ + tag for tag in candidate_tags if tag.get("name") in kept_tag_names + ] + if out_tags: + out["tags"] = out_tags out["paths"] = kept_paths seed_refs: set[str] = set() @@ -584,11 +610,20 @@ def _summarize_drift( def _unknown_classifications(source: dict[str, Any]) -> list[str]: """Flag tags or paths the policy doesn't already cover. - The skill's policy currently knows about the `agent`, `schedules`, - `factory`, and `networking` tags (kept) and `memory_stores`/`memory`/ - `harness-support` (dropped). Anything else needs human triage. + The skill's policy knows about the public agent and factory tag + hierarchies, plus `memory_stores`/`memory`/`harness-support` (dropped). + Anything else needs human triage. """ - KNOWN_TAGS = {"agent", "schedules", "factory", "networking"} | set(EXCLUDED_TAGS) + KNOWN_TAGS = { + "agent", + "schedules", + "factory", + "factory-notifications", + "factory-metrics", + "factory-scorers", + "factory-benchmarks", + "networking", + } | set(EXCLUDED_TAGS) notes: list[str] = [] for tag in source.get("tags") or []: @@ -618,10 +653,16 @@ def _unknown_classifications(source: dict[str, Any]) -> list[str]: def _self_test() -> int: """Sanity-check the transform on a small synthetic spec.""" sample = { - "openapi": "3.0.0", + "openapi": "3.2.0", "info": {"title": "t", "version": "1"}, "tags": [ - {"name": "agent"}, + {"name": "agent", "summary": "Agents"}, + { + "name": "schedules", + "summary": "Scheduled Agents", + "parent": "agent", + }, + {"name": "unused", "summary": "Unused"}, {"name": "memory_stores", "x-internal": True}, {"name": "harness-support"}, ], @@ -688,6 +729,13 @@ def _self_test() -> int: "responses": {"200": {"description": "ok"}}, } }, + "/schedules": { + "get": { + "tags": ["schedules"], + "operationId": "listSchedules", + "responses": {"200": {"description": "ok"}}, + } + }, }, "components": { "securitySchemes": {"bearerAuth": {"type": "http", "scheme": "bearer"}}, @@ -778,6 +826,7 @@ def _self_test() -> int: assert paths == { "/agent/run", "/agent/runs/{runId}/followups", + "/schedules", }, f"unexpected paths: {paths}" schemas = set(out["components"]["schemas"].keys()) @@ -810,8 +859,11 @@ def _self_test() -> int: assert "BENCHMARK_TRIAL" not in pruned["description"] assert "CUSTOM_WEBHOOK" not in pruned["description"] - tag_names = [t["name"] for t in out.get("tags") or []] - assert tag_names == ["agent"], f"unexpected tags: {tag_names}" + tags = {t["name"]: t for t in out.get("tags") or []} + assert set(tags) == {"agent", "schedules"}, f"unexpected tags: {set(tags)}" + assert tags["agent"]["summary"] == "Agents" + assert tags["schedules"]["summary"] == "Scheduled Agents" + assert tags["schedules"]["parent"] == "agent" assert out["components"].get("securitySchemes"), "securitySchemes should be preserved" assert out["info"]["title"] == "Warp Platform API" diff --git a/astro.config.mjs b/astro.config.mjs index f2a468a8c..a272cbf62 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -1,4 +1,5 @@ // @ts-check +import { readFileSync } from 'node:fs'; import { defineConfig, envField } from 'astro/config'; import remarkGfm from 'remark-gfm'; import mermaid from 'astro-mermaid'; @@ -7,6 +8,7 @@ import sitemap from '@astrojs/sitemap'; import starlight from '@astrojs/starlight'; import starlightLlmsTxt from 'starlight-llms-txt'; import starlightSidebarTopics from 'starlight-sidebar-topics'; +import { parse } from 'yaml'; import pageTitleOverride from './src/plugins/page-title-override.ts'; import remarkHeadingVars from './src/plugins/heading-vars.ts'; import { varsTransformPlugin } from './src/plugins/vars-transform.ts'; @@ -15,6 +17,10 @@ import { sidebarTopics } from './src/sidebar.ts'; import docsMarkdownIntegration from './src/integrations/docs-markdown-integration.js'; import { DOCS_ORIGIN } from './src/lib/site.js'; +const openApiVersion = parse( + readFileSync(new URL('./developers/agent-api-openapi.yaml', import.meta.url), 'utf8'), +).openapi; + // https://astro.build/config export default defineConfig({ site: DOCS_ORIGIN, @@ -200,12 +206,12 @@ export default defineConfig({ { label: 'Oz Agent API (OpenAPI spec, YAML)', url: 'https://docs.warp.dev/openapi.yaml', - description: 'Machine-readable OpenAPI 3.0 specification for the Oz Agent API.', + description: `Machine-readable OpenAPI ${openApiVersion} specification for the Oz Agent API.`, }, { label: 'Oz Agent API (OpenAPI spec, JSON)', url: 'https://docs.warp.dev/openapi.json', - description: 'Machine-readable OpenAPI 3.0 specification (JSON format) for the Oz Agent API.', + description: `Machine-readable OpenAPI ${openApiVersion} specification (JSON format) for the Oz Agent API.`, }, ], // Excludes pages that cause a stack overflow in hast-util-to-text diff --git a/src/pages/api.astro b/src/pages/api.astro index 4738c273c..1c0905030 100644 --- a/src/pages/api.astro +++ b/src/pages/api.astro @@ -395,7 +395,7 @@ const specBaseUrl = (specObject.servers as Array<{ url?: string }> | undefined)? } })(); - +