open-managed-agents 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. package/LICENSE +93 -0
  2. package/README.md +248 -0
  3. package/bin/oma.mjs +499 -0
  4. package/dist/scripts/alpha-openai-compatible-fixture.mjs +134 -0
  5. package/dist/scripts/alpha-smoke-models.mjs +92 -0
  6. package/dist/scripts/alpha-smoke.mjs +581 -0
  7. package/dist/scripts/oma-doctor.js +230 -0
  8. package/dist/scripts/oma-models.js +299 -0
  9. package/dist/scripts/oma-workspaces.js +133 -0
  10. package/dist/src/control-plane/admin/auth.js +43 -0
  11. package/dist/src/control-plane/admin/routes.js +76 -0
  12. package/dist/src/control-plane/admin/service.js +102 -0
  13. package/dist/src/control-plane/admission.js +90 -0
  14. package/dist/src/control-plane/agents/routes.js +63 -0
  15. package/dist/src/control-plane/agents/service.js +687 -0
  16. package/dist/src/control-plane/agents/store.js +391 -0
  17. package/dist/src/control-plane/agents/types.js +1 -0
  18. package/dist/src/control-plane/api-constants.js +3 -0
  19. package/dist/src/control-plane/app.js +907 -0
  20. package/dist/src/control-plane/console/auth.js +68 -0
  21. package/dist/src/control-plane/console/static.js +112 -0
  22. package/dist/src/control-plane/deployment-runtime-config.js +328 -0
  23. package/dist/src/control-plane/deployment-runtime-event-coordinator.js +25 -0
  24. package/dist/src/control-plane/deployment-runtime-turn-guard.js +14 -0
  25. package/dist/src/control-plane/deployment-session-coordinator.js +25 -0
  26. package/dist/src/control-plane/deployment-session-output-coordinator.js +27 -0
  27. package/dist/src/control-plane/deployment-storage.js +354 -0
  28. package/dist/src/control-plane/egress/image.js +48 -0
  29. package/dist/src/control-plane/egress/policy.js +571 -0
  30. package/dist/src/control-plane/egress/presets.js +77 -0
  31. package/dist/src/control-plane/egress/proxy.js +72 -0
  32. package/dist/src/control-plane/egress/ssrf.js +106 -0
  33. package/dist/src/control-plane/egress/utils/debug.js +14 -0
  34. package/dist/src/control-plane/egress/vendor/http-proxy.js +335 -0
  35. package/dist/src/control-plane/egress/vendor/mitm-ca.js +226 -0
  36. package/dist/src/control-plane/egress/vendor/mitm-leaf.js +124 -0
  37. package/dist/src/control-plane/egress/vendor/parent-proxy.js +438 -0
  38. package/dist/src/control-plane/egress/vendor/request-filter.js +105 -0
  39. package/dist/src/control-plane/egress/vendor/sandbox-config.js +1 -0
  40. package/dist/src/control-plane/egress/vendor/tls-terminate-proxy.js +269 -0
  41. package/dist/src/control-plane/environments/routes.js +54 -0
  42. package/dist/src/control-plane/environments/service.js +112 -0
  43. package/dist/src/control-plane/environments/store.js +132 -0
  44. package/dist/src/control-plane/environments/types.js +1 -0
  45. package/dist/src/control-plane/errors.js +81 -0
  46. package/dist/src/control-plane/events/broadcaster.js +217 -0
  47. package/dist/src/control-plane/events/constants.js +2 -0
  48. package/dist/src/control-plane/events/persist.js +39 -0
  49. package/dist/src/control-plane/events/request.js +190 -0
  50. package/dist/src/control-plane/events/routes.js +159 -0
  51. package/dist/src/control-plane/events/runtime-helpers.js +134 -0
  52. package/dist/src/control-plane/events/service.js +1985 -0
  53. package/dist/src/control-plane/events/session-guards.js +29 -0
  54. package/dist/src/control-plane/events/sse.js +6 -0
  55. package/dist/src/control-plane/events/store.js +772 -0
  56. package/dist/src/control-plane/events/tool-persistence.js +102 -0
  57. package/dist/src/control-plane/events/types.js +21 -0
  58. package/dist/src/control-plane/files/routes.js +121 -0
  59. package/dist/src/control-plane/files/service.js +65 -0
  60. package/dist/src/control-plane/files/store-common.js +87 -0
  61. package/dist/src/control-plane/files/store-local.js +488 -0
  62. package/dist/src/control-plane/files/store-memory.js +270 -0
  63. package/dist/src/control-plane/files/store.js +2 -0
  64. package/dist/src/control-plane/files/types.js +7 -0
  65. package/dist/src/control-plane/http.js +25 -0
  66. package/dist/src/control-plane/ids.js +43 -0
  67. package/dist/src/control-plane/logging.js +263 -0
  68. package/dist/src/control-plane/models/auth-storage-backend.js +238 -0
  69. package/dist/src/control-plane/models/catalog.js +78 -0
  70. package/dist/src/control-plane/models/config-security.js +376 -0
  71. package/dist/src/control-plane/models/deployment-config.js +93 -0
  72. package/dist/src/control-plane/models/routes.js +32 -0
  73. package/dist/src/control-plane/models/service.js +138 -0
  74. package/dist/src/control-plane/observability/instruments.js +65 -0
  75. package/dist/src/control-plane/observability/metrics.js +125 -0
  76. package/dist/src/control-plane/observability/routes.js +95 -0
  77. package/dist/src/control-plane/openapi/document.js +282 -0
  78. package/dist/src/control-plane/openapi/routes.js +78 -0
  79. package/dist/src/control-plane/request-idempotency.js +85 -0
  80. package/dist/src/control-plane/secrets/envelope.js +132 -0
  81. package/dist/src/control-plane/secrets/master-key.js +44 -0
  82. package/dist/src/control-plane/secrets/routes.js +20 -0
  83. package/dist/src/control-plane/secrets/service.js +71 -0
  84. package/dist/src/control-plane/secrets/store.js +212 -0
  85. package/dist/src/control-plane/secrets/types.js +3 -0
  86. package/dist/src/control-plane/sessions/pi/custom-tools.js +146 -0
  87. package/dist/src/control-plane/sessions/pi/mcp/bridge.js +527 -0
  88. package/dist/src/control-plane/sessions/pi/mcp/client.js +157 -0
  89. package/dist/src/control-plane/sessions/pi/mcp/credential.js +28 -0
  90. package/dist/src/control-plane/sessions/pi/mcp/fetch.js +69 -0
  91. package/dist/src/control-plane/sessions/pi/mcp/probe.js +202 -0
  92. package/dist/src/control-plane/sessions/pi/mcp/runtime.js +13 -0
  93. package/dist/src/control-plane/sessions/pi/runner.js +1104 -0
  94. package/dist/src/control-plane/sessions/pi/sandbox/cma-glob.js +388 -0
  95. package/dist/src/control-plane/sessions/pi/sandbox/cma-grep.js +124 -0
  96. package/dist/src/control-plane/sessions/pi/sandbox/docker-egress.js +347 -0
  97. package/dist/src/control-plane/sessions/pi/sandbox/docker.js +1589 -0
  98. package/dist/src/control-plane/sessions/pi/sandbox/glob.js +48 -0
  99. package/dist/src/control-plane/sessions/pi/sandbox/image.js +7 -0
  100. package/dist/src/control-plane/sessions/pi/sandbox/microsandbox.js +1677 -0
  101. package/dist/src/control-plane/sessions/pi/sandbox/provider.js +561 -0
  102. package/dist/src/control-plane/sessions/pi/sandbox/selection.js +168 -0
  103. package/dist/src/control-plane/sessions/pi/span-normalizer.js +82 -0
  104. package/dist/src/control-plane/sessions/pi/tool-permissions.js +392 -0
  105. package/dist/src/control-plane/sessions/pi/translator.js +100 -0
  106. package/dist/src/control-plane/sessions/request.js +164 -0
  107. package/dist/src/control-plane/sessions/resources.js +63 -0
  108. package/dist/src/control-plane/sessions/routes.js +88 -0
  109. package/dist/src/control-plane/sessions/serialize.js +24 -0
  110. package/dist/src/control-plane/sessions/service.js +733 -0
  111. package/dist/src/control-plane/sessions/store.js +538 -0
  112. package/dist/src/control-plane/sessions/types.js +1 -0
  113. package/dist/src/control-plane/skills/archive.js +169 -0
  114. package/dist/src/control-plane/skills/routes.js +41 -0
  115. package/dist/src/control-plane/skills/service.js +29 -0
  116. package/dist/src/control-plane/skills/store.js +233 -0
  117. package/dist/src/control-plane/skills/types.js +5 -0
  118. package/dist/src/control-plane/sqlite-transaction.js +15 -0
  119. package/dist/src/control-plane/vaults/mcp-oauth-validate.js +165 -0
  120. package/dist/src/control-plane/vaults/oauth-refresh-ticker.js +43 -0
  121. package/dist/src/control-plane/vaults/oauth-refresh.js +448 -0
  122. package/dist/src/control-plane/vaults/routes.js +66 -0
  123. package/dist/src/control-plane/vaults/service.js +553 -0
  124. package/dist/src/control-plane/vaults/store.js +691 -0
  125. package/dist/src/control-plane/vaults/types.js +1 -0
  126. package/dist/src/control-plane/wake-loop.js +65 -0
  127. package/dist/src/control-plane/wiring.js +92 -0
  128. package/dist/src/control-plane/workspace.js +4 -0
  129. package/dist/src/control-plane/workspaces/store.js +158 -0
  130. package/dist/src/egress-proxy-main.js +103 -0
  131. package/dist/src/main.js +124 -0
  132. package/dist/src/types/agents.js +1 -0
  133. package/dist/src/types/common.js +1 -0
  134. package/dist/src/types/environments.js +1 -0
  135. package/dist/src/types/events.js +121 -0
  136. package/dist/src/types/files.js +1 -0
  137. package/dist/src/types/json.js +19 -0
  138. package/dist/src/types/sessions.js +1 -0
  139. package/dist/ui/managed-agents-console/README.md +52 -0
  140. package/dist/ui/managed-agents-console/docs/agents.md +23 -0
  141. package/dist/ui/managed-agents-console/docs/console.md +23 -0
  142. package/dist/ui/managed-agents-console/docs/dreams.md +5 -0
  143. package/dist/ui/managed-agents-console/docs/environments.md +27 -0
  144. package/dist/ui/managed-agents-console/docs/events.md +19 -0
  145. package/dist/ui/managed-agents-console/docs/files.md +17 -0
  146. package/dist/ui/managed-agents-console/docs/github.md +11 -0
  147. package/dist/ui/managed-agents-console/docs/integrations.md +19 -0
  148. package/dist/ui/managed-agents-console/docs/memory.md +11 -0
  149. package/dist/ui/managed-agents-console/docs/migration.md +17 -0
  150. package/dist/ui/managed-agents-console/docs/multiagent.md +11 -0
  151. package/dist/ui/managed-agents-console/docs/outcomes.md +11 -0
  152. package/dist/ui/managed-agents-console/docs/overview.md +41 -0
  153. package/dist/ui/managed-agents-console/docs/permissions.md +24 -0
  154. package/dist/ui/managed-agents-console/docs/quickstart.md +51 -0
  155. package/dist/ui/managed-agents-console/docs/reference.md +27 -0
  156. package/dist/ui/managed-agents-console/docs/sandbox-reference.md +19 -0
  157. package/dist/ui/managed-agents-console/docs/sandbox-security.md +15 -0
  158. package/dist/ui/managed-agents-console/docs/scheduled-deployments.md +5 -0
  159. package/dist/ui/managed-agents-console/docs/self-hosted-sandboxes.md +15 -0
  160. package/dist/ui/managed-agents-console/docs/session-operations.md +21 -0
  161. package/dist/ui/managed-agents-console/docs/sessions.md +21 -0
  162. package/dist/ui/managed-agents-console/docs/skills.md +15 -0
  163. package/dist/ui/managed-agents-console/docs/tools.md +23 -0
  164. package/dist/ui/managed-agents-console/docs/vaults.md +19 -0
  165. package/dist/ui/managed-agents-console/docs/webhooks.md +11 -0
  166. package/dist/ui/managed-agents-console/index.html +47 -0
  167. package/dist/ui/managed-agents-console/serve.mjs +116 -0
  168. package/dist/ui/managed-agents-console/src/agents-files.jsx +273 -0
  169. package/dist/ui/managed-agents-console/src/api.js +1043 -0
  170. package/dist/ui/managed-agents-console/src/app.jsx +633 -0
  171. package/dist/ui/managed-agents-console/src/auth.jsx +215 -0
  172. package/dist/ui/managed-agents-console/src/console.css +733 -0
  173. package/dist/ui/managed-agents-console/src/data.js +188 -0
  174. package/dist/ui/managed-agents-console/src/detail.jsx +719 -0
  175. package/dist/ui/managed-agents-console/src/docs.jsx +200 -0
  176. package/dist/ui/managed-agents-console/src/environments.jsx +365 -0
  177. package/dist/ui/managed-agents-console/src/forms.jsx +494 -0
  178. package/dist/ui/managed-agents-console/src/icons.jsx +48 -0
  179. package/dist/ui/managed-agents-console/src/skills.jsx +21 -0
  180. package/dist/ui/managed-agents-console/src/sse.js +185 -0
  181. package/dist/ui/managed-agents-console/src/states.jsx +90 -0
  182. package/dist/ui/managed-agents-console/src/tweaks-panel.jsx +541 -0
  183. package/dist/ui/managed-agents-console/src/ui.jsx +190 -0
  184. package/dist/ui/managed-agents-console/src/vaults-data.js +89 -0
  185. package/dist/ui/managed-agents-console/src/vaults.jsx +171 -0
  186. package/dist/ui/managed-agents-console/vendor/babel.min.js +4 -0
  187. package/dist/ui/managed-agents-console/vendor/react-dom.production.min.js +267 -0
  188. package/dist/ui/managed-agents-console/vendor/react.production.min.js +31 -0
  189. package/dist/ui/openapi-docs/VENDOR.md +27 -0
  190. package/dist/ui/openapi-docs/index.html +16 -0
  191. package/dist/ui/openapi-docs/swagger-initializer.js +14 -0
  192. package/dist/ui/openapi-docs/vendor/LICENSE +202 -0
  193. package/dist/ui/openapi-docs/vendor/NOTICE +2 -0
  194. package/dist/ui/openapi-docs/vendor/swagger-ui-bundle.js +2 -0
  195. package/dist/ui/openapi-docs/vendor/swagger-ui-standalone-preset.js +2 -0
  196. package/dist/ui/openapi-docs/vendor/swagger-ui.css +3 -0
  197. package/package.json +53 -0
@@ -0,0 +1,282 @@
1
+ import { FILES_API_BETA, MANAGED_AGENTS_BETA, SKILLS_API_BETA, } from "../api-constants.js";
2
+ import { EVENT_TYPES } from "../../types/events.js";
3
+ const DOCUMENTED_EVENT_TYPES = EVENT_TYPES;
4
+ const TAG_DESCRIPTIONS = {
5
+ Agents: "Versioned Managed Agents definitions.",
6
+ Environments: "Sandbox execution environment configuration.",
7
+ Files: "Workspace uploads, session outputs, and downloads.",
8
+ Skills: "Custom reusable skill bundles and immutable versions.",
9
+ "Secrets (OMA)": "OMA-specific write-only workspace secrets.",
10
+ Vaults: "Vault and MCP credential lifecycle.",
11
+ Sessions: "Managed Agent session lifecycle.",
12
+ "Session events": "User input, event history, and SSE streaming.",
13
+ "Models (OMA)": "OMA-specific provider/model readiness catalog.",
14
+ "Administration (OMA)": "OMA-specific local workspace and API-key administration.",
15
+ "Operations (OMA)": "OMA-specific health and metrics endpoints.",
16
+ };
17
+ const ref = (name) => ({ $ref: `#/components/schemas/${name}` });
18
+ const jsonContent = (schema, example) => ({
19
+ "application/json": { schema, ...(example === undefined ? {} : { example }) },
20
+ });
21
+ const jsonResponse = (description, schema, example) => ({
22
+ description,
23
+ content: jsonContent(schema, example),
24
+ });
25
+ const noContent = (description) => ({ description });
26
+ const jsonBody = (schema, required = true, example) => ({
27
+ required,
28
+ content: jsonContent(schema, example),
29
+ });
30
+ const multipartBody = (properties, required) => ({
31
+ required: true,
32
+ content: {
33
+ "multipart/form-data": {
34
+ schema: { type: "object", properties, required, additionalProperties: false },
35
+ },
36
+ },
37
+ });
38
+ const pathParam = (name, description) => ({
39
+ name,
40
+ in: "path",
41
+ required: true,
42
+ ...(description === undefined ? {} : { description }),
43
+ schema: { type: "string", minLength: 1 },
44
+ });
45
+ const queryParam = (name, schema, description) => ({
46
+ name,
47
+ in: "query",
48
+ required: false,
49
+ ...(description === undefined ? {} : { description }),
50
+ schema,
51
+ });
52
+ const headerParam = (name, schema, required, description) => ({
53
+ name,
54
+ in: "header",
55
+ required,
56
+ ...(description === undefined ? {} : { description }),
57
+ schema,
58
+ });
59
+ const limit = queryParam("limit", { type: "integer", minimum: 1, maximum: 100 });
60
+ const page = queryParam("page", { type: "string", minLength: 1 }, "Opaque cursor; return it unchanged.");
61
+ const includeArchived = queryParam("include_archived", { type: "boolean", default: false });
62
+ const idempotencyKey = headerParam("idempotency-key", { type: "string", minLength: 1, maxLength: 255 }, false, "Optional idempotency key for safely retrying this write.");
63
+ const commonErrors = {
64
+ "400": jsonResponse("Invalid request", ref("Error")),
65
+ "401": jsonResponse("Authentication failed", ref("Error")),
66
+ "404": jsonResponse("Resource or route not found", ref("Error")),
67
+ "409": jsonResponse("Concurrent modification or idempotency conflict", ref("Error")),
68
+ "413": jsonResponse("Request too large", ref("Error")),
69
+ "429": jsonResponse("Workspace admission limit exceeded", ref("Error")),
70
+ "500": jsonResponse("Internal server error", ref("Error")),
71
+ };
72
+ function responses(status, schema, description = "Success") {
73
+ return {
74
+ [String(status)]: schema === undefined ? noContent(description) : jsonResponse(description, schema),
75
+ ...commonErrors,
76
+ };
77
+ }
78
+ function route(contract) {
79
+ const { success, ...rest } = contract;
80
+ return {
81
+ ...rest,
82
+ responses: success?.mediaType === undefined
83
+ ? responses(success?.status ?? 200, success?.schema, success?.description ?? "Success")
84
+ : {
85
+ [String(success.status ?? 200)]: {
86
+ description: success.description ?? "Success",
87
+ content: {
88
+ [success.mediaType]: { schema: success.schema ?? { type: "string" } },
89
+ },
90
+ },
91
+ ...commonErrors,
92
+ },
93
+ };
94
+ }
95
+ const agentId = pathParam("id", "Agent ID.");
96
+ const vaultId = pathParam("vaultId", "Vault ID.");
97
+ const credentialId = pathParam("credentialId", "Vault credential ID.");
98
+ const sessionId = pathParam("sessionId", "Session ID.");
99
+ export const OPENAPI_ROUTE_CONTRACTS = [
100
+ route({ method: "get", path: "/health", operationId: "getHealth", tag: "Operations (OMA)", summary: "Check appliance health", auth: "none", success: { schema: ref("Health") } }),
101
+ route({ method: "get", path: "/metrics", operationId: "getMetrics", tag: "Operations (OMA)", summary: "Read Prometheus metrics", description: "This route is registered only when metrics are enabled and the deployment exposure policy permits it. Otherwise it returns 404.", auth: "metrics", success: { schema: { type: "string" }, mediaType: "text/plain", description: "Prometheus exposition" } }),
102
+ route({ method: "post", path: "/v1/agents", operationId: "createAgent", tag: "Agents", summary: "Create an agent", auth: "workspace", beta: "managed", requestBody: jsonBody(ref("CreateAgentRequest"), true, { name: "Coding agent", model: "claude-sonnet-5" }), success: { schema: ref("Agent") } }),
103
+ route({ method: "get", path: "/v1/agents", operationId: "listAgents", tag: "Agents", summary: "List agents", auth: "workspace", beta: "managed", parameters: [limit, page, includeArchived], success: { schema: ref("ForwardAgentPage") } }),
104
+ route({ method: "get", path: "/v1/agents/{id}/versions", operationId: "listAgentVersions", tag: "Agents", summary: "List immutable agent versions", auth: "workspace", beta: "managed", parameters: [agentId, limit, page], success: { schema: ref("AgentVersionsPage") } }),
105
+ route({ method: "get", path: "/v1/agents/{id}", operationId: "getAgent", tag: "Agents", summary: "Retrieve an agent or historical version", auth: "workspace", beta: "managed", parameters: [agentId, queryParam("version", { type: "integer", minimum: 1 })], success: { schema: ref("Agent") } }),
106
+ route({ method: "post", path: "/v1/agents/{id}", operationId: "updateAgent", tag: "Agents", summary: "Create a new immutable agent version", auth: "workspace", beta: "managed", parameters: [agentId], requestBody: jsonBody(ref("UpdateAgentRequest")), success: { schema: ref("Agent") } }),
107
+ route({ method: "post", path: "/v1/agents/{id}/archive", operationId: "archiveAgent", tag: "Agents", summary: "Archive an agent", auth: "workspace", beta: "managed", parameters: [agentId], success: { schema: ref("Agent") } }),
108
+ route({ method: "post", path: "/v1/environments", operationId: "createEnvironment", tag: "Environments", summary: "Create an environment", auth: "workspace", beta: "managed", requestBody: jsonBody(ref("CreateEnvironmentRequest")), success: { schema: ref("Environment") } }),
109
+ route({ method: "get", path: "/v1/environments", operationId: "listEnvironments", tag: "Environments", summary: "List environments", auth: "workspace", beta: "managed", parameters: [limit, page, includeArchived], success: { schema: ref("ForwardEnvironmentPage") } }),
110
+ route({ method: "get", path: "/v1/environments/networking-presets", operationId: "listEnvironmentNetworkingPresets", tag: "Environments", summary: "List safe networking presets and deployment capability", auth: "workspace", beta: "managed", success: { schema: ref("EnvironmentNetworkingPresetCatalog") } }),
111
+ route({ method: "post", path: "/v1/environments/networking-presets/validate", operationId: "validateEnvironmentNetworkingHosts", tag: "Environments", summary: "Validate and normalize a custom hostname allowlist", auth: "workspace", beta: "managed", requestBody: jsonBody(ref("ValidateEnvironmentNetworkingHostsRequest")), success: { schema: ref("ValidateEnvironmentNetworkingHostsResponse") } }),
112
+ route({ method: "get", path: "/v1/environments/{id}", operationId: "getEnvironment", tag: "Environments", summary: "Retrieve an environment", auth: "workspace", beta: "managed", parameters: [pathParam("id", "Environment ID.")], success: { schema: ref("Environment") } }),
113
+ route({ method: "post", path: "/v1/environments/{id}/archive", operationId: "archiveEnvironment", tag: "Environments", summary: "Archive an environment", auth: "workspace", beta: "managed", parameters: [pathParam("id", "Environment ID.")], success: { schema: ref("Environment") } }),
114
+ route({ method: "delete", path: "/v1/environments/{id}", operationId: "deleteEnvironment", tag: "Environments", summary: "Delete an unreferenced environment", description: "OMA deliberately refuses deletion while any durable session references the environment.", auth: "workspace", beta: "managed", parameters: [pathParam("id", "Environment ID.")], success: { schema: ref("DeletedEnvironment") } }),
115
+ route({ method: "post", path: "/v1/files", operationId: "uploadFile", tag: "Files", summary: "Upload a file", auth: "workspace", beta: "files", requestBody: multipartBody({ file: { type: "string", format: "binary" } }, ["file"]), success: { schema: ref("File") } }),
116
+ route({ method: "get", path: "/v1/files", operationId: "listFiles", tag: "Files", summary: "List files", auth: "workspace", beta: "files", parameters: [limit, queryParam("after_id", { type: "string" }), queryParam("before_id", { type: "string" }), queryParam("scope_id", { type: "string" })], success: { schema: ref("FilePage") } }),
117
+ route({ method: "get", path: "/v1/files/{id}", operationId: "getFile", tag: "Files", summary: "Retrieve file metadata", auth: "workspace", beta: "files", parameters: [pathParam("id", "File ID.")], success: { schema: ref("File") } }),
118
+ route({ method: "get", path: "/v1/files/{id}/content", operationId: "downloadFile", tag: "Files", summary: "Download file content", auth: "workspace", beta: "files", parameters: [pathParam("id", "File ID.")], success: { schema: { type: "string", format: "binary" }, mediaType: "application/octet-stream", description: "Raw file bytes" } }),
119
+ route({ method: "delete", path: "/v1/files/{id}", operationId: "deleteFile", tag: "Files", summary: "Delete a file", auth: "workspace", beta: "files", parameters: [pathParam("id", "File ID.")], success: { schema: ref("DeletedFile") } }),
120
+ route({ method: "post", path: "/v1/skills", operationId: "createSkill", tag: "Skills", summary: "Create a custom skill", auth: "workspace", beta: "skills", requestBody: multipartBody({ display_title: { type: "string" }, "files[]": { type: "array", items: { type: "string", format: "binary" }, minItems: 1 } }, ["files[]"]), success: { schema: ref("Skill") } }),
121
+ route({ method: "get", path: "/v1/skills", operationId: "listSkills", tag: "Skills", summary: "List skills", auth: "workspace", beta: "skills", parameters: [limit, page], success: { schema: ref("SkillPage") } }),
122
+ route({ method: "get", path: "/v1/skills/{id}", operationId: "getSkill", tag: "Skills", summary: "Retrieve a skill", auth: "workspace", beta: "skills", parameters: [pathParam("id", "Skill ID.")], success: { schema: ref("Skill") } }),
123
+ route({ method: "delete", path: "/v1/skills/{id}", operationId: "deleteSkill", tag: "Skills", summary: "Delete a skill", auth: "workspace", beta: "skills", parameters: [pathParam("id", "Skill ID.")], success: { schema: ref("DeletedSkill") } }),
124
+ route({ method: "post", path: "/v1/skills/{id}/versions", operationId: "createSkillVersion", tag: "Skills", summary: "Create a skill version", auth: "workspace", beta: "skills", parameters: [pathParam("id", "Skill ID.")], requestBody: multipartBody({ "files[]": { type: "array", items: { type: "string", format: "binary" }, minItems: 1 } }, ["files[]"]), success: { schema: ref("SkillVersion") } }),
125
+ route({ method: "get", path: "/v1/skills/{id}/versions", operationId: "listSkillVersions", tag: "Skills", summary: "List skill versions", auth: "workspace", beta: "skills", parameters: [pathParam("id", "Skill ID."), limit, page], success: { schema: ref("SkillVersionPage") } }),
126
+ route({ method: "get", path: "/v1/skills/{id}/versions/{version}", operationId: "getSkillVersion", tag: "Skills", summary: "Retrieve a skill version", auth: "workspace", beta: "skills", parameters: [pathParam("id", "Skill ID."), pathParam("version", "Version or latest.")], success: { schema: ref("SkillVersion") } }),
127
+ route({ method: "delete", path: "/v1/skills/{id}/versions/{version}", operationId: "deleteSkillVersion", tag: "Skills", summary: "Delete a skill version", auth: "workspace", beta: "skills", parameters: [pathParam("id", "Skill ID."), pathParam("version", "Version or latest.")], success: { schema: ref("DeletedSkillVersion") } }),
128
+ route({ method: "post", path: "/v1/secrets", operationId: "upsertSecret", tag: "Secrets (OMA)", summary: "Create or replace a write-only secret", auth: "workspace", beta: "managed", requestBody: jsonBody(ref("CreateSecretRequest")), success: { status: 201, schema: ref("Secret") } }),
129
+ route({ method: "get", path: "/v1/secrets", operationId: "listSecrets", tag: "Secrets (OMA)", summary: "List secret metadata", auth: "workspace", beta: "managed", success: { schema: { type: "array", items: ref("Secret") } } }),
130
+ route({ method: "delete", path: "/v1/secrets/{name}", operationId: "deleteSecret", tag: "Secrets (OMA)", summary: "Delete a secret", auth: "workspace", beta: "managed", parameters: [pathParam("name", "Secret name.")], success: { status: 204, description: "Deleted" } }),
131
+ route({ method: "post", path: "/v1/vaults", operationId: "createVault", tag: "Vaults", summary: "Create a vault", auth: "workspace", beta: "managed", requestBody: jsonBody(ref("CreateVaultRequest")), success: { schema: ref("Vault") } }),
132
+ route({ method: "get", path: "/v1/vaults", operationId: "listVaults", tag: "Vaults", summary: "List vaults", auth: "workspace", beta: "managed", parameters: [limit, page, includeArchived], success: { schema: ref("ForwardVaultPage") } }),
133
+ route({ method: "get", path: "/v1/vaults/{vaultId}", operationId: "getVault", tag: "Vaults", summary: "Retrieve a vault", auth: "workspace", beta: "managed", parameters: [vaultId], success: { schema: ref("Vault") } }),
134
+ route({ method: "post", path: "/v1/vaults/{vaultId}/archive", operationId: "archiveVault", tag: "Vaults", summary: "Archive a vault", auth: "workspace", beta: "managed", parameters: [vaultId], success: { schema: ref("Vault") } }),
135
+ route({ method: "post", path: "/v1/vaults/{vaultId}", operationId: "updateVault", tag: "Vaults", summary: "Update a vault", auth: "workspace", beta: "managed", parameters: [vaultId], requestBody: jsonBody(ref("UpdateVaultRequest")), success: { schema: ref("Vault") } }),
136
+ route({ method: "delete", path: "/v1/vaults/{vaultId}", operationId: "deleteVault", tag: "Vaults", summary: "Delete a vault", auth: "workspace", beta: "managed", parameters: [vaultId], success: { schema: ref("DeletedVault") } }),
137
+ route({ method: "post", path: "/v1/vaults/{vaultId}/credentials", operationId: "createVaultCredential", tag: "Vaults", summary: "Create a vault credential", auth: "workspace", beta: "managed", parameters: [vaultId], requestBody: jsonBody(ref("CreateCredentialRequest")), success: { schema: ref("VaultCredential") } }),
138
+ route({ method: "get", path: "/v1/vaults/{vaultId}/credentials", operationId: "listVaultCredentials", tag: "Vaults", summary: "List vault credentials", auth: "workspace", beta: "managed", parameters: [vaultId, limit, page, includeArchived], success: { schema: ref("ForwardCredentialPage") } }),
139
+ route({ method: "post", path: "/v1/vaults/{vaultId}/credentials/{credentialId}/archive", operationId: "archiveVaultCredential", tag: "Vaults", summary: "Archive a vault credential", auth: "workspace", beta: "managed", parameters: [vaultId, credentialId], success: { schema: ref("VaultCredential") } }),
140
+ route({ method: "post", path: "/v1/vaults/{vaultId}/credentials/{credentialId}/mcp_oauth_validate", operationId: "validateVaultCredential", tag: "Vaults", summary: "Validate an MCP OAuth credential", auth: "workspace", beta: "managed", parameters: [vaultId, credentialId], success: { schema: { type: "object", additionalProperties: true } } }),
141
+ route({ method: "get", path: "/v1/vaults/{vaultId}/credentials/{credentialId}", operationId: "getVaultCredential", tag: "Vaults", summary: "Retrieve vault credential metadata", auth: "workspace", beta: "managed", parameters: [vaultId, credentialId], success: { schema: ref("VaultCredential") } }),
142
+ route({ method: "post", path: "/v1/vaults/{vaultId}/credentials/{credentialId}", operationId: "updateVaultCredential", tag: "Vaults", summary: "Update a vault credential", auth: "workspace", beta: "managed", parameters: [vaultId, credentialId], requestBody: jsonBody(ref("UpdateCredentialRequest")), success: { schema: ref("VaultCredential") } }),
143
+ route({ method: "delete", path: "/v1/vaults/{vaultId}/credentials/{credentialId}", operationId: "deleteVaultCredential", tag: "Vaults", summary: "Delete a vault credential", auth: "workspace", beta: "managed", parameters: [vaultId, credentialId], success: { status: 204, description: "Deleted" } }),
144
+ route({ method: "post", path: "/v1/sessions", operationId: "createSession", tag: "Sessions", summary: "Create a session", auth: "workspace", beta: "managed", parameters: [idempotencyKey], requestBody: jsonBody(ref("CreateSessionRequest")), success: { schema: ref("Session") } }),
145
+ route({ method: "get", path: "/v1/sessions", operationId: "listSessions", tag: "Sessions", summary: "List sessions with forward/backward cursors", auth: "workspace", beta: "managed", parameters: [limit, page, queryParam("order", { type: "string", enum: ["asc", "desc"], default: "desc" }), queryParam("agent_id", { type: "string" }), includeArchived], success: { schema: ref("SessionPage") } }),
146
+ route({ method: "get", path: "/v1/sessions/{id}", operationId: "getSession", tag: "Sessions", summary: "Retrieve a session", auth: "workspace", beta: "managed", parameters: [pathParam("id", "Session ID.")], success: { schema: ref("Session") } }),
147
+ route({ method: "post", path: "/v1/sessions/{id}/archive", operationId: "archiveSession", tag: "Sessions", summary: "Archive an idle session", auth: "workspace", beta: "managed", parameters: [pathParam("id", "Session ID.")], success: { schema: ref("Session") } }),
148
+ route({ method: "delete", path: "/v1/sessions/{id}", operationId: "deleteSession", tag: "Sessions", summary: "Delete an idle session", auth: "workspace", beta: "managed", parameters: [pathParam("id", "Session ID.")], success: { schema: ref("DeletedSession") } }),
149
+ route({ method: "post", path: "/v1/sessions/{sessionId}/events", operationId: "sendSessionEvents", tag: "Session events", summary: "Send user events to a session", auth: "workspace", beta: "managed", parameters: [sessionId, idempotencyKey], requestBody: jsonBody(ref("SendEventsRequest"), true, { events: [{ type: "user.message", content: [{ type: "text", text: "Hello" }] }] }), success: { schema: ref("EventPage") } }),
150
+ route({ method: "get", path: "/v1/sessions/{sessionId}/events", operationId: "listSessionEvents", tag: "Session events", summary: "List session events", auth: "workspace", beta: "managed", parameters: [sessionId, limit, page, queryParam("order", { type: "string", enum: ["asc", "desc"] }), queryParam("types[]", { type: "array", items: { type: "string", enum: DOCUMENTED_EVENT_TYPES } }, "Repeat to filter by an event type currently emitted by OMA.")], success: { schema: ref("EventPage") } }),
151
+ route({ method: "get", path: "/v1/sessions/{sessionId}/events/stream", operationId: "streamSessionEvents", tag: "Session events", summary: "Stream persisted session events over SSE", description: "OMA streams complete persisted events. Assistant text is emitted as a buffered `agent.message` after generation, not as token-preview deltas. The unsupported `event_deltas[]` query parameter is rejected with HTTP 400.", auth: "workspace", beta: "managed", parameters: [sessionId, headerParam("last-event-id", { type: "string" }, false, "Resume after this event ID.")], success: { schema: { type: "string", description: "SSE frames with id, event, and JSON data fields." }, mediaType: "text/event-stream", description: "SSE stream" } }),
152
+ route({ method: "get", path: "/v1/model-catalog", operationId: "listModelCatalog", tag: "Models (OMA)", summary: "List deployment-enabled model catalog entries", description: "OMA-specific discovery endpoint for provider/model readiness. It never returns base URLs, credential sources, header values, file paths, raw Pi config, or secrets.", auth: "workspace", beta: "managed", parameters: [queryParam("provider", { type: "string", minLength: 1 }, "Exact provider id."), queryParam("available", { type: "boolean", default: false }, "When true, include only models with configured local credentials."), limit, page], success: { schema: ref("ModelCatalogPage") } }),
153
+ route({ method: "post", path: "/admin/workspaces", operationId: "adminCreateWorkspace", tag: "Administration (OMA)", summary: "Create a workspace", auth: "admin", requestBody: jsonBody(ref("AdminCreateWorkspaceRequest")), success: { status: 201, schema: ref("AdminWorkspace") } }),
154
+ route({ method: "get", path: "/admin/workspaces", operationId: "adminListWorkspaces", tag: "Administration (OMA)", summary: "List workspaces", auth: "admin", success: { schema: { type: "array", items: ref("AdminWorkspace") } } }),
155
+ route({ method: "get", path: "/admin/workspaces/{id}", operationId: "adminGetWorkspace", tag: "Administration (OMA)", summary: "Retrieve a workspace", auth: "admin", parameters: [pathParam("id", "Workspace ID.")], success: { schema: ref("AdminWorkspace") } }),
156
+ route({ method: "post", path: "/admin/workspaces/{id}/keys", operationId: "adminMintWorkspaceKey", tag: "Administration (OMA)", summary: "Mint a workspace API key", auth: "admin", parameters: [pathParam("id", "Workspace ID.")], requestBody: jsonBody(ref("AdminMintKeyRequest"), false), success: { status: 201, schema: ref("AdminMintedKey") } }),
157
+ route({ method: "get", path: "/admin/workspaces/{id}/keys", operationId: "adminListWorkspaceKeys", tag: "Administration (OMA)", summary: "List workspace API key metadata", auth: "admin", parameters: [pathParam("id", "Workspace ID.")], success: { schema: { type: "array", items: ref("AdminKeyMetadata") } } }),
158
+ route({ method: "get", path: "/admin/workspaces/{id}/mcp-credentials", operationId: "adminListWorkspaceMcpCredentials", tag: "Administration (OMA)", summary: "List token-free MCP credential operational metadata", auth: "admin", parameters: [pathParam("id", "Workspace ID."), limit, page], success: { schema: ref("GenericForwardPage") } }),
159
+ route({ method: "delete", path: "/admin/keys/{sha256}", operationId: "adminRevokeWorkspaceKey", tag: "Administration (OMA)", summary: "Revoke a workspace API key", auth: "admin", parameters: [pathParam("sha256", "SHA-256 key fingerprint.")], success: { schema: ref("AdminKeyMetadata") } }),
160
+ ];
161
+ const schemas = {
162
+ Error: { type: "object", required: ["type", "error", "request_id"], properties: { type: { const: "error" }, error: { type: "object", required: ["type", "message"], properties: { type: { type: "string" }, message: { type: "string" } }, additionalProperties: true }, request_id: { type: "string" } }, additionalProperties: false },
163
+ JsonObject: { type: "object", additionalProperties: true },
164
+ StringMap: { type: "object", additionalProperties: { type: "string" } },
165
+ NullableString: { type: ["string", "null"] },
166
+ ModelInput: { oneOf: [{ type: "string" }, { type: "object", required: ["id"], properties: { provider: { type: "string", minLength: 1 }, id: { type: "string", minLength: 1 }, speed: { type: "string", enum: ["standard", "fast"] } }, additionalProperties: false }] },
167
+ CreateAgentRequest: { type: "object", required: ["name", "model"], properties: { name: { type: "string", minLength: 1 }, model: ref("ModelInput"), system: ref("NullableString"), description: ref("NullableString"), tools: { type: "array", items: ref("JsonObject") }, skills: { type: "array", items: ref("JsonObject") }, mcp_servers: { type: "array", items: ref("JsonObject") }, metadata: ref("StringMap"), multiagent: { type: "null", description: "Full multi-agent runtime is not implemented. Omit this field or send null." } }, additionalProperties: false },
168
+ UpdateAgentRequest: { type: "object", required: ["version"], properties: { version: { type: "integer", minimum: 1 }, name: { type: "string", minLength: 1 }, model: ref("ModelInput"), system: ref("NullableString"), description: ref("NullableString"), tools: { type: ["array", "null"], items: ref("JsonObject") }, skills: { type: ["array", "null"], items: ref("JsonObject") }, mcp_servers: { type: ["array", "null"], items: ref("JsonObject") }, metadata: { type: "object", additionalProperties: { type: ["string", "null"] } }, multiagent: { type: "null", description: "Full multi-agent runtime is not implemented. Omit this field or send null." } }, additionalProperties: false },
169
+ Agent: { type: "object", required: ["id", "type", "name", "model", "version", "created_at", "updated_at", "archived_at"], properties: { id: { type: "string" }, type: { const: "agent" }, name: { type: "string" }, model: { type: "object", required: ["provider", "id", "speed"], properties: { provider: { type: "string" }, id: { type: "string" }, speed: { enum: ["standard", "fast"] } }, additionalProperties: false }, system: ref("NullableString"), description: ref("NullableString"), tools: { type: "array", items: ref("JsonObject") }, skills: { type: "array", items: ref("JsonObject") }, mcp_servers: { type: "array", items: ref("JsonObject") }, metadata: ref("StringMap"), multiagent: { type: ["object", "null"] }, version: { type: "integer", minimum: 1 }, created_at: { type: "string", format: "date-time" }, updated_at: { type: "string", format: "date-time" }, archived_at: { type: ["string", "null"], format: "date-time" } }, additionalProperties: false },
170
+ CreateEnvironmentRequest: { type: "object", required: ["name", "config"], properties: { name: { type: "string", minLength: 1 }, config: ref("JsonObject") }, additionalProperties: false },
171
+ Environment: { type: "object", required: ["id", "type", "name", "config", "created_at", "updated_at", "archived_at"], properties: { id: { type: "string" }, type: { const: "environment" }, name: { type: "string" }, config: ref("JsonObject"), created_at: { type: "string", format: "date-time" }, updated_at: { type: "string", format: "date-time" }, archived_at: { type: ["string", "null"], format: "date-time" } } },
172
+ DeletedEnvironment: { type: "object", required: ["type", "id"], properties: { type: { const: "environment_deleted" }, id: { type: "string" } }, additionalProperties: false },
173
+ EnvironmentNetworkingPresetCatalog: { type: "object", required: ["type", "deployment", "presets", "custom"], properties: { type: { const: "environment_networking_presets" }, deployment: { type: "object", required: ["provider", "egress_supported", "reason"], properties: { provider: { type: ["string", "null"] }, egress_supported: { type: "boolean" }, reason: { type: ["string", "null"] } }, additionalProperties: false }, presets: { type: "array", items: { type: "object", required: ["id", "version", "name", "description", "networking"], properties: { id: { type: "string" }, version: { type: "integer", minimum: 1 }, name: { type: "string" }, description: { type: "string" }, networking: { type: "object", required: ["type", "allowed_hosts"], properties: { type: { const: "limited" }, allowed_hosts: { type: "array", items: { type: "string" } } }, additionalProperties: false } }, additionalProperties: false } }, custom: { type: "object", required: ["https_only", "wildcard_matches_bare_domain"], properties: { https_only: { const: true }, wildcard_matches_bare_domain: { const: false } }, additionalProperties: false } }, additionalProperties: false },
174
+ ValidateEnvironmentNetworkingHostsRequest: { type: "object", required: ["allowed_hosts"], properties: { allowed_hosts: { type: "array", items: { type: "string" } } }, additionalProperties: false },
175
+ ValidateEnvironmentNetworkingHostsResponse: { type: "object", required: ["allowed_hosts"], properties: { allowed_hosts: { type: "array", items: { type: "string" } } }, additionalProperties: false },
176
+ File: { type: "object", required: ["id", "type", "filename", "mime_type", "size_bytes", "created_at", "downloadable", "scope"], properties: { id: { type: "string" }, type: { const: "file" }, filename: { type: "string" }, mime_type: { type: "string" }, size_bytes: { type: "integer", minimum: 0 }, downloadable: { type: "boolean" }, scope: { type: ["object", "null"] }, created_at: { type: "string", format: "date-time" } }, additionalProperties: false },
177
+ DeletedFile: { type: "object", required: ["id", "type"], properties: { id: { type: "string" }, type: { const: "file_deleted" } }, additionalProperties: false },
178
+ Skill: { type: "object", required: ["id", "type", "display_title", "source", "latest_version", "created_at", "updated_at"], properties: { id: { type: "string" }, type: { const: "skill" }, display_title: { type: "string" }, source: { const: "custom" }, latest_version: { type: ["string", "null"] }, created_at: { type: "string", format: "date-time" }, updated_at: { type: "string", format: "date-time" } }, additionalProperties: false },
179
+ SkillVersion: { type: "object", required: ["id", "type", "skill_id", "version", "name", "description", "directory", "created_at"], properties: { id: { type: "string" }, type: { const: "skill_version" }, skill_id: { type: "string" }, version: { type: "string" }, name: { type: "string" }, description: { type: "string" }, directory: { type: "string" }, created_at: { type: "string", format: "date-time" } }, additionalProperties: false },
180
+ DeletedSkill: { type: "object", required: ["id", "type"], properties: { id: { type: "string" }, type: { const: "skill_deleted" } }, additionalProperties: false },
181
+ DeletedSkillVersion: { type: "object", required: ["id", "type"], properties: { id: { type: "string" }, type: { const: "skill_version_deleted" } }, additionalProperties: false },
182
+ CreateSecretRequest: { type: "object", required: ["name", "value"], properties: { name: { type: "string", minLength: 1, maxLength: 256 }, value: { type: "string", minLength: 1, writeOnly: true } }, additionalProperties: false },
183
+ Secret: { type: "object", required: ["id", "type", "name", "created_at", "updated_at"], properties: { id: { type: "string" }, type: { const: "secret" }, name: { type: "string" }, created_at: { type: "string", format: "date-time" }, updated_at: { type: "string", format: "date-time" } }, additionalProperties: false },
184
+ CreateVaultRequest: { type: "object", required: ["display_name"], properties: { display_name: { type: "string", minLength: 1 }, metadata: ref("StringMap") }, additionalProperties: false },
185
+ UpdateVaultRequest: { type: "object", properties: { display_name: { type: "string", minLength: 1 }, metadata: ref("StringMap") }, additionalProperties: false },
186
+ Vault: { type: "object", required: ["id", "type", "display_name", "metadata", "created_at", "updated_at", "archived_at"], properties: { id: { type: "string" }, type: { const: "vault" }, display_name: { type: "string" }, metadata: ref("StringMap"), created_at: { type: "string", format: "date-time" }, updated_at: { type: "string", format: "date-time" }, archived_at: { type: ["string", "null"], format: "date-time" } } },
187
+ DeletedVault: { type: "object", required: ["id", "type"], properties: { id: { type: "string" }, type: { const: "vault_deleted" } } },
188
+ CreateCredentialRequest: { type: "object", required: ["auth"], properties: { display_name: ref("NullableString"), metadata: ref("StringMap"), auth: ref("JsonObject") }, additionalProperties: false },
189
+ UpdateCredentialRequest: { type: "object", properties: { display_name: ref("NullableString"), metadata: ref("StringMap"), auth: ref("JsonObject") }, additionalProperties: false },
190
+ VaultCredential: { type: "object", required: ["id", "type", "vault_id", "metadata", "auth", "created_at", "updated_at", "archived_at"], properties: { id: { type: "string" }, type: { const: "vault_credential" }, vault_id: { type: "string" }, display_name: ref("NullableString"), metadata: ref("StringMap"), auth: ref("JsonObject"), created_at: { type: "string", format: "date-time" }, updated_at: { type: "string", format: "date-time" }, archived_at: { type: ["string", "null"], format: "date-time" } }, additionalProperties: false },
191
+ CreateSessionRequest: { type: "object", required: ["agent", "environment_id"], properties: { agent: { oneOf: [{ type: "string" }, { type: "object", required: ["type", "id"], properties: { type: { const: "agent" }, id: { type: "string" }, version: { type: "integer", minimum: 1 } }, additionalProperties: false }] }, environment_id: { type: "string" }, vault_ids: { type: "array", items: { type: "string" } }, title: ref("NullableString"), metadata: ref("StringMap"), resources: { type: "array", items: ref("JsonObject") } }, additionalProperties: false },
192
+ Session: { type: "object", required: ["id", "type", "agent", "environment_id", "vault_ids", "status", "metadata", "created_at", "updated_at", "archived_at", "resources"], properties: { id: { type: "string" }, type: { const: "session" }, agent: { type: "object", required: ["type", "id", "version"], properties: { type: { const: "agent" }, id: { type: "string" }, version: { type: "integer" } } }, environment_id: { type: "string" }, vault_ids: { type: "array", items: { type: "string" } }, status: { enum: ["idle", "running", "rescheduling", "terminated"] }, title: ref("NullableString"), metadata: ref("StringMap"), created_at: { type: "string", format: "date-time" }, updated_at: { type: "string", format: "date-time" }, archived_at: { type: ["string", "null"], format: "date-time" }, usage: { type: "null" }, resources: { type: "array", items: ref("JsonObject") } }, additionalProperties: false },
193
+ DeletedSession: { type: "object", required: ["id", "type"], properties: { id: { type: "string" }, type: { const: "session_deleted" } }, additionalProperties: false },
194
+ Event: { type: "object", required: ["id", "type", "processed_at"], properties: { id: { type: "string" }, type: { type: "string", enum: DOCUMENTED_EVENT_TYPES }, processed_at: { type: ["string", "null"], format: "date-time" } }, additionalProperties: true },
195
+ SendEventsRequest: { type: "object", required: ["events"], properties: { events: { type: "array", minItems: 1, maxItems: 200, items: { oneOf: [{ type: "object", required: ["type", "content"], properties: { type: { const: "user.message" }, content: { type: "array", items: ref("JsonObject") } }, additionalProperties: false }, { type: "object", required: ["type"], properties: { type: { const: "user.interrupt" } }, additionalProperties: false }, { type: "object", required: ["type", "custom_tool_use_id"], properties: { type: { const: "user.custom_tool_result" }, custom_tool_use_id: { type: "string" }, content: { type: "array", items: ref("JsonObject") }, is_error: { type: "boolean" } }, additionalProperties: false }, { type: "object", required: ["type", "tool_use_id", "result"], properties: { type: { const: "user.tool_confirmation" }, tool_use_id: { type: "string" }, result: { enum: ["allow", "deny"] }, deny_message: ref("NullableString") }, additionalProperties: false }] } } }, additionalProperties: false },
196
+ ModelCatalogEntry: { type: "object", required: ["type", "provider", "id", "name", "provider_name", "reasoning", "input", "context_window", "max_output_tokens", "credentials_configured", "default"], properties: { type: { const: "model" }, provider: { type: "string" }, id: { type: "string" }, name: { type: "string" }, provider_name: { type: "string" }, reasoning: { type: "boolean" }, input: { type: "array", items: { type: "string" } }, context_window: { type: "integer", minimum: 0 }, max_output_tokens: { type: "integer", minimum: 0 }, credentials_configured: { type: "boolean" }, default: { type: "boolean" } }, additionalProperties: false },
197
+ AdminCreateWorkspaceRequest: { type: "object", required: ["name"], properties: { name: { type: "string", minLength: 1 } }, additionalProperties: false },
198
+ AdminMintKeyRequest: { type: "object", properties: { label: { type: "string", minLength: 1, default: "default" } }, additionalProperties: false },
199
+ AdminWorkspace: { type: "object", required: ["id", "name", "created_at"], properties: { id: { type: "string" }, name: { type: "string" }, created_at: { type: "string", format: "date-time" } }, additionalProperties: false },
200
+ AdminMintedKey: { type: "object", required: ["workspace_id", "label", "key_sha256", "api_key"], properties: { workspace_id: { type: "string" }, label: { type: "string" }, key_sha256: { type: "string" }, api_key: { type: "string", writeOnly: true } }, additionalProperties: false },
201
+ AdminKeyMetadata: { type: "object", required: ["key_sha256", "workspace_id", "label", "created_at", "revoked_at"], properties: { key_sha256: { type: "string" }, workspace_id: { type: "string" }, label: { type: "string" }, created_at: { type: "string", format: "date-time" }, revoked_at: { type: ["string", "null"], format: "date-time" } }, additionalProperties: false },
202
+ Health: { type: "object", required: ["status", "version", "uptime_seconds", "checks"], properties: { status: { enum: ["ok", "degraded"] }, version: { type: "string" }, uptime_seconds: { type: "integer", minimum: 0 }, checks: { type: "object", required: ["storage", "runtime"], properties: { storage: ref("HealthCheck"), runtime: ref("HealthCheck") }, additionalProperties: false } }, additionalProperties: false },
203
+ HealthCheck: { type: "object", required: ["status"], properties: { status: { enum: ["ok", "failed"] }, detail: { type: "string" } }, additionalProperties: false },
204
+ };
205
+ for (const [name, item] of [
206
+ ["ForwardAgentPage", "Agent"],
207
+ ["AgentVersionsPage", "Agent"],
208
+ ["ForwardEnvironmentPage", "Environment"],
209
+ ["SkillPage", "Skill"],
210
+ ["SkillVersionPage", "SkillVersion"],
211
+ ["ForwardVaultPage", "Vault"],
212
+ ["ForwardCredentialPage", "VaultCredential"],
213
+ ]) {
214
+ const hasMore = name !== "AgentVersionsPage";
215
+ schemas[name] = {
216
+ type: "object",
217
+ required: ["data", "next_page", ...(hasMore ? ["has_more"] : [])],
218
+ properties: {
219
+ data: { type: "array", items: ref(item) },
220
+ next_page: { type: ["string", "null"] },
221
+ ...(hasMore ? { has_more: { type: "boolean" } } : {}),
222
+ },
223
+ additionalProperties: false,
224
+ };
225
+ }
226
+ schemas.FilePage = { type: "object", required: ["data", "has_more", "first_id", "last_id"], properties: { data: { type: "array", items: ref("File") }, has_more: { type: "boolean" }, first_id: { type: ["string", "null"] }, last_id: { type: ["string", "null"] } }, additionalProperties: false };
227
+ schemas.SessionPage = { type: "object", required: ["data", "next_page", "prev_page"], properties: { data: { type: "array", items: ref("Session") }, next_page: { type: ["string", "null"] }, prev_page: { type: ["string", "null"] } }, additionalProperties: false };
228
+ schemas.EventPage = { type: "object", required: ["data"], properties: { data: { type: "array", items: ref("Event") }, next_page: { type: ["string", "null"] } }, additionalProperties: false };
229
+ schemas.GenericForwardPage = { type: "object", required: ["data", "has_more", "next_page"], properties: { data: { type: "array", items: ref("JsonObject") }, has_more: { type: "boolean" }, next_page: { type: ["string", "null"] } }, additionalProperties: false };
230
+ schemas.ModelCatalogPage = { type: "object", required: ["data", "next_page"], properties: { data: { type: "array", items: ref("ModelCatalogEntry") }, next_page: { type: ["string", "null"] } }, additionalProperties: false };
231
+ function betaParameter(kind) {
232
+ const feature = kind === "files" ? FILES_API_BETA : kind === "skills" ? SKILLS_API_BETA : MANAGED_AGENTS_BETA;
233
+ const alternative = kind === "managed" ? "" : ` The general ${MANAGED_AGENTS_BETA} beta is also accepted.`;
234
+ return headerParam("anthropic-beta", { type: "string", example: feature }, true, `Required beta feature header. Multiple features are comma-separated.${alternative}`);
235
+ }
236
+ export function createOpenApiDocument() {
237
+ const paths = {};
238
+ for (const contract of OPENAPI_ROUTE_CONTRACTS) {
239
+ const parameters = [
240
+ ...(contract.beta === undefined ? [] : [betaParameter(contract.beta)]),
241
+ ...(contract.parameters ?? []),
242
+ ];
243
+ const operation = {
244
+ operationId: contract.operationId,
245
+ tags: [contract.tag],
246
+ summary: contract.summary,
247
+ ...(contract.description === undefined ? {} : { description: contract.description }),
248
+ security: contract.auth === "none"
249
+ ? []
250
+ : contract.auth === "metrics"
251
+ ? [{}, { MetricsBearer: [] }]
252
+ : [{ [contract.auth === "workspace" ? "WorkspaceApiKey" : "AdminApiKey"]: [] }],
253
+ ...(parameters.length === 0 ? {} : { parameters }),
254
+ ...(contract.requestBody === undefined ? {} : { requestBody: contract.requestBody }),
255
+ responses: contract.responses,
256
+ };
257
+ (paths[contract.path] ??= {})[contract.method] = operation;
258
+ }
259
+ return {
260
+ openapi: "3.1.0",
261
+ info: {
262
+ title: "Open Managed Agents API",
263
+ version: "0.0.1-alpha",
264
+ description: "The currently shipped OMA API surface. Unsupported Claude Managed Agents operations are intentionally omitted.",
265
+ },
266
+ servers: [{ url: "/", description: "This OMA appliance" }],
267
+ tags: [...new Set(OPENAPI_ROUTE_CONTRACTS.map((contract) => contract.tag))]
268
+ .map((name) => ({ name, description: TAG_DESCRIPTIONS[name] })),
269
+ paths,
270
+ components: {
271
+ securitySchemes: {
272
+ WorkspaceApiKey: { type: "apiKey", in: "header", name: "x-api-key", description: "Workspace-scoped API key." },
273
+ AdminApiKey: { type: "apiKey", in: "header", name: "x-admin-key", description: "Local appliance administrator key. Keep it out of URLs, cookies, and persistent browser storage." },
274
+ MetricsBearer: { type: "http", scheme: "bearer", description: "Optional deployment-configured metrics bearer token." },
275
+ },
276
+ schemas,
277
+ },
278
+ };
279
+ }
280
+ export function openApiContractRouteKeys() {
281
+ return OPENAPI_ROUTE_CONTRACTS.map((contract) => `${contract.method.toUpperCase()} ${contract.path}`).sort();
282
+ }
@@ -0,0 +1,78 @@
1
+ import { createReadStream, realpathSync, statSync } from "node:fs";
2
+ import { extname, resolve, sep } from "node:path";
3
+ import { Readable } from "node:stream";
4
+ import { createOpenApiDocument } from "./document.js";
5
+ export const OPENAPI_DOCUMENT_PATH = "/openapi.json";
6
+ export const OPENAPI_DOCS_MOUNT = "/docs";
7
+ const CONTENT_TYPES = new Map([
8
+ [".css", "text/css; charset=utf-8"],
9
+ [".html", "text/html; charset=utf-8"],
10
+ [".js", "text/javascript; charset=utf-8"],
11
+ ]);
12
+ const DOCS_CSP = [
13
+ "default-src 'none'",
14
+ "script-src 'self'",
15
+ "style-src 'self' 'unsafe-inline'",
16
+ "img-src 'self' data:",
17
+ "connect-src 'self'",
18
+ "font-src 'self' data:",
19
+ "base-uri 'none'",
20
+ "form-action 'none'",
21
+ "frame-ancestors 'none'",
22
+ ].join("; ");
23
+ export function registerOpenApiRoutes(app, config) {
24
+ const realRoot = realpathSync(resolve(config.root));
25
+ const serialized = JSON.stringify(createOpenApiDocument(), null, 2) + "\n";
26
+ app.get(OPENAPI_DOCUMENT_PATH, (c) => {
27
+ setDocsHeaders(c);
28
+ c.header("content-type", "application/json; charset=utf-8");
29
+ return c.body(serialized);
30
+ });
31
+ app.get(OPENAPI_DOCS_MOUNT, (c) => c.redirect(`${OPENAPI_DOCS_MOUNT}/`, 301));
32
+ app.get(`${OPENAPI_DOCS_MOUNT}/*`, (c) => {
33
+ const raw = c.req.path.slice(OPENAPI_DOCS_MOUNT.length + 1);
34
+ const relative = raw === "" ? "index.html" : decodeOrNull(raw);
35
+ if (relative === null || relative.includes("\0"))
36
+ return notFound(c);
37
+ const candidate = resolve(realRoot, relative);
38
+ if (!contains(realRoot, candidate))
39
+ return notFound(c);
40
+ let file;
41
+ try {
42
+ file = realpathSync(candidate);
43
+ }
44
+ catch {
45
+ return notFound(c);
46
+ }
47
+ if (!contains(realRoot, file) || !statSync(file).isFile())
48
+ return notFound(c);
49
+ const contentType = CONTENT_TYPES.get(extname(file));
50
+ if (contentType === undefined)
51
+ return notFound(c);
52
+ setDocsHeaders(c);
53
+ c.header("content-type", contentType);
54
+ return c.body(Readable.toWeb(createReadStream(file)));
55
+ });
56
+ }
57
+ function contains(root, candidate) {
58
+ return candidate === root || candidate.startsWith(root + sep);
59
+ }
60
+ function decodeOrNull(value) {
61
+ try {
62
+ return decodeURIComponent(value);
63
+ }
64
+ catch {
65
+ return null;
66
+ }
67
+ }
68
+ function notFound(c) {
69
+ setDocsHeaders(c);
70
+ return c.text("Not found\n", 404);
71
+ }
72
+ function setDocsHeaders(c) {
73
+ c.header("cache-control", "no-store");
74
+ c.header("content-security-policy", DOCS_CSP);
75
+ c.header("referrer-policy", "no-referrer");
76
+ c.header("x-content-type-options", "nosniff");
77
+ c.header("x-frame-options", "DENY");
78
+ }
@@ -0,0 +1,85 @@
1
+ import { createHash } from "node:crypto";
2
+ import { conflict, invalidRequest, toApiErrorBody } from "./errors.js";
3
+ export const IDEMPOTENCY_RESPONSE_TTL_MS = 24 * 60 * 60 * 1000;
4
+ export const IDEMPOTENCY_ABANDONED_IN_PROGRESS_MS = 5 * 60 * 1000;
5
+ export const IDEMPOTENCY_RETRY_AFTER_SECONDS = 5;
6
+ export const IDEMPOTENCY_HEARTBEAT_INTERVAL_MS = 60 * 1000;
7
+ const MAX_IDEMPOTENCY_KEY_LENGTH = 255;
8
+ export function validateIdempotencyKey(value) {
9
+ if (value.length === 0) {
10
+ throw invalidRequest("`Idempotency-Key` must not be empty");
11
+ }
12
+ if (value.length > MAX_IDEMPOTENCY_KEY_LENGTH) {
13
+ throw invalidRequest(`\`Idempotency-Key\` must be at most ${MAX_IDEMPOTENCY_KEY_LENGTH} characters`);
14
+ }
15
+ if (!/^[\x21-\x7E]+$/.test(value)) {
16
+ throw invalidRequest("`Idempotency-Key` must contain only visible ASCII characters");
17
+ }
18
+ return value;
19
+ }
20
+ export function requestFingerprint(method, concretePath, rawBody) {
21
+ const hash = createHash("sha256");
22
+ hash.update(method);
23
+ hash.update("\n");
24
+ hash.update(concretePath);
25
+ hash.update("\n");
26
+ hash.update(rawBody);
27
+ return hash.digest("hex");
28
+ }
29
+ export function reserveWindow(now = new Date()) {
30
+ return {
31
+ now: now.toISOString(),
32
+ expiresAt: new Date(now.getTime() + IDEMPOTENCY_RESPONSE_TTL_MS).toISOString(),
33
+ abandonedBefore: new Date(now.getTime() - IDEMPOTENCY_ABANDONED_IN_PROGRESS_MS).toISOString(),
34
+ };
35
+ }
36
+ export function completionWindow(now = new Date()) {
37
+ return {
38
+ now: now.toISOString(),
39
+ expiresAt: new Date(now.getTime() + IDEMPOTENCY_RESPONSE_TTL_MS).toISOString(),
40
+ };
41
+ }
42
+ export async function withIdempotencyReservationHeartbeat(ledger, input, operation) {
43
+ if (!ledger || !input)
44
+ return operation;
45
+ const refresh = () => {
46
+ ledger.refreshIdempotencyReservation({
47
+ ...input,
48
+ ...completionWindow(),
49
+ });
50
+ };
51
+ refresh();
52
+ const timer = setInterval(refresh, IDEMPOTENCY_HEARTBEAT_INTERVAL_MS);
53
+ timer.unref?.();
54
+ try {
55
+ return await operation;
56
+ }
57
+ finally {
58
+ clearInterval(timer);
59
+ }
60
+ }
61
+ export function idempotencyCompletion(workspaceId, idempotency, response, resource) {
62
+ return {
63
+ ...idempotency,
64
+ workspaceId,
65
+ responseStatus: response.status,
66
+ responseBody: response.body,
67
+ ...completionWindow(),
68
+ ...(resource === undefined
69
+ ? {}
70
+ : { resourceType: resource.type, resourceId: resource.id }),
71
+ };
72
+ }
73
+ export function idempotencyConflictResponse(requestId) {
74
+ // This is client retry guidance in seconds. It is intentionally much shorter
75
+ // than the abandoned in-progress threshold used for crash recovery.
76
+ const error = conflict("A request with this `Idempotency-Key` is already in progress; retry later");
77
+ return {
78
+ status: error.status,
79
+ body: toApiErrorBody(error, requestId),
80
+ headers: { "retry-after": String(IDEMPOTENCY_RETRY_AFTER_SECONDS) },
81
+ };
82
+ }
83
+ export function idempotencyMismatchError() {
84
+ return invalidRequest("`Idempotency-Key` was already used for a different request");
85
+ }