@kindgi/api 0.1.4 → 0.1.5-rc.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.
- package/dist/agent-binding.d.ts +13 -0
- package/dist/agent-binding.d.ts.map +1 -1
- package/dist/agent-pins.d.ts.map +1 -1
- package/dist/agent-pins.js +18 -2
- package/dist/agent-pins.js.map +1 -1
- package/dist/app.d.ts +110 -17
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +163 -35
- package/dist/app.js.map +1 -1
- package/dist/block-publish.d.ts +56 -0
- package/dist/block-publish.d.ts.map +1 -0
- package/dist/block-publish.js +132 -0
- package/dist/block-publish.js.map +1 -0
- package/dist/caller.d.ts +24 -0
- package/dist/caller.d.ts.map +1 -0
- package/dist/caller.js +47 -0
- package/dist/caller.js.map +1 -0
- package/dist/capability-binding.d.ts +11 -0
- package/dist/capability-binding.d.ts.map +1 -1
- package/dist/derive-agent-version.d.ts +7 -0
- package/dist/derive-agent-version.d.ts.map +1 -1
- package/dist/derive-agent-version.js +4 -0
- package/dist/derive-agent-version.js.map +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +73 -7
- package/dist/errors.js.map +1 -1
- package/dist/eval-case-binding.d.ts +16 -4
- package/dist/eval-case-binding.d.ts.map +1 -1
- package/dist/eval-run-binding.d.ts +31 -0
- package/dist/eval-run-binding.d.ts.map +1 -1
- package/dist/eval-run-dispatcher.d.ts +7 -0
- package/dist/eval-run-dispatcher.d.ts.map +1 -1
- package/dist/eval-run-dispatcher.js.map +1 -1
- package/dist/eval-sample.d.ts +11 -0
- package/dist/eval-sample.d.ts.map +1 -0
- package/dist/eval-sample.js +34 -0
- package/dist/eval-sample.js.map +1 -0
- package/dist/eval-suite-binding.d.ts +13 -0
- package/dist/eval-suite-binding.d.ts.map +1 -1
- package/dist/eval-suite-binding.js.map +1 -1
- package/dist/flow-binding.d.ts +18 -0
- package/dist/flow-binding.d.ts.map +1 -1
- package/dist/flow-pins.d.ts.map +1 -1
- package/dist/flow-pins.js +18 -2
- package/dist/flow-pins.js.map +1 -1
- package/dist/gate.d.ts.map +1 -1
- package/dist/gate.js +25 -0
- package/dist/gate.js.map +1 -1
- package/dist/handler-binding.d.ts +32 -0
- package/dist/handler-binding.d.ts.map +1 -1
- package/dist/hitl-binding.d.ts +23 -0
- package/dist/hitl-binding.d.ts.map +1 -1
- package/dist/identity-directory-binding.d.ts +82 -4
- package/dist/identity-directory-binding.d.ts.map +1 -1
- package/dist/identity-provider-binding.d.ts +197 -17
- package/dist/identity-provider-binding.d.ts.map +1 -1
- package/dist/improvement-pass-binding.d.ts +196 -0
- package/dist/improvement-pass-binding.d.ts.map +1 -0
- package/dist/improvement-pass-binding.js +9 -0
- package/dist/improvement-pass-binding.js.map +1 -0
- package/dist/index.d.ts +35 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -3
- package/dist/index.js.map +1 -1
- package/dist/judged-dispatcher.d.ts +25 -4
- package/dist/judged-dispatcher.d.ts.map +1 -1
- package/dist/judged-dispatcher.js +43 -6
- package/dist/judged-dispatcher.js.map +1 -1
- package/dist/judgment-binding.d.ts +25 -1
- package/dist/judgment-binding.d.ts.map +1 -1
- package/dist/mcp-endpoint-binding.d.ts +7 -0
- package/dist/mcp-endpoint-binding.d.ts.map +1 -1
- package/dist/memory-binding.d.ts +124 -17
- package/dist/memory-binding.d.ts.map +1 -1
- package/dist/memory-erasure-binding.d.ts +145 -0
- package/dist/memory-erasure-binding.d.ts.map +1 -0
- package/dist/memory-erasure-binding.js +4 -0
- package/dist/memory-erasure-binding.js.map +1 -0
- package/dist/middleware/auth.d.ts +66 -13
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/auth.js +150 -50
- package/dist/middleware/auth.js.map +1 -1
- package/dist/middleware/authorize.d.ts +6 -0
- package/dist/middleware/authorize.d.ts.map +1 -1
- package/dist/middleware/authorize.js +113 -4
- package/dist/middleware/authorize.js.map +1 -1
- package/dist/middleware/error-mapper.d.ts +5 -0
- package/dist/middleware/error-mapper.d.ts.map +1 -1
- package/dist/middleware/error-mapper.js +14 -1
- package/dist/middleware/error-mapper.js.map +1 -1
- package/dist/middleware/idempotency.d.ts +70 -5
- package/dist/middleware/idempotency.d.ts.map +1 -1
- package/dist/middleware/idempotency.js +174 -41
- package/dist/middleware/idempotency.js.map +1 -1
- package/dist/middleware/key-project.d.ts +17 -0
- package/dist/middleware/key-project.d.ts.map +1 -0
- package/dist/middleware/key-project.js +75 -0
- package/dist/middleware/key-project.js.map +1 -0
- package/dist/middleware/principal.d.ts.map +1 -1
- package/dist/middleware/principal.js +9 -5
- package/dist/middleware/principal.js.map +1 -1
- package/dist/middleware/project-ref.d.ts.map +1 -1
- package/dist/middleware/project-ref.js +3 -0
- package/dist/middleware/project-ref.js.map +1 -1
- package/dist/openapi/generate.d.ts.map +1 -1
- package/dist/openapi/generate.js +5 -2
- package/dist/openapi/generate.js.map +1 -1
- package/dist/openapi/operations.d.ts.map +1 -1
- package/dist/openapi/operations.js +918 -139
- package/dist/openapi/operations.js.map +1 -1
- package/dist/openapi/schemas.d.ts +90 -13
- package/dist/openapi/schemas.d.ts.map +1 -1
- package/dist/openapi/schemas.js +2081 -359
- package/dist/openapi/schemas.js.map +1 -1
- package/dist/person-grants-binding.d.ts +77 -0
- package/dist/person-grants-binding.d.ts.map +1 -0
- package/dist/person-grants-binding.js +4 -0
- package/dist/person-grants-binding.js.map +1 -0
- package/dist/proposal-service.d.ts +121 -0
- package/dist/proposal-service.d.ts.map +1 -0
- package/dist/proposal-service.js +447 -0
- package/dist/proposal-service.js.map +1 -0
- package/dist/proposal-status.d.ts +60 -0
- package/dist/proposal-status.d.ts.map +1 -0
- package/dist/proposal-status.js +109 -0
- package/dist/proposal-status.js.map +1 -0
- package/dist/provider-binding.d.ts +10 -0
- package/dist/provider-binding.d.ts.map +1 -1
- package/dist/publish-refused.d.ts +18 -3
- package/dist/publish-refused.d.ts.map +1 -1
- package/dist/publish-refused.js +18 -3
- package/dist/publish-refused.js.map +1 -1
- package/dist/routes/adapters.d.ts +2 -1
- package/dist/routes/adapters.d.ts.map +1 -1
- package/dist/routes/adapters.js +3 -1
- package/dist/routes/adapters.js.map +1 -1
- package/dist/routes/agent-releases.d.ts +55 -3
- package/dist/routes/agent-releases.d.ts.map +1 -1
- package/dist/routes/agent-releases.js +85 -55
- package/dist/routes/agent-releases.js.map +1 -1
- package/dist/routes/agents.d.ts +12 -1
- package/dist/routes/agents.d.ts.map +1 -1
- package/dist/routes/agents.js +100 -2
- package/dist/routes/agents.js.map +1 -1
- package/dist/routes/approvals.d.ts +15 -3
- package/dist/routes/approvals.d.ts.map +1 -1
- package/dist/routes/approvals.js +133 -122
- package/dist/routes/approvals.js.map +1 -1
- package/dist/routes/artifacts.d.ts +25 -3
- package/dist/routes/artifacts.d.ts.map +1 -1
- package/dist/routes/artifacts.js +116 -7
- package/dist/routes/artifacts.js.map +1 -1
- package/dist/routes/auth.d.ts +25 -1
- package/dist/routes/auth.d.ts.map +1 -1
- package/dist/routes/auth.js +655 -281
- package/dist/routes/auth.js.map +1 -1
- package/dist/routes/blocks.d.ts.map +1 -1
- package/dist/routes/blocks.js +2 -42
- package/dist/routes/blocks.js.map +1 -1
- package/dist/routes/capabilities.d.ts +2 -1
- package/dist/routes/capabilities.d.ts.map +1 -1
- package/dist/routes/capabilities.js +6 -1
- package/dist/routes/capabilities.js.map +1 -1
- package/dist/routes/compliance.d.ts +9 -10
- package/dist/routes/compliance.d.ts.map +1 -1
- package/dist/routes/compliance.js +42 -61
- package/dist/routes/compliance.js.map +1 -1
- package/dist/routes/conversations.d.ts +8 -1
- package/dist/routes/conversations.d.ts.map +1 -1
- package/dist/routes/conversations.js +87 -8
- package/dist/routes/conversations.js.map +1 -1
- package/dist/routes/cost.d.ts +7 -1
- package/dist/routes/cost.d.ts.map +1 -1
- package/dist/routes/cost.js +22 -3
- package/dist/routes/cost.js.map +1 -1
- package/dist/routes/denied.d.ts +11 -0
- package/dist/routes/denied.d.ts.map +1 -0
- package/dist/routes/denied.js +17 -0
- package/dist/routes/denied.js.map +1 -0
- package/dist/routes/deployments.d.ts +2 -1
- package/dist/routes/deployments.d.ts.map +1 -1
- package/dist/routes/deployments.js +44 -12
- package/dist/routes/deployments.js.map +1 -1
- package/dist/routes/eval-comparison.d.ts.map +1 -1
- package/dist/routes/eval-comparison.js +69 -1
- package/dist/routes/eval-comparison.js.map +1 -1
- package/dist/routes/eval-overrides.d.ts +18 -0
- package/dist/routes/eval-overrides.d.ts.map +1 -0
- package/dist/routes/eval-overrides.js +81 -0
- package/dist/routes/eval-overrides.js.map +1 -0
- package/dist/routes/eval-runs.d.ts +10 -1
- package/dist/routes/eval-runs.d.ts.map +1 -1
- package/dist/routes/eval-runs.js +63 -7
- package/dist/routes/eval-runs.js.map +1 -1
- package/dist/routes/eval-suites.d.ts.map +1 -1
- package/dist/routes/eval-suites.js +20 -1
- package/dist/routes/eval-suites.js.map +1 -1
- package/dist/routes/event-triggers.d.ts +5 -1
- package/dist/routes/event-triggers.d.ts.map +1 -1
- package/dist/routes/event-triggers.js +26 -3
- package/dist/routes/event-triggers.js.map +1 -1
- package/dist/routes/export-signing-keys.d.ts +12 -0
- package/dist/routes/export-signing-keys.d.ts.map +1 -0
- package/dist/routes/export-signing-keys.js +24 -0
- package/dist/routes/export-signing-keys.js.map +1 -0
- package/dist/routes/flows.d.ts.map +1 -1
- package/dist/routes/flows.js +9 -1
- package/dist/routes/flows.js.map +1 -1
- package/dist/routes/gate-policies.d.ts +4 -1
- package/dist/routes/gate-policies.d.ts.map +1 -1
- package/dist/routes/gate-policies.js +29 -5
- package/dist/routes/gate-policies.js.map +1 -1
- package/dist/routes/guardrails.d.ts +16 -14
- package/dist/routes/guardrails.d.ts.map +1 -1
- package/dist/routes/guardrails.js +39 -3
- package/dist/routes/guardrails.js.map +1 -1
- package/dist/routes/identity.d.ts +20 -4
- package/dist/routes/identity.d.ts.map +1 -1
- package/dist/routes/identity.js +246 -6
- package/dist/routes/identity.js.map +1 -1
- package/dist/routes/improvement-passes.d.ts +52 -0
- package/dist/routes/improvement-passes.d.ts.map +1 -0
- package/dist/routes/improvement-passes.js +449 -0
- package/dist/routes/improvement-passes.js.map +1 -0
- package/dist/routes/judged-suites.d.ts +50 -0
- package/dist/routes/judged-suites.d.ts.map +1 -1
- package/dist/routes/judged-suites.js +66 -27
- package/dist/routes/judged-suites.js.map +1 -1
- package/dist/routes/judgment-context.d.ts +18 -2
- package/dist/routes/judgment-context.d.ts.map +1 -1
- package/dist/routes/judgment-context.js +63 -5
- package/dist/routes/judgment-context.js.map +1 -1
- package/dist/routes/judgment-flow-context.d.ts.map +1 -1
- package/dist/routes/judgment-flow-context.js +14 -2
- package/dist/routes/judgment-flow-context.js.map +1 -1
- package/dist/routes/judgments.d.ts.map +1 -1
- package/dist/routes/judgments.js +8 -1
- package/dist/routes/judgments.js.map +1 -1
- package/dist/routes/mcp.d.ts.map +1 -1
- package/dist/routes/mcp.js +26 -1
- package/dist/routes/mcp.js.map +1 -1
- package/dist/routes/memory-access.d.ts +43 -0
- package/dist/routes/memory-access.d.ts.map +1 -0
- package/dist/routes/memory-access.js +129 -0
- package/dist/routes/memory-access.js.map +1 -0
- package/dist/routes/memory-erasures.d.ts +25 -0
- package/dist/routes/memory-erasures.d.ts.map +1 -0
- package/dist/routes/memory-erasures.js +214 -0
- package/dist/routes/memory-erasures.js.map +1 -0
- package/dist/routes/memory-parse.d.ts +38 -0
- package/dist/routes/memory-parse.d.ts.map +1 -0
- package/dist/routes/memory-parse.js +199 -0
- package/dist/routes/memory-parse.js.map +1 -0
- package/dist/routes/memory.d.ts +9 -4
- package/dist/routes/memory.d.ts.map +1 -1
- package/dist/routes/memory.js +226 -234
- package/dist/routes/memory.js.map +1 -1
- package/dist/routes/observations.d.ts +4 -1
- package/dist/routes/observations.d.ts.map +1 -1
- package/dist/routes/observations.js +8 -2
- package/dist/routes/observations.js.map +1 -1
- package/dist/routes/pagination.d.ts +7 -0
- package/dist/routes/pagination.d.ts.map +1 -1
- package/dist/routes/pagination.js +10 -0
- package/dist/routes/pagination.js.map +1 -1
- package/dist/routes/policies.d.ts +2 -1
- package/dist/routes/policies.d.ts.map +1 -1
- package/dist/routes/policies.js +3 -1
- package/dist/routes/policies.js.map +1 -1
- package/dist/routes/project-mismatch.d.ts +22 -0
- package/dist/routes/project-mismatch.d.ts.map +1 -0
- package/dist/routes/project-mismatch.js +34 -0
- package/dist/routes/project-mismatch.js.map +1 -0
- package/dist/routes/projects.d.ts +15 -4
- package/dist/routes/projects.d.ts.map +1 -1
- package/dist/routes/projects.js +100 -9
- package/dist/routes/projects.js.map +1 -1
- package/dist/routes/proposals.d.ts +25 -17
- package/dist/routes/proposals.d.ts.map +1 -1
- package/dist/routes/proposals.js +340 -507
- package/dist/routes/proposals.js.map +1 -1
- package/dist/routes/provenance.d.ts +17 -3
- package/dist/routes/provenance.d.ts.map +1 -1
- package/dist/routes/provenance.js +79 -103
- package/dist/routes/provenance.js.map +1 -1
- package/dist/routes/providers.d.ts +17 -1
- package/dist/routes/providers.d.ts.map +1 -1
- package/dist/routes/providers.js +110 -3
- package/dist/routes/providers.js.map +1 -1
- package/dist/routes/public-run-tokens.d.ts.map +1 -1
- package/dist/routes/public-run-tokens.js +3 -0
- package/dist/routes/public-run-tokens.js.map +1 -1
- package/dist/routes/runs.d.ts +10 -0
- package/dist/routes/runs.d.ts.map +1 -1
- package/dist/routes/runs.js +92 -42
- package/dist/routes/runs.js.map +1 -1
- package/dist/routes/schedules.d.ts +21 -13
- package/dist/routes/schedules.d.ts.map +1 -1
- package/dist/routes/schedules.js +416 -55
- package/dist/routes/schedules.js.map +1 -1
- package/dist/routes/segments.d.ts +2 -0
- package/dist/routes/segments.d.ts.map +1 -1
- package/dist/routes/segments.js +5 -0
- package/dist/routes/segments.js.map +1 -1
- package/dist/routes/service-accounts.d.ts +17 -0
- package/dist/routes/service-accounts.d.ts.map +1 -0
- package/dist/routes/service-accounts.js +212 -0
- package/dist/routes/service-accounts.js.map +1 -0
- package/dist/routes/sign-in-options.d.ts +50 -0
- package/dist/routes/sign-in-options.d.ts.map +1 -0
- package/dist/routes/sign-in-options.js +98 -0
- package/dist/routes/sign-in-options.js.map +1 -0
- package/dist/routes/signing-keys.d.ts +2 -1
- package/dist/routes/signing-keys.d.ts.map +1 -1
- package/dist/routes/signing-keys.js +3 -1
- package/dist/routes/signing-keys.js.map +1 -1
- package/dist/routes/tenant-access.d.ts +13 -0
- package/dist/routes/tenant-access.d.ts.map +1 -0
- package/dist/routes/tenant-access.js +26 -0
- package/dist/routes/tenant-access.js.map +1 -0
- package/dist/routes/tenant.d.ts.map +1 -1
- package/dist/routes/tenant.js +4 -0
- package/dist/routes/tenant.js.map +1 -1
- package/dist/routes/token-sign-in.d.ts +36 -0
- package/dist/routes/token-sign-in.d.ts.map +1 -0
- package/dist/routes/token-sign-in.js +101 -0
- package/dist/routes/token-sign-in.js.map +1 -0
- package/dist/routes/tokens.d.ts +15 -5
- package/dist/routes/tokens.d.ts.map +1 -1
- package/dist/routes/tokens.js +162 -43
- package/dist/routes/tokens.js.map +1 -1
- package/dist/routes/tools.d.ts.map +1 -1
- package/dist/routes/tools.js +9 -1
- package/dist/routes/tools.js.map +1 -1
- package/dist/routes/trigger-access.d.ts +29 -0
- package/dist/routes/trigger-access.d.ts.map +1 -0
- package/dist/routes/trigger-access.js +33 -0
- package/dist/routes/trigger-access.js.map +1 -0
- package/dist/routes/webhook-endpoints.d.ts +2 -1
- package/dist/routes/webhook-endpoints.d.ts.map +1 -1
- package/dist/routes/webhook-endpoints.js +11 -3
- package/dist/routes/webhook-endpoints.js.map +1 -1
- package/dist/routes/webhooks.d.ts +5 -1
- package/dist/routes/webhooks.d.ts.map +1 -1
- package/dist/routes/webhooks.js +25 -2
- package/dist/routes/webhooks.js.map +1 -1
- package/dist/run-failure.d.ts +21 -0
- package/dist/run-failure.d.ts.map +1 -0
- package/dist/run-failure.js +29 -0
- package/dist/run-failure.js.map +1 -0
- package/dist/service-account-binding.d.ts +108 -0
- package/dist/service-account-binding.d.ts.map +1 -0
- package/dist/service-account-binding.js +4 -0
- package/dist/service-account-binding.js.map +1 -0
- package/dist/session-store-binding.d.ts +61 -13
- package/dist/session-store-binding.d.ts.map +1 -1
- package/dist/signed-export.d.ts +89 -0
- package/dist/signed-export.d.ts.map +1 -0
- package/dist/signed-export.js +149 -0
- package/dist/signed-export.js.map +1 -0
- package/dist/supervisor-binding.d.ts +186 -413
- package/dist/supervisor-binding.d.ts.map +1 -1
- package/dist/testing/app-bindings.d.ts +33 -0
- package/dist/testing/app-bindings.d.ts.map +1 -0
- package/dist/testing/app-bindings.js +112 -0
- package/dist/testing/app-bindings.js.map +1 -0
- package/dist/testing/index.d.ts +11 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +13 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/stub-binding.d.ts +34 -0
- package/dist/testing/stub-binding.d.ts.map +1 -0
- package/dist/testing/stub-binding.js +42 -0
- package/dist/testing/stub-binding.js.map +1 -0
- package/dist/testing/trigger-registry.d.ts +21 -0
- package/dist/testing/trigger-registry.d.ts.map +1 -0
- package/dist/testing/trigger-registry.js +206 -0
- package/dist/testing/trigger-registry.js.map +1 -0
- package/dist/token-admin.d.ts +46 -8
- package/dist/token-admin.d.ts.map +1 -1
- package/dist/token-admin.js.map +1 -1
- package/dist/tool-binding.d.ts +13 -0
- package/dist/tool-binding.d.ts.map +1 -1
- package/dist/trigger-binding.d.ts +2 -2
- package/dist/trigger-binding.d.ts.map +1 -1
- package/dist/trigger-binding.js +1 -1
- package/dist/trigger-binding.js.map +1 -1
- package/dist/types.d.ts +16 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/webhook-endpoint-binding.d.ts +19 -3
- package/dist/webhook-endpoint-binding.d.ts.map +1 -1
- package/dist/webhook-endpoint-binding.js +1 -1
- package/dist/webhook-endpoint-binding.js.map +1 -1
- package/openapi.json +15385 -8788
- package/package.json +26 -22
- package/src/agent-binding.ts +14 -0
- package/src/agent-pins.ts +18 -2
- package/src/app.ts +366 -80
- package/src/block-publish.ts +181 -0
- package/src/caller.ts +62 -0
- package/src/capability-binding.ts +12 -0
- package/src/derive-agent-version.ts +9 -1
- package/src/errors.ts +73 -7
- package/src/eval-case-binding.ts +17 -1
- package/src/eval-run-binding.ts +31 -0
- package/src/eval-run-dispatcher.ts +7 -0
- package/src/eval-sample.ts +42 -0
- package/src/eval-suite-binding.ts +14 -0
- package/src/flow-binding.ts +19 -0
- package/src/flow-pins.ts +18 -2
- package/src/gate.ts +26 -0
- package/src/handler-binding.ts +36 -1
- package/src/hitl-binding.ts +24 -0
- package/src/identity-directory-binding.ts +85 -4
- package/src/identity-provider-binding.ts +216 -21
- package/src/improvement-pass-binding.ts +193 -0
- package/src/index.ts +153 -31
- package/src/judged-dispatcher.ts +78 -11
- package/src/judgment-binding.ts +25 -1
- package/src/mcp-endpoint-binding.ts +7 -0
- package/src/memory-binding.ts +121 -17
- package/src/memory-erasure-binding.ts +156 -0
- package/src/middleware/auth.ts +228 -62
- package/src/middleware/authorize.ts +139 -3
- package/src/middleware/error-mapper.ts +15 -1
- package/src/middleware/idempotency.ts +230 -43
- package/src/middleware/key-project.ts +86 -0
- package/src/middleware/principal.ts +9 -5
- package/src/middleware/project-ref.ts +3 -0
- package/src/openapi/generate.ts +11 -2
- package/src/openapi/operations.ts +1059 -142
- package/src/openapi/schemas.ts +2387 -469
- package/src/person-grants-binding.ts +76 -0
- package/src/proposal-service.ts +640 -0
- package/src/proposal-status.ts +176 -0
- package/src/provider-binding.ts +10 -0
- package/src/publish-refused.ts +38 -9
- package/src/routes/adapters.ts +4 -0
- package/src/routes/agent-releases.ts +121 -69
- package/src/routes/agents.ts +128 -1
- package/src/routes/approvals.ts +164 -154
- package/src/routes/artifacts.ts +181 -11
- package/src/routes/auth.ts +804 -336
- package/src/routes/blocks.ts +2 -53
- package/src/routes/capabilities.ts +10 -1
- package/src/routes/compliance.ts +60 -99
- package/src/routes/conversations.ts +101 -7
- package/src/routes/cost.ts +32 -3
- package/src/routes/denied.ts +28 -0
- package/src/routes/deployments.ts +62 -16
- package/src/routes/eval-comparison.ts +81 -2
- package/src/routes/eval-overrides.ts +108 -0
- package/src/routes/eval-runs.ts +86 -6
- package/src/routes/eval-suites.ts +25 -1
- package/src/routes/event-triggers.ts +27 -3
- package/src/routes/export-signing-keys.ts +31 -0
- package/src/routes/flows.ts +12 -1
- package/src/routes/gate-policies.ts +37 -6
- package/src/routes/guardrails.ts +61 -2
- package/src/routes/identity.ts +328 -10
- package/src/routes/improvement-passes.ts +541 -0
- package/src/routes/judged-suites.ts +113 -43
- package/src/routes/judgment-context.ts +76 -5
- package/src/routes/judgment-flow-context.ts +16 -2
- package/src/routes/judgments.ts +17 -3
- package/src/routes/mcp.ts +29 -1
- package/src/routes/memory-access.ts +179 -0
- package/src/routes/memory-erasures.ts +240 -0
- package/src/routes/memory-parse.ts +250 -0
- package/src/routes/memory.ts +244 -286
- package/src/routes/observations.ts +15 -2
- package/src/routes/pagination.ts +12 -0
- package/src/routes/policies.ts +7 -1
- package/src/routes/project-mismatch.ts +56 -0
- package/src/routes/projects.ts +107 -13
- package/src/routes/proposals.ts +370 -611
- package/src/routes/provenance.ts +99 -133
- package/src/routes/providers.ts +142 -3
- package/src/routes/public-run-tokens.ts +3 -0
- package/src/routes/runs.ts +119 -39
- package/src/routes/schedules.ts +472 -60
- package/src/routes/segments.ts +11 -0
- package/src/routes/service-accounts.ts +262 -0
- package/src/routes/sign-in-options.ts +168 -0
- package/src/routes/signing-keys.ts +7 -1
- package/src/routes/tenant-access.ts +37 -0
- package/src/routes/tenant.ts +6 -0
- package/src/routes/token-sign-in.ts +161 -0
- package/src/routes/tokens.ts +172 -46
- package/src/routes/tools.ts +12 -1
- package/src/routes/trigger-access.ts +72 -0
- package/src/routes/webhook-endpoints.ts +15 -3
- package/src/routes/webhooks.ts +26 -2
- package/src/run-failure.ts +42 -0
- package/src/service-account-binding.ts +113 -0
- package/src/session-store-binding.ts +65 -13
- package/src/signed-export.ts +250 -0
- package/src/supervisor-binding.ts +169 -409
- package/src/testing/app-bindings.ts +142 -0
- package/src/testing/index.ts +21 -0
- package/src/testing/stub-binding.ts +53 -0
- package/src/testing/trigger-registry.ts +259 -0
- package/src/token-admin.ts +40 -8
- package/src/tool-binding.ts +14 -0
- package/src/trigger-binding.ts +8 -1
- package/src/types.ts +16 -0
- package/src/webhook-endpoint-binding.ts +18 -3
|
@@ -86,7 +86,7 @@ const IdempotencyKeyParam: ParameterSpec = {
|
|
|
86
86
|
in: 'header',
|
|
87
87
|
required: false,
|
|
88
88
|
description:
|
|
89
|
-
|
|
89
|
+
"Caller-supplied idempotency key, scoped to the caller: the same key from someone else in the tenant is their own request (from 0.1.5). Retries with the same key return the original response byte-identical (per `docs/API-ROUTE-CONVENTIONS.md` §3.1). A retry sent while the first request still runs is answered `409 idempotency-key-in-flight` with `Retry-After`, on a runtime whose store holds keys (from 0.1.5); retry after it, and you get the first request's answer. An answer that carries a secret (a new API key or public run token, a session token, a generated signing secret) isn't kept: a retry gets `409 idempotency-key-replay-withheld`, with the first request's status and when it succeeded (from 0.1.5).",
|
|
90
90
|
schema: { type: 'string', minLength: 1 },
|
|
91
91
|
};
|
|
92
92
|
|
|
@@ -106,6 +106,14 @@ const TokenIdPathParam: ParameterSpec = {
|
|
|
106
106
|
schema: { type: 'string', format: 'uuid' },
|
|
107
107
|
};
|
|
108
108
|
|
|
109
|
+
const ServiceAccountIdPathParam: ParameterSpec = {
|
|
110
|
+
name: 'serviceAccountId',
|
|
111
|
+
in: 'path',
|
|
112
|
+
required: true,
|
|
113
|
+
description: 'The service account id.',
|
|
114
|
+
schema: { type: 'string' },
|
|
115
|
+
};
|
|
116
|
+
|
|
109
117
|
const SigningKeyIdPathParam: ParameterSpec = {
|
|
110
118
|
name: 'keyId',
|
|
111
119
|
in: 'path',
|
|
@@ -182,6 +190,14 @@ const RunEvalRunIdQueryParam: ParameterSpec = {
|
|
|
182
190
|
schema: { type: 'string', minLength: 1 },
|
|
183
191
|
};
|
|
184
192
|
|
|
193
|
+
const RunTriggerIdQueryParam: ParameterSpec = {
|
|
194
|
+
name: 'triggerId',
|
|
195
|
+
in: 'query',
|
|
196
|
+
required: false,
|
|
197
|
+
description: 'Only the runs this trigger started (`Run.trigger.triggerId`).',
|
|
198
|
+
schema: { type: 'string', format: 'uuid' },
|
|
199
|
+
};
|
|
200
|
+
|
|
185
201
|
const LiveProjectQueryParam: ParameterSpec = {
|
|
186
202
|
name: 'projectId',
|
|
187
203
|
in: 'query',
|
|
@@ -472,11 +488,19 @@ const ObservationUntilQueryParam: ParameterSpec = {
|
|
|
472
488
|
schema: { type: 'string', format: 'date-time' },
|
|
473
489
|
};
|
|
474
490
|
|
|
491
|
+
const ErasureIdPathParam: ParameterSpec = {
|
|
492
|
+
name: 'erasureId',
|
|
493
|
+
in: 'path',
|
|
494
|
+
required: true,
|
|
495
|
+
description: 'The erasure (a UUID).',
|
|
496
|
+
schema: { type: 'string', format: 'uuid' },
|
|
497
|
+
};
|
|
498
|
+
|
|
475
499
|
const FactIdPathParam: ParameterSpec = {
|
|
476
500
|
name: 'factId',
|
|
477
501
|
in: 'path',
|
|
478
502
|
required: true,
|
|
479
|
-
description: '
|
|
503
|
+
description: 'The fact id (kept across revisions).',
|
|
480
504
|
schema: { type: 'string' },
|
|
481
505
|
};
|
|
482
506
|
|
|
@@ -497,6 +521,32 @@ const FactScopeQueryParam: ParameterSpec = {
|
|
|
497
521
|
schema: { type: 'string' },
|
|
498
522
|
};
|
|
499
523
|
|
|
524
|
+
const FactAsOfQueryParam: ParameterSpec = {
|
|
525
|
+
name: 'asOf',
|
|
526
|
+
in: 'query',
|
|
527
|
+
required: false,
|
|
528
|
+
description:
|
|
529
|
+
'Read memory as it stood at this time (ISO 8601): the revision that was current then, including one since superseded or deleted.',
|
|
530
|
+
schema: { type: 'string', format: 'date-time' },
|
|
531
|
+
};
|
|
532
|
+
|
|
533
|
+
const FactVersionQueryParam: ParameterSpec = {
|
|
534
|
+
name: 'version',
|
|
535
|
+
in: 'query',
|
|
536
|
+
required: false,
|
|
537
|
+
description: 'A revision number: that revision, current or not.',
|
|
538
|
+
schema: { type: 'integer', minimum: 1 },
|
|
539
|
+
};
|
|
540
|
+
|
|
541
|
+
const FactExpectVersionQueryParam: ParameterSpec = {
|
|
542
|
+
name: 'expectVersion',
|
|
543
|
+
in: 'query',
|
|
544
|
+
required: false,
|
|
545
|
+
description:
|
|
546
|
+
'Only if the current revision is still this one; otherwise `409 fact-changed` with `currentVersion`.',
|
|
547
|
+
schema: { type: 'integer', minimum: 1 },
|
|
548
|
+
};
|
|
549
|
+
|
|
500
550
|
// ---------------- scope triplet ----------------
|
|
501
551
|
//
|
|
502
552
|
// Shared parameters for the `?scopeKind + ?scopeId + ?inherit` filter.
|
|
@@ -531,20 +581,19 @@ const InheritQueryParam: ParameterSpec = {
|
|
|
531
581
|
schema: { type: 'boolean', default: true },
|
|
532
582
|
};
|
|
533
583
|
|
|
534
|
-
const
|
|
535
|
-
name: '
|
|
536
|
-
in: '
|
|
584
|
+
const ImprovementPassIdPathParam: ParameterSpec = {
|
|
585
|
+
name: 'passId',
|
|
586
|
+
in: 'path',
|
|
537
587
|
required: true,
|
|
538
|
-
description:
|
|
539
|
-
|
|
540
|
-
schema: { type: 'string', minLength: 1 },
|
|
588
|
+
description: 'The improvement pass id (a UUID).',
|
|
589
|
+
schema: { type: 'string', format: 'uuid' },
|
|
541
590
|
};
|
|
542
591
|
|
|
543
592
|
const ProposalIdPathParam: ParameterSpec = {
|
|
544
593
|
name: 'proposalId',
|
|
545
594
|
in: 'path',
|
|
546
595
|
required: true,
|
|
547
|
-
description: '
|
|
596
|
+
description: 'The proposal id (a UUID).',
|
|
548
597
|
schema: { type: 'string', format: 'uuid' },
|
|
549
598
|
};
|
|
550
599
|
|
|
@@ -577,7 +626,7 @@ const ProposalStatusQueryParam: ParameterSpec = {
|
|
|
577
626
|
name: 'status',
|
|
578
627
|
in: 'query',
|
|
579
628
|
required: false,
|
|
580
|
-
description: '
|
|
629
|
+
description: 'Only proposals with this (derived) status.',
|
|
581
630
|
schema: { $ref: '#/components/schemas/FixProposalStatus' },
|
|
582
631
|
};
|
|
583
632
|
|
|
@@ -585,7 +634,7 @@ const ProposalTierQueryParam: ParameterSpec = {
|
|
|
585
634
|
name: 'tier',
|
|
586
635
|
in: 'query',
|
|
587
636
|
required: false,
|
|
588
|
-
description: '
|
|
637
|
+
description: 'Only proposals of this tier.',
|
|
589
638
|
schema: { $ref: '#/components/schemas/ProposalTier' },
|
|
590
639
|
};
|
|
591
640
|
|
|
@@ -1250,6 +1299,9 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
1250
1299
|
'Agent or flow not found; or `projectId` names no project of this tenant (`project-not-found`).',
|
|
1251
1300
|
),
|
|
1252
1301
|
'422': ErrorResponse('Guardrail violation or budget exceeded.'),
|
|
1302
|
+
'409': ErrorResponse(
|
|
1303
|
+
"Idempotency-Key was reused with a different body; or an erasure of the turn's person (its conversation or its `participantId`) is in progress (`erasure-in-progress`): no new turn starts for them until it completes.",
|
|
1304
|
+
),
|
|
1253
1305
|
'400': ErrorResponse(
|
|
1254
1306
|
"Malformed request body, or the body's `projectId` isn't a project id (a UUID).",
|
|
1255
1307
|
),
|
|
@@ -1274,6 +1326,7 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
1274
1326
|
RunAgentIdQueryParam,
|
|
1275
1327
|
RunReplaysQueryParam,
|
|
1276
1328
|
RunEvalRunIdQueryParam,
|
|
1329
|
+
RunTriggerIdQueryParam,
|
|
1277
1330
|
RunIncludeQueryParam,
|
|
1278
1331
|
],
|
|
1279
1332
|
responses: {
|
|
@@ -1513,7 +1566,7 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
1513
1566
|
operationId: 'tokens.mint',
|
|
1514
1567
|
summary: 'Mint an API key',
|
|
1515
1568
|
description:
|
|
1516
|
-
|
|
1569
|
+
"An API key acts for one principal (`for`: a person or a service account; default the caller), with that principal's grants. Its `role` is a ceiling under them and its `projectId` a limit. Returns the plaintext token exactly once. A person or a service account's key mints its own keys; only a tenant admin mints for someone else, or an `admin` key. A caller can only grant capabilities it holds, and a key limited to a project mints only keys limited to it. Only mounted when the deployment supplies a `TokenAdmin`.",
|
|
1517
1570
|
tags: ['tokens'],
|
|
1518
1571
|
security: 'bearer',
|
|
1519
1572
|
parameters: [IdempotencyKeyParam],
|
|
@@ -1521,12 +1574,17 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
1521
1574
|
responses: {
|
|
1522
1575
|
'201': { description: 'Token minted.', schema: ref('MintTokenResult') },
|
|
1523
1576
|
...CommonMutationErrors,
|
|
1524
|
-
'
|
|
1577
|
+
'409': ErrorResponse(
|
|
1578
|
+
"Idempotency-Key reused with a different body (`idempotency-key-body-mismatch`), or a retry of a request that succeeded: its answer carried a secret, which isn't kept (`idempotency-key-replay-withheld`, with its `status` and `at`).",
|
|
1579
|
+
),
|
|
1580
|
+
'403': ErrorResponse(
|
|
1581
|
+
"Not a tenant admin where one is needed, or a capability the caller does not hold (`permission-denied`); an `admin` key for a principal that isn't a tenant admin (`role-exceeds-principal`); a key limited to a project minting for another (`key-project-mismatch`).",
|
|
1582
|
+
),
|
|
1525
1583
|
'400': ErrorResponse(
|
|
1526
1584
|
"Malformed request body, or the body's `projectId` isn't a project id (a UUID).",
|
|
1527
1585
|
),
|
|
1528
1586
|
'404': ErrorResponse(
|
|
1529
|
-
"The body's `projectId` names no project of this tenant (`project-not-found`).",
|
|
1587
|
+
"The body's `projectId` names no project of this tenant (`project-not-found`), or `for` names no person or service account (`principal-not-found`).",
|
|
1530
1588
|
),
|
|
1531
1589
|
},
|
|
1532
1590
|
},
|
|
@@ -1536,15 +1594,27 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
1536
1594
|
openapiPath: '/v1/tokens',
|
|
1537
1595
|
operationId: 'tokens.list',
|
|
1538
1596
|
summary: 'List API keys',
|
|
1539
|
-
description:
|
|
1597
|
+
description:
|
|
1598
|
+
"Newest first. Never returns secrets. A tenant admin sees every key (`?principal=` for one principal's); anyone else sees their own.",
|
|
1540
1599
|
tags: ['tokens'],
|
|
1541
1600
|
security: 'bearer',
|
|
1542
|
-
parameters: [
|
|
1601
|
+
parameters: [
|
|
1602
|
+
CursorQueryParam,
|
|
1603
|
+
LimitQueryParam,
|
|
1604
|
+
{
|
|
1605
|
+
name: 'principal',
|
|
1606
|
+
in: 'query',
|
|
1607
|
+
required: false,
|
|
1608
|
+
description:
|
|
1609
|
+
"Tenant admins: only this principal's keys, `user:<id>` or `service-account:<id>`.",
|
|
1610
|
+
schema: { type: 'string' },
|
|
1611
|
+
},
|
|
1612
|
+
],
|
|
1543
1613
|
responses: {
|
|
1544
1614
|
'200': { description: 'A page of keys.', schema: ref('ApiTokenPage') },
|
|
1545
1615
|
...CommonAuthErrors,
|
|
1546
|
-
'400': ErrorResponse('Malformed cursor
|
|
1547
|
-
'403': ErrorResponse('
|
|
1616
|
+
'400': ErrorResponse('Malformed cursor or `principal`.'),
|
|
1617
|
+
'403': ErrorResponse('A caller with no keys of its own that is not a tenant admin.'),
|
|
1548
1618
|
},
|
|
1549
1619
|
},
|
|
1550
1620
|
{
|
|
@@ -1553,15 +1623,16 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
1553
1623
|
openapiPath: '/v1/tokens/{tokenId}',
|
|
1554
1624
|
operationId: 'tokens.get',
|
|
1555
1625
|
summary: 'Read an API key',
|
|
1556
|
-
description:
|
|
1626
|
+
description:
|
|
1627
|
+
"Never returns the secret. A tenant admin reads any key; anyone else only their own (someone else's reads as missing).",
|
|
1557
1628
|
tags: ['tokens'],
|
|
1558
1629
|
security: 'bearer',
|
|
1559
1630
|
parameters: [TokenIdPathParam],
|
|
1560
1631
|
responses: {
|
|
1561
1632
|
'200': { description: 'The key.', schema: ref('ApiToken') },
|
|
1562
1633
|
...CommonAuthErrors,
|
|
1563
|
-
'403': ErrorResponse('
|
|
1564
|
-
'404': ErrorResponse('No token with that id
|
|
1634
|
+
'403': ErrorResponse('A caller with no keys of its own that is not a tenant admin.'),
|
|
1635
|
+
'404': ErrorResponse('No token with that id that the caller may see.'),
|
|
1565
1636
|
},
|
|
1566
1637
|
},
|
|
1567
1638
|
{
|
|
@@ -1570,15 +1641,143 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
1570
1641
|
openapiPath: '/v1/tokens/{tokenId}/revoke',
|
|
1571
1642
|
operationId: 'tokens.revoke',
|
|
1572
1643
|
summary: 'Revoke an API key',
|
|
1573
|
-
description:
|
|
1644
|
+
description:
|
|
1645
|
+
'Takes effect on the next request. A tenant admin revokes any key; anyone else only their own.',
|
|
1574
1646
|
tags: ['tokens'],
|
|
1575
1647
|
security: 'bearer',
|
|
1576
1648
|
parameters: [TokenIdPathParam, IdempotencyKeyParam],
|
|
1577
1649
|
responses: {
|
|
1578
1650
|
'200': { description: 'Revoked.', schema: ref('RevokeTokenResult') },
|
|
1579
1651
|
...CommonMutationErrors,
|
|
1652
|
+
'403': ErrorResponse('A caller with no keys of its own that is not a tenant admin.'),
|
|
1653
|
+
'404': ErrorResponse('No token with that id that the caller may see.'),
|
|
1654
|
+
},
|
|
1655
|
+
},
|
|
1656
|
+
// ---------- service accounts ----------
|
|
1657
|
+
{
|
|
1658
|
+
method: 'post',
|
|
1659
|
+
honoPath: '/v1/service-accounts',
|
|
1660
|
+
openapiPath: '/v1/service-accounts',
|
|
1661
|
+
operationId: 'serviceAccounts.create',
|
|
1662
|
+
summary: 'Create a service account',
|
|
1663
|
+
description:
|
|
1664
|
+
"A named, non-human principal with its first grants, written before it is returned. It isn't a tenant member unless a grant makes it one (`{kind: 'tenant-member'}`: read the tenant's settings); give it only what its job needs. Mint its keys at `POST /v1/tokens` with `for`. Tenant admins only. Mounted when the deployment supplies a `ServiceAccountBinding`.",
|
|
1665
|
+
tags: ['service-accounts'],
|
|
1666
|
+
security: 'bearer',
|
|
1667
|
+
parameters: [IdempotencyKeyParam],
|
|
1668
|
+
requestBody: { required: true, schema: ref('CreateServiceAccountBody') },
|
|
1669
|
+
responses: {
|
|
1670
|
+
'201': { description: 'Created.', schema: ref('ServiceAccount') },
|
|
1671
|
+
...CommonMutationErrors,
|
|
1580
1672
|
'403': ErrorResponse('Not a tenant admin.'),
|
|
1581
|
-
'404': ErrorResponse('
|
|
1673
|
+
'404': ErrorResponse('A grant names no project of this tenant (`project-not-found`).'),
|
|
1674
|
+
'409': ErrorResponse(
|
|
1675
|
+
'An active service account has the name (`service-account-name-taken`), or an idempotency conflict.',
|
|
1676
|
+
),
|
|
1677
|
+
},
|
|
1678
|
+
},
|
|
1679
|
+
{
|
|
1680
|
+
method: 'get',
|
|
1681
|
+
honoPath: '/v1/service-accounts',
|
|
1682
|
+
openapiPath: '/v1/service-accounts',
|
|
1683
|
+
operationId: 'serviceAccounts.list',
|
|
1684
|
+
summary: 'List service accounts',
|
|
1685
|
+
description:
|
|
1686
|
+
'Oldest first; active only unless `?includeUnregistered=true`. Tenant admins only.',
|
|
1687
|
+
tags: ['service-accounts'],
|
|
1688
|
+
security: 'bearer',
|
|
1689
|
+
parameters: [
|
|
1690
|
+
CursorQueryParam,
|
|
1691
|
+
LimitQueryParam,
|
|
1692
|
+
{
|
|
1693
|
+
name: 'includeUnregistered',
|
|
1694
|
+
in: 'query',
|
|
1695
|
+
required: false,
|
|
1696
|
+
description: '`true`: unregistered accounts too.',
|
|
1697
|
+
schema: { type: 'string', enum: ['true', 'false'] },
|
|
1698
|
+
},
|
|
1699
|
+
],
|
|
1700
|
+
responses: {
|
|
1701
|
+
'200': { description: 'A page of service accounts.', schema: ref('ServiceAccountPage') },
|
|
1702
|
+
...CommonAuthErrors,
|
|
1703
|
+
'403': ErrorResponse('Not a tenant admin.'),
|
|
1704
|
+
},
|
|
1705
|
+
},
|
|
1706
|
+
{
|
|
1707
|
+
method: 'get',
|
|
1708
|
+
honoPath: '/v1/service-accounts/:serviceAccountId',
|
|
1709
|
+
openapiPath: '/v1/service-accounts/{serviceAccountId}',
|
|
1710
|
+
operationId: 'serviceAccounts.get',
|
|
1711
|
+
summary: 'Read a service account',
|
|
1712
|
+
description: 'Unregistered ones too. Tenant admins only.',
|
|
1713
|
+
tags: ['service-accounts'],
|
|
1714
|
+
security: 'bearer',
|
|
1715
|
+
parameters: [ServiceAccountIdPathParam],
|
|
1716
|
+
responses: {
|
|
1717
|
+
'200': { description: 'The service account.', schema: ref('ServiceAccount') },
|
|
1718
|
+
...CommonAuthErrors,
|
|
1719
|
+
'403': ErrorResponse('Not a tenant admin.'),
|
|
1720
|
+
'404': ErrorResponse('No such service account (`service-account-not-found`).'),
|
|
1721
|
+
},
|
|
1722
|
+
},
|
|
1723
|
+
{
|
|
1724
|
+
method: 'post',
|
|
1725
|
+
honoPath: '/v1/service-accounts/:serviceAccountId/grant',
|
|
1726
|
+
openapiPath: '/v1/service-accounts/{serviceAccountId}/grant',
|
|
1727
|
+
operationId: 'serviceAccounts.grant',
|
|
1728
|
+
summary: 'Grant a service account',
|
|
1729
|
+
description:
|
|
1730
|
+
"Tenant admin, or a role on a project (replacing the account's role there). Written before the call answers. Tenant admins only.",
|
|
1731
|
+
tags: ['service-accounts'],
|
|
1732
|
+
security: 'bearer',
|
|
1733
|
+
parameters: [ServiceAccountIdPathParam, IdempotencyKeyParam],
|
|
1734
|
+
requestBody: { required: true, schema: ref('ServiceAccountGrantBody') },
|
|
1735
|
+
responses: {
|
|
1736
|
+
'200': { description: 'The account, with its grants.', schema: ref('ServiceAccount') },
|
|
1737
|
+
...CommonMutationErrors,
|
|
1738
|
+
'403': ErrorResponse('Not a tenant admin.'),
|
|
1739
|
+
'404': ErrorResponse(
|
|
1740
|
+
'No such service account (`service-account-not-found`), or no such project (`project-not-found`).',
|
|
1741
|
+
),
|
|
1742
|
+
'409': ErrorResponse(
|
|
1743
|
+
'The account is unregistered (`service-account-unregistered`), or an idempotency conflict.',
|
|
1744
|
+
),
|
|
1745
|
+
},
|
|
1746
|
+
},
|
|
1747
|
+
{
|
|
1748
|
+
method: 'post',
|
|
1749
|
+
honoPath: '/v1/service-accounts/:serviceAccountId/ungrant',
|
|
1750
|
+
openapiPath: '/v1/service-accounts/{serviceAccountId}/ungrant',
|
|
1751
|
+
operationId: 'serviceAccounts.ungrant',
|
|
1752
|
+
summary: 'Remove a grant from a service account',
|
|
1753
|
+
description: 'A no-op when the account does not hold it. Tenant admins only.',
|
|
1754
|
+
tags: ['service-accounts'],
|
|
1755
|
+
security: 'bearer',
|
|
1756
|
+
parameters: [ServiceAccountIdPathParam, IdempotencyKeyParam],
|
|
1757
|
+
requestBody: { required: true, schema: ref('ServiceAccountUngrantBody') },
|
|
1758
|
+
responses: {
|
|
1759
|
+
'200': { description: 'The account, with its grants.', schema: ref('ServiceAccount') },
|
|
1760
|
+
...CommonMutationErrors,
|
|
1761
|
+
'403': ErrorResponse('Not a tenant admin.'),
|
|
1762
|
+
'404': ErrorResponse('No such service account (`service-account-not-found`).'),
|
|
1763
|
+
},
|
|
1764
|
+
},
|
|
1765
|
+
{
|
|
1766
|
+
method: 'post',
|
|
1767
|
+
honoPath: '/v1/service-accounts/:serviceAccountId/unregister',
|
|
1768
|
+
openapiPath: '/v1/service-accounts/{serviceAccountId}/unregister',
|
|
1769
|
+
operationId: 'serviceAccounts.unregister',
|
|
1770
|
+
summary: 'Unregister a service account',
|
|
1771
|
+
description:
|
|
1772
|
+
'A tombstone: its grants go and its keys stop working; it stays readable. Idempotent. Tenant admins only.',
|
|
1773
|
+
tags: ['service-accounts'],
|
|
1774
|
+
security: 'bearer',
|
|
1775
|
+
parameters: [ServiceAccountIdPathParam, IdempotencyKeyParam],
|
|
1776
|
+
responses: {
|
|
1777
|
+
'200': { description: 'The unregistered account.', schema: ref('ServiceAccount') },
|
|
1778
|
+
...CommonMutationErrors,
|
|
1779
|
+
'403': ErrorResponse('Not a tenant admin.'),
|
|
1780
|
+
'404': ErrorResponse('No such service account (`service-account-not-found`).'),
|
|
1582
1781
|
},
|
|
1583
1782
|
},
|
|
1584
1783
|
{
|
|
@@ -1596,6 +1795,9 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
1596
1795
|
responses: {
|
|
1597
1796
|
'201': { description: 'Token minted.', schema: ref('MintPublicRunTokenResult') },
|
|
1598
1797
|
...CommonMutationErrors,
|
|
1798
|
+
'409': ErrorResponse(
|
|
1799
|
+
"Idempotency-Key reused with a different body (`idempotency-key-body-mismatch`), or a retry of a request that succeeded: its answer carried a secret, which isn't kept (`idempotency-key-replay-withheld`, with its `status` and `at`).",
|
|
1800
|
+
),
|
|
1599
1801
|
'400': ErrorResponse('Malformed body, or `expiresInSeconds` above the deployment maximum.'),
|
|
1600
1802
|
'403': ErrorResponse('The caller may not read one of the runs (`permission-denied`).'),
|
|
1601
1803
|
'404': ErrorResponse('A run does not exist under this tenant (`run-not-found`).'),
|
|
@@ -1751,11 +1953,11 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
1751
1953
|
operationId: 'approvals.auditBundle',
|
|
1752
1954
|
summary: 'Export a signed audit bundle for a decided approval',
|
|
1753
1955
|
description:
|
|
1754
|
-
"
|
|
1956
|
+
"Signs the approval, its decision and its evidence with the deployment's export key, and records the export (an `export-signed` audit event). The same envelope as the other signed exports, so one verifier reads all three; check `publicKey` against `GET /v1/export-signing-keys`. For a decided approval only (approved, rejected, escalated, expired, withdrawn): a pending one is `409 approval-not-decided`. A deployment with no export key answers `404 signing-not-configured`.",
|
|
1755
1957
|
tags: ['approvals'],
|
|
1756
1958
|
security: 'bearer',
|
|
1757
1959
|
parameters: [ApprovalIdPathParam, IdempotencyKeyParam],
|
|
1758
|
-
requestBody: { required:
|
|
1960
|
+
requestBody: { required: false, schema: ref('ExportAuditBundleBody') },
|
|
1759
1961
|
responses: {
|
|
1760
1962
|
'200': { description: 'Signed audit bundle.', schema: ref('ExportAuditBundleResult') },
|
|
1761
1963
|
...CommonMutationErrors,
|
|
@@ -1843,7 +2045,7 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
1843
2045
|
'201': { description: 'The derived agent version.', schema: ref('Agent') },
|
|
1844
2046
|
...CommonMutationErrors,
|
|
1845
2047
|
'409': ErrorResponse(
|
|
1846
|
-
"Idempotency-Key was reused with a different body, or resource-state conflict. Or `registry-read-only`: this registry takes no writes (under `kindgi dev`, the pack's files are the source); the message says what to do instead.",
|
|
2048
|
+
"Idempotency-Key was reused with a different body, or resource-state conflict. Or `agent-project-mismatch`: the agent belongs to another project than the body's `projectId` (agents never move; the message doesn't name the project). Or `registry-read-only`: this registry takes no writes (under `kindgi dev`, the pack's files are the source); the message says what to do instead.",
|
|
1847
2049
|
),
|
|
1848
2050
|
'400': ErrorResponse(
|
|
1849
2051
|
"`validation-failed`: `from` has no pins, a swap names a block it doesn't reference, or a version that isn't published, active or the right kind (see `details.issues`); or `projectId` isn't a project id (a UUID).",
|
|
@@ -1887,7 +2089,7 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
1887
2089
|
"Validation failed (see `details.issues`); or `projectId` isn't a project id (a UUID).",
|
|
1888
2090
|
),
|
|
1889
2091
|
'409': ErrorResponse(
|
|
1890
|
-
"
|
|
2092
|
+
"`agent-already-registered`: that (id, version) is taken. Or `agent-project-mismatch`: the agent's versions live in another project (an agent belongs to the project its first version was published into and never moves; the message doesn't name the project). Or `registry-read-only`: this registry takes no writes (under `kindgi dev`, the pack's files are the source); the message says what to do instead.",
|
|
1891
2093
|
),
|
|
1892
2094
|
'404': ErrorResponse(
|
|
1893
2095
|
"The body's `projectId` names no project of this tenant (`project-not-found`).",
|
|
@@ -2344,7 +2546,7 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
2344
2546
|
"Validation failed (see `details.issues`); or `projectId` isn't a project id (a UUID).",
|
|
2345
2547
|
),
|
|
2346
2548
|
'409': ErrorResponse(
|
|
2347
|
-
"
|
|
2549
|
+
"`flow-already-registered`: that (id, version) is taken. Or `flow-project-mismatch`: the flow's versions live in another project (a flow belongs to the project its first version was published into and never moves; the message doesn't name the project). Or `registry-read-only`: this registry takes no writes (under `kindgi dev`, the pack's files are the source); the message says what to do instead.",
|
|
2348
2550
|
),
|
|
2349
2551
|
'404': ErrorResponse(
|
|
2350
2552
|
"The body's `projectId` names no project of this tenant (`project-not-found`).",
|
|
@@ -2484,7 +2686,7 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
2484
2686
|
"Validation failed (see `details.issues`); or `projectId` isn't a project id (a UUID).",
|
|
2485
2687
|
),
|
|
2486
2688
|
'409': ErrorResponse(
|
|
2487
|
-
"
|
|
2689
|
+
"`tool-already-registered`: that (id, version) is taken. Or `tool-project-mismatch`: the tool's versions live in another project (a tool belongs to the project its first version was published into and never moves; the message doesn't name the project). Or `registry-read-only`: this registry takes no writes (under `kindgi dev`, the pack's files are the source); the message says what to do instead.",
|
|
2488
2690
|
),
|
|
2489
2691
|
'404': ErrorResponse(
|
|
2490
2692
|
"The body's `projectId` names no project of this tenant (`project-not-found`).",
|
|
@@ -2594,6 +2796,9 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
2594
2796
|
'404': ErrorResponse(
|
|
2595
2797
|
"The body's `projectId` names no project of this tenant (`project-not-found`).",
|
|
2596
2798
|
),
|
|
2799
|
+
'422': ErrorResponse(
|
|
2800
|
+
"`guardrail-config-invalid`: the guardrail's `config` breaks the `configSchema` of the pack check it names, which the pack service would refuse on every call. `details.issues` lists each problem, `{ path, message }` with `path` a JSON pointer into the guardrail (`/config/maxChars`); the message names the guardrail, the check and the setting. Checked when the check's deployment carries its schema.",
|
|
2801
|
+
),
|
|
2597
2802
|
},
|
|
2598
2803
|
},
|
|
2599
2804
|
{
|
|
@@ -2698,6 +2903,32 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
2698
2903
|
'404': ErrorResponse('No conversation with that id under this tenant.'),
|
|
2699
2904
|
},
|
|
2700
2905
|
},
|
|
2906
|
+
{
|
|
2907
|
+
method: 'post',
|
|
2908
|
+
honoPath: '/v1/conversations/:conversationId/unregister',
|
|
2909
|
+
openapiPath: '/v1/conversations/{conversationId}/unregister',
|
|
2910
|
+
operationId: 'conversations.unregister',
|
|
2911
|
+
summary: 'Unregister a conversation',
|
|
2912
|
+
description:
|
|
2913
|
+
"A tombstone: from now on no read, list or recall of earlier conversations returns it, and no message can be added. The retention sweep removes it after the tenant's grace.",
|
|
2914
|
+
tags: ['conversations'],
|
|
2915
|
+
security: 'bearer',
|
|
2916
|
+
parameters: [ConversationIdPathParam, IdempotencyKeyParam],
|
|
2917
|
+
responses: {
|
|
2918
|
+
'200': {
|
|
2919
|
+
description: 'The conversation, with `unregisteredAt`.',
|
|
2920
|
+
schema: ref('Conversation'),
|
|
2921
|
+
},
|
|
2922
|
+
...CommonMutationErrors,
|
|
2923
|
+
'400': ErrorResponse('`conversationId` is not a conversation id (a UUID).'),
|
|
2924
|
+
'404': ErrorResponse(
|
|
2925
|
+
'No conversation with that id under this tenant, or it is unregistered already.',
|
|
2926
|
+
),
|
|
2927
|
+
'501': ErrorResponse(
|
|
2928
|
+
"`conversation-unregister-unsupported`: this runtime can't unregister conversations.",
|
|
2929
|
+
),
|
|
2930
|
+
},
|
|
2931
|
+
},
|
|
2701
2932
|
{
|
|
2702
2933
|
method: 'get',
|
|
2703
2934
|
honoPath: '/v1/conversations/:conversationId/messages',
|
|
@@ -2730,7 +2961,7 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
2730
2961
|
operationId: 'memory.listFacts',
|
|
2731
2962
|
summary: 'List facts',
|
|
2732
2963
|
description:
|
|
2733
|
-
|
|
2964
|
+
"Cursor-paginated: the current revision of each fact the caller may see. That is tenant-wide facts, the projects they may read (with those projects' orgs), their own user facts, and every end user's and conversation's facts in the projects they may write; a tenant admin sees every fact. Filters: `?type=` (exact match on `Fact.type`), `?scope=` (URL-encoded JSON partial memory `Scope`), `?scopeKind + ?scopeId + ?inherit` (discriminated `PlatformScope` triplet — threaded into the binding as `platformScope`; both fields coexist), `?asOf=` (memory as it stood then). Sort order is binding-defined.",
|
|
2734
2965
|
tags: ['memory'],
|
|
2735
2966
|
security: 'bearer',
|
|
2736
2967
|
parameters: [
|
|
@@ -2741,11 +2972,14 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
2741
2972
|
ScopeKindQueryParam,
|
|
2742
2973
|
ScopeIdQueryParam,
|
|
2743
2974
|
InheritQueryParam,
|
|
2975
|
+
FactAsOfQueryParam,
|
|
2744
2976
|
],
|
|
2745
2977
|
responses: {
|
|
2746
2978
|
'200': { description: 'Page of facts.', schema: ref('FactCollectionPage') },
|
|
2747
2979
|
...CommonAuthErrors,
|
|
2748
|
-
'400': ErrorResponse(
|
|
2980
|
+
'400': ErrorResponse(
|
|
2981
|
+
'Malformed query parameter (e.g. `scope` not valid JSON, `asOf` not a time).',
|
|
2982
|
+
),
|
|
2749
2983
|
},
|
|
2750
2984
|
},
|
|
2751
2985
|
{
|
|
@@ -2754,13 +2988,36 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
2754
2988
|
openapiPath: '/v1/memory/facts/{factId}',
|
|
2755
2989
|
operationId: 'memory.getFact',
|
|
2756
2990
|
summary: 'Fetch a fact',
|
|
2991
|
+
description:
|
|
2992
|
+
'Its current revision; `?version=` reads one revision, `?asOf=` the revision current at that time. A fact the caller may not see is not found.',
|
|
2757
2993
|
tags: ['memory'],
|
|
2758
2994
|
security: 'bearer',
|
|
2759
|
-
parameters: [FactIdPathParam],
|
|
2995
|
+
parameters: [FactIdPathParam, FactVersionQueryParam, FactAsOfQueryParam],
|
|
2760
2996
|
responses: {
|
|
2761
2997
|
'200': { description: 'Fact.', schema: ref('Fact') },
|
|
2762
2998
|
...CommonAuthErrors,
|
|
2763
|
-
'
|
|
2999
|
+
'400': ErrorResponse('`version` is not a revision number, or `asOf` not a time.'),
|
|
3000
|
+
'404': ErrorResponse('No fact with that id the caller may see (or no such revision).'),
|
|
3001
|
+
},
|
|
3002
|
+
},
|
|
3003
|
+
{
|
|
3004
|
+
method: 'get',
|
|
3005
|
+
honoPath: '/v1/memory/facts/:factId/revisions',
|
|
3006
|
+
openapiPath: '/v1/memory/facts/{factId}/revisions',
|
|
3007
|
+
operationId: 'memory.listFactRevisions',
|
|
3008
|
+
summary: "List a fact's revisions",
|
|
3009
|
+
description:
|
|
3010
|
+
'Every revision of the fact, newest first, superseded and deleted ones included: who changed it, when and why (`invalidatedBy`, `invalidatedAt`, `invalidationReason`).',
|
|
3011
|
+
tags: ['memory'],
|
|
3012
|
+
security: 'bearer',
|
|
3013
|
+
parameters: [FactIdPathParam],
|
|
3014
|
+
responses: {
|
|
3015
|
+
'200': { description: 'The revisions.', schema: ref('FactRevisionList') },
|
|
3016
|
+
...CommonAuthErrors,
|
|
3017
|
+
'404': ErrorResponse('No fact with that id the caller may see.'),
|
|
3018
|
+
'501': ErrorResponse(
|
|
3019
|
+
"`memory-operation-unsupported`: this runtime's memory doesn't keep fact history.",
|
|
3020
|
+
),
|
|
2764
3021
|
},
|
|
2765
3022
|
},
|
|
2766
3023
|
{
|
|
@@ -2770,7 +3027,7 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
2770
3027
|
operationId: 'memory.writeFact',
|
|
2771
3028
|
summary: 'Write a fact',
|
|
2772
3029
|
description:
|
|
2773
|
-
|
|
3030
|
+
"Persists a new fact. `type` selects the retrieval policy (which indexes populate). Semantic-indexed types require an embedding provider bound on the deployment; if unavailable, the route returns `400 bad-input`. The caller needs write where the scope says: `write` on its project (an end user's or a conversation's fact included), `write` on its conversation outside a project, `admin` on its org for an org-wide fact, being that user for a user's fact, and tenant `admin` for a tenant-wide fact. The fact records who wrote it (`attributedTo`).",
|
|
2774
3031
|
tags: ['memory'],
|
|
2775
3032
|
security: 'bearer',
|
|
2776
3033
|
parameters: [IdempotencyKeyParam],
|
|
@@ -2781,6 +3038,10 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
2781
3038
|
'400': ErrorResponse(
|
|
2782
3039
|
'Malformed body, or the fact type requires semantic indexing and no embedding provider is bound.',
|
|
2783
3040
|
),
|
|
3041
|
+
'403': ErrorResponse("`permission-denied`: the caller may not write in the fact's scope."),
|
|
3042
|
+
'409': ErrorResponse(
|
|
3043
|
+
"Idempotency-Key was reused with a different body; or an erasure of the fact's person (by scope or subject) or conversation is in progress (`erasure-in-progress`): nothing new is stored for them until it completes.",
|
|
3044
|
+
),
|
|
2784
3045
|
},
|
|
2785
3046
|
},
|
|
2786
3047
|
{
|
|
@@ -2788,19 +3049,71 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
2788
3049
|
honoPath: '/v1/memory/facts/:factId/supersede',
|
|
2789
3050
|
openapiPath: '/v1/memory/facts/{factId}/supersede',
|
|
2790
3051
|
operationId: 'memory.supersedeFact',
|
|
2791
|
-
summary:
|
|
3052
|
+
summary: "Change a fact's content",
|
|
2792
3053
|
description:
|
|
2793
|
-
'
|
|
3054
|
+
'Writes the next revision (same fact id, `version` one more) and closes the current one; the old revision stays readable with `?version=`, `?asOf=` and in the history until the retention sweep removes it. `expectVersion` refuses if someone changed it first.',
|
|
2794
3055
|
tags: ['memory'],
|
|
2795
3056
|
security: 'bearer',
|
|
2796
3057
|
parameters: [FactIdPathParam, IdempotencyKeyParam],
|
|
3058
|
+
requestBody: { required: true, schema: ref('SupersedeFactBody') },
|
|
2797
3059
|
responses: {
|
|
2798
|
-
'200': {
|
|
2799
|
-
description: 'Superseded (or already superseded).',
|
|
2800
|
-
schema: ref('SupersedeFactResult'),
|
|
2801
|
-
},
|
|
3060
|
+
'200': { description: 'The new revision.', schema: ref('Fact') },
|
|
2802
3061
|
...CommonMutationErrors,
|
|
2803
|
-
'
|
|
3062
|
+
'403': ErrorResponse("`permission-denied`: the caller may not write in the fact's scope."),
|
|
3063
|
+
'404': ErrorResponse('No fact with that id the caller may see, or it was deleted.'),
|
|
3064
|
+
'409': ErrorResponse(
|
|
3065
|
+
'`fact-changed`: the current revision is not `expectVersion` (`details.currentVersion`); `legal-hold`: the fact is under legal hold.',
|
|
3066
|
+
),
|
|
3067
|
+
},
|
|
3068
|
+
},
|
|
3069
|
+
{
|
|
3070
|
+
method: 'delete',
|
|
3071
|
+
honoPath: '/v1/memory/facts/:factId',
|
|
3072
|
+
openapiPath: '/v1/memory/facts/{factId}',
|
|
3073
|
+
operationId: 'memory.deleteFact',
|
|
3074
|
+
summary: 'Delete a fact',
|
|
3075
|
+
description:
|
|
3076
|
+
'Closes the current revision (`invalidationReason: deleted`): the fact is no longer listed, fetched or retrieved, and its history stays readable until the retention sweep removes it.',
|
|
3077
|
+
tags: ['memory'],
|
|
3078
|
+
security: 'bearer',
|
|
3079
|
+
parameters: [FactIdPathParam, FactExpectVersionQueryParam],
|
|
3080
|
+
responses: {
|
|
3081
|
+
'200': { description: 'The closed revision.', schema: ref('Fact') },
|
|
3082
|
+
...CommonAuthErrors,
|
|
3083
|
+
'400': ErrorResponse('`expectVersion` is not a revision number.'),
|
|
3084
|
+
'403': ErrorResponse("`permission-denied`: the caller may not write in the fact's scope."),
|
|
3085
|
+
'404': ErrorResponse('No fact with that id the caller may see, or it was deleted.'),
|
|
3086
|
+
'409': ErrorResponse(
|
|
3087
|
+
'`fact-changed`: the current revision is not `expectVersion`; `legal-hold`: the fact is under legal hold.',
|
|
3088
|
+
),
|
|
3089
|
+
'501': ErrorResponse(
|
|
3090
|
+
"`memory-operation-unsupported`: this runtime's memory can't delete facts.",
|
|
3091
|
+
),
|
|
3092
|
+
},
|
|
3093
|
+
},
|
|
3094
|
+
{
|
|
3095
|
+
method: 'post',
|
|
3096
|
+
honoPath: '/v1/memory/facts/:factId/verify',
|
|
3097
|
+
openapiPath: '/v1/memory/facts/{factId}/verify',
|
|
3098
|
+
operationId: 'memory.verifyFact',
|
|
3099
|
+
summary: 'Mark a fact verified',
|
|
3100
|
+
description:
|
|
3101
|
+
'A person who may write in its scope checked it: the next revision has `trust: verified`, `verifiedBy` and `verifiedAt`, and the same content.',
|
|
3102
|
+
tags: ['memory'],
|
|
3103
|
+
security: 'bearer',
|
|
3104
|
+
parameters: [FactIdPathParam, IdempotencyKeyParam],
|
|
3105
|
+
requestBody: { required: false, schema: ref('VerifyFactBody') },
|
|
3106
|
+
responses: {
|
|
3107
|
+
'200': { description: 'The verified revision.', schema: ref('Fact') },
|
|
3108
|
+
...CommonMutationErrors,
|
|
3109
|
+
'403': ErrorResponse("`permission-denied`: the caller may not write in the fact's scope."),
|
|
3110
|
+
'404': ErrorResponse('No fact with that id the caller may see, or it was deleted.'),
|
|
3111
|
+
'409': ErrorResponse(
|
|
3112
|
+
'`fact-changed`: the current revision is not `expectVersion`; `legal-hold`: the fact is under legal hold.',
|
|
3113
|
+
),
|
|
3114
|
+
'501': ErrorResponse(
|
|
3115
|
+
"`memory-operation-unsupported`: this runtime's memory can't verify facts.",
|
|
3116
|
+
),
|
|
2804
3117
|
},
|
|
2805
3118
|
},
|
|
2806
3119
|
{
|
|
@@ -2810,7 +3123,7 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
2810
3123
|
operationId: 'memory.retrieve',
|
|
2811
3124
|
summary: 'Retrieve facts by intent',
|
|
2812
3125
|
description:
|
|
2813
|
-
'
|
|
3126
|
+
'Retrieval over the facts the caller may see (as for listing), current revisions only. `mode`: `list` (newest first, no query), `keyword` (full-text), `semantic` (by meaning), or `both` (the two searches fused by rank: reciprocal rank fusion). Searching by meaning needs embeddings on the deployment (`KINDGI_MEMORY_EMBEDDINGS`); without them `semantic` and `both` answer `422 semantic-unavailable`.',
|
|
2814
3127
|
tags: ['memory'],
|
|
2815
3128
|
security: 'bearer',
|
|
2816
3129
|
parameters: [IdempotencyKeyParam],
|
|
@@ -2818,38 +3131,179 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
2818
3131
|
responses: {
|
|
2819
3132
|
'200': { description: 'Retrieval results.', schema: ref('RetrieveMemoryResult') },
|
|
2820
3133
|
...CommonMutationErrors,
|
|
3134
|
+
'400': ErrorResponse('Malformed intent.'),
|
|
3135
|
+
'422': ErrorResponse(
|
|
3136
|
+
'`semantic-unavailable`: `semantic` or `both` asked to search by meaning, and the deployment has no embeddings (`KINDGI_MEMORY_EMBEDDINGS`).',
|
|
3137
|
+
),
|
|
3138
|
+
'501': ErrorResponse(
|
|
3139
|
+
"`memory-operation-unsupported`: this runtime's memory can't retrieve by intent.",
|
|
3140
|
+
),
|
|
3141
|
+
},
|
|
3142
|
+
},
|
|
3143
|
+
|
|
3144
|
+
// ---------- memory erasures (a person's words) ----------
|
|
3145
|
+
{
|
|
3146
|
+
method: 'post',
|
|
3147
|
+
honoPath: '/v1/memory/erasures',
|
|
3148
|
+
openapiPath: '/v1/memory/erasures',
|
|
3149
|
+
operationId: 'memory.createErasure',
|
|
3150
|
+
summary: "Erase a person's words",
|
|
3151
|
+
description:
|
|
3152
|
+
"Starts erasing, in the background, one fact (`factId`), a person (`subject`: an app's end user `participant`, or an `external` subject facts name) or one conversation (`conversationId`): their facts, conversations (messages, recall rows), the runs that served them (input, output, journal, snapshots) and the free text they left in provenance; facts written from them go to review. Answers `202` with the erasure; follow it with `GET /v1/memory/erasures/{erasureId}`. A completed erasure keeps no identifier, only a keyed hash for a replay after a backup restore; `warnings` says when this deployment can't keep one (`erasure-unmatchable`: no erasure ledger key, `KINDGI_ERASURE_LEDGER_KEY`). Requires `admin` on the tenant.",
|
|
3153
|
+
tags: ['memory'],
|
|
3154
|
+
security: 'bearer',
|
|
3155
|
+
parameters: [IdempotencyKeyParam],
|
|
3156
|
+
requestBody: { required: true, schema: ref('CreateMemoryErasureBody') },
|
|
3157
|
+
responses: {
|
|
3158
|
+
'202': { description: 'Started.', schema: ref('MemoryErasureCreated') },
|
|
3159
|
+
...CommonMutationErrors,
|
|
2821
3160
|
'400': ErrorResponse(
|
|
2822
|
-
|
|
3161
|
+
"Not exactly one of `factId`, `subject` or `conversationId`; or a `subject` of kind `user` (erasing a Kindgi user isn't offered).",
|
|
3162
|
+
),
|
|
3163
|
+
'403': ErrorResponse('Not a tenant admin.'),
|
|
3164
|
+
'409': ErrorResponse(
|
|
3165
|
+
'`legal-hold`: a fact it reaches is under legal hold (`details.factIds`); nothing started.',
|
|
2823
3166
|
),
|
|
2824
3167
|
},
|
|
2825
3168
|
},
|
|
3169
|
+
{
|
|
3170
|
+
method: 'get',
|
|
3171
|
+
honoPath: '/v1/memory/erasures',
|
|
3172
|
+
openapiPath: '/v1/memory/erasures',
|
|
3173
|
+
operationId: 'memory.listErasures',
|
|
3174
|
+
summary: 'List erasures',
|
|
3175
|
+
description:
|
|
3176
|
+
'Cursor-paginated, newest first: each erasure, how far it got and what it cleared. A completed one shows no selector. Requires `admin` on the tenant.',
|
|
3177
|
+
tags: ['memory'],
|
|
3178
|
+
security: 'bearer',
|
|
3179
|
+
parameters: [LimitQueryParam, CursorQueryParam],
|
|
3180
|
+
responses: {
|
|
3181
|
+
'200': { description: 'Page of erasures.', schema: ref('MemoryErasurePage') },
|
|
3182
|
+
...CommonAuthErrors,
|
|
3183
|
+
'403': ErrorResponse('Not a tenant admin.'),
|
|
3184
|
+
'400': ErrorResponse('`cursor` is not one this list issued.'),
|
|
3185
|
+
},
|
|
3186
|
+
},
|
|
3187
|
+
{
|
|
3188
|
+
method: 'get',
|
|
3189
|
+
honoPath: '/v1/memory/erasures/export',
|
|
3190
|
+
openapiPath: '/v1/memory/erasures/export',
|
|
3191
|
+
operationId: 'memory.exportErasures',
|
|
3192
|
+
summary: 'Export the erasure ledger',
|
|
3193
|
+
description:
|
|
3194
|
+
"The whole ledger, oldest first, content-free: each erasure's selector kind, the keyed hash of whom it erased, who asked and when. Keep it off-box: restoring a backup rolls the ledger back too, and `POST /v1/memory/erasures/replay` with it runs the erasures again. Requires `admin` on the tenant.",
|
|
3195
|
+
tags: ['memory'],
|
|
3196
|
+
security: 'bearer',
|
|
3197
|
+
responses: {
|
|
3198
|
+
'200': { description: 'The ledger.', schema: ref('MemoryErasureLedger') },
|
|
3199
|
+
...CommonAuthErrors,
|
|
3200
|
+
'403': ErrorResponse('Not a tenant admin.'),
|
|
3201
|
+
},
|
|
3202
|
+
},
|
|
3203
|
+
{
|
|
3204
|
+
method: 'post',
|
|
3205
|
+
honoPath: '/v1/memory/erasures/replay',
|
|
3206
|
+
openapiPath: '/v1/memory/erasures/replay',
|
|
3207
|
+
operationId: 'memory.replayErasures',
|
|
3208
|
+
summary: 'Replay erasures after a backup restore',
|
|
3209
|
+
description:
|
|
3210
|
+
"Takes the ledger `GET /v1/memory/erasures/export` gave, puts back the rows the restore lost, and finds each erasure's person (or fact, or conversation) again by its keyed hash: those run again (`replayed`); ones nothing in the tenant matches are only restored (`restored`); ones with no keyed hash, or a key this deployment doesn't hold, are `unmatched`. Requires `admin` on the tenant.",
|
|
3211
|
+
tags: ['memory'],
|
|
3212
|
+
security: 'bearer',
|
|
3213
|
+
parameters: [IdempotencyKeyParam],
|
|
3214
|
+
requestBody: { required: true, schema: ref('ReplayMemoryErasuresBody') },
|
|
3215
|
+
responses: {
|
|
3216
|
+
'200': { description: 'What was replayed.', schema: ref('ReplayMemoryErasuresResult') },
|
|
3217
|
+
...CommonMutationErrors,
|
|
3218
|
+
'400': ErrorResponse('Not `{erasures: [...]}` as the export gave them.'),
|
|
3219
|
+
'403': ErrorResponse('Not a tenant admin.'),
|
|
3220
|
+
},
|
|
3221
|
+
},
|
|
3222
|
+
{
|
|
3223
|
+
method: 'post',
|
|
3224
|
+
honoPath: '/v1/memory/erasures/:erasureId/resume',
|
|
3225
|
+
openapiPath: '/v1/memory/erasures/{erasureId}/resume',
|
|
3226
|
+
operationId: 'memory.resumeErasure',
|
|
3227
|
+
summary: 'Resume an erasure',
|
|
3228
|
+
description:
|
|
3229
|
+
"Tries an unfinished erasure again now. With `force: true`, an erasure `waiting-on-run` (a turn of the person's in a flow that serves other people) stops waiting: the run is cancelled and the erasure goes on; without it, it waits until its deadline (`waitingOn.until`). A finished erasure comes back as it is. Requires `admin` on the tenant.",
|
|
3230
|
+
tags: ['memory'],
|
|
3231
|
+
security: 'bearer',
|
|
3232
|
+
parameters: [ErasureIdPathParam, IdempotencyKeyParam],
|
|
3233
|
+
requestBody: { required: false, schema: ref('ResumeMemoryErasureBody') },
|
|
3234
|
+
responses: {
|
|
3235
|
+
'200': { description: 'The erasure.', schema: ref('MemoryErasure') },
|
|
3236
|
+
...CommonMutationErrors,
|
|
3237
|
+
'400': ErrorResponse('The body is `{force?: boolean}`.'),
|
|
3238
|
+
'403': ErrorResponse('Not a tenant admin.'),
|
|
3239
|
+
'404': ErrorResponse('No such erasure in this tenant.'),
|
|
3240
|
+
},
|
|
3241
|
+
},
|
|
3242
|
+
{
|
|
3243
|
+
method: 'get',
|
|
3244
|
+
honoPath: '/v1/memory/erasures/:erasureId',
|
|
3245
|
+
openapiPath: '/v1/memory/erasures/{erasureId}',
|
|
3246
|
+
operationId: 'memory.getErasure',
|
|
3247
|
+
summary: 'Get an erasure',
|
|
3248
|
+
description:
|
|
3249
|
+
'One erasure: its status (`pending`, `running`, `completed`, `failed`), phase, what each store cleared (`counts`), and `lastError` (a code, or `not-yet:<reason>` while it waits for a run to finish). Requires `admin` on the tenant.',
|
|
3250
|
+
tags: ['memory'],
|
|
3251
|
+
security: 'bearer',
|
|
3252
|
+
parameters: [ErasureIdPathParam],
|
|
3253
|
+
responses: {
|
|
3254
|
+
'200': { description: 'The erasure.', schema: ref('MemoryErasure') },
|
|
3255
|
+
...CommonAuthErrors,
|
|
3256
|
+
'403': ErrorResponse('Not a tenant admin.'),
|
|
3257
|
+
'404': ErrorResponse('No such erasure in this tenant.'),
|
|
3258
|
+
},
|
|
3259
|
+
},
|
|
2826
3260
|
|
|
2827
|
-
// ---------- proposals
|
|
3261
|
+
// ---------- improvement proposals ----------
|
|
2828
3262
|
{
|
|
2829
3263
|
method: 'get',
|
|
2830
3264
|
honoPath: '/v1/proposals',
|
|
2831
3265
|
openapiPath: '/v1/proposals',
|
|
2832
3266
|
operationId: 'proposals.list',
|
|
2833
|
-
summary: 'List
|
|
3267
|
+
summary: 'List improvement proposals',
|
|
2834
3268
|
description:
|
|
2835
|
-
'
|
|
3269
|
+
'Newest first, cursor-paginated, only the proposals of agents the caller can read. Filters: `?agentId=`, `?tier=`, `?status=` (statuses are derived, so a page filtered by status can hold fewer rows than `limit`), and the live scope a proposal is for (`scopeKind`, `scopeId`, `segment`, exactly as the promotions history takes it).',
|
|
2836
3270
|
tags: ['proposals'],
|
|
2837
3271
|
security: 'bearer',
|
|
2838
3272
|
parameters: [
|
|
2839
|
-
SupervisorIdHeaderParam,
|
|
2840
3273
|
LimitQueryParam,
|
|
2841
3274
|
CursorQueryParam,
|
|
2842
3275
|
ProposalStatusQueryParam,
|
|
2843
3276
|
AgentIdQueryParam,
|
|
2844
3277
|
ProposalTierQueryParam,
|
|
2845
|
-
|
|
3278
|
+
PromotionScopeKindQueryParam,
|
|
2846
3279
|
ScopeIdQueryParam,
|
|
2847
|
-
|
|
3280
|
+
SegmentQueryParam,
|
|
2848
3281
|
],
|
|
2849
3282
|
responses: {
|
|
2850
3283
|
'200': { description: 'Page of proposals.', schema: ref('FixProposalCollectionPage') },
|
|
2851
3284
|
...CommonAuthErrors,
|
|
2852
|
-
'400': ErrorResponse('
|
|
3285
|
+
'400': ErrorResponse('A malformed query parameter.'),
|
|
3286
|
+
},
|
|
3287
|
+
},
|
|
3288
|
+
{
|
|
3289
|
+
method: 'post',
|
|
3290
|
+
honoPath: '/v1/proposals/improve',
|
|
3291
|
+
openapiPath: '/v1/proposals/improve',
|
|
3292
|
+
operationId: 'proposals.improve',
|
|
3293
|
+
summary: 'Start an improvement pass',
|
|
3294
|
+
description:
|
|
3295
|
+
"The runtime looks for better values for the version's tunable settings (keys its settings blocks' schemas mark `x-kindgi-tunable`) on the test set, within the budget, and writes its best candidate as an improvement proposal, which waits for a reviewer when requested. It answers at once with the pass, `running`. Checked first: the version is active and pins a settings block with tunable keys (`400 validation-failed`), the agent registry takes writes (`409 registry-read-only`), and the agent has a live version for the whole tenant (`409 proposal-needs-pin`). Needs `publish` on the agent. Without improvement passes in this runtime, `501 improve-unsupported`.",
|
|
3296
|
+
tags: ['proposals'],
|
|
3297
|
+
security: 'bearer',
|
|
3298
|
+
parameters: [IdempotencyKeyParam],
|
|
3299
|
+
requestBody: { required: true, schema: ref('ImproveBody') },
|
|
3300
|
+
responses: {
|
|
3301
|
+
'202': { description: 'The pass, running.', schema: ref('ImprovementPass') },
|
|
3302
|
+
...CommonMutationErrors,
|
|
3303
|
+
'404': ErrorResponse(
|
|
3304
|
+
'`fromVersion` (or the version serving the scope) is not an active version.',
|
|
3305
|
+
),
|
|
3306
|
+
'501': ErrorResponse('`improve-unsupported`: this runtime runs no improvement passes.'),
|
|
2853
3307
|
},
|
|
2854
3308
|
},
|
|
2855
3309
|
{
|
|
@@ -2857,93 +3311,82 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
2857
3311
|
honoPath: '/v1/proposals/:proposalId',
|
|
2858
3312
|
openapiPath: '/v1/proposals/{proposalId}',
|
|
2859
3313
|
operationId: 'proposals.get',
|
|
2860
|
-
summary: 'Fetch
|
|
3314
|
+
summary: 'Fetch an improvement proposal',
|
|
3315
|
+
description: 'Needs `read` on its agent.',
|
|
2861
3316
|
tags: ['proposals'],
|
|
2862
3317
|
security: 'bearer',
|
|
2863
|
-
parameters: [
|
|
3318
|
+
parameters: [ProposalIdPathParam],
|
|
2864
3319
|
responses: {
|
|
2865
|
-
'200': { description: '
|
|
3320
|
+
'200': { description: 'The proposal.', schema: ref('FixProposal') },
|
|
2866
3321
|
...CommonAuthErrors,
|
|
2867
|
-
'
|
|
2868
|
-
'404': ErrorResponse('No proposal visible under this supervisor with that id.'),
|
|
3322
|
+
'404': ErrorResponse('No such proposal (or none the caller can read).'),
|
|
2869
3323
|
},
|
|
2870
3324
|
},
|
|
2871
3325
|
{
|
|
2872
3326
|
method: 'post',
|
|
2873
3327
|
honoPath: '/v1/proposals',
|
|
2874
3328
|
openapiPath: '/v1/proposals',
|
|
2875
|
-
operationId: 'proposals.
|
|
2876
|
-
summary: '
|
|
3329
|
+
operationId: 'proposals.create',
|
|
3330
|
+
summary: 'Propose new content for a data block',
|
|
2877
3331
|
description:
|
|
2878
|
-
'
|
|
3332
|
+
'A hand-written proposal: new settings values or a new prompt template for a block `fromVersion` pins, for a live scope. Checked as publishing that block version would be (its schema carries over), and refused when it equals the pinned content. The same change from the same version for the same scope is one proposal: answered `200` with `X-Proposal-Deduped: true`. Needs `publish` on the agent.',
|
|
2879
3333
|
tags: ['proposals'],
|
|
2880
3334
|
security: 'bearer',
|
|
2881
|
-
parameters: [
|
|
2882
|
-
requestBody: { required: true, schema: ref('
|
|
3335
|
+
parameters: [IdempotencyKeyParam],
|
|
3336
|
+
requestBody: { required: true, schema: ref('CreateProposalBody') },
|
|
2883
3337
|
responses: {
|
|
2884
|
-
'201': { description: '
|
|
3338
|
+
'201': { description: 'The proposal, a `draft`.', schema: ref('FixProposal') },
|
|
3339
|
+
'200': { description: 'The same proposal, made before.', schema: ref('FixProposal') },
|
|
2885
3340
|
...CommonMutationErrors,
|
|
3341
|
+
'404': ErrorResponse(
|
|
3342
|
+
"`fromVersion` isn't an active version of the agent (`agent-version-not-found`).",
|
|
3343
|
+
),
|
|
2886
3344
|
},
|
|
2887
3345
|
},
|
|
2888
3346
|
{
|
|
2889
3347
|
method: 'post',
|
|
2890
|
-
honoPath: '/v1/proposals/:proposalId/
|
|
2891
|
-
openapiPath: '/v1/proposals/{proposalId}/
|
|
2892
|
-
operationId: 'proposals.
|
|
2893
|
-
summary: '
|
|
3348
|
+
honoPath: '/v1/proposals/:proposalId/evaluate',
|
|
3349
|
+
openapiPath: '/v1/proposals/{proposalId}/evaluate',
|
|
3350
|
+
operationId: 'proposals.evaluate',
|
|
3351
|
+
summary: 'Compare a proposal on a test set',
|
|
2894
3352
|
description:
|
|
2895
|
-
|
|
3353
|
+
"The first evaluation publishes the block version and derives the agent version (`derivedFrom.proposalId`); they serve no scope until a promotion makes them live. Then a comparison eval run replays that version on the test set, against the recorded outputs (`baseline: 'recorded'`). Needs `publish` on the agent, and a live version of it for the whole tenant: an agent with none serves its latest version wherever nothing is pinned, so a new version would go live there at once (`409 proposal-needs-pin`). Allowed from `draft`, `evaluated`, `not-better`, `evaluation-failed`, `refused`, `superseded` and `expired`.",
|
|
2896
3354
|
tags: ['proposals'],
|
|
2897
3355
|
security: 'bearer',
|
|
2898
|
-
parameters: [
|
|
2899
|
-
requestBody: { required: true, schema: ref('
|
|
3356
|
+
parameters: [ProposalIdPathParam, IdempotencyKeyParam],
|
|
3357
|
+
requestBody: { required: true, schema: ref('EvaluateProposalBody') },
|
|
2900
3358
|
responses: {
|
|
2901
|
-
'
|
|
3359
|
+
'202': { description: 'The proposal, `evaluating`.', schema: ref('FixProposal') },
|
|
2902
3360
|
...CommonMutationErrors,
|
|
2903
|
-
'404': ErrorResponse('No proposal
|
|
2904
|
-
'
|
|
3361
|
+
'404': ErrorResponse('No such proposal, or no such test set.'),
|
|
3362
|
+
'409': ErrorResponse(
|
|
3363
|
+
"`proposal-needs-pin`: the agent has no live version for the whole tenant. `proposal-invalid-state-transition`: the proposal's status doesn't allow it. `registry-read-only`: the agent registry takes no writes (under `kindgi dev`).",
|
|
3364
|
+
),
|
|
2905
3365
|
},
|
|
2906
3366
|
},
|
|
2907
3367
|
{
|
|
2908
3368
|
method: 'post',
|
|
2909
|
-
honoPath: '/v1/proposals/:proposalId/
|
|
2910
|
-
openapiPath: '/v1/proposals/{proposalId}/
|
|
2911
|
-
operationId: 'proposals.
|
|
2912
|
-
summary:
|
|
3369
|
+
honoPath: '/v1/proposals/:proposalId/request',
|
|
3370
|
+
openapiPath: '/v1/proposals/{proposalId}/request',
|
|
3371
|
+
operationId: 'proposals.request',
|
|
3372
|
+
summary: "Request a proposal's promotion for its scope",
|
|
2913
3373
|
description:
|
|
2914
|
-
|
|
3374
|
+
"A promotion of the candidate for the proposal's scope, with its evaluation's comparison, through the scope's gate: as `POST /v1/agents/{agentId}/promotions` answers. Needs `promote` on the agent. Allowed from `evaluated`, `not-better` (the gate decides), `refused`, `superseded` and `expired`.",
|
|
2915
3375
|
tags: ['proposals'],
|
|
2916
3376
|
security: 'bearer',
|
|
2917
|
-
parameters: [
|
|
2918
|
-
requestBody: { required: false, schema: ref('
|
|
3377
|
+
parameters: [ProposalIdPathParam, IdempotencyKeyParam],
|
|
3378
|
+
requestBody: { required: false, schema: ref('ProposalReasonBody') },
|
|
2919
3379
|
responses: {
|
|
2920
|
-
'
|
|
2921
|
-
|
|
2922
|
-
|
|
3380
|
+
'201': { description: 'Promoted: the proposal, `promoted`.', schema: ref('FixProposal') },
|
|
3381
|
+
'202': {
|
|
3382
|
+
description: 'The gate passed and an approval is open: the proposal, `in-review`.',
|
|
3383
|
+
schema: ref('FixProposal'),
|
|
2923
3384
|
},
|
|
2924
3385
|
...CommonMutationErrors,
|
|
2925
|
-
'404': ErrorResponse('No proposal
|
|
2926
|
-
'
|
|
2927
|
-
},
|
|
2928
|
-
},
|
|
2929
|
-
{
|
|
2930
|
-
method: 'post',
|
|
2931
|
-
honoPath: '/v1/proposals/:proposalId/apply',
|
|
2932
|
-
openapiPath: '/v1/proposals/{proposalId}/apply',
|
|
2933
|
-
operationId: 'proposals.apply',
|
|
2934
|
-
summary: 'Apply an approved proposal',
|
|
2935
|
-
description:
|
|
2936
|
-
'Materializes the proposed change into a new agent version, registers it in the agent registry, and transitions the proposal to `applied`. Legal only from `approved`.',
|
|
2937
|
-
tags: ['proposals'],
|
|
2938
|
-
security: 'bearer',
|
|
2939
|
-
parameters: [SupervisorIdHeaderParam, ProposalIdPathParam, IdempotencyKeyParam],
|
|
2940
|
-
requestBody: { required: false, schema: ref('ApplyProposalBody') },
|
|
2941
|
-
responses: {
|
|
2942
|
-
'200': { description: 'Proposal applied.', schema: ref('ApplyProposalResult') },
|
|
2943
|
-
...CommonMutationErrors,
|
|
2944
|
-
'404': ErrorResponse('No proposal visible under this supervisor with that id.'),
|
|
3386
|
+
'404': ErrorResponse('No such proposal.'),
|
|
3387
|
+
'409': ErrorResponse("The proposal's status doesn't allow it."),
|
|
2945
3388
|
'422': ErrorResponse(
|
|
2946
|
-
'
|
|
3389
|
+
'`gate-failed`: the gate refused it (the error carries the checks and `proposalId`).',
|
|
2947
3390
|
),
|
|
2948
3391
|
},
|
|
2949
3392
|
},
|
|
@@ -2952,17 +3395,18 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
2952
3395
|
honoPath: '/v1/proposals/:proposalId/rollback',
|
|
2953
3396
|
openapiPath: '/v1/proposals/{proposalId}/rollback',
|
|
2954
3397
|
operationId: 'proposals.rollback',
|
|
2955
|
-
summary: 'Roll back
|
|
3398
|
+
summary: 'Roll back a promoted proposal',
|
|
2956
3399
|
description:
|
|
2957
|
-
|
|
3400
|
+
"The scope goes back to the version its own pin held before the proposal's promotion (or, with none, falls back to the scope above). Only while the proposal's version still serves the scope. Needs `promote` on the agent.",
|
|
2958
3401
|
tags: ['proposals'],
|
|
2959
3402
|
security: 'bearer',
|
|
2960
|
-
parameters: [
|
|
2961
|
-
requestBody: { required:
|
|
3403
|
+
parameters: [ProposalIdPathParam, IdempotencyKeyParam],
|
|
3404
|
+
requestBody: { required: false, schema: ref('ProposalReasonBody') },
|
|
2962
3405
|
responses: {
|
|
2963
|
-
'200': { description: '
|
|
3406
|
+
'200': { description: 'The proposal, `rolled-back`.', schema: ref('FixProposal') },
|
|
2964
3407
|
...CommonMutationErrors,
|
|
2965
|
-
'404': ErrorResponse('No proposal
|
|
3408
|
+
'404': ErrorResponse('No such proposal.'),
|
|
3409
|
+
'409': ErrorResponse("It isn't promoted, or its version doesn't serve the scope anymore."),
|
|
2966
3410
|
},
|
|
2967
3411
|
},
|
|
2968
3412
|
{
|
|
@@ -2970,17 +3414,74 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
2970
3414
|
honoPath: '/v1/proposals/:proposalId/withdraw',
|
|
2971
3415
|
openapiPath: '/v1/proposals/{proposalId}/withdraw',
|
|
2972
3416
|
operationId: 'proposals.withdraw',
|
|
2973
|
-
summary: 'Withdraw a
|
|
3417
|
+
summary: 'Withdraw a proposal',
|
|
2974
3418
|
description:
|
|
2975
|
-
|
|
3419
|
+
"Closes it. Not while it's in review (decide its approval instead), nor once promoted, rejected or rolled back. Needs `publish` on the agent.",
|
|
2976
3420
|
tags: ['proposals'],
|
|
2977
3421
|
security: 'bearer',
|
|
2978
|
-
parameters: [
|
|
3422
|
+
parameters: [ProposalIdPathParam, IdempotencyKeyParam],
|
|
2979
3423
|
requestBody: { required: true, schema: ref('WithdrawProposalBody') },
|
|
2980
3424
|
responses: {
|
|
2981
|
-
'200': { description: '
|
|
3425
|
+
'200': { description: 'The proposal, `withdrawn`.', schema: ref('FixProposal') },
|
|
2982
3426
|
...CommonMutationErrors,
|
|
2983
|
-
'404': ErrorResponse('No proposal
|
|
3427
|
+
'404': ErrorResponse('No such proposal.'),
|
|
3428
|
+
'409': ErrorResponse("The proposal's status doesn't allow it."),
|
|
3429
|
+
},
|
|
3430
|
+
},
|
|
3431
|
+
|
|
3432
|
+
// ---------- improvement passes ----------
|
|
3433
|
+
{
|
|
3434
|
+
method: 'get',
|
|
3435
|
+
honoPath: '/v1/improvement-passes',
|
|
3436
|
+
openapiPath: '/v1/improvement-passes',
|
|
3437
|
+
operationId: 'improvementPasses.list',
|
|
3438
|
+
summary: 'List improvement passes',
|
|
3439
|
+
description:
|
|
3440
|
+
'Newest first, only the passes of agents the caller can read. `?agentId=` narrows them.',
|
|
3441
|
+
tags: ['proposals'],
|
|
3442
|
+
security: 'bearer',
|
|
3443
|
+
parameters: [LimitQueryParam, CursorQueryParam, AgentIdQueryParam],
|
|
3444
|
+
responses: {
|
|
3445
|
+
'200': { description: 'Page of passes.', schema: ref('ImprovementPassCollectionPage') },
|
|
3446
|
+
...CommonAuthErrors,
|
|
3447
|
+
'501': ErrorResponse('`improve-unsupported`: this runtime runs no improvement passes.'),
|
|
3448
|
+
},
|
|
3449
|
+
},
|
|
3450
|
+
{
|
|
3451
|
+
method: 'get',
|
|
3452
|
+
honoPath: '/v1/improvement-passes/:passId',
|
|
3453
|
+
openapiPath: '/v1/improvement-passes/{passId}',
|
|
3454
|
+
operationId: 'improvementPasses.get',
|
|
3455
|
+
summary: 'Fetch an improvement pass',
|
|
3456
|
+
description:
|
|
3457
|
+
'Its status, the candidates it compared and what they cost, and once it ends, what it found. Needs `read` on its agent.',
|
|
3458
|
+
tags: ['proposals'],
|
|
3459
|
+
security: 'bearer',
|
|
3460
|
+
parameters: [ImprovementPassIdPathParam],
|
|
3461
|
+
responses: {
|
|
3462
|
+
'200': { description: 'The pass.', schema: ref('ImprovementPass') },
|
|
3463
|
+
...CommonAuthErrors,
|
|
3464
|
+
'404': ErrorResponse('No such pass (or none the caller can read).'),
|
|
3465
|
+
'501': ErrorResponse('`improve-unsupported`: this runtime runs no improvement passes.'),
|
|
3466
|
+
},
|
|
3467
|
+
},
|
|
3468
|
+
{
|
|
3469
|
+
method: 'post',
|
|
3470
|
+
honoPath: '/v1/improvement-passes/:passId/cancel',
|
|
3471
|
+
openapiPath: '/v1/improvement-passes/{passId}/cancel',
|
|
3472
|
+
operationId: 'improvementPasses.cancel',
|
|
3473
|
+
summary: 'Cancel an improvement pass',
|
|
3474
|
+
description:
|
|
3475
|
+
'A running pass stops and ends `cancelled`, writing no proposal. Needs `publish` on its agent.',
|
|
3476
|
+
tags: ['proposals'],
|
|
3477
|
+
security: 'bearer',
|
|
3478
|
+
parameters: [ImprovementPassIdPathParam, IdempotencyKeyParam],
|
|
3479
|
+
responses: {
|
|
3480
|
+
'200': { description: 'The pass, cancelled.', schema: ref('ImprovementPass') },
|
|
3481
|
+
...CommonMutationErrors,
|
|
3482
|
+
'404': ErrorResponse('No such pass.'),
|
|
3483
|
+
'409': ErrorResponse('`improvement-pass-finished`: it has ended already.'),
|
|
3484
|
+
'501': ErrorResponse('`improve-unsupported`: this runtime runs no improvement passes.'),
|
|
2984
3485
|
},
|
|
2985
3486
|
},
|
|
2986
3487
|
|
|
@@ -3027,6 +3528,21 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
3027
3528
|
'404': ErrorResponse('No provenance record for that run under this tenant.'),
|
|
3028
3529
|
},
|
|
3029
3530
|
},
|
|
3531
|
+
{
|
|
3532
|
+
method: 'get',
|
|
3533
|
+
honoPath: '/v1/export-signing-keys',
|
|
3534
|
+
openapiPath: '/v1/export-signing-keys',
|
|
3535
|
+
operationId: 'exportSigningKeys.list',
|
|
3536
|
+
summary: 'List the keys this deployment signs exports with',
|
|
3537
|
+
description:
|
|
3538
|
+
"The public keys of the deployment's export signing key, active first: what a verifier pins. An export's embedded `publicKey` only proves its bytes weren't changed; this list says who signed them. Empty when the deployment doesn't sign exports. Any authenticated caller may read it.",
|
|
3539
|
+
tags: ['export-signing-keys'],
|
|
3540
|
+
security: 'bearer',
|
|
3541
|
+
responses: {
|
|
3542
|
+
'200': { description: 'The keys.', schema: ref('ExportSigningKeyList') },
|
|
3543
|
+
...CommonAuthErrors,
|
|
3544
|
+
},
|
|
3545
|
+
},
|
|
3030
3546
|
{
|
|
3031
3547
|
method: 'post',
|
|
3032
3548
|
honoPath: '/v1/provenance/:runId/export',
|
|
@@ -3034,11 +3550,11 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
3034
3550
|
operationId: 'provenance.export',
|
|
3035
3551
|
summary: 'Export a signed provenance bundle for a run',
|
|
3036
3552
|
description:
|
|
3037
|
-
"
|
|
3553
|
+
"Signs the run's provenance (and, when asked, its messages) with the deployment's export key, and records the export (an `export-signed` audit event). The same envelope as the other signed exports; check `publicKey` against `GET /v1/export-signing-keys`. A deployment with no export key answers `404 signing-not-configured`.",
|
|
3038
3554
|
tags: ['provenance'],
|
|
3039
3555
|
security: 'bearer',
|
|
3040
3556
|
parameters: [RunIdPathParam, IdempotencyKeyParam],
|
|
3041
|
-
requestBody: { required:
|
|
3557
|
+
requestBody: { required: false, schema: ref('ExportProvenanceBody') },
|
|
3042
3558
|
responses: {
|
|
3043
3559
|
'200': { description: 'Signed bundle.', schema: ref('ExportProvenanceResult') },
|
|
3044
3560
|
...CommonMutationErrors,
|
|
@@ -3056,7 +3572,7 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
3056
3572
|
operationId: 'artifacts.list',
|
|
3057
3573
|
summary: 'List artifact metadata',
|
|
3058
3574
|
description:
|
|
3059
|
-
'Cursor-paginated. Metadata rows only (no bytes). Filters: `?ownerRunId=`, `?contentType=`, `?tag.<key>=<value>` (repeatable — every provided tag must match as AND). Sort order is binding-defined (typically `createdAt desc, blobId desc`).',
|
|
3575
|
+
'Cursor-paginated. Metadata rows only (no bytes). Filters: `?ownerRunId=`, `?projectId=`, `?contentType=`, `?tag.<key>=<value>` (repeatable — every provided tag must match as AND). Sort order is binding-defined (typically `createdAt desc, blobId desc`). With authorization on, only artifacts in projects the caller can read are listed.',
|
|
3060
3576
|
tags: ['artifacts'],
|
|
3061
3577
|
security: 'bearer',
|
|
3062
3578
|
parameters: [
|
|
@@ -3076,6 +3592,13 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
3076
3592
|
description: 'Filter by exact content-type match.',
|
|
3077
3593
|
schema: { type: 'string' },
|
|
3078
3594
|
},
|
|
3595
|
+
{
|
|
3596
|
+
name: 'projectId',
|
|
3597
|
+
in: 'query',
|
|
3598
|
+
required: false,
|
|
3599
|
+
description: 'Filter to the artifacts of one project.',
|
|
3600
|
+
schema: { type: 'string' },
|
|
3601
|
+
},
|
|
3079
3602
|
],
|
|
3080
3603
|
responses: {
|
|
3081
3604
|
'200': { description: 'Page of blob metadata.', schema: ref('ArtifactCollectionPage') },
|
|
@@ -3090,7 +3613,7 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
3090
3613
|
operationId: 'artifacts.upload',
|
|
3091
3614
|
summary: 'Upload an artifact',
|
|
3092
3615
|
description:
|
|
3093
|
-
|
|
3616
|
+
"Multipart upload. `file` part carries the bytes; other form fields carry metadata (`name`, `contentType`, `tags` (JSON), `ownerRunId`, `projectId`, `expectedHash`). Framework computes sha256 and returns it in `BlobMeta.hash`. If `expectedHash` was supplied and diverges, response is `400 blob-hash-mismatch`. Content-type sniffing is NOT performed server-side — the framework trusts the caller. The artifact belongs to its owner run's project, else `projectId`, else the tenant's default project; uploading needs `write` there. An upload over the runtime's cap (default 100 MB) is `413 artifact-too-large`.",
|
|
3094
3617
|
tags: ['artifacts'],
|
|
3095
3618
|
security: 'bearer',
|
|
3096
3619
|
parameters: [IdempotencyKeyParam],
|
|
@@ -3107,7 +3630,12 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
3107
3630
|
'201': { description: 'Upload accepted; metadata returned.', schema: ref('BlobMeta') },
|
|
3108
3631
|
...CommonMutationErrors,
|
|
3109
3632
|
'400': ErrorResponse(
|
|
3110
|
-
|
|
3633
|
+
"Malformed multipart body, bad tag JSON, hash mismatch, declared size mismatch, or a `projectId` that isn't the owner run's.",
|
|
3634
|
+
),
|
|
3635
|
+
'403': ErrorResponse('No `write` on the project (`permission-denied`).'),
|
|
3636
|
+
'404': ErrorResponse('No such owner run (`run-not-found`).'),
|
|
3637
|
+
'413': ErrorResponse(
|
|
3638
|
+
'Over the upload cap (`artifact-too-large`; `details.maxBytes` says how much).',
|
|
3111
3639
|
),
|
|
3112
3640
|
},
|
|
3113
3641
|
},
|
|
@@ -3137,7 +3665,9 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
3137
3665
|
schema: { type: 'string', format: 'binary' },
|
|
3138
3666
|
},
|
|
3139
3667
|
...CommonAuthErrors,
|
|
3140
|
-
'404': ErrorResponse(
|
|
3668
|
+
'404': ErrorResponse(
|
|
3669
|
+
"No blob with that id under this tenant, or one in a project the caller can't read.",
|
|
3670
|
+
),
|
|
3141
3671
|
},
|
|
3142
3672
|
},
|
|
3143
3673
|
{
|
|
@@ -3190,6 +3720,8 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
3190
3720
|
responses: {
|
|
3191
3721
|
'200': { description: 'Delete acknowledged.', schema: ref('DeleteArtifactResult') },
|
|
3192
3722
|
...CommonMutationErrors,
|
|
3723
|
+
'403': ErrorResponse('No `write` on its project (`permission-denied`).'),
|
|
3724
|
+
'404': ErrorResponse("An artifact in a project the caller can't read (`blob-not-found`)."),
|
|
3193
3725
|
},
|
|
3194
3726
|
},
|
|
3195
3727
|
|
|
@@ -3317,6 +3849,23 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
3317
3849
|
'404': ErrorResponse('No provider with that id under this tenant.'),
|
|
3318
3850
|
},
|
|
3319
3851
|
},
|
|
3852
|
+
{
|
|
3853
|
+
method: 'get',
|
|
3854
|
+
honoPath: '/v1/providers/:providerId/check',
|
|
3855
|
+
openapiPath: '/v1/providers/{providerId}/check',
|
|
3856
|
+
operationId: 'providers.check',
|
|
3857
|
+
summary: "Check a provider's registration",
|
|
3858
|
+
description:
|
|
3859
|
+
"Runs the provider's adapter check over its stored registration (its `adapter_config`, its metadata, whether it names a `secret_ref`): the check `POST /v1/providers` runs before it stores one. Static: no network call, no secret read. `issues` lists what would keep the runtime from building the provider, each with a JSON-pointer `path`; an adapter this runtime doesn't have is one (`/adapter_id`). `checked` is false when this runtime has no check for the provider's adapter.",
|
|
3860
|
+
tags: ['providers'],
|
|
3861
|
+
security: 'bearer',
|
|
3862
|
+
parameters: [ProviderIdPathParam],
|
|
3863
|
+
responses: {
|
|
3864
|
+
'200': { description: 'The check.', schema: ref('ProviderCheckResult') },
|
|
3865
|
+
...CommonAuthErrors,
|
|
3866
|
+
'404': ErrorResponse('No provider with that id under this tenant.'),
|
|
3867
|
+
},
|
|
3868
|
+
},
|
|
3320
3869
|
{
|
|
3321
3870
|
method: 'post',
|
|
3322
3871
|
honoPath: '/v1/providers',
|
|
@@ -3324,7 +3873,7 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
3324
3873
|
operationId: 'providers.register',
|
|
3325
3874
|
summary: 'Register a model provider',
|
|
3326
3875
|
description:
|
|
3327
|
-
'Body is a full `ProviderMetadata`. Server validates shape: provider-level `id` + `region` non-empty; `models[]` non-empty with unique `name` per entry; per-model `contextWindow` positive integer; per-model `features` against the closed enum; per-model `cost` non-negative; optional per-model `p95LatencyMs` / `maxOutputTokens` well-shaped; optional `labels` within their limits — same rules as `@kindgi/capabilities.createProviderRegistry`. Secrets (API keys, endpoints) are NOT part of the wire shape; deployments store them inside the binding.',
|
|
3876
|
+
'Body is a full `ProviderMetadata`. Server validates shape: provider-level `id` + `region` non-empty; `models[]` non-empty with unique `name` per entry; per-model `contextWindow` positive integer; per-model `features` against the closed enum; per-model `cost` non-negative; optional per-model `p95LatencyMs` / `maxOutputTokens` well-shaped; optional `labels` within their limits — same rules as `@kindgi/capabilities.createProviderRegistry`. Secrets (API keys, endpoints) are NOT part of the wire shape; deployments store them inside the binding. When the runtime has the adapter the body names, that adapter checks the registration first (its `adapter_config`, the metadata and the presence of `secret_ref`; static: no network, no secret read): a problem refuses it with `422 provider-config-invalid`.',
|
|
3328
3877
|
tags: ['providers'],
|
|
3329
3878
|
security: 'bearer',
|
|
3330
3879
|
parameters: [IdempotencyKeyParam],
|
|
@@ -3334,6 +3883,9 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
3334
3883
|
...CommonMutationErrors,
|
|
3335
3884
|
'400': ErrorResponse('Validation failed (see `details.reason`).'),
|
|
3336
3885
|
'409': ErrorResponse('Provider already registered at that id.'),
|
|
3886
|
+
'422': ErrorResponse(
|
|
3887
|
+
"`provider-config-invalid`: a `send_traceparent` that isn't a boolean, or the provider's adapter refuses the registration (its `adapter_config`, its metadata, or a missing `secret_ref`); `details.issues` lists each (`path`, a JSON pointer, and `message`), the registration's own fields first, as other validation errors do. Nothing is stored.",
|
|
3888
|
+
),
|
|
3337
3889
|
},
|
|
3338
3890
|
},
|
|
3339
3891
|
{
|
|
@@ -3378,6 +3930,9 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
3378
3930
|
),
|
|
3379
3931
|
'404': ErrorResponse('`run-not-found`.'),
|
|
3380
3932
|
'409': ErrorResponse('`run-not-finished`: the run has no output to judge yet.'),
|
|
3933
|
+
'410': ErrorResponse(
|
|
3934
|
+
"`run-erased`: an erasure cleared the run's content (a person's words were removed); there's nothing to judge.",
|
|
3935
|
+
),
|
|
3381
3936
|
},
|
|
3382
3937
|
},
|
|
3383
3938
|
{
|
|
@@ -4150,7 +4705,9 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
4150
4705
|
'400': ErrorResponse(
|
|
4151
4706
|
"Validation failed (see `details.issues`); or `projectId` isn't a project id (a UUID).",
|
|
4152
4707
|
),
|
|
4153
|
-
'409': ErrorResponse(
|
|
4708
|
+
'409': ErrorResponse(
|
|
4709
|
+
"`eval-suite-already-registered`: that (id, version) is taken. Or `eval-suite-project-mismatch`: the suite's versions live in another project (a suite belongs to the project its first version was published into and never moves; the message doesn't name the project).",
|
|
4710
|
+
),
|
|
4154
4711
|
'404': ErrorResponse(
|
|
4155
4712
|
"The body's `projectId` names no project of this tenant (`project-not-found`).",
|
|
4156
4713
|
),
|
|
@@ -4163,7 +4720,7 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
4163
4720
|
operationId: 'evalSuites.buildFromJudgments',
|
|
4164
4721
|
summary: 'Build a test set from judgments',
|
|
4165
4722
|
description:
|
|
4166
|
-
"Publishes a `judged` eval suite version whose cases are copies of judged runs of one agent (optionally one version) or flow, newest first, at most 1000. Each case holds the run's input, what the turn read (`context`), the judged output, and each item's judgments summed up: yes and no counts, the weight behind yes and behind all judgments (an unclassified judgment counts 1), and the reasons. `judgeClassIds` counts only judgments of those classes; `minJudgments` leaves out runs with fewer. Needs `admin` on the project.",
|
|
4723
|
+
"Publishes a `judged` eval suite version whose cases are copies of judged runs of one agent (optionally one version) or flow, newest first, at most 1000. Each case holds the run's input, what the turn read (`context`), the judged output, and each item's judgments summed up: yes and no counts, the weight behind yes and behind all judgments (an unclassified judgment counts 1), and the reasons. `judgeClassIds` counts only judgments of those classes; `minJudgments` leaves out runs with fewer; `segments` keeps only runs started in that segment path or below it. Needs `admin` on the project.",
|
|
4167
4724
|
tags: ['eval-suites'],
|
|
4168
4725
|
security: 'bearer',
|
|
4169
4726
|
parameters: [EvalSuiteIdPathParam, IdempotencyKeyParam],
|
|
@@ -4173,7 +4730,9 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
4173
4730
|
...CommonMutationErrors,
|
|
4174
4731
|
'400': ErrorResponse("Malformed body; or `projectId` isn't a project id (a UUID)."),
|
|
4175
4732
|
'403': ErrorResponse('`permission-denied`.'),
|
|
4176
|
-
'409': ErrorResponse(
|
|
4733
|
+
'409': ErrorResponse(
|
|
4734
|
+
"`eval-suite-already-registered`: that (id, version) is taken. Or `eval-suite-project-mismatch`: the suite belongs to another project than the body's `projectId` (suites never move).",
|
|
4735
|
+
),
|
|
4177
4736
|
'501': ErrorResponse('`test-sets-not-supported`: this deployment cannot build test sets.'),
|
|
4178
4737
|
'404': ErrorResponse(
|
|
4179
4738
|
"The body's `projectId` names no project of this tenant (`project-not-found`).",
|
|
@@ -4485,7 +5044,7 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
4485
5044
|
operationId: 'auth.providers.list',
|
|
4486
5045
|
summary: 'List identity providers configured for the tenant',
|
|
4487
5046
|
description:
|
|
4488
|
-
|
|
5047
|
+
"Returns the tenant's identity providers (OIDC, SAML, OAuth 2.0), each with `signIn` when the deployment sets it. Secrets appear only as REFERENCES (`clientSecretRef`, `spSigningKeyRef`…); a plaintext secret is never on the wire.",
|
|
4489
5048
|
tags: ['auth'],
|
|
4490
5049
|
security: 'bearer',
|
|
4491
5050
|
responses: {
|
|
@@ -4496,24 +5055,168 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
4496
5055
|
...CommonAuthErrors,
|
|
4497
5056
|
},
|
|
4498
5057
|
},
|
|
5058
|
+
{
|
|
5059
|
+
method: 'get',
|
|
5060
|
+
honoPath: '/v1/auth/sign-in-options',
|
|
5061
|
+
openapiPath: '/v1/auth/sign-in-options',
|
|
5062
|
+
operationId: 'auth.signInOptions',
|
|
5063
|
+
summary: 'How a person can sign in',
|
|
5064
|
+
description:
|
|
5065
|
+
'Public: nobody is signed in yet. With `email`, the ways in for that email\'s domain: the identity providers of the one tenant the domain is verified for (an unverified domain offers none), then any the deployment offers everyone it has added (`owner: deployment`, "Continue with Google"); without, an empty list: sign-in is email first, so nothing is offered before an email. `methods` says which ways in the deployment allows: identity providers, an API token (`POST /v1/auth/token-sign-in`), and an emailed sign-in link (`emailLink`, with a captcha site key when it needs one); `identityProviders` and `apiToken` both `false` when nobody can sign in to the console. Always mounted. The answer depends only on the domain: two people at the same domain get the same answer, whether or not either has an account. Rate-limited per client (`429 rate-limit-exceeded`, with `Retry-After`).',
|
|
5066
|
+
tags: ['auth'],
|
|
5067
|
+
security: 'public',
|
|
5068
|
+
parameters: [
|
|
5069
|
+
{
|
|
5070
|
+
name: 'email',
|
|
5071
|
+
in: 'query',
|
|
5072
|
+
required: false,
|
|
5073
|
+
schema: { type: 'string', minLength: 3 },
|
|
5074
|
+
description: 'The email the person typed; only its domain is used.',
|
|
5075
|
+
},
|
|
5076
|
+
],
|
|
5077
|
+
responses: {
|
|
5078
|
+
'200': { description: 'The ways to sign in (possibly none).', schema: ref('SignInOptions') },
|
|
5079
|
+
'400': ErrorResponse('`email` is not an email address.'),
|
|
5080
|
+
'429': ErrorResponse('Too many lookups from this client.'),
|
|
5081
|
+
},
|
|
5082
|
+
},
|
|
5083
|
+
{
|
|
5084
|
+
method: 'post',
|
|
5085
|
+
honoPath: '/v1/auth/token-sign-in',
|
|
5086
|
+
openapiPath: '/v1/auth/token-sign-in',
|
|
5087
|
+
operationId: 'auth.tokenSignIn',
|
|
5088
|
+
summary: 'Sign in to the console with an API token',
|
|
5089
|
+
description:
|
|
5090
|
+
"The API token in `Authorization` is exchanged once for a browser session in the session cookie (HttpOnly; the same as a sign-in with an identity provider), so the browser never keeps the token. Only a person's full key opens a session: a service account's key, or a narrowed one (a `member` role, or one project), is refused `403 token-sign-in-not-allowed`. The session ends after its lifetime, or when the key expires if sooner. `403 token-sign-in-off` when the deployment doesn't allow it (always mounted, so a console gets that answer); `400 token-sign-in-needs-an-api-token` when the request is already signed in by a session.",
|
|
5091
|
+
tags: ['auth'],
|
|
5092
|
+
security: 'bearer',
|
|
5093
|
+
responses: {
|
|
5094
|
+
'200': {
|
|
5095
|
+
description: 'Signed in: the session cookie is set.',
|
|
5096
|
+
schema: ref('TokenSignInResult'),
|
|
5097
|
+
},
|
|
5098
|
+
...CommonAuthErrors,
|
|
5099
|
+
'400': ErrorResponse(
|
|
5100
|
+
'Signed in by a session, not an API token (`token-sign-in-needs-an-api-token`).',
|
|
5101
|
+
),
|
|
5102
|
+
'403': ErrorResponse(
|
|
5103
|
+
"Not allowed here (`token-sign-in-off`), or not this key (`token-sign-in-not-allowed`): a service account's, or a narrowed one.",
|
|
5104
|
+
),
|
|
5105
|
+
'409': ErrorResponse(
|
|
5106
|
+
"A retry with the Idempotency-Key of a sign-in that succeeded: its session was in the cookie, which isn't kept (`idempotency-key-replay-withheld`). Sign in again without the key.",
|
|
5107
|
+
),
|
|
5108
|
+
},
|
|
5109
|
+
},
|
|
4499
5110
|
{
|
|
4500
5111
|
method: 'post',
|
|
4501
5112
|
honoPath: '/v1/auth/providers',
|
|
4502
5113
|
openapiPath: '/v1/auth/providers',
|
|
4503
5114
|
operationId: 'auth.providers.register',
|
|
4504
|
-
summary: 'Register
|
|
5115
|
+
summary: 'Register an identity provider (OIDC, SAML or OAuth 2.0)',
|
|
4505
5116
|
description:
|
|
4506
|
-
'Unique per tenant on `providerId`: re-registering a known provider returns `409 identity-provider-already-registered`
|
|
5117
|
+
'Unique per tenant on `providerId`: re-registering a known provider returns `409 identity-provider-already-registered`; change it with `PATCH /v1/auth/providers/{providerId}`, which keeps its sign-in URLs. Secrets are given by reference (`clientSecretRef`, `spSigningKeyRef`…); a `clientSecret` (or a raw key) is refused with `400 invalid-provider-config`. The deployment may check the configuration (OIDC discovery, SAML metadata): `422 identity-provider-invalid` says what failed. The answer carries the stored provider when the deployment returns it, with `signIn`: what to give the identity provider.',
|
|
4507
5118
|
tags: ['auth'],
|
|
4508
5119
|
security: 'bearer',
|
|
4509
5120
|
parameters: [IdempotencyKeyParam],
|
|
4510
|
-
requestBody: { required: true, schema: ref('
|
|
5121
|
+
requestBody: { required: true, schema: ref('RegisterIdentityProviderBody') },
|
|
4511
5122
|
responses: {
|
|
4512
5123
|
'201': {
|
|
4513
5124
|
description: 'Provider registered.',
|
|
4514
5125
|
schema: ref('RegisterIdentityProviderResult'),
|
|
4515
5126
|
},
|
|
4516
5127
|
...CommonMutationErrors,
|
|
5128
|
+
'422': ErrorResponse(
|
|
5129
|
+
'The deployment could not use the configuration (`identity-provider-invalid`).',
|
|
5130
|
+
),
|
|
5131
|
+
},
|
|
5132
|
+
},
|
|
5133
|
+
{
|
|
5134
|
+
method: 'get',
|
|
5135
|
+
honoPath: '/v1/auth/providers/:providerId',
|
|
5136
|
+
openapiPath: '/v1/auth/providers/{providerId}',
|
|
5137
|
+
operationId: 'auth.providers.get',
|
|
5138
|
+
summary: 'Get one identity provider',
|
|
5139
|
+
description:
|
|
5140
|
+
'The provider as stored, with `signIn` when the deployment sets it. Secrets appear only as references.',
|
|
5141
|
+
tags: ['auth'],
|
|
5142
|
+
security: 'bearer',
|
|
5143
|
+
parameters: [
|
|
5144
|
+
{
|
|
5145
|
+
name: 'providerId',
|
|
5146
|
+
in: 'path',
|
|
5147
|
+
required: true,
|
|
5148
|
+
schema: { type: 'string', minLength: 1 },
|
|
5149
|
+
},
|
|
5150
|
+
],
|
|
5151
|
+
responses: {
|
|
5152
|
+
'200': { description: 'The provider.', schema: ref('GetIdentityProviderResult') },
|
|
5153
|
+
...CommonAuthErrors,
|
|
5154
|
+
'404': ErrorResponse('No identity provider registered with that id under this tenant.'),
|
|
5155
|
+
},
|
|
5156
|
+
},
|
|
5157
|
+
{
|
|
5158
|
+
method: 'get',
|
|
5159
|
+
honoPath: '/v1/auth/providers/:providerId/sign-in',
|
|
5160
|
+
openapiPath: '/v1/auth/providers/{providerId}/sign-in',
|
|
5161
|
+
operationId: 'auth.providers.signIn',
|
|
5162
|
+
summary: 'What to give the identity provider, before or after registering',
|
|
5163
|
+
description:
|
|
5164
|
+
"The redirect URI (OIDC) or the ACS URL, entity ID and metadata URL (SAML) a provider under this `providerId` gets: the same before it's registered, after, and after an unregister and a new registration. So an admin sets up the identity provider's side first, then registers with what it gives back. `kind` is required until the provider is registered. Not mounted when the deployment can't say.",
|
|
5165
|
+
tags: ['auth'],
|
|
5166
|
+
security: 'bearer',
|
|
5167
|
+
parameters: [
|
|
5168
|
+
{
|
|
5169
|
+
name: 'providerId',
|
|
5170
|
+
in: 'path',
|
|
5171
|
+
required: true,
|
|
5172
|
+
schema: { type: 'string', minLength: 1 },
|
|
5173
|
+
},
|
|
5174
|
+
{
|
|
5175
|
+
name: 'kind',
|
|
5176
|
+
in: 'query',
|
|
5177
|
+
required: false,
|
|
5178
|
+
schema: { $ref: '#/components/schemas/IdentityProviderKind' },
|
|
5179
|
+
description: "The provider's kind; default: the registered provider's.",
|
|
5180
|
+
},
|
|
5181
|
+
],
|
|
5182
|
+
responses: {
|
|
5183
|
+
'200': {
|
|
5184
|
+
description: 'What to give the identity provider.',
|
|
5185
|
+
schema: ref('IdentityProviderSignInUrls'),
|
|
5186
|
+
},
|
|
5187
|
+
...CommonAuthErrors,
|
|
5188
|
+
'400': ErrorResponse(
|
|
5189
|
+
"`kind` missing for a provider that isn't registered, or a kind this deployment doesn't sign in with (`bad-input`).",
|
|
5190
|
+
),
|
|
5191
|
+
},
|
|
5192
|
+
},
|
|
5193
|
+
{
|
|
5194
|
+
method: 'patch',
|
|
5195
|
+
honoPath: '/v1/auth/providers/:providerId',
|
|
5196
|
+
openapiPath: '/v1/auth/providers/{providerId}',
|
|
5197
|
+
operationId: 'auth.providers.update',
|
|
5198
|
+
summary: 'Change an identity provider, keeping its sign-in URLs',
|
|
5199
|
+
description:
|
|
5200
|
+
"Merges the changes into the stored provider and checks the result as a registration is (`400 invalid-provider-config`; `422 identity-provider-invalid` when the deployment can't use it). The provider keeps its `signIn`, so nothing changes on the identity provider's side. Not mounted when the deployment can't update providers.",
|
|
5201
|
+
tags: ['auth'],
|
|
5202
|
+
security: 'bearer',
|
|
5203
|
+
parameters: [
|
|
5204
|
+
{
|
|
5205
|
+
name: 'providerId',
|
|
5206
|
+
in: 'path',
|
|
5207
|
+
required: true,
|
|
5208
|
+
schema: { type: 'string', minLength: 1 },
|
|
5209
|
+
},
|
|
5210
|
+
IdempotencyKeyParam,
|
|
5211
|
+
],
|
|
5212
|
+
requestBody: { required: true, schema: ref('UpdateIdentityProviderBody') },
|
|
5213
|
+
responses: {
|
|
5214
|
+
'200': { description: 'Updated.', schema: ref('UpdateIdentityProviderResult') },
|
|
5215
|
+
...CommonMutationErrors,
|
|
5216
|
+
'404': ErrorResponse('No identity provider registered with that id under this tenant.'),
|
|
5217
|
+
'422': ErrorResponse(
|
|
5218
|
+
'The deployment could not use the configuration (`identity-provider-invalid`).',
|
|
5219
|
+
),
|
|
4517
5220
|
},
|
|
4518
5221
|
},
|
|
4519
5222
|
{
|
|
@@ -4603,14 +5306,19 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
4603
5306
|
operationId: 'auth.refresh',
|
|
4604
5307
|
summary: 'Refresh the current session token',
|
|
4605
5308
|
description:
|
|
4606
|
-
'Requires a session token (`kgi_sk_*`); bearer tokens are managed via `/v1/tokens`. When the deployment wired a `refreshToken` callback and the provider issued a refresh token, provider tokens rotate too; otherwise only the framework session token rotates. OAuth 2.1 BCP refresh-token rotation: the OLD session token is invalidated (marked rotated) — reusing it after refresh returns `401 refresh-token-invalid` so compliant clients can retry with the fresh token instead of prompting a re-auth.',
|
|
5309
|
+
'Requires a session token (`kgi_sk_*`); bearer tokens are managed via `/v1/tokens`. When the deployment wired a `refreshToken` callback and the provider issued a refresh token, provider tokens rotate too; otherwise only the framework session token rotates. OAuth 2.1 BCP refresh-token rotation: the OLD session token is invalidated (marked rotated) — reusing it after refresh returns `401 refresh-token-invalid` so compliant clients can retry with the fresh token instead of prompting a re-auth. A browser session (the session cookie) is not refreshed: `400 cookie-session-not-refreshable`, so a new token never reaches page scripts; it ends at its TTL.',
|
|
4607
5310
|
tags: ['auth'],
|
|
4608
5311
|
security: 'bearer',
|
|
4609
5312
|
parameters: [IdempotencyKeyParam],
|
|
4610
5313
|
responses: {
|
|
4611
5314
|
'200': { description: 'New session token.', schema: ref('RefreshResult') },
|
|
4612
5315
|
...CommonMutationErrors,
|
|
4613
|
-
'
|
|
5316
|
+
'409': ErrorResponse(
|
|
5317
|
+
"Idempotency-Key reused with a different body (`idempotency-key-body-mismatch`), or a retry of a request that succeeded: its answer carried a secret, which isn't kept (`idempotency-key-replay-withheld`, with its `status` and `at`).",
|
|
5318
|
+
),
|
|
5319
|
+
'400': ErrorResponse(
|
|
5320
|
+
'Caller presented a bearer token (refresh is session-only), or a browser session (cookie).',
|
|
5321
|
+
),
|
|
4614
5322
|
'404': ErrorResponse('Session no longer exists.'),
|
|
4615
5323
|
'422': ErrorResponse('Refresh with the provider failed.'),
|
|
4616
5324
|
},
|
|
@@ -4622,7 +5330,7 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
4622
5330
|
operationId: 'auth.logout',
|
|
4623
5331
|
summary: 'Revoke the current session',
|
|
4624
5332
|
description:
|
|
4625
|
-
'Requires a session token (`kgi_sk_*`); bearer tokens are managed via `/v1/tokens`. Idempotent — revoking an already-revoked session returns `{ revoked: false }`.',
|
|
5333
|
+
'Requires a session token (`kgi_sk_*`); bearer tokens are managed via `/v1/tokens`. Idempotent — revoking an already-revoked session returns `{ revoked: false }`. A browser session (the session cookie) also gets its cookie cleared (`Set-Cookie` with `Max-Age=0`).',
|
|
4626
5334
|
tags: ['auth'],
|
|
4627
5335
|
security: 'bearer',
|
|
4628
5336
|
parameters: [IdempotencyKeyParam],
|
|
@@ -4640,7 +5348,7 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
4640
5348
|
operationId: 'identity.users.list',
|
|
4641
5349
|
summary: 'List users in the tenant',
|
|
4642
5350
|
description:
|
|
4643
|
-
'Cursor-paginated list of tenant users (sort order is binding-defined). Optional `?query=` is a prefix match on `displayName` — the natural filter shape for a "search users" surface. `primaryEmail` may be redacted per tenant policy.',
|
|
5351
|
+
'Cursor-paginated list of tenant users (sort order is binding-defined), for tenant admins only. Optional `?query=` is a prefix match on `displayName` — the natural filter shape for a "search users" surface. `primaryEmail` may be redacted per tenant policy. Anyone else adds a person to a project by their email or id (`POST /v1/projects/{projectId}/memberships`).',
|
|
4644
5352
|
tags: ['identity'],
|
|
4645
5353
|
security: 'bearer',
|
|
4646
5354
|
parameters: [
|
|
@@ -4653,10 +5361,39 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
4653
5361
|
description: 'Prefix match on `displayName`.',
|
|
4654
5362
|
schema: { type: 'string' },
|
|
4655
5363
|
},
|
|
5364
|
+
{
|
|
5365
|
+
name: 'includeUnregistered',
|
|
5366
|
+
in: 'query',
|
|
5367
|
+
required: false,
|
|
5368
|
+
description: 'With `true`, people who were removed (`unregisteredAt`) too.',
|
|
5369
|
+
schema: { type: 'boolean' },
|
|
5370
|
+
},
|
|
4656
5371
|
],
|
|
4657
5372
|
responses: {
|
|
4658
5373
|
'200': { description: 'Page of users.', schema: ref('UserCollectionPage') },
|
|
4659
5374
|
...CommonAuthErrors,
|
|
5375
|
+
'403': ErrorResponse('Not a tenant admin.'),
|
|
5376
|
+
},
|
|
5377
|
+
},
|
|
5378
|
+
{
|
|
5379
|
+
method: 'post',
|
|
5380
|
+
honoPath: '/v1/identity/users',
|
|
5381
|
+
openapiPath: '/v1/identity/users',
|
|
5382
|
+
operationId: 'identity.users.create',
|
|
5383
|
+
summary: 'Add a person',
|
|
5384
|
+
description:
|
|
5385
|
+
"Adds a person to the tenant as a tenant member, written before it answers: they can read the tenant's settings (providers, policies, adapters, signing keys, deployments), not its projects. Give them a role to work (project or team membership, or tenant admin), then mint their first API key at `POST /v1/tokens` with `for`. Tenant admins only. Mounted when the identity directory can add people.",
|
|
5386
|
+
tags: ['identity'],
|
|
5387
|
+
security: 'bearer',
|
|
5388
|
+
parameters: [IdempotencyKeyParam],
|
|
5389
|
+
requestBody: { required: true, schema: ref('CreateUserBody') },
|
|
5390
|
+
responses: {
|
|
5391
|
+
'201': { description: 'The new person.', schema: ref('UserRecord') },
|
|
5392
|
+
...CommonMutationErrors,
|
|
5393
|
+
'403': ErrorResponse('Not a tenant admin.'),
|
|
5394
|
+
'409': ErrorResponse(
|
|
5395
|
+
'Another person of the tenant has the email (`identity-user-email-taken`), or an idempotency conflict.',
|
|
5396
|
+
),
|
|
4660
5397
|
},
|
|
4661
5398
|
},
|
|
4662
5399
|
{
|
|
@@ -4665,6 +5402,7 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
4665
5402
|
openapiPath: '/v1/identity/users/{userId}',
|
|
4666
5403
|
operationId: 'identity.users.get',
|
|
4667
5404
|
summary: 'Get a user by id',
|
|
5405
|
+
description: 'A tenant admin, or the person themselves.',
|
|
4668
5406
|
tags: ['identity'],
|
|
4669
5407
|
security: 'bearer',
|
|
4670
5408
|
parameters: [
|
|
@@ -4673,6 +5411,7 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
4673
5411
|
responses: {
|
|
4674
5412
|
'200': { description: 'User record.', schema: ref('UserRecord') },
|
|
4675
5413
|
...CommonAuthErrors,
|
|
5414
|
+
'403': ErrorResponse("Someone else's record, and not a tenant admin."),
|
|
4676
5415
|
'404': ErrorResponse('No user with that id under this tenant.'),
|
|
4677
5416
|
},
|
|
4678
5417
|
},
|
|
@@ -4683,7 +5422,7 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
4683
5422
|
operationId: 'identity.users.listSessions',
|
|
4684
5423
|
summary: 'List active sessions for a user',
|
|
4685
5424
|
description:
|
|
4686
|
-
'Returns the wire-safe `IdentitySessionSummary` shape — provider access-token + refresh-token never cross the wire, even to admins. Unknown user id returns an empty list (call `GET /v1/identity/users/:userId` first to distinguish "no sessions" from "no user").',
|
|
5425
|
+
'A tenant admin, or the person themselves. Returns the wire-safe `IdentitySessionSummary` shape — provider access-token + refresh-token never cross the wire, even to admins. Unknown user id returns an empty list (call `GET /v1/identity/users/:userId` first to distinguish "no sessions" from "no user").',
|
|
4687
5426
|
tags: ['identity'],
|
|
4688
5427
|
security: 'bearer',
|
|
4689
5428
|
parameters: [
|
|
@@ -4692,6 +5431,34 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
4692
5431
|
responses: {
|
|
4693
5432
|
'200': { description: 'Page of sessions.', schema: ref('IdentitySessionCollectionPage') },
|
|
4694
5433
|
...CommonAuthErrors,
|
|
5434
|
+
'403': ErrorResponse("Someone else's sessions, and not a tenant admin."),
|
|
5435
|
+
},
|
|
5436
|
+
},
|
|
5437
|
+
{
|
|
5438
|
+
method: 'post',
|
|
5439
|
+
honoPath: '/v1/identity/users/:userId/unregister',
|
|
5440
|
+
openapiPath: '/v1/identity/users/{userId}/unregister',
|
|
5441
|
+
operationId: 'identity.users.unregister',
|
|
5442
|
+
summary: 'Remove a person',
|
|
5443
|
+
description:
|
|
5444
|
+
"Removes a person from the tenant, in one step: they're marked removed (`unregisteredAt`; their record stays, so their history still says who they were), every API key and session of theirs is revoked, and every grant and membership they hold is taken away, all before it answers. Their keys get `401` at once. Their email is free again: adding it makes a new person. Removing someone already removed changes nothing. Refused for yourself and the deployment's seed user (`identity-user-unregister-refused`), and for the only tenant admin (`last-tenant-admin`). Tenant admins only. Mounted when the identity directory can remove people.",
|
|
5445
|
+
tags: ['identity'],
|
|
5446
|
+
security: 'bearer',
|
|
5447
|
+
parameters: [
|
|
5448
|
+
{ name: 'userId', in: 'path', required: true, schema: { type: 'string', minLength: 1 } },
|
|
5449
|
+
IdempotencyKeyParam,
|
|
5450
|
+
],
|
|
5451
|
+
responses: {
|
|
5452
|
+
'200': {
|
|
5453
|
+
description: 'The removed person, and what removing them took away.',
|
|
5454
|
+
schema: ref('UnregisterUserResult'),
|
|
5455
|
+
},
|
|
5456
|
+
...CommonMutationErrors,
|
|
5457
|
+
'403': ErrorResponse('Not a tenant admin.'),
|
|
5458
|
+
'404': ErrorResponse('No user with that id under this tenant (`identity-user-not-found`).'),
|
|
5459
|
+
'409': ErrorResponse(
|
|
5460
|
+
'Yourself or the seed user (`identity-user-unregister-refused`, `details.reason`), the only tenant admin (`last-tenant-admin`), or an idempotency conflict.',
|
|
5461
|
+
),
|
|
4695
5462
|
},
|
|
4696
5463
|
},
|
|
4697
5464
|
{
|
|
@@ -4701,7 +5468,7 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
4701
5468
|
operationId: 'identity.users.revokeSessions',
|
|
4702
5469
|
summary: 'Revoke every active session for a user',
|
|
4703
5470
|
description:
|
|
4704
|
-
'
|
|
5471
|
+
"A tenant admin revokes anyone's sessions; anyone else only their own. Idempotent. Under the hood, deployments typically delegate to `SessionStoreBinding.revokeAllForUser`. Returns `{ revokedCount: 0 }` when the user was already fully signed out.",
|
|
4705
5472
|
tags: ['identity'],
|
|
4706
5473
|
security: 'bearer',
|
|
4707
5474
|
parameters: [
|
|
@@ -4711,9 +5478,83 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
4711
5478
|
responses: {
|
|
4712
5479
|
'200': { description: 'Revocation outcome.', schema: ref('RevokeSessionsResult') },
|
|
4713
5480
|
...CommonMutationErrors,
|
|
5481
|
+
'403': ErrorResponse("Another person's sessions, and not a tenant admin."),
|
|
4714
5482
|
'500': ErrorResponse('Session revocation failed inside the caller-plugged binding.'),
|
|
4715
5483
|
},
|
|
4716
5484
|
},
|
|
5485
|
+
{
|
|
5486
|
+
method: 'get',
|
|
5487
|
+
honoPath: '/v1/identity/users/:userId/grants',
|
|
5488
|
+
openapiPath: '/v1/identity/users/{userId}/grants',
|
|
5489
|
+
operationId: 'identity.users.grants',
|
|
5490
|
+
summary: "Read a person's grants",
|
|
5491
|
+
description:
|
|
5492
|
+
"What the person may do, as granted directly: tenant admin, project and team roles, the reviewer roster. A tenant admin reads anyone's; anyone else only their own.",
|
|
5493
|
+
tags: ['identity'],
|
|
5494
|
+
security: 'bearer',
|
|
5495
|
+
parameters: [
|
|
5496
|
+
{ name: 'userId', in: 'path', required: true, schema: { type: 'string', minLength: 1 } },
|
|
5497
|
+
],
|
|
5498
|
+
responses: {
|
|
5499
|
+
'200': { description: "The person's grants.", schema: ref('PersonGrants') },
|
|
5500
|
+
...CommonAuthErrors,
|
|
5501
|
+
'403': ErrorResponse("Another person's grants, and not a tenant admin."),
|
|
5502
|
+
'404': ErrorResponse('No user with that id under this tenant (`identity-user-not-found`).'),
|
|
5503
|
+
'501': ErrorResponse('The runtime has no authorization store (`person-grants-unsupported`).'),
|
|
5504
|
+
},
|
|
5505
|
+
},
|
|
5506
|
+
{
|
|
5507
|
+
method: 'post',
|
|
5508
|
+
honoPath: '/v1/identity/users/:userId/grant',
|
|
5509
|
+
openapiPath: '/v1/identity/users/{userId}/grant',
|
|
5510
|
+
operationId: 'identity.users.grant',
|
|
5511
|
+
summary: 'Make a person a tenant admin',
|
|
5512
|
+
description:
|
|
5513
|
+
"Written before the call answers, so the person's next request holds it. A no-op when held. Tenant admins only.",
|
|
5514
|
+
tags: ['identity'],
|
|
5515
|
+
security: 'bearer',
|
|
5516
|
+
parameters: [
|
|
5517
|
+
{ name: 'userId', in: 'path', required: true, schema: { type: 'string', minLength: 1 } },
|
|
5518
|
+
IdempotencyKeyParam,
|
|
5519
|
+
],
|
|
5520
|
+
requestBody: { required: true, schema: ref('PersonGrantBody') },
|
|
5521
|
+
responses: {
|
|
5522
|
+
'200': { description: "The person's grants, after.", schema: ref('PersonGrants') },
|
|
5523
|
+
...CommonMutationErrors,
|
|
5524
|
+
'403': ErrorResponse('Not a tenant admin.'),
|
|
5525
|
+
'404': ErrorResponse('No user with that id under this tenant (`identity-user-not-found`).'),
|
|
5526
|
+
'409': ErrorResponse(
|
|
5527
|
+
'The person was removed from the tenant (`identity-user-unregistered`), or an idempotency conflict.',
|
|
5528
|
+
),
|
|
5529
|
+
'501': ErrorResponse('The runtime has no authorization store (`person-grants-unsupported`).'),
|
|
5530
|
+
},
|
|
5531
|
+
},
|
|
5532
|
+
{
|
|
5533
|
+
method: 'post',
|
|
5534
|
+
honoPath: '/v1/identity/users/:userId/ungrant',
|
|
5535
|
+
openapiPath: '/v1/identity/users/{userId}/ungrant',
|
|
5536
|
+
operationId: 'identity.users.ungrant',
|
|
5537
|
+
summary: 'Remove tenant admin from a person',
|
|
5538
|
+
description:
|
|
5539
|
+
'A no-op when not held. Refused for the only person who is a tenant admin (`last-tenant-admin`: make someone else one first), and for the seed user, whom the runtime makes tenant admin at every boot (`seed-user-admin`: unset `KINDGI_SEED_USER_ID` and restart it first). Tenant admins only.',
|
|
5540
|
+
tags: ['identity'],
|
|
5541
|
+
security: 'bearer',
|
|
5542
|
+
parameters: [
|
|
5543
|
+
{ name: 'userId', in: 'path', required: true, schema: { type: 'string', minLength: 1 } },
|
|
5544
|
+
IdempotencyKeyParam,
|
|
5545
|
+
],
|
|
5546
|
+
requestBody: { required: true, schema: ref('PersonGrantBody') },
|
|
5547
|
+
responses: {
|
|
5548
|
+
'200': { description: "The person's grants, after.", schema: ref('PersonGrants') },
|
|
5549
|
+
...CommonMutationErrors,
|
|
5550
|
+
'403': ErrorResponse('Not a tenant admin.'),
|
|
5551
|
+
'404': ErrorResponse('No user with that id under this tenant (`identity-user-not-found`).'),
|
|
5552
|
+
'409': ErrorResponse(
|
|
5553
|
+
'The only person who is a tenant admin (`last-tenant-admin`), the seed user (`seed-user-admin`), or an idempotency conflict.',
|
|
5554
|
+
),
|
|
5555
|
+
'501': ErrorResponse('The runtime has no authorization store (`person-grants-unsupported`).'),
|
|
5556
|
+
},
|
|
5557
|
+
},
|
|
4717
5558
|
{
|
|
4718
5559
|
method: 'get',
|
|
4719
5560
|
honoPath: '/v1/identity/whoami',
|
|
@@ -4751,7 +5592,7 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
4751
5592
|
},
|
|
4752
5593
|
...CommonMutationErrors,
|
|
4753
5594
|
'409': ErrorResponse(
|
|
4754
|
-
"Idempotency-Key was reused with a different body, or resource-state conflict. Or `registry-read-only`: this registry takes no writes (under `kindgi dev`, the pack's files are the source); the message says what to do instead.",
|
|
5595
|
+
"Idempotency-Key was reused with a different body, or resource-state conflict. Or `tool-project-mismatch`, `agent-project-mismatch` or `flow-project-mismatch`: one of the image's tools, agents or flows belongs to another project (`details.primitive`, `details.id`; the message doesn't name the project); nothing was deployed, even when it was unchanged. Or `registry-read-only`: this registry takes no writes (under `kindgi dev`, the pack's files are the source); the message says what to do instead.",
|
|
4755
5596
|
),
|
|
4756
5597
|
'400': ErrorResponse(
|
|
4757
5598
|
'Signature invalid, image unverifiable, or deployment-validation-failed with per-primitive `details[]`.',
|
|
@@ -4951,11 +5792,11 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
4951
5792
|
operationId: 'compliance.evidence.export',
|
|
4952
5793
|
summary: 'Export a signed compliance-evidence bundle',
|
|
4953
5794
|
description:
|
|
4954
|
-
"
|
|
5795
|
+
"Signs the evidence the filter matches (exportable kinds only) with the deployment's export key, and records the export (an `export-signed` audit event). The same envelope as the other signed exports; check `publicKey` against `GET /v1/export-signing-keys`. A deployment with no export key answers `404 signing-not-configured`.",
|
|
4955
5796
|
tags: ['compliance'],
|
|
4956
5797
|
security: 'bearer',
|
|
4957
5798
|
parameters: [IdempotencyKeyParam],
|
|
4958
|
-
requestBody: { required:
|
|
5799
|
+
requestBody: { required: false, schema: ref('ExportComplianceEvidenceBody') },
|
|
4959
5800
|
responses: {
|
|
4960
5801
|
'200': {
|
|
4961
5802
|
description: 'Signed evidence bundle.',
|
|
@@ -5476,12 +6317,13 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
5476
6317
|
operationId: 'projects.getDefault',
|
|
5477
6318
|
summary: "Fetch the tenant's Default project",
|
|
5478
6319
|
description:
|
|
5479
|
-
'Returns the row where `Project.isDefault = true` (exactly one per tenant). Returns 404 `project-not-found` when no Default has been provisioned.',
|
|
6320
|
+
'Returns the row where `Project.isDefault = true` (exactly one per tenant), to a caller who can read it, as `GET /v1/projects/{projectId}` checks. Returns 404 `project-not-found` when no Default has been provisioned.',
|
|
5480
6321
|
tags: ['projects'],
|
|
5481
6322
|
security: 'bearer',
|
|
5482
6323
|
responses: {
|
|
5483
6324
|
'200': { description: 'Default project.', schema: ref('Project') },
|
|
5484
6325
|
...CommonAuthErrors,
|
|
6326
|
+
'403': ErrorResponse("The caller can't read the Default project."),
|
|
5485
6327
|
'404': ErrorResponse('Tenant has no Default project.'),
|
|
5486
6328
|
},
|
|
5487
6329
|
},
|
|
@@ -5651,7 +6493,7 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
5651
6493
|
operationId: 'projects.memberships.add',
|
|
5652
6494
|
summary: 'Add a user directly to a project',
|
|
5653
6495
|
description:
|
|
5654
|
-
'Idempotent on `(projectId, userId)` — re-adding an existing member with a different role does NOT overwrite; use PATCH for role changes.',
|
|
6496
|
+
'Names the person by exactly one of `userId` and `email` (matched as the runtime matches emails when it adds a person); someone who is not a person of this tenant, or was removed from it, is refused with 404 `identity-user-not-found`. Idempotent on `(projectId, userId)` — re-adding an existing member with a different role does NOT overwrite; use PATCH for role changes.',
|
|
5655
6497
|
tags: ['projects'],
|
|
5656
6498
|
security: 'bearer',
|
|
5657
6499
|
parameters: [
|
|
@@ -5671,7 +6513,9 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
5671
6513
|
schema: ref('AddProjectMembershipResult'),
|
|
5672
6514
|
},
|
|
5673
6515
|
...CommonMutationErrors,
|
|
5674
|
-
'404': ErrorResponse(
|
|
6516
|
+
'404': ErrorResponse(
|
|
6517
|
+
'No project with that id under this tenant (`project-not-found`), or the person named is not a member of this tenant (`identity-user-not-found`).',
|
|
6518
|
+
),
|
|
5675
6519
|
},
|
|
5676
6520
|
},
|
|
5677
6521
|
{
|
|
@@ -5876,7 +6720,7 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
5876
6720
|
operationId: 'env.put',
|
|
5877
6721
|
summary: 'Upsert an env entry',
|
|
5878
6722
|
description:
|
|
5879
|
-
|
|
6723
|
+
"Requires the `env:write` capability. Every write bumps `revision`; optional `ifRevision` guards against concurrent updates (409 `env-write-conflict`). Env values aren't secret: they're recorded with each run that uses them. A credential goes in `/v1/secrets`.",
|
|
5880
6724
|
tags: ['env'],
|
|
5881
6725
|
security: 'bearer',
|
|
5882
6726
|
parameters: [
|
|
@@ -6229,7 +7073,16 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
6229
7073
|
summary: 'Fetch a cron schedule',
|
|
6230
7074
|
tags: ['schedules'],
|
|
6231
7075
|
security: 'bearer',
|
|
6232
|
-
parameters: [
|
|
7076
|
+
parameters: [
|
|
7077
|
+
TriggerIdPathParam,
|
|
7078
|
+
{
|
|
7079
|
+
name: 'upcoming',
|
|
7080
|
+
in: 'query',
|
|
7081
|
+
required: false,
|
|
7082
|
+
description: 'Include the next N occurrences (`upcoming`), 1 to 20.',
|
|
7083
|
+
schema: { type: 'integer', minimum: 1, maximum: 20 },
|
|
7084
|
+
},
|
|
7085
|
+
],
|
|
6233
7086
|
responses: {
|
|
6234
7087
|
'200': { description: 'Schedule record.', schema: ref('ScheduleRecord') },
|
|
6235
7088
|
...CommonAuthErrors,
|
|
@@ -6304,6 +7157,67 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
6304
7157
|
...CommonMutationErrors,
|
|
6305
7158
|
},
|
|
6306
7159
|
},
|
|
7160
|
+
{
|
|
7161
|
+
method: 'get',
|
|
7162
|
+
honoPath: '/v1/schedules/:triggerId/fires',
|
|
7163
|
+
openapiPath: '/v1/schedules/{triggerId}/fires',
|
|
7164
|
+
operationId: 'schedules.fires',
|
|
7165
|
+
summary: "A schedule's fire history",
|
|
7166
|
+
description:
|
|
7167
|
+
'Newest first: each occurrence (and `run-now`) the schedule fired for, and what came of it: the run it started, or why it was skipped, refused or failed.',
|
|
7168
|
+
tags: ['schedules'],
|
|
7169
|
+
security: 'bearer',
|
|
7170
|
+
parameters: [TriggerIdPathParam, LimitQueryParam, CursorQueryParam],
|
|
7171
|
+
responses: {
|
|
7172
|
+
'200': { description: 'Page of fires.', schema: ref('ScheduleFirePage') },
|
|
7173
|
+
...CommonAuthErrors,
|
|
7174
|
+
'404': ErrorResponse('No cron trigger with that id.'),
|
|
7175
|
+
'501': ErrorResponse(
|
|
7176
|
+
'`trigger-operation-unsupported`: this deployment keeps no fire history.',
|
|
7177
|
+
),
|
|
7178
|
+
},
|
|
7179
|
+
},
|
|
7180
|
+
{
|
|
7181
|
+
method: 'post',
|
|
7182
|
+
honoPath: '/v1/schedules/:triggerId/run-now',
|
|
7183
|
+
openapiPath: '/v1/schedules/{triggerId}/run-now',
|
|
7184
|
+
operationId: 'schedules.runNow',
|
|
7185
|
+
summary: 'Run a schedule now',
|
|
7186
|
+
description:
|
|
7187
|
+
"One fire outside the schedule (`manual: true` in its history), starting one run as the schedule's owner. The schedule's next occurrence is unchanged.",
|
|
7188
|
+
tags: ['schedules'],
|
|
7189
|
+
security: 'bearer',
|
|
7190
|
+
parameters: [TriggerIdPathParam, IdempotencyKeyParam],
|
|
7191
|
+
responses: {
|
|
7192
|
+
'202': {
|
|
7193
|
+
description: 'The fire; its run starts in the background.',
|
|
7194
|
+
schema: ref('ScheduleFire'),
|
|
7195
|
+
},
|
|
7196
|
+
...CommonMutationErrors,
|
|
7197
|
+
'404': ErrorResponse('No cron trigger with that id.'),
|
|
7198
|
+
'501': ErrorResponse('`trigger-operation-unsupported`: this deployment has no run-now.'),
|
|
7199
|
+
},
|
|
7200
|
+
},
|
|
7201
|
+
{
|
|
7202
|
+
method: 'post',
|
|
7203
|
+
honoPath: '/v1/schedules/:triggerId/owner',
|
|
7204
|
+
openapiPath: '/v1/schedules/{triggerId}/owner',
|
|
7205
|
+
operationId: 'schedules.takeOwnership',
|
|
7206
|
+
summary: 'Take over a schedule',
|
|
7207
|
+
description:
|
|
7208
|
+
"The caller becomes the schedule's owner, so its runs act as the caller from the next fire. Needs `admin` on the schedule's project and `execute` on what it runs. For a schedule whose owner left or lost access.",
|
|
7209
|
+
tags: ['schedules'],
|
|
7210
|
+
security: 'bearer',
|
|
7211
|
+
parameters: [TriggerIdPathParam, IdempotencyKeyParam],
|
|
7212
|
+
responses: {
|
|
7213
|
+
'200': { description: 'The schedule, with its new owner.', schema: ref('ScheduleRecord') },
|
|
7214
|
+
...CommonMutationErrors,
|
|
7215
|
+
'404': ErrorResponse('No cron trigger with that id.'),
|
|
7216
|
+
'501': ErrorResponse(
|
|
7217
|
+
"`trigger-operation-unsupported`: this deployment can't change a schedule's owner.",
|
|
7218
|
+
),
|
|
7219
|
+
},
|
|
7220
|
+
},
|
|
6307
7221
|
|
|
6308
7222
|
// ---------- event-triggers (trigger surface) ----------
|
|
6309
7223
|
{
|
|
@@ -6556,12 +7470,15 @@ export const OPERATIONS: readonly OperationSpec[] = [
|
|
|
6556
7470
|
operationId: 'webhookEndpoints.generateSecret',
|
|
6557
7471
|
summary: 'Generate a webhook signing secret',
|
|
6558
7472
|
description:
|
|
6559
|
-
'Returns a new strong secret (`whsec_` + base64 of 32 random bytes). Nothing is stored: put it in your secrets, then register the endpoint with its name.',
|
|
7473
|
+
'Returns a new strong secret (`whsec_` + base64 of 32 random bytes). Nothing is stored: put it in your secrets, then register the endpoint with its name. Sent with an `Idempotency-Key`, a retry gets `409 idempotency-key-replay-withheld`, not the secret again.',
|
|
6560
7474
|
tags: ['webhook-endpoints'],
|
|
6561
7475
|
security: 'bearer',
|
|
6562
7476
|
responses: {
|
|
6563
7477
|
'200': { description: 'A new secret.', schema: ref('GeneratedWebhookSecret') },
|
|
6564
7478
|
...CommonAuthErrors,
|
|
7479
|
+
'409': ErrorResponse(
|
|
7480
|
+
"A retry with the Idempotency-Key of a request that succeeded: the secret isn't kept (`idempotency-key-replay-withheld`).",
|
|
7481
|
+
),
|
|
6565
7482
|
},
|
|
6566
7483
|
},
|
|
6567
7484
|
{
|