@flowdular/sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.ai/agents/README.md +27 -0
- package/.ai/agents/module-executor.md +36 -0
- package/.ai/agents/reviewer.md +23 -0
- package/.ai/agents/sandbox/agentic-engineer.md +31 -0
- package/.ai/agents/sandbox/backend-engineer.md +36 -0
- package/.ai/agents/sandbox/business-manager.md +23 -0
- package/.ai/agents/sandbox/frontend-engineer.md +27 -0
- package/.ai/agents/sandbox/ux-designer.md +23 -0
- package/.ai/agents/spec-author.md +29 -0
- package/.ai/blueprints/add-migration/README.md +5 -0
- package/.ai/blueprints/add-migration/allowed-paths.yaml +23 -0
- package/.ai/blueprints/add-migration/blueprint.json +14 -0
- package/.ai/blueprints/add-migration/examples/invalid/input-destructive.json +6 -0
- package/.ai/blueprints/add-migration/examples/invalid/plan-unnumbered-file.json +9 -0
- package/.ai/blueprints/add-migration/examples/valid/input.json +6 -0
- package/.ai/blueprints/add-migration/examples/valid/plan.json +9 -0
- package/.ai/blueprints/add-migration/gates.yaml +30 -0
- package/.ai/blueprints/add-migration/input.schema.json +23 -0
- package/.ai/blueprints/add-migration/plan.schema.json +54 -0
- package/.ai/blueprints/add-migration/required-files.yaml +18 -0
- package/.ai/blueprints/add-migration/spec-requirements.yaml +13 -0
- package/.ai/blueprints/add-migration/steps.yaml +62 -0
- package/.ai/blueprints/author-spec/README.md +5 -0
- package/.ai/blueprints/author-spec/allowed-paths.yaml +7 -0
- package/.ai/blueprints/author-spec/blueprint.json +14 -0
- package/.ai/blueprints/author-spec/examples/invalid/input-missing-outcome.json +5 -0
- package/.ai/blueprints/author-spec/examples/valid/input.json +6 -0
- package/.ai/blueprints/author-spec/gates.yaml +13 -0
- package/.ai/blueprints/author-spec/input.schema.json +20 -0
- package/.ai/blueprints/author-spec/plan.schema.json +14 -0
- package/.ai/blueprints/author-spec/required-files.yaml +6 -0
- package/.ai/blueprints/author-spec/spec-requirements.yaml +35 -0
- package/.ai/blueprints/author-spec/steps.yaml +28 -0
- package/.ai/blueprints/author-spec/templates/module.yaml +45 -0
- package/.ai/blueprints/bug-fix/README.md +5 -0
- package/.ai/blueprints/bug-fix/allowed-paths.yaml +29 -0
- package/.ai/blueprints/bug-fix/blueprint.json +14 -0
- package/.ai/blueprints/bug-fix/examples/invalid/input-no-symptom.json +4 -0
- package/.ai/blueprints/bug-fix/examples/invalid/plan-no-test.json +8 -0
- package/.ai/blueprints/bug-fix/examples/valid/input.json +6 -0
- package/.ai/blueprints/bug-fix/examples/valid/plan.json +8 -0
- package/.ai/blueprints/bug-fix/gates.yaml +30 -0
- package/.ai/blueprints/bug-fix/input.schema.json +25 -0
- package/.ai/blueprints/bug-fix/plan.schema.json +53 -0
- package/.ai/blueprints/bug-fix/required-files.yaml +7 -0
- package/.ai/blueprints/bug-fix/spec-requirements.yaml +7 -0
- package/.ai/blueprints/bug-fix/steps.yaml +51 -0
- package/.ai/blueprints/core-extend/README.md +5 -0
- package/.ai/blueprints/core-extend/allowed-paths.yaml +49 -0
- package/.ai/blueprints/core-extend/blueprint.json +14 -0
- package/.ai/blueprints/core-extend/examples/invalid/input-unknown-package.json +5 -0
- package/.ai/blueprints/core-extend/examples/invalid/plan-missing-gates.json +7 -0
- package/.ai/blueprints/core-extend/examples/valid/input.json +6 -0
- package/.ai/blueprints/core-extend/examples/valid/plan.json +10 -0
- package/.ai/blueprints/core-extend/gates.yaml +16 -0
- package/.ai/blueprints/core-extend/input.schema.json +54 -0
- package/.ai/blueprints/core-extend/plan.schema.json +39 -0
- package/.ai/blueprints/core-extend/required-files.yaml +36 -0
- package/.ai/blueprints/core-extend/spec-requirements.yaml +17 -0
- package/.ai/blueprints/core-extend/steps.yaml +54 -0
- package/.ai/blueprints/edit-module/README.md +9 -0
- package/.ai/blueprints/edit-module/allowed-paths.yaml +27 -0
- package/.ai/blueprints/edit-module/blueprint.json +20 -0
- package/.ai/blueprints/edit-module/examples/invalid/input-unknown-change.json +5 -0
- package/.ai/blueprints/edit-module/examples/invalid/plan-touches-platform.json +15 -0
- package/.ai/blueprints/edit-module/examples/valid/input.json +5 -0
- package/.ai/blueprints/edit-module/examples/valid/plan.json +25 -0
- package/.ai/blueprints/edit-module/gates.yaml +30 -0
- package/.ai/blueprints/edit-module/input.schema.json +31 -0
- package/.ai/blueprints/edit-module/plan.schema.json +65 -0
- package/.ai/blueprints/edit-module/required-files.yaml +80 -0
- package/.ai/blueprints/edit-module/spec-requirements.yaml +15 -0
- package/.ai/blueprints/edit-module/steps.yaml +115 -0
- package/.ai/blueprints/new-module/README.md +7 -0
- package/.ai/blueprints/new-module/allowed-paths.yaml +27 -0
- package/.ai/blueprints/new-module/blueprint.json +20 -0
- package/.ai/blueprints/new-module/examples/invalid/input-spec-outside-modules.json +4 -0
- package/.ai/blueprints/new-module/examples/invalid/plan-unknown-gate.json +8 -0
- package/.ai/blueprints/new-module/examples/valid/input.json +5 -0
- package/.ai/blueprints/new-module/examples/valid/plan.json +22 -0
- package/.ai/blueprints/new-module/gates.yaml +30 -0
- package/.ai/blueprints/new-module/input.schema.json +21 -0
- package/.ai/blueprints/new-module/plan.schema.json +58 -0
- package/.ai/blueprints/new-module/required-files.yaml +73 -0
- package/.ai/blueprints/new-module/spec-requirements.yaml +30 -0
- package/.ai/blueprints/new-module/steps.yaml +138 -0
- package/.ai/blueprints/release/README.md +5 -0
- package/.ai/blueprints/release/allowed-paths.yaml +19 -0
- package/.ai/blueprints/release/blueprint.json +14 -0
- package/.ai/blueprints/release/examples/invalid/input-bad-version.json +4 -0
- package/.ai/blueprints/release/examples/invalid/plan-bad-branch.json +7 -0
- package/.ai/blueprints/release/examples/valid/input.json +5 -0
- package/.ai/blueprints/release/examples/valid/plan.json +20 -0
- package/.ai/blueprints/release/gates.yaml +20 -0
- package/.ai/blueprints/release/input.schema.json +24 -0
- package/.ai/blueprints/release/plan.schema.json +46 -0
- package/.ai/blueprints/release/required-files.yaml +19 -0
- package/.ai/blueprints/release/spec-requirements.yaml +8 -0
- package/.ai/blueprints/release/steps.yaml +47 -0
- package/.ai/blueprints/security-review/README.md +5 -0
- package/.ai/blueprints/security-review/allowed-paths.yaml +6 -0
- package/.ai/blueprints/security-review/blueprint.json +14 -0
- package/.ai/blueprints/security-review/examples/invalid/input-unknown-kind.json +4 -0
- package/.ai/blueprints/security-review/examples/invalid/plan-finding-without-scenario.json +14 -0
- package/.ai/blueprints/security-review/examples/valid/input.json +4 -0
- package/.ai/blueprints/security-review/examples/valid/plan.json +19 -0
- package/.ai/blueprints/security-review/gates.yaml +22 -0
- package/.ai/blueprints/security-review/input.schema.json +20 -0
- package/.ai/blueprints/security-review/plan.schema.json +65 -0
- package/.ai/blueprints/security-review/required-files.yaml +6 -0
- package/.ai/blueprints/security-review/spec-requirements.yaml +9 -0
- package/.ai/blueprints/security-review/steps.yaml +38 -0
- package/.ai/policies/capabilities.yaml +164 -0
- package/.ai/policies/model-routing.yaml +72 -0
- package/.ai/policies/path-ownership.yaml +65 -0
- package/.ai/policies/task-budgets.yaml +37 -0
- package/.ai/references/catalog/LICENSE +21 -0
- package/.ai/references/catalog/migrations/0001_catalog_core.down.sql +2 -0
- package/.ai/references/catalog/migrations/0001_catalog_core.up.sql +21 -0
- package/.ai/references/catalog/migrations/0002_catalog_history.down.sql +3 -0
- package/.ai/references/catalog/migrations/0002_catalog_history.up.sql +20 -0
- package/.ai/references/catalog/migrations/0003_catalog_history_service_actors.down.sql +3 -0
- package/.ai/references/catalog/migrations/0003_catalog_history_service_actors.up.sql +36 -0
- package/.ai/references/catalog/migrations/0004_catalog_idempotency_ledger.down.sql +3 -0
- package/.ai/references/catalog/migrations/0004_catalog_idempotency_ledger.up.sql +19 -0
- package/.ai/references/catalog/migrations/README.md +3 -0
- package/.ai/references/catalog/module.json +27 -0
- package/.ai/references/catalog/package.json +49 -0
- package/.ai/references/catalog/spec/module.yaml +86 -0
- package/.ai/references/catalog/src/acl/permissions.ts +6 -0
- package/.ai/references/catalog/src/agent/tools.ts +164 -0
- package/.ai/references/catalog/src/api/endpoints.ts +243 -0
- package/.ai/references/catalog/src/client/CatalogHistoryDrawer.tsrx +123 -0
- package/.ai/references/catalog/src/client/CatalogItemForm.tsrx +190 -0
- package/.ai/references/catalog/src/client/CatalogView.tsrx +473 -0
- package/.ai/references/catalog/src/client/api.ts +111 -0
- package/.ai/references/catalog/src/client/contribution.tsrx +61 -0
- package/.ai/references/catalog/src/client/index.ts +18 -0
- package/.ai/references/catalog/src/client/navigation-copy.ts +9 -0
- package/.ai/references/catalog/src/client/state.ts +24 -0
- package/.ai/references/catalog/src/domain/types.ts +32 -0
- package/.ai/references/catalog/src/domain/variables.ts +111 -0
- package/.ai/references/catalog/src/index.ts +31 -0
- package/.ai/references/catalog/src/platform.ts +35 -0
- package/.ai/references/catalog/src/server/index.ts +4 -0
- package/.ai/references/catalog/src/server/runtime.ts +86 -0
- package/.ai/references/catalog/src/services/catalog-service.ts +306 -0
- package/.ai/references/catalog/src/services/database-repository.ts +440 -0
- package/.ai/references/catalog/src/services/index.ts +4 -0
- package/.ai/references/catalog/src/services/migration.ts +171 -0
- package/.ai/references/catalog/src/services/repository.ts +36 -0
- package/.ai/references/catalog/src/services/target-idempotency.ts +59 -0
- package/.ai/references/catalog/tests/agent-tools.test.ts +277 -0
- package/.ai/references/catalog/tests/endpoints.test.ts +320 -0
- package/.ai/references/catalog/tests/idempotency.test.ts +297 -0
- package/.ai/references/catalog/tests/migrations.test.ts +149 -0
- package/.ai/references/catalog/tests/module.test.ts +271 -0
- package/.ai/references/catalog/tests/support/database.ts +76 -0
- package/.ai/references/catalog/translations/en.json +101 -0
- package/.ai/references/catalog/translations/pl.json +101 -0
- package/.ai/references/catalog/tsconfig.json +15 -0
- package/.ai/references/catalog/vitest.config.ts +16 -0
- package/.ai/references/catalog.provenance.json +55 -0
- package/.ai/skills/README.md +36 -0
- package/.ai/skills/agent-tool-design/SKILL.md +209 -0
- package/.ai/skills/auth-security-review/SKILL.md +96 -0
- package/.ai/skills/auto-review/SKILL.md +112 -0
- package/.ai/skills/bug-hunt/SKILL.md +110 -0
- package/.ai/skills/business-agent-design/SKILL.md +188 -0
- package/.ai/skills/cli-extension/SKILL.md +114 -0
- package/.ai/skills/core-extend/SKILL.md +104 -0
- package/.ai/skills/database-adapter/SKILL.md +204 -0
- package/.ai/skills/database-adapter/references/first-run-and-matrix.md +105 -0
- package/.ai/skills/migration-authoring/SKILL.md +167 -0
- package/.ai/skills/module-new/SKILL.md +180 -0
- package/.ai/skills/module-update/SKILL.md +100 -0
- package/.ai/skills/perf-audit/SKILL.md +105 -0
- package/.ai/skills/release-eject-pr/SKILL.md +113 -0
- package/.ai/skills/spec-approval/SKILL.md +112 -0
- package/.ai/skills/test-hardening/SKILL.md +86 -0
- package/.ai/skills/translations-i18n/SKILL.md +85 -0
- package/.ai/skills/ux-design/SKILL.md +97 -0
- package/.ai/skills/variables/SKILL.md +164 -0
- package/.ai/skills/workflow-development/SKILL.md +199 -0
- package/AGENTS.md +59 -0
- package/LICENSE +21 -0
- package/README.md +24 -0
- package/docs/agent-contract.md +45 -0
- package/docs/design-system.md +217 -0
- package/modules/agents/migrations/0001_agents_core.down.sql +4 -0
- package/modules/agents/migrations/0001_agents_core.up.sql +106 -0
- package/modules/agents/migrations/0002_provider_connections.down.sql +1 -0
- package/modules/agents/migrations/0002_provider_connections.up.sql +34 -0
- package/modules/agents/migrations/0003_resource_audit.down.sql +1 -0
- package/modules/agents/migrations/0003_resource_audit.up.sql +25 -0
- package/modules/agents/migrations/0004_run_grants.down.sql +1 -0
- package/modules/agents/migrations/0004_run_grants.up.sql +19 -0
- package/modules/agents/migrations/0005_long_running_limits.down.sql +2 -0
- package/modules/agents/migrations/0005_long_running_limits.up.sql +14 -0
- package/modules/agents/migrations/0006_agent_skills.down.sql +3 -0
- package/modules/agents/migrations/0006_agent_skills.up.sql +44 -0
- package/modules/agents/migrations/0007_model_readiness.down.sql +1 -0
- package/modules/agents/migrations/0007_model_readiness.up.sql +18 -0
- package/modules/agents/migrations/0008_output_limits.down.sql +2 -0
- package/modules/agents/migrations/0008_output_limits.up.sql +8 -0
- package/modules/agents/migrations/0009_agent_audit_v3.down.sql +1 -0
- package/modules/agents/migrations/0009_agent_audit_v3.up.sql +25 -0
- package/modules/agents/migrations/0012_agent_run_costs.down.sql +3 -0
- package/modules/agents/migrations/0012_agent_run_costs.up.sql +32 -0
- package/modules/agents/migrations/0013_workflow_prerequisites.down.sql +3 -0
- package/modules/agents/migrations/0013_workflow_prerequisites.up.sql +97 -0
- package/modules/agents/migrations/0014_agent_action_audit.down.sql +1 -0
- package/modules/agents/migrations/0014_agent_action_audit.up.sql +25 -0
- package/modules/agents/migrations/0015_agent_run_actors.down.sql +1 -0
- package/modules/agents/migrations/0015_agent_run_actors.up.sql +17 -0
- package/modules/agents/migrations/0016_module_owned_agents.down.sql +6 -0
- package/modules/agents/migrations/0016_module_owned_agents.up.sql +68 -0
- package/modules/agents/migrations/0017_agent_authorization_subjects.down.sql +2 -0
- package/modules/agents/migrations/0017_agent_authorization_subjects.up.sql +18 -0
- package/modules/agents/migrations/0018_agent_child_tenant_isolation.down.sql +12 -0
- package/modules/agents/migrations/0018_agent_child_tenant_isolation.up.sql +88 -0
- package/modules/agents/migrations/0019_background_recovery_grants.down.sql +6 -0
- package/modules/agents/migrations/0019_background_recovery_grants.up.sql +17 -0
- package/modules/agents/migrations/0020_provider_summary_role.down.sql +2 -0
- package/modules/agents/migrations/0020_provider_summary_role.up.sql +17 -0
- package/modules/agents/migrations/0021_agents_agent_reconciliation_role.down.sql +4 -0
- package/modules/agents/migrations/0021_agents_agent_reconciliation_role.up.sql +7 -0
- package/modules/agents/migrations/README.md +39 -0
- package/modules/agents/module.json +38 -0
- package/modules/agents/package.json +56 -0
- package/modules/agents/spec/module.yaml +271 -0
- package/modules/agents/spec/procedures-compatibility.md +63 -0
- package/modules/agents/src/acl/permissions.ts +13 -0
- package/modules/agents/src/api/endpoints.ts +1122 -0
- package/modules/agents/src/cli/commands.json +29 -0
- package/modules/agents/src/cli/index.ts +162 -0
- package/modules/agents/src/client/AgentDashboardWidget.tsrx +32 -0
- package/modules/agents/src/client/AgentDefinitionForm.tsrx +362 -0
- package/modules/agents/src/client/AgentDefinitionList.tsrx +127 -0
- package/modules/agents/src/client/AgentPlaygroundView.tsrx +246 -0
- package/modules/agents/src/client/AgentProcedureForm.tsrx +182 -0
- package/modules/agents/src/client/AgentProcedureList.tsrx +118 -0
- package/modules/agents/src/client/AgentProceduresView.tsrx +253 -0
- package/modules/agents/src/client/AgentProvidersView.tsrx +248 -0
- package/modules/agents/src/client/AgentRunsView.tsrx +304 -0
- package/modules/agents/src/client/AgentUsageView.tsrx +233 -0
- package/modules/agents/src/client/AgentsView.tsrx +339 -0
- package/modules/agents/src/client/ModuleAgentBindingForm.tsrx +239 -0
- package/modules/agents/src/client/ModuleAgentList.tsrx +122 -0
- package/modules/agents/src/client/ProviderConnectionForm.tsrx +273 -0
- package/modules/agents/src/client/ProviderConnectionList.tsrx +229 -0
- package/modules/agents/src/client/ProviderModelEditor.tsrx +313 -0
- package/modules/agents/src/client/RunTimeline.tsrx +212 -0
- package/modules/agents/src/client/agents.css +349 -0
- package/modules/agents/src/client/api.ts +373 -0
- package/modules/agents/src/client/contribution.tsrx +181 -0
- package/modules/agents/src/client/index.ts +21 -0
- package/modules/agents/src/client/presentation.ts +162 -0
- package/modules/agents/src/client/state.ts +100 -0
- package/modules/agents/src/domain/context-variables.ts +58 -0
- package/modules/agents/src/domain/run-timeline.ts +145 -0
- package/modules/agents/src/domain/types.ts +481 -0
- package/modules/agents/src/index.ts +88 -0
- package/modules/agents/src/platform.ts +82 -0
- package/modules/agents/src/server/action-execution.ts +811 -0
- package/modules/agents/src/server/define-agent.ts +170 -0
- package/modules/agents/src/server/index.ts +67 -0
- package/modules/agents/src/server/run-execution.ts +231 -0
- package/modules/agents/src/server/run-queue.ts +96 -0
- package/modules/agents/src/server/runtime.ts +448 -0
- package/modules/agents/src/server/tools.ts +18 -0
- package/modules/agents/src/services/agent-service.ts +2167 -0
- package/modules/agents/src/services/credential-vault.ts +133 -0
- package/modules/agents/src/services/database-repository.ts +2786 -0
- package/modules/agents/src/services/index.ts +33 -0
- package/modules/agents/src/services/migration.ts +1152 -0
- package/modules/agents/src/services/module-agent-preflight.ts +76 -0
- package/modules/agents/src/services/outbound-policy.ts +136 -0
- package/modules/agents/src/services/provider-broker.ts +80 -0
- package/modules/agents/src/services/provider-repository.ts +589 -0
- package/modules/agents/src/services/provider-service.ts +968 -0
- package/modules/agents/src/services/repository.ts +294 -0
- package/modules/agents/src/services/run-grant.ts +305 -0
- package/modules/agents/src/services/usage-service.ts +119 -0
- package/modules/agents/src/services/worker.ts +442 -0
- package/modules/agents/src/settings.ts +244 -0
- package/modules/agents/translations/en.json +403 -0
- package/modules/agents/translations/pl.json +403 -0
- package/modules/auth/README.md +215 -0
- package/modules/auth/migrations/0001_auth_core.up.sql +108 -0
- package/modules/auth/migrations/0002_bundled_module_scopes.up.sql +26 -0
- package/modules/auth/migrations/0003_agent_core_scopes.up.sql +12 -0
- package/modules/auth/migrations/0004_owner_only_development_scopes.up.sql +8 -0
- package/modules/auth/migrations/0005_agent_provider_scopes.up.sql +13 -0
- package/modules/auth/migrations/0006_tenant_slug.up.sql +6 -0
- package/modules/auth/migrations/0007_sandbox_scopes.up.sql +13 -0
- package/modules/auth/migrations/0008_api_tokens.up.sql +43 -0
- package/modules/auth/migrations/0009_module_settings.up.sql +24 -0
- package/modules/auth/migrations/0010_sign_in_lockout.up.sql +11 -0
- package/modules/auth/migrations/0011_session_ids_and_password_reset.up.sql +7 -0
- package/modules/auth/migrations/0012_roles.up.sql +31 -0
- package/modules/auth/migrations/0013_audit.up.sql +27 -0
- package/modules/auth/migrations/0014_audit_actor.up.sql +4 -0
- package/modules/auth/migrations/0015_account_security.up.sql +81 -0
- package/modules/auth/module.json +26 -0
- package/modules/auth/package.json +61 -0
- package/modules/auth/spec/module.yaml +190 -0
- package/modules/auth/src/acl/scopes.ts +86 -0
- package/modules/auth/src/api/attempt-limiter.ts +42 -0
- package/modules/auth/src/api/client-address.ts +14 -0
- package/modules/auth/src/api/cookies.ts +52 -0
- package/modules/auth/src/api/origin.ts +40 -0
- package/modules/auth/src/cli/commands.json +74 -0
- package/modules/auth/src/cli/database.ts +51 -0
- package/modules/auth/src/cli/greenfield.ts +173 -0
- package/modules/auth/src/cli/index.ts +184 -0
- package/modules/auth/src/cli/provisioning.ts +211 -0
- package/modules/auth/src/client/AuthBackdrop.tsrx +137 -0
- package/modules/auth/src/client/AuthenticationCore.tsrx +630 -0
- package/modules/auth/src/client/PasswordChangeRequired.tsrx +145 -0
- package/modules/auth/src/client/PublicAuthFlows.tsrx +379 -0
- package/modules/auth/src/client/api.ts +464 -0
- package/modules/auth/src/client/audit/AuditView.tsrx +357 -0
- package/modules/auth/src/client/audit/api.ts +164 -0
- package/modules/auth/src/client/audit/audit-columns.tsrx +47 -0
- package/modules/auth/src/client/audit/audit-row.ts +38 -0
- package/modules/auth/src/client/auth.css +483 -0
- package/modules/auth/src/client/contribution.tsrx +100 -0
- package/modules/auth/src/client/index.ts +32 -0
- package/modules/auth/src/client/security/SecurityView.tsrx +253 -0
- package/modules/auth/src/client/settings/PreferencesCard.tsrx +65 -0
- package/modules/auth/src/client/settings/SettingsView.tsrx +212 -0
- package/modules/auth/src/client/settings/WorkspaceCard.tsrx +59 -0
- package/modules/auth/src/client/settings/api.ts +115 -0
- package/modules/auth/src/client/slug.ts +26 -0
- package/modules/auth/src/client/state.ts +115 -0
- package/modules/auth/src/client/tokens/ApiTokenForm.tsrx +153 -0
- package/modules/auth/src/client/tokens/ApiTokenSecret.tsrx +35 -0
- package/modules/auth/src/client/tokens/ApiTokensView.tsrx +216 -0
- package/modules/auth/src/client/tokens/api.ts +59 -0
- package/modules/auth/src/client/tokens/state.ts +26 -0
- package/modules/auth/src/client/tokens/token-columns.tsrx +64 -0
- package/modules/auth/src/client/translations.ts +23 -0
- package/modules/auth/src/domain/types.ts +152 -0
- package/modules/auth/src/index.ts +42 -0
- package/modules/auth/src/middleware/authentication.ts +97 -0
- package/modules/auth/src/platform.ts +0 -0
- package/modules/auth/src/server/actor.ts +12 -0
- package/modules/auth/src/server/audit-endpoints.ts +51 -0
- package/modules/auth/src/server/composition.ts +9 -0
- package/modules/auth/src/server/endpoints.ts +893 -0
- package/modules/auth/src/server/http.ts +153 -0
- package/modules/auth/src/server/index.ts +37 -0
- package/modules/auth/src/server/roles-endpoints.ts +120 -0
- package/modules/auth/src/server/runtime.ts +705 -0
- package/modules/auth/src/server/session-endpoints.ts +86 -0
- package/modules/auth/src/server/session-security.ts +62 -0
- package/modules/auth/src/server/token-endpoints.ts +106 -0
- package/modules/auth/src/services/auth-service-error.ts +11 -0
- package/modules/auth/src/services/auth-service.ts +2309 -0
- package/modules/auth/src/services/database-repository.ts +1825 -0
- package/modules/auth/src/services/mail-delivery.ts +27 -0
- package/modules/auth/src/services/migration.ts +591 -0
- package/modules/auth/src/services/password.ts +115 -0
- package/modules/auth/src/services/repository.ts +395 -0
- package/modules/auth/src/services/settings-store.ts +92 -0
- package/modules/auth/src/services/totp.ts +135 -0
- package/modules/auth/src/services/validation.ts +186 -0
- package/modules/auth/src/settings.ts +150 -0
- package/modules/auth/translations/en.json +263 -0
- package/modules/auth/translations/pl.json +263 -0
- package/modules/automations/migrations/0001_automations_core.down.sql +10 -0
- package/modules/automations/migrations/0001_automations_core.up.sql +76 -0
- package/modules/automations/migrations/0002_automations_targets.down.sql +9 -0
- package/modules/automations/migrations/0002_automations_targets.up.sql +37 -0
- package/modules/automations/migrations/0003_automations_scheduler_role.down.sql +3 -0
- package/modules/automations/migrations/0003_automations_scheduler_role.up.sql +19 -0
- package/modules/automations/migrations/0004_automations_trigger_routing_role.down.sql +3 -0
- package/modules/automations/migrations/0004_automations_trigger_routing_role.up.sql +18 -0
- package/modules/automations/migrations/README.md +3 -0
- package/modules/automations/module.json +31 -0
- package/modules/automations/package.json +55 -0
- package/modules/automations/spec/module.yaml +93 -0
- package/modules/automations/src/acl/permissions.ts +10 -0
- package/modules/automations/src/api/endpoints.ts +480 -0
- package/modules/automations/src/client/AutomationScheduleForm.tsrx +218 -0
- package/modules/automations/src/client/AutomationSchedulesView.tsrx +339 -0
- package/modules/automations/src/client/AutomationTriggerForm.tsrx +190 -0
- package/modules/automations/src/client/AutomationTriggersView.tsrx +329 -0
- package/modules/automations/src/client/api.ts +148 -0
- package/modules/automations/src/client/contribution.tsrx +70 -0
- package/modules/automations/src/client/index.ts +20 -0
- package/modules/automations/src/client/presentation.ts +38 -0
- package/modules/automations/src/client/state.ts +40 -0
- package/modules/automations/src/client/target-selection.ts +44 -0
- package/modules/automations/src/domain/cadence.ts +44 -0
- package/modules/automations/src/domain/types.ts +110 -0
- package/modules/automations/src/domain/variables.ts +178 -0
- package/modules/automations/src/index.ts +39 -0
- package/modules/automations/src/platform.ts +73 -0
- package/modules/automations/src/server/execution.ts +77 -0
- package/modules/automations/src/server/index.ts +39 -0
- package/modules/automations/src/server/runtime.ts +218 -0
- package/modules/automations/src/server/targets.ts +116 -0
- package/modules/automations/src/services/automations-service.ts +10 -0
- package/modules/automations/src/services/database-repository.ts +763 -0
- package/modules/automations/src/services/index.ts +5 -0
- package/modules/automations/src/services/migration.ts +223 -0
- package/modules/automations/src/services/repository.ts +119 -0
- package/modules/automations/src/services/schedule-service.ts +837 -0
- package/modules/automations/src/services/secret-vault.ts +124 -0
- package/modules/automations/src/services/trigger-service.ts +648 -0
- package/modules/automations/src/settings.ts +69 -0
- package/modules/automations/translations/en.json +126 -0
- package/modules/automations/translations/pl.json +126 -0
- package/modules/automations-workflows-integration/module.json +27 -0
- package/modules/automations-workflows-integration/package.json +48 -0
- package/modules/automations-workflows-integration/spec/module.yaml +93 -0
- package/modules/automations-workflows-integration/src/index.ts +14 -0
- package/modules/automations-workflows-integration/src/platform.ts +24 -0
- package/modules/automations-workflows-integration/src/server/adapter.ts +272 -0
- package/modules/automations-workflows-integration/src/server/index.ts +11 -0
- package/modules/automations-workflows-integration/src/server/tools.ts +0 -0
- package/modules/automations-workflows-integration/translations/en.json +21 -0
- package/modules/automations-workflows-integration/translations/pl.json +21 -0
- package/modules/profile/migrations/0001_profile_core.down.sql +1 -0
- package/modules/profile/migrations/0001_profile_core.up.sql +13 -0
- package/modules/profile/migrations/0002_profile_language.down.sql +1 -0
- package/modules/profile/migrations/0002_profile_language.up.sql +12 -0
- package/modules/profile/migrations/README.md +3 -0
- package/modules/profile/module.json +23 -0
- package/modules/profile/package.json +55 -0
- package/modules/profile/spec/module.yaml +136 -0
- package/modules/profile/src/acl/permissions.ts +5 -0
- package/modules/profile/src/api/endpoints.ts +184 -0
- package/modules/profile/src/client/DisplayNameCard.tsrx +59 -0
- package/modules/profile/src/client/LanguageCard.tsrx +89 -0
- package/modules/profile/src/client/PasswordCard.tsrx +79 -0
- package/modules/profile/src/client/ProfileView.tsrx +192 -0
- package/modules/profile/src/client/SessionsCard.tsrx +158 -0
- package/modules/profile/src/client/api.ts +134 -0
- package/modules/profile/src/client/contribution.tsrx +61 -0
- package/modules/profile/src/client/index.ts +15 -0
- package/modules/profile/src/client/password.ts +41 -0
- package/modules/profile/src/client/sessions-api.ts +52 -0
- package/modules/profile/src/client/state.ts +23 -0
- package/modules/profile/src/domain/types.ts +21 -0
- package/modules/profile/src/index.ts +21 -0
- package/modules/profile/src/platform.ts +23 -0
- package/modules/profile/src/server/index.ts +7 -0
- package/modules/profile/src/server/runtime.ts +84 -0
- package/modules/profile/src/services/database-repository.ts +154 -0
- package/modules/profile/src/services/index.ts +6 -0
- package/modules/profile/src/services/migration.ts +58 -0
- package/modules/profile/src/services/profile-service.ts +114 -0
- package/modules/profile/src/services/repository.ts +13 -0
- package/modules/profile/translations/en.json +58 -0
- package/modules/profile/translations/pl.json +58 -0
- package/modules/sandbox/migrations/0001_sandbox_core.down.sql +6 -0
- package/modules/sandbox/migrations/0001_sandbox_core.up.sql +70 -0
- package/modules/sandbox/migrations/0002_sandbox_session_lifecycle.down.sql +36 -0
- package/modules/sandbox/migrations/0002_sandbox_session_lifecycle.up.sql +37 -0
- package/modules/sandbox/migrations/README.md +7 -0
- package/modules/sandbox/module.json +31 -0
- package/modules/sandbox/package.json +56 -0
- package/modules/sandbox/spec/module.yaml +111 -0
- package/modules/sandbox/src/acl/permissions.ts +18 -0
- package/modules/sandbox/src/api/endpoints.ts +439 -0
- package/modules/sandbox/src/cli/commands.json +84 -0
- package/modules/sandbox/src/cli/index.ts +450 -0
- package/modules/sandbox/src/client/SandboxAccessView.tsrx +191 -0
- package/modules/sandbox/src/client/SandboxGrantForm.tsrx +134 -0
- package/modules/sandbox/src/client/SandboxGrantList.tsrx +83 -0
- package/modules/sandbox/src/client/SandboxSessionList.tsrx +56 -0
- package/modules/sandbox/src/client/api.ts +87 -0
- package/modules/sandbox/src/client/contribution.tsrx +47 -0
- package/modules/sandbox/src/client/index.ts +18 -0
- package/modules/sandbox/src/client/presentation.ts +47 -0
- package/modules/sandbox/src/client/state.ts +20 -0
- package/modules/sandbox/src/domain/types.ts +125 -0
- package/modules/sandbox/src/index.ts +33 -0
- package/modules/sandbox/src/platform.ts +28 -0
- package/modules/sandbox/src/server/index.ts +20 -0
- package/modules/sandbox/src/server/runtime.ts +119 -0
- package/modules/sandbox/src/services/database-repository.ts +567 -0
- package/modules/sandbox/src/services/directory.ts +33 -0
- package/modules/sandbox/src/services/index.ts +19 -0
- package/modules/sandbox/src/services/migration.ts +145 -0
- package/modules/sandbox/src/services/repository.ts +55 -0
- package/modules/sandbox/src/services/sandbox-service-error.ts +10 -0
- package/modules/sandbox/src/services/sandbox-service.ts +533 -0
- package/modules/sandbox/translations/en.json +77 -0
- package/modules/sandbox/translations/pl.json +77 -0
- package/modules/system/module.json +18 -0
- package/modules/system/package.json +56 -0
- package/modules/system/spec/module.yaml +104 -0
- package/modules/system/src/acl/permissions.ts +10 -0
- package/modules/system/src/client/ModuleSettingRow.tsrx +191 -0
- package/modules/system/src/client/ModuleSettingsSection.tsrx +155 -0
- package/modules/system/src/client/ModulesView.tsrx +241 -0
- package/modules/system/src/client/api.ts +36 -0
- package/modules/system/src/client/contribution.tsrx +48 -0
- package/modules/system/src/client/index.ts +26 -0
- package/modules/system/src/client/module-columns.tsrx +66 -0
- package/modules/system/src/client/overview-api.ts +30 -0
- package/modules/system/src/client/setting-copy.ts +30 -0
- package/modules/system/src/client/settings-api.ts +57 -0
- package/modules/system/src/client/state.ts +16 -0
- package/modules/system/src/index.ts +11 -0
- package/modules/system/src/platform.ts +11 -0
- package/modules/system/src/server/endpoints.ts +372 -0
- package/modules/system/src/server/index.ts +11 -0
- package/modules/system/src/server/module-catalog.ts +117 -0
- package/modules/system/translations/en.json +64 -0
- package/modules/system/translations/pl.json +64 -0
- package/modules/users/migrations/README.md +3 -0
- package/modules/users/module.json +27 -0
- package/modules/users/package.json +54 -0
- package/modules/users/spec/module.yaml +79 -0
- package/modules/users/src/acl/permissions.ts +6 -0
- package/modules/users/src/api/endpoints.ts +222 -0
- package/modules/users/src/client/InviteMemberForm.tsrx +62 -0
- package/modules/users/src/client/MemberDrawer.tsrx +298 -0
- package/modules/users/src/client/RoleForm.tsrx +140 -0
- package/modules/users/src/client/RolesView.tsrx +288 -0
- package/modules/users/src/client/UserAccountForm.tsrx +86 -0
- package/modules/users/src/client/UsersView.tsrx +486 -0
- package/modules/users/src/client/api.ts +172 -0
- package/modules/users/src/client/contribution.tsrx +92 -0
- package/modules/users/src/client/index.ts +19 -0
- package/modules/users/src/client/member-columns.tsrx +52 -0
- package/modules/users/src/client/roles-api.ts +90 -0
- package/modules/users/src/client/state.ts +42 -0
- package/modules/users/src/index.ts +27 -0
- package/modules/users/src/platform.ts +11 -0
- package/modules/users/src/services/index.ts +2 -0
- package/modules/users/src/services/users-service.ts +142 -0
- package/modules/users/translations/en.json +133 -0
- package/modules/users/translations/pl.json +133 -0
- package/modules/workflows/migrations/0001_workflows_core.down.sql +19 -0
- package/modules/workflows/migrations/0001_workflows_core.up.sql +228 -0
- package/modules/workflows/migrations/0002_workflows_authorization_subject.down.sql +1 -0
- package/modules/workflows/migrations/0002_workflows_authorization_subject.up.sql +9 -0
- package/modules/workflows/migrations/0003_workflows_worker_role.up.sql +34 -0
- package/modules/workflows/migrations/README.md +7 -0
- package/modules/workflows/module.json +31 -0
- package/modules/workflows/package.json +55 -0
- package/modules/workflows/spec/module.yaml +227 -0
- package/modules/workflows/src/acl/permissions.ts +10 -0
- package/modules/workflows/src/api/endpoints.ts +852 -0
- package/modules/workflows/src/client/WorkflowCanvas.tsrx +819 -0
- package/modules/workflows/src/client/WorkflowCreateForm.tsrx +111 -0
- package/modules/workflows/src/client/WorkflowEditor.tsrx +443 -0
- package/modules/workflows/src/client/WorkflowExecutionHistory.tsrx +169 -0
- package/modules/workflows/src/client/WorkflowFixtureDrawer.tsrx +206 -0
- package/modules/workflows/src/client/WorkflowInputForm.tsrx +125 -0
- package/modules/workflows/src/client/WorkflowInputSchemaEditor.tsrx +185 -0
- package/modules/workflows/src/client/WorkflowInspector.tsrx +471 -0
- package/modules/workflows/src/client/WorkflowLiveConfirmation.tsrx +67 -0
- package/modules/workflows/src/client/WorkflowMappingEditor.tsrx +283 -0
- package/modules/workflows/src/client/WorkflowNodePalette.tsrx +50 -0
- package/modules/workflows/src/client/WorkflowPointerField.tsrx +178 -0
- package/modules/workflows/src/client/WorkflowRevisionReview.tsrx +49 -0
- package/modules/workflows/src/client/WorkflowRunInspector.tsrx +143 -0
- package/modules/workflows/src/client/WorkflowTestPanel.tsrx +109 -0
- package/modules/workflows/src/client/WorkflowValidationPanel.tsrx +139 -0
- package/modules/workflows/src/client/WorkflowsView.tsrx +1060 -0
- package/modules/workflows/src/client/api.ts +312 -0
- package/modules/workflows/src/client/canvas-model.ts +472 -0
- package/modules/workflows/src/client/connected-node.ts +71 -0
- package/modules/workflows/src/client/contribution.tsrx +57 -0
- package/modules/workflows/src/client/create-model.ts +15 -0
- package/modules/workflows/src/client/draft-repair.ts +86 -0
- package/modules/workflows/src/client/index.ts +19 -0
- package/modules/workflows/src/client/input-model.ts +124 -0
- package/modules/workflows/src/client/mapping-model.ts +110 -0
- package/modules/workflows/src/client/pointer-model.ts +123 -0
- package/modules/workflows/src/client/presentation.ts +62 -0
- package/modules/workflows/src/client/run-actions.ts +19 -0
- package/modules/workflows/src/client/state.ts +57 -0
- package/modules/workflows/src/client/viewport.ts +107 -0
- package/modules/workflows/src/client/workflows.css +899 -0
- package/modules/workflows/src/domain/events.ts +399 -0
- package/modules/workflows/src/domain/graph.ts +1136 -0
- package/modules/workflows/src/domain/types.ts +563 -0
- package/modules/workflows/src/index.ts +27 -0
- package/modules/workflows/src/platform.ts +49 -0
- package/modules/workflows/src/server/index.ts +13 -0
- package/modules/workflows/src/server/runtime.ts +266 -0
- package/modules/workflows/src/services/cursor-codec.ts +62 -0
- package/modules/workflows/src/services/database-repository.ts +2407 -0
- package/modules/workflows/src/services/index.ts +6 -0
- package/modules/workflows/src/services/migration.ts +375 -0
- package/modules/workflows/src/services/payload-codec.ts +264 -0
- package/modules/workflows/src/services/repository.ts +285 -0
- package/modules/workflows/src/services/simulation.ts +359 -0
- package/modules/workflows/src/services/worker.ts +1196 -0
- package/modules/workflows/src/services/workflows-service.ts +1395 -0
- package/modules/workflows/translations/en.json +348 -0
- package/modules/workflows/translations/pl.json +348 -0
- package/modules.json +41 -0
- package/package.json +125 -0
- package/packages/ai-provider/package.json +46 -0
- package/packages/ai-provider/src/catalog.ts +102 -0
- package/packages/ai-provider/src/errors.ts +110 -0
- package/packages/ai-provider/src/index.ts +33 -0
- package/packages/ai-provider/src/model.ts +198 -0
- package/packages/ai-provider/src/pricing.ts +73 -0
- package/packages/cli-protocol/package.json +40 -0
- package/packages/cli-protocol/src/index.ts +113 -0
- package/packages/client/package.json +46 -0
- package/packages/client/src/ApplicationShell.tsrx +374 -0
- package/packages/client/src/contributions.ts +172 -0
- package/packages/client/src/i18n/index.ts +30 -0
- package/packages/client/src/i18n/locale.ts +25 -0
- package/packages/client/src/i18n/locales/en.json +66 -0
- package/packages/client/src/i18n/locales/pl.json +66 -0
- package/packages/client/src/i18n/runtime.ts +201 -0
- package/packages/client/src/i18n/translations.ts +88 -0
- package/packages/client/src/index.ts +55 -0
- package/packages/client/src/routing.ts +9 -0
- package/packages/client/src/shell/BrandMark.tsrx +10 -0
- package/packages/client/src/shell/CommandPalette.tsrx +79 -0
- package/packages/client/src/shell/ContributionOutlets.tsrx +31 -0
- package/packages/client/src/shell/DashboardView.tsrx +60 -0
- package/packages/client/src/shell/MobileHeader.tsrx +24 -0
- package/packages/client/src/shell/OrganizationSwitcher.tsrx +100 -0
- package/packages/client/src/shell/OverviewCharts.tsrx +167 -0
- package/packages/client/src/shell/PrimaryNavigation.tsrx +75 -0
- package/packages/client/src/shell/Sidebar.tsrx +76 -0
- package/packages/client/src/shell/Topbar.tsrx +44 -0
- package/packages/client/src/shell/UserMenu.tsrx +103 -0
- package/packages/client/src/shell/WorkspaceContent.tsrx +30 -0
- package/packages/client/src/shell/identity.ts +12 -0
- package/packages/client/src/shell/navigation.ts +68 -0
- package/packages/client/src/shell/shell.css +734 -0
- package/packages/client/src/shell/types.ts +29 -0
- package/packages/client/src/state.ts +63 -0
- package/packages/client/src/web.ts +39 -0
- package/packages/coding-agent/package.json +44 -0
- package/packages/coding-agent/src/drivers/byok.ts +322 -0
- package/packages/coding-agent/src/drivers/claude-code.ts +290 -0
- package/packages/coding-agent/src/drivers/codex.ts +281 -0
- package/packages/coding-agent/src/index.ts +56 -0
- package/packages/coding-agent/src/registry.ts +119 -0
- package/packages/coding-agent/src/roles/contract.ts +60 -0
- package/packages/coding-agent/src/roles/defaults.ts +134 -0
- package/packages/coding-agent/src/roles/handoff.ts +41 -0
- package/packages/coding-agent/src/roles/registry.ts +156 -0
- package/packages/coding-agent/src/roles/skills.ts +72 -0
- package/packages/coding-agent/src/roles/sync.ts +88 -0
- package/packages/coding-agent/src/types.ts +102 -0
- package/packages/coding-agent/src/workspace.ts +275 -0
- package/packages/contracts/package.json +38 -0
- package/packages/contracts/schemas/blueprint.schema.json +48 -0
- package/packages/contracts/schemas/cli-extension.schema.json +90 -0
- package/packages/contracts/schemas/module-artifact.schema.json +82 -0
- package/packages/contracts/schemas/module-catalog.schema.json +48 -0
- package/packages/contracts/schemas/module-spec.schema.json +111 -0
- package/packages/contracts/schemas/module.schema.json +156 -0
- package/packages/contracts/schemas/platform-spec.schema.json +17 -0
- package/packages/contracts/schemas/project.schema.json +270 -0
- package/packages/contracts/src/index.ts +191 -0
- package/packages/contracts/src/module-distribution.ts +47 -0
- package/packages/contracts/src/schemas.ts +18 -0
- package/packages/contracts/src/variables.ts +156 -0
- package/packages/contracts/src/web.ts +60 -0
- package/packages/database/package.json +43 -0
- package/packages/database/src/contracts.ts +399 -0
- package/packages/database/src/index.ts +112 -0
- package/packages/database/src/migrations.ts +444 -0
- package/packages/database/src/postgresql.ts +517 -0
- package/packages/database/src/provider.ts +639 -0
- package/packages/database/src/record-history.ts +201 -0
- package/packages/database/src/registry.ts +265 -0
- package/packages/database/src/reset.ts +87 -0
- package/packages/database-pglite/package.json +42 -0
- package/packages/database-pglite/src/driver.ts +168 -0
- package/packages/database-pglite/src/index.ts +2 -0
- package/packages/database-testing/package.json +44 -0
- package/packages/database-testing/src/index.ts +8 -0
- package/packages/database-testing/src/pglite.ts +124 -0
- package/packages/database-testing/src/postgres.ts +184 -0
- package/packages/database-testing/src/provider.ts +43 -0
- package/packages/database-testing/src/vitest-preset.ts +23 -0
- package/packages/dev-console/README.md +6 -0
- package/packages/dev-console/package.json +38 -0
- package/packages/dev-console/src/index.mjs +220 -0
- package/packages/harness/package.json +47 -0
- package/packages/harness/schemas/task-packet.schema.json +48 -0
- package/packages/harness/src/catalog.ts +24 -0
- package/packages/harness/src/errors.ts +9 -0
- package/packages/harness/src/index.ts +53 -0
- package/packages/harness/src/preamble.ts +31 -0
- package/packages/harness/src/runtime.ts +833 -0
- package/packages/harness/src/task-packet.ts +86 -0
- package/packages/harness/src/tool-adapters.ts +106 -0
- package/packages/harness/src/tool-contract.ts +242 -0
- package/packages/harness/src/vercel-ai-provider.ts +198 -0
- package/packages/kernel/package.json +44 -0
- package/packages/kernel/src/acl.ts +20 -0
- package/packages/kernel/src/actor.ts +139 -0
- package/packages/kernel/src/agent-registry.ts +81 -0
- package/packages/kernel/src/capability-registry.ts +28 -0
- package/packages/kernel/src/errors.ts +9 -0
- package/packages/kernel/src/index.ts +90 -0
- package/packages/kernel/src/legacy-local-state.ts +103 -0
- package/packages/kernel/src/module-compatibility.ts +70 -0
- package/packages/kernel/src/module-registry.ts +124 -0
- package/packages/kernel/src/module-settings.ts +403 -0
- package/packages/kernel/src/record-history.ts +146 -0
- package/packages/kernel/src/runtime-config.ts +51 -0
- package/packages/kernel/src/tool-registry.ts +25 -0
- package/packages/kernel/src/variable-registry.ts +339 -0
- package/packages/sandbox/README.md +691 -0
- package/packages/sandbox/bin/flowdular-sandbox.mjs +393 -0
- package/packages/sandbox/dist/client/assets/App-ClMOrpyg.js +11 -0
- package/packages/sandbox/dist/client/assets/PreviewHost-BHiHrfbQ.js +1 -0
- package/packages/sandbox/dist/client/assets/auto-buGEq6de.js +3 -0
- package/packages/sandbox/dist/client/assets/ibm-plex-mono-cyrillic-400-normal-BSMlKf0J.woff2 +0 -0
- package/packages/sandbox/dist/client/assets/ibm-plex-mono-cyrillic-400-normal-CEL4l2ZJ.woff +0 -0
- package/packages/sandbox/dist/client/assets/ibm-plex-mono-cyrillic-500-normal-Ael50iVv.woff +0 -0
- package/packages/sandbox/dist/client/assets/ibm-plex-mono-cyrillic-500-normal-Bq9vWWag.woff2 +0 -0
- package/packages/sandbox/dist/client/assets/ibm-plex-mono-cyrillic-ext-400-normal-DMdlQ8Kv.woff +0 -0
- package/packages/sandbox/dist/client/assets/ibm-plex-mono-cyrillic-ext-400-normal-xuaO2J-f.woff2 +0 -0
- package/packages/sandbox/dist/client/assets/ibm-plex-mono-cyrillic-ext-500-normal-BIfNGwUT.woff +0 -0
- package/packages/sandbox/dist/client/assets/ibm-plex-mono-cyrillic-ext-500-normal-BqneJy0T.woff2 +0 -0
- package/packages/sandbox/dist/client/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
- package/packages/sandbox/dist/client/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
- package/packages/sandbox/dist/client/assets/ibm-plex-mono-latin-500-normal-CB9ihrfo.woff +0 -0
- package/packages/sandbox/dist/client/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
- package/packages/sandbox/dist/client/assets/ibm-plex-mono-latin-ext-400-normal-BmRBH3aV.woff2 +0 -0
- package/packages/sandbox/dist/client/assets/ibm-plex-mono-latin-ext-400-normal-D3D2R8hC.woff +0 -0
- package/packages/sandbox/dist/client/assets/ibm-plex-mono-latin-ext-500-normal-CAhNIIs5.woff2 +0 -0
- package/packages/sandbox/dist/client/assets/ibm-plex-mono-latin-ext-500-normal-CZ70TYgx.woff +0 -0
- package/packages/sandbox/dist/client/assets/ibm-plex-mono-vietnamese-400-normal-BulugwFq.woff2 +0 -0
- package/packages/sandbox/dist/client/assets/ibm-plex-mono-vietnamese-400-normal-DDuiU_S-.woff +0 -0
- package/packages/sandbox/dist/client/assets/ibm-plex-mono-vietnamese-500-normal-C8zxqsMH.woff +0 -0
- package/packages/sandbox/dist/client/assets/ibm-plex-mono-vietnamese-500-normal-DZ4AoWbu.woff2 +0 -0
- package/packages/sandbox/dist/client/assets/ibm-plex-sans-cyrillic-ext-wght-normal-d45eAU9y.woff2 +0 -0
- package/packages/sandbox/dist/client/assets/ibm-plex-sans-cyrillic-wght-normal-BAAhND-U.woff2 +0 -0
- package/packages/sandbox/dist/client/assets/ibm-plex-sans-greek-wght-normal-CmyJS8uq.woff2 +0 -0
- package/packages/sandbox/dist/client/assets/ibm-plex-sans-latin-ext-wght-normal-CIII54If.woff2 +0 -0
- package/packages/sandbox/dist/client/assets/ibm-plex-sans-latin-wght-normal-IvpUvPa2.woff2 +0 -0
- package/packages/sandbox/dist/client/assets/ibm-plex-sans-vietnamese-wght-normal-Dg1JeJN0.woff2 +0 -0
- package/packages/sandbox/dist/client/assets/index-CvwhlQ87.js +4 -0
- package/packages/sandbox/dist/client/assets/styles-BPWaGf55.js +3 -0
- package/packages/sandbox/dist/client/assets/styles-Dx1_KOag.css +1 -0
- package/packages/sandbox/dist/client/favicon.svg +1 -0
- package/packages/sandbox/dist/server/assets/auto-CVGNYyb3.js +12785 -0
- package/packages/sandbox/dist/server/assets/chunk-DDJLRBDX-3OUNo51g.js +4125 -0
- package/packages/sandbox/dist/server/assets/nodefs-DVSI7kG0.js +24 -0
- package/packages/sandbox/dist/server/assets/opfs-ahp-D56iokt1.js +388 -0
- package/packages/sandbox/dist/server/assets/token-Bvaq7Anz.js +55 -0
- package/packages/sandbox/dist/server/assets/token-util-BqSvdIPQ.js +3 -0
- package/packages/sandbox/dist/server/assets/token-util-CktFFT4z.js +494 -0
- package/packages/sandbox/dist/server/entry.js +91671 -0
- package/packages/sandbox/dist/server/favicon.svg +1 -0
- package/packages/sandbox/dist/server/index.html +161 -0
- package/packages/sandbox/index.html +159 -0
- package/packages/sandbox/octane.config.ts +36 -0
- package/packages/sandbox/package.json +83 -0
- package/packages/sandbox/public/favicon.svg +1 -0
- package/packages/sandbox/public/og.png +0 -0
- package/packages/sandbox/src/App.tsrx +924 -0
- package/packages/sandbox/src/client/ApprovalHandoff.tsrx +39 -0
- package/packages/sandbox/src/client/ChatPane.tsrx +694 -0
- package/packages/sandbox/src/client/ConnectView.tsrx +86 -0
- package/packages/sandbox/src/client/DiffPane.tsrx +150 -0
- package/packages/sandbox/src/client/EjectModal.tsrx +571 -0
- package/packages/sandbox/src/client/GateResults.tsrx +60 -0
- package/packages/sandbox/src/client/GitHubSettingsModal.tsrx +219 -0
- package/packages/sandbox/src/client/NewSessionForm.tsrx +214 -0
- package/packages/sandbox/src/client/SessionBar.tsrx +151 -0
- package/packages/sandbox/src/client/SessionPicker.tsrx +472 -0
- package/packages/sandbox/src/client/SpecEditor.tsrx +109 -0
- package/packages/sandbox/src/client/SpecReviewCard.tsrx +321 -0
- package/packages/sandbox/src/client/WorkCard.tsrx +128 -0
- package/packages/sandbox/src/client/WorkbenchModal.tsrx +161 -0
- package/packages/sandbox/src/client/WorkspaceMenu.tsrx +100 -0
- package/packages/sandbox/src/client/api.ts +797 -0
- package/packages/sandbox/src/client/attachments.ts +73 -0
- package/packages/sandbox/src/client/dashboard.ts +46 -0
- package/packages/sandbox/src/client/github-settings.ts +48 -0
- package/packages/sandbox/src/client/highlight.ts +105 -0
- package/packages/sandbox/src/client/i18n.ts +32 -0
- package/packages/sandbox/src/client/locales/en.json +466 -0
- package/packages/sandbox/src/client/locales/pl.json +466 -0
- package/packages/sandbox/src/client/session-labels.ts +77 -0
- package/packages/sandbox/src/client/state.ts +108 -0
- package/packages/sandbox/src/index.ts +10 -0
- package/packages/sandbox/src/preview/PreviewHost.tsrx +373 -0
- package/packages/sandbox/src/preview/load-module.ts +16 -0
- package/packages/sandbox/src/server/attachments.ts +308 -0
- package/packages/sandbox/src/server/auto-review.ts +181 -0
- package/packages/sandbox/src/server/checkpoints.ts +90 -0
- package/packages/sandbox/src/server/config.ts +460 -0
- package/packages/sandbox/src/server/dashboard.ts +245 -0
- package/packages/sandbox/src/server/delivery/configuration.ts +193 -0
- package/packages/sandbox/src/server/delivery/git-pr.ts +1473 -0
- package/packages/sandbox/src/server/delivery/index.ts +83 -0
- package/packages/sandbox/src/server/delivery/local.ts +151 -0
- package/packages/sandbox/src/server/delivery/official-modules.ts +516 -0
- package/packages/sandbox/src/server/delivery/plan.ts +218 -0
- package/packages/sandbox/src/server/delivery/policies.ts +239 -0
- package/packages/sandbox/src/server/delivery/record.ts +41 -0
- package/packages/sandbox/src/server/delivery/steps.ts +464 -0
- package/packages/sandbox/src/server/delivery/types.ts +158 -0
- package/packages/sandbox/src/server/dependencies.ts +88 -0
- package/packages/sandbox/src/server/diff.ts +230 -0
- package/packages/sandbox/src/server/gates.ts +388 -0
- package/packages/sandbox/src/server/index.ts +139 -0
- package/packages/sandbox/src/server/path-guard.ts +282 -0
- package/packages/sandbox/src/server/planning.ts +749 -0
- package/packages/sandbox/src/server/platform-client.ts +189 -0
- package/packages/sandbox/src/server/preview-database-host.ts +340 -0
- package/packages/sandbox/src/server/preview-database-protocol.ts +163 -0
- package/packages/sandbox/src/server/preview-database-proxy.ts +356 -0
- package/packages/sandbox/src/server/preview-database.ts +109 -0
- package/packages/sandbox/src/server/preview-ipc.ts +15 -0
- package/packages/sandbox/src/server/preview-modules.ts +83 -0
- package/packages/sandbox/src/server/preview-revision.ts +44 -0
- package/packages/sandbox/src/server/preview-runtime.ts +467 -0
- package/packages/sandbox/src/server/preview-worker-manager.ts +436 -0
- package/packages/sandbox/src/server/preview-worker.ts +168 -0
- package/packages/sandbox/src/server/reference.ts +251 -0
- package/packages/sandbox/src/server/routes.ts +2258 -0
- package/packages/sandbox/src/server/runtime.ts +188 -0
- package/packages/sandbox/src/server/session-owner.ts +23 -0
- package/packages/sandbox/src/server/sessions.ts +849 -0
- package/packages/sandbox/src/server/spec.ts +471 -0
- package/packages/sandbox/src/server/turn-lifecycle.ts +56 -0
- package/packages/sandbox/src/server/turns.ts +993 -0
- package/packages/sandbox/src/server/workspace-install.ts +266 -0
- package/packages/sandbox/src/server/workspace-root.ts +73 -0
- package/packages/sandbox/src/styles.css +1573 -0
- package/packages/sandbox/vite.config.ts +133 -0
- package/packages/server/package.json +43 -0
- package/packages/server/src/application-routes.ts +21 -0
- package/packages/server/src/composition.ts +48 -0
- package/packages/server/src/endpoint.ts +142 -0
- package/packages/server/src/http.ts +128 -0
- package/packages/server/src/index.ts +46 -0
- package/packages/server/src/response-lifetime.ts +56 -0
- package/packages/server/src/security-headers.ts +130 -0
- package/packages/server/src/web-html.ts +55 -0
- package/packages/server/src/web.ts +361 -0
- package/packages/ui/package.json +46 -0
- package/packages/ui/src/brand/BrandMark.tsrx +66 -0
- package/packages/ui/src/brand/mark.ts +44 -0
- package/packages/ui/src/components/Alert.tsrx +17 -0
- package/packages/ui/src/components/Avatar.tsrx +18 -0
- package/packages/ui/src/components/Button.tsrx +29 -0
- package/packages/ui/src/components/Chart.tsrx +274 -0
- package/packages/ui/src/components/CheckGrid.tsrx +93 -0
- package/packages/ui/src/components/ConfirmDialog.tsrx +63 -0
- package/packages/ui/src/components/Drawer.tsrx +71 -0
- package/packages/ui/src/components/EmptyState.tsrx +26 -0
- package/packages/ui/src/components/Filters.tsrx +39 -0
- package/packages/ui/src/components/FormField.tsrx +27 -0
- package/packages/ui/src/components/Kpi.tsrx +36 -0
- package/packages/ui/src/components/PageHeader.tsrx +26 -0
- package/packages/ui/src/components/ScopeSummary.tsrx +76 -0
- package/packages/ui/src/components/SearchField.tsrx +24 -0
- package/packages/ui/src/components/SettingRow.tsrx +50 -0
- package/packages/ui/src/components/Switch.tsrx +21 -0
- package/packages/ui/src/components/Table.tsrx +267 -0
- package/packages/ui/src/components/TableCard.tsrx +52 -0
- package/packages/ui/src/components/Tag.tsrx +28 -0
- package/packages/ui/src/components/VariableField.tsrx +284 -0
- package/packages/ui/src/components/VariableInput.tsrx +7 -0
- package/packages/ui/src/components/VariableSelect.tsrx +72 -0
- package/packages/ui/src/components/VariableTextarea.tsrx +9 -0
- package/packages/ui/src/components/variable-field.ts +61 -0
- package/packages/ui/src/components/variable-select.ts +69 -0
- package/packages/ui/src/icons/Icon.tsrx +56 -0
- package/packages/ui/src/index.ts +81 -0
- package/packages/ui/src/initials.ts +10 -0
- package/packages/ui/src/styles/base.css +71 -0
- package/packages/ui/src/styles/components.css +1859 -0
- package/packages/ui/src/styles/index.css +3 -0
- package/packages/ui/src/styles/tokens.css +124 -0
- package/tsconfig.base.json +18 -0
|
@@ -0,0 +1,2786 @@
|
|
|
1
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
2
|
+
import {
|
|
3
|
+
runDatabaseMigrations,
|
|
4
|
+
type DatabaseHandle,
|
|
5
|
+
type DatabaseTransaction,
|
|
6
|
+
} from '@flowdular/sdk/database';
|
|
7
|
+
import { normalizeActor, type Actor } from '@flowdular/sdk/kernel';
|
|
8
|
+
import type {
|
|
9
|
+
AgentExecutionDefinition,
|
|
10
|
+
AgentExecutionEvent,
|
|
11
|
+
AgentExecutionResult,
|
|
12
|
+
AgentOutputContract,
|
|
13
|
+
AgentUsage,
|
|
14
|
+
JsonValue,
|
|
15
|
+
} from '@flowdular/sdk/harness';
|
|
16
|
+
import { usageCostMicros } from '@flowdular/sdk/harness/catalog';
|
|
17
|
+
import type {
|
|
18
|
+
AgentAuditEvent,
|
|
19
|
+
AgentAuditPage,
|
|
20
|
+
AgentDefinition,
|
|
21
|
+
AgentDefinitionRevision,
|
|
22
|
+
AgentActionInvocation,
|
|
23
|
+
AgentRevisionProcedure,
|
|
24
|
+
ModuleAgentBinding,
|
|
25
|
+
ModuleAgentDefinition,
|
|
26
|
+
AgentProcedure,
|
|
27
|
+
AgentProcedureSnapshot,
|
|
28
|
+
AgentRun,
|
|
29
|
+
AgentRunDetail,
|
|
30
|
+
AgentRunExecution,
|
|
31
|
+
AgentUsageAgent,
|
|
32
|
+
AgentUsageBucket,
|
|
33
|
+
AgentUsageDay,
|
|
34
|
+
AuditChainVerification,
|
|
35
|
+
} from '../domain/types.ts';
|
|
36
|
+
import { databaseMigrations } from './migration.ts';
|
|
37
|
+
import type { EncryptedCredential } from './credential-vault.ts';
|
|
38
|
+
import {
|
|
39
|
+
DuplicateAgentKeyError,
|
|
40
|
+
DuplicateAgentProcedureKeyError,
|
|
41
|
+
DuplicateActionIdempotencyKeyError,
|
|
42
|
+
DuplicateRunIdempotencyKeyError,
|
|
43
|
+
ModuleAgentBindingConflictError,
|
|
44
|
+
type AgentRepository,
|
|
45
|
+
type PendingAgentAuditEvent,
|
|
46
|
+
type RecoverableRun,
|
|
47
|
+
} from './repository.ts';
|
|
48
|
+
import { usageDay } from './usage-service.ts';
|
|
49
|
+
import { moduleAgentDefinitionHash } from '../server/define-agent.ts';
|
|
50
|
+
|
|
51
|
+
interface AgentRow {
|
|
52
|
+
id: string;
|
|
53
|
+
tenant_id: string;
|
|
54
|
+
agent_key: string;
|
|
55
|
+
name: string;
|
|
56
|
+
description: string;
|
|
57
|
+
instructions: string;
|
|
58
|
+
provider: string;
|
|
59
|
+
model: string;
|
|
60
|
+
allowed_tools_json: string;
|
|
61
|
+
max_steps: number;
|
|
62
|
+
timeout_ms: number | string;
|
|
63
|
+
temperature_milli: number;
|
|
64
|
+
max_output_tokens: number | string;
|
|
65
|
+
status: AgentDefinition['status'];
|
|
66
|
+
revision: number;
|
|
67
|
+
created_by: string;
|
|
68
|
+
created_at: number | string;
|
|
69
|
+
updated_by: string;
|
|
70
|
+
updated_at: number | string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
interface RunRow {
|
|
74
|
+
id: string;
|
|
75
|
+
tenant_id: string;
|
|
76
|
+
agent_id: string;
|
|
77
|
+
agent_name: string;
|
|
78
|
+
agent_revision: number;
|
|
79
|
+
instructions_snapshot: string;
|
|
80
|
+
provider: string;
|
|
81
|
+
model: string;
|
|
82
|
+
allowed_tools_json: string;
|
|
83
|
+
max_steps: number;
|
|
84
|
+
timeout_ms: number | string;
|
|
85
|
+
temperature_milli: number;
|
|
86
|
+
max_output_tokens: number | string;
|
|
87
|
+
trigger: AgentRun['trigger'];
|
|
88
|
+
status: AgentRun['status'];
|
|
89
|
+
input: string;
|
|
90
|
+
output: string | null;
|
|
91
|
+
structured_output_json: string | null;
|
|
92
|
+
output_contract_json: string;
|
|
93
|
+
workflow_run_id: string | null;
|
|
94
|
+
request_hash: string;
|
|
95
|
+
requested_by: string;
|
|
96
|
+
requested_actor_json: string;
|
|
97
|
+
authorization_subject_json: string | null;
|
|
98
|
+
permission_snapshot_json: string;
|
|
99
|
+
tool_grants_json: string;
|
|
100
|
+
usage_json: string | null;
|
|
101
|
+
failure_code: string | null;
|
|
102
|
+
failure_message: string | null;
|
|
103
|
+
attempt: number;
|
|
104
|
+
queued_at: number | string;
|
|
105
|
+
started_at: number | string | null;
|
|
106
|
+
completed_at: number | string | null;
|
|
107
|
+
lease_expires_at: number | string | null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
interface AgentRevisionRow {
|
|
111
|
+
tenant_id: string;
|
|
112
|
+
agent_id: string;
|
|
113
|
+
revision: number;
|
|
114
|
+
agent_key: string;
|
|
115
|
+
name: string;
|
|
116
|
+
description: string;
|
|
117
|
+
instructions: string;
|
|
118
|
+
provider: string;
|
|
119
|
+
model: string;
|
|
120
|
+
allowed_tools_json: string;
|
|
121
|
+
skills_json: string;
|
|
122
|
+
max_steps: number;
|
|
123
|
+
timeout_ms: number | string;
|
|
124
|
+
temperature_milli: number;
|
|
125
|
+
max_output_tokens: number | string;
|
|
126
|
+
status: AgentDefinition['status'];
|
|
127
|
+
retained_by: string;
|
|
128
|
+
retained_at: number | string;
|
|
129
|
+
module_id: string | null;
|
|
130
|
+
module_definition_revision: number | null;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
interface ModuleAgentDefinitionRow {
|
|
134
|
+
agent_id: string;
|
|
135
|
+
module_id: string;
|
|
136
|
+
agent_key: string;
|
|
137
|
+
definition_revision: number;
|
|
138
|
+
content_hash: string;
|
|
139
|
+
name: string;
|
|
140
|
+
description: string;
|
|
141
|
+
instructions: string;
|
|
142
|
+
allowed_tools_json: string;
|
|
143
|
+
max_steps: number;
|
|
144
|
+
timeout_ms: number | string;
|
|
145
|
+
temperature_milli: number;
|
|
146
|
+
max_output_tokens: number | string;
|
|
147
|
+
registered_at: number | string;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
interface ModuleAgentBindingRow {
|
|
151
|
+
tenant_id: string;
|
|
152
|
+
agent_id: string;
|
|
153
|
+
provider: string;
|
|
154
|
+
model: string;
|
|
155
|
+
enabled_tools_json: string;
|
|
156
|
+
status: ModuleAgentBinding['status'];
|
|
157
|
+
module_definition_revision: number;
|
|
158
|
+
executable_revision: number;
|
|
159
|
+
revision: number;
|
|
160
|
+
updated_by: string;
|
|
161
|
+
updated_at: number | string;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
interface ActionRow {
|
|
165
|
+
id: string;
|
|
166
|
+
tenant_id: string;
|
|
167
|
+
workflow_run_id: string;
|
|
168
|
+
node_run_id: string;
|
|
169
|
+
action_id: string;
|
|
170
|
+
contract_version: number;
|
|
171
|
+
actor_json: string;
|
|
172
|
+
authorization_subject_json: string | null;
|
|
173
|
+
permission_snapshot_json: string;
|
|
174
|
+
input_json: string;
|
|
175
|
+
idempotency_key: string;
|
|
176
|
+
request_hash: string;
|
|
177
|
+
status: AgentActionInvocation['status'];
|
|
178
|
+
output_json: string | null;
|
|
179
|
+
failure_code: string | null;
|
|
180
|
+
attempt: number;
|
|
181
|
+
queued_at: number | string;
|
|
182
|
+
started_at: number | string | null;
|
|
183
|
+
completed_at: number | string | null;
|
|
184
|
+
lease_expires_at: number | string | null;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
interface RunEventRow {
|
|
188
|
+
sequence: number | string;
|
|
189
|
+
event_type: AgentExecutionEvent['type'];
|
|
190
|
+
message: string;
|
|
191
|
+
metadata_json: string;
|
|
192
|
+
occurred_at: number | string;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
interface AuditRow {
|
|
196
|
+
id: string;
|
|
197
|
+
tenant_id: string;
|
|
198
|
+
sequence: number | string;
|
|
199
|
+
actor_id: string;
|
|
200
|
+
action: string;
|
|
201
|
+
subject_type: AgentAuditEvent['subjectType'];
|
|
202
|
+
subject_id: string;
|
|
203
|
+
metadata_json: string;
|
|
204
|
+
occurred_at: number | string;
|
|
205
|
+
previous_hash: string | null;
|
|
206
|
+
event_hash: string;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
interface RecoverableRow {
|
|
210
|
+
tenant_id: string;
|
|
211
|
+
id: string;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
interface SkillRow {
|
|
215
|
+
id: string;
|
|
216
|
+
tenant_id: string;
|
|
217
|
+
skill_key: string;
|
|
218
|
+
name: string;
|
|
219
|
+
description: string;
|
|
220
|
+
instructions: string;
|
|
221
|
+
required_tools_json: string;
|
|
222
|
+
status: AgentProcedure['status'];
|
|
223
|
+
revision: number;
|
|
224
|
+
created_by: string;
|
|
225
|
+
created_at: number | string;
|
|
226
|
+
updated_by: string;
|
|
227
|
+
updated_at: number | string;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
interface SkillSnapshotRow {
|
|
231
|
+
skill_id: string;
|
|
232
|
+
skill_key: string;
|
|
233
|
+
skill_name: string;
|
|
234
|
+
skill_revision: number;
|
|
235
|
+
required_tools_json: string;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
interface UsageRow {
|
|
239
|
+
day: string;
|
|
240
|
+
agent_id: string;
|
|
241
|
+
agent_name: string;
|
|
242
|
+
runs: number | string;
|
|
243
|
+
input_tokens: number | string;
|
|
244
|
+
output_tokens: number | string;
|
|
245
|
+
cost_micro_usd: number | string | null;
|
|
246
|
+
unpriced_runs: number | string;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function stringArray(value: string): readonly string[] {
|
|
250
|
+
const parsed: unknown = JSON.parse(value);
|
|
251
|
+
if (
|
|
252
|
+
!Array.isArray(parsed) ||
|
|
253
|
+
parsed.some((item) => typeof item !== 'string')
|
|
254
|
+
) {
|
|
255
|
+
throw new Error('Stored string array is invalid.');
|
|
256
|
+
}
|
|
257
|
+
return parsed as string[];
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function usage(value: string | null): AgentUsage | null {
|
|
261
|
+
return value === null ? null : (JSON.parse(value) as AgentUsage);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function jsonValue(value: string | null): JsonValue | null {
|
|
265
|
+
return value === null ? null : (JSON.parse(value) as JsonValue);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function metadata(
|
|
269
|
+
value: string,
|
|
270
|
+
): Readonly<Record<string, string | number | boolean>> {
|
|
271
|
+
return JSON.parse(value) as Record<string, string | number | boolean>;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function stableMetadata(
|
|
275
|
+
value: Readonly<Record<string, string | number | boolean>>,
|
|
276
|
+
): string {
|
|
277
|
+
return JSON.stringify(
|
|
278
|
+
Object.fromEntries(
|
|
279
|
+
Object.entries(value).sort(([left], [right]) =>
|
|
280
|
+
left.localeCompare(right),
|
|
281
|
+
),
|
|
282
|
+
),
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function fromAgentRow(row: AgentRow): AgentDefinition {
|
|
287
|
+
return {
|
|
288
|
+
id: row.id,
|
|
289
|
+
tenantId: row.tenant_id,
|
|
290
|
+
key: row.agent_key,
|
|
291
|
+
name: row.name,
|
|
292
|
+
description: row.description,
|
|
293
|
+
instructions: row.instructions,
|
|
294
|
+
provider: row.provider,
|
|
295
|
+
model: row.model,
|
|
296
|
+
allowedTools: stringArray(row.allowed_tools_json),
|
|
297
|
+
procedureIds: [],
|
|
298
|
+
maxSteps: row.max_steps,
|
|
299
|
+
timeoutMs: integer(row.timeout_ms),
|
|
300
|
+
temperature: row.temperature_milli / 1_000,
|
|
301
|
+
maxOutputTokens: integer(row.max_output_tokens),
|
|
302
|
+
status: row.status,
|
|
303
|
+
revision: row.revision,
|
|
304
|
+
createdBy: row.created_by,
|
|
305
|
+
createdAt: integer(row.created_at),
|
|
306
|
+
updatedBy: row.updated_by,
|
|
307
|
+
updatedAt: integer(row.updated_at),
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function fromRunRow(row: RunRow): AgentRun {
|
|
312
|
+
const requestedActor = normalizeActor(
|
|
313
|
+
JSON.parse(row.requested_actor_json) as Actor,
|
|
314
|
+
);
|
|
315
|
+
if (!requestedActor) throw new Error('Stored agent run actor is invalid.');
|
|
316
|
+
return {
|
|
317
|
+
id: row.id,
|
|
318
|
+
tenantId: row.tenant_id,
|
|
319
|
+
agentId: row.agent_id,
|
|
320
|
+
agentName: row.agent_name,
|
|
321
|
+
agentRevision: row.agent_revision,
|
|
322
|
+
trigger: row.trigger,
|
|
323
|
+
status: row.status,
|
|
324
|
+
input: row.input,
|
|
325
|
+
output: row.output,
|
|
326
|
+
structuredOutput: jsonValue(row.structured_output_json),
|
|
327
|
+
outputContract: JSON.parse(row.output_contract_json) as AgentOutputContract,
|
|
328
|
+
workflowRunId: row.workflow_run_id,
|
|
329
|
+
provider: row.provider,
|
|
330
|
+
model: row.model,
|
|
331
|
+
requestedBy: row.requested_by,
|
|
332
|
+
requestedActor,
|
|
333
|
+
authorizationSubject:
|
|
334
|
+
row.authorization_subject_json === null
|
|
335
|
+
? null
|
|
336
|
+
: (JSON.parse(
|
|
337
|
+
row.authorization_subject_json,
|
|
338
|
+
) as AgentRun['authorizationSubject']),
|
|
339
|
+
permissionSnapshot: stringArray(row.permission_snapshot_json),
|
|
340
|
+
toolGrants: stringArray(row.tool_grants_json),
|
|
341
|
+
procedureSnapshots: [],
|
|
342
|
+
usage: usage(row.usage_json),
|
|
343
|
+
failureCode: row.failure_code,
|
|
344
|
+
failureMessage: row.failure_message,
|
|
345
|
+
attempt: row.attempt,
|
|
346
|
+
queuedAt: integer(row.queued_at),
|
|
347
|
+
startedAt: integerOrNull(row.started_at),
|
|
348
|
+
completedAt: integerOrNull(row.completed_at),
|
|
349
|
+
leaseExpiresAt: integerOrNull(row.lease_expires_at),
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function fromRevisionRow(row: AgentRevisionRow): AgentDefinitionRevision {
|
|
354
|
+
return {
|
|
355
|
+
tenantId: row.tenant_id,
|
|
356
|
+
agentId: row.agent_id,
|
|
357
|
+
revision: row.revision,
|
|
358
|
+
key: row.agent_key,
|
|
359
|
+
name: row.name,
|
|
360
|
+
description: row.description,
|
|
361
|
+
instructions: row.instructions,
|
|
362
|
+
provider: row.provider,
|
|
363
|
+
model: row.model,
|
|
364
|
+
allowedTools: stringArray(row.allowed_tools_json),
|
|
365
|
+
procedures: JSON.parse(row.skills_json) as AgentRevisionProcedure[],
|
|
366
|
+
maxSteps: row.max_steps,
|
|
367
|
+
timeoutMs: integer(row.timeout_ms),
|
|
368
|
+
temperature: row.temperature_milli / 1_000,
|
|
369
|
+
maxOutputTokens: integer(row.max_output_tokens),
|
|
370
|
+
status: row.status,
|
|
371
|
+
ownership:
|
|
372
|
+
row.module_id === null
|
|
373
|
+
? { kind: 'tenant' }
|
|
374
|
+
: {
|
|
375
|
+
kind: 'module',
|
|
376
|
+
moduleId: row.module_id,
|
|
377
|
+
definitionRevision: row.module_definition_revision!,
|
|
378
|
+
},
|
|
379
|
+
moduleDefinitionRevision: row.module_definition_revision,
|
|
380
|
+
retainedBy: row.retained_by,
|
|
381
|
+
retainedAt: integer(row.retained_at),
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function fromModuleBindingRow(row: ModuleAgentBindingRow): ModuleAgentBinding {
|
|
386
|
+
return {
|
|
387
|
+
tenantId: row.tenant_id,
|
|
388
|
+
agentId: row.agent_id,
|
|
389
|
+
provider: row.provider,
|
|
390
|
+
model: row.model,
|
|
391
|
+
enabledTools: stringArray(row.enabled_tools_json),
|
|
392
|
+
status: row.status,
|
|
393
|
+
moduleDefinitionRevision: row.module_definition_revision,
|
|
394
|
+
executableRevision: row.executable_revision,
|
|
395
|
+
revision: row.revision,
|
|
396
|
+
updatedBy: row.updated_by,
|
|
397
|
+
updatedAt: integer(row.updated_at),
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function fromActionRow(row: ActionRow): AgentActionInvocation {
|
|
402
|
+
return {
|
|
403
|
+
id: row.id,
|
|
404
|
+
tenantId: row.tenant_id,
|
|
405
|
+
workflowRunId: row.workflow_run_id,
|
|
406
|
+
nodeRunId: row.node_run_id,
|
|
407
|
+
actionId: row.action_id,
|
|
408
|
+
contractVersion: row.contract_version,
|
|
409
|
+
actor: JSON.parse(row.actor_json) as AgentActionInvocation['actor'],
|
|
410
|
+
authorizationSubject:
|
|
411
|
+
row.authorization_subject_json === null
|
|
412
|
+
? null
|
|
413
|
+
: (JSON.parse(
|
|
414
|
+
row.authorization_subject_json,
|
|
415
|
+
) as AgentActionInvocation['authorizationSubject']),
|
|
416
|
+
permissionSnapshot: stringArray(row.permission_snapshot_json),
|
|
417
|
+
input: JSON.parse(row.input_json) as JsonValue,
|
|
418
|
+
idempotencyKey: row.idempotency_key,
|
|
419
|
+
requestHash: row.request_hash,
|
|
420
|
+
status: row.status,
|
|
421
|
+
output: jsonValue(row.output_json),
|
|
422
|
+
code: row.failure_code,
|
|
423
|
+
attempt: row.attempt,
|
|
424
|
+
queuedAt: integer(row.queued_at),
|
|
425
|
+
startedAt: integerOrNull(row.started_at),
|
|
426
|
+
completedAt: integerOrNull(row.completed_at),
|
|
427
|
+
leaseExpiresAt: integerOrNull(row.lease_expires_at),
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
function fromSkillRow(row: SkillRow): AgentProcedure {
|
|
432
|
+
return {
|
|
433
|
+
id: row.id,
|
|
434
|
+
tenantId: row.tenant_id,
|
|
435
|
+
key: row.skill_key,
|
|
436
|
+
name: row.name,
|
|
437
|
+
description: row.description,
|
|
438
|
+
instructions: row.instructions,
|
|
439
|
+
requiredTools: stringArray(row.required_tools_json),
|
|
440
|
+
status: row.status,
|
|
441
|
+
revision: row.revision,
|
|
442
|
+
createdBy: row.created_by,
|
|
443
|
+
createdAt: integer(row.created_at),
|
|
444
|
+
updatedBy: row.updated_by,
|
|
445
|
+
updatedAt: integer(row.updated_at),
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function executionFromRow(row: RunRow): AgentRunExecution {
|
|
450
|
+
const definition: AgentExecutionDefinition = {
|
|
451
|
+
id: row.agent_id,
|
|
452
|
+
name: row.agent_name,
|
|
453
|
+
revision: row.agent_revision,
|
|
454
|
+
instructions: row.instructions_snapshot,
|
|
455
|
+
provider: row.provider,
|
|
456
|
+
model: row.model,
|
|
457
|
+
allowedTools: stringArray(row.allowed_tools_json),
|
|
458
|
+
maxSteps: row.max_steps,
|
|
459
|
+
timeoutMs: integer(row.timeout_ms),
|
|
460
|
+
temperature: row.temperature_milli / 1_000,
|
|
461
|
+
maxOutputTokens: integer(row.max_output_tokens),
|
|
462
|
+
};
|
|
463
|
+
return { run: fromRunRow(row), definition };
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/* SUM() over BIGINT is NUMERIC in PostgreSQL, and the driver hands NUMERIC
|
|
467
|
+
back as a string. Aggregates leave this repository as numbers. */
|
|
468
|
+
function integer(value: number | string | null): number {
|
|
469
|
+
return typeof value === 'number' ? value : Number(value ?? 0);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/* A nullable BIGINT must stay null: coercing it to 0 would turn "never started"
|
|
473
|
+
into "started at the epoch". */
|
|
474
|
+
function integerOrNull(value: number | string | null): number | null {
|
|
475
|
+
return value === null ? null : integer(value);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
function fromUsageRow(row: UsageRow): AgentUsageBucket {
|
|
479
|
+
return {
|
|
480
|
+
runs: integer(row.runs),
|
|
481
|
+
inputTokens: integer(row.input_tokens),
|
|
482
|
+
outputTokens: integer(row.output_tokens),
|
|
483
|
+
costMicroUsd: integer(row.cost_micro_usd),
|
|
484
|
+
unpricedRuns: integer(row.unpriced_runs),
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
const USAGE_COLUMNS = `COUNT(*) AS runs,
|
|
489
|
+
COALESCE(SUM(input_tokens), 0) AS input_tokens,
|
|
490
|
+
COALESCE(SUM(output_tokens), 0) AS output_tokens,
|
|
491
|
+
COALESCE(SUM(cost_micro_usd), 0) AS cost_micro_usd,
|
|
492
|
+
SUM(CASE WHEN cost_micro_usd IS NULL THEN 1 ELSE 0 END) AS unpriced_runs`;
|
|
493
|
+
|
|
494
|
+
function fromAuditRow(row: AuditRow): AgentAuditEvent {
|
|
495
|
+
return {
|
|
496
|
+
id: row.id,
|
|
497
|
+
tenantId: row.tenant_id,
|
|
498
|
+
sequence: integer(row.sequence),
|
|
499
|
+
actorId: row.actor_id,
|
|
500
|
+
action: row.action,
|
|
501
|
+
subjectType: row.subject_type,
|
|
502
|
+
subjectId: row.subject_id,
|
|
503
|
+
metadata: metadata(row.metadata_json),
|
|
504
|
+
occurredAt: integer(row.occurred_at),
|
|
505
|
+
previousHash: row.previous_hash,
|
|
506
|
+
eventHash: row.event_hash,
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
function auditHash(value: {
|
|
511
|
+
tenantId: string;
|
|
512
|
+
sequence: number;
|
|
513
|
+
actorId: string;
|
|
514
|
+
action: string;
|
|
515
|
+
subjectType: AgentAuditEvent['subjectType'];
|
|
516
|
+
subjectId: string;
|
|
517
|
+
metadataJson: string;
|
|
518
|
+
occurredAt: number;
|
|
519
|
+
previousHash: string | null;
|
|
520
|
+
}): string {
|
|
521
|
+
return createHash('sha256')
|
|
522
|
+
.update(
|
|
523
|
+
JSON.stringify([
|
|
524
|
+
value.tenantId,
|
|
525
|
+
value.sequence,
|
|
526
|
+
value.actorId,
|
|
527
|
+
value.action,
|
|
528
|
+
value.subjectType,
|
|
529
|
+
value.subjectId,
|
|
530
|
+
value.metadataJson,
|
|
531
|
+
value.occurredAt,
|
|
532
|
+
value.previousHash,
|
|
533
|
+
]),
|
|
534
|
+
)
|
|
535
|
+
.digest('hex');
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
const DEFAULT_MAX_OUTPUT_TOKENS = 4_096;
|
|
539
|
+
|
|
540
|
+
const RUN_COLUMNS = `agent_runs.id, agent_runs.tenant_id, agent_id, agent_name, agent_revision,
|
|
541
|
+
instructions_snapshot, provider, model, allowed_tools_json, max_steps,
|
|
542
|
+
COALESCE(agent_run_execution_limits.timeout_ms, agent_runs.timeout_ms) AS timeout_ms,
|
|
543
|
+
temperature_milli,
|
|
544
|
+
COALESCE(agent_run_output_limits.max_output_tokens, ${DEFAULT_MAX_OUTPUT_TOKENS}) AS max_output_tokens,
|
|
545
|
+
trigger, status, input, output, requested_by,
|
|
546
|
+
permission_snapshot_json, tool_grants_json, usage_json, failure_code,
|
|
547
|
+
failure_message, attempt, queued_at, started_at, completed_at, lease_expires_at,
|
|
548
|
+
agent_run_contracts.structured_output_json,
|
|
549
|
+
COALESCE(agent_run_contracts.output_contract_json, '{"kind":"text"}') AS output_contract_json,
|
|
550
|
+
agent_run_contracts.workflow_run_id,
|
|
551
|
+
COALESCE(agent_run_contracts.request_hash, '') AS request_hash,
|
|
552
|
+
agent_run_actors.actor_json AS requested_actor_json,
|
|
553
|
+
agent_run_actors.authorization_subject_json`;
|
|
554
|
+
const RUN_FROM = `agent_runs LEFT JOIN agent_run_execution_limits
|
|
555
|
+
ON agent_run_execution_limits.run_id = agent_runs.id
|
|
556
|
+
LEFT JOIN agent_run_output_limits
|
|
557
|
+
ON agent_run_output_limits.run_id = agent_runs.id
|
|
558
|
+
LEFT JOIN agent_run_contracts ON agent_run_contracts.run_id = agent_runs.id
|
|
559
|
+
JOIN agent_run_actors ON agent_run_actors.run_id = agent_runs.id
|
|
560
|
+
AND agent_run_actors.tenant_id = agent_runs.tenant_id`;
|
|
561
|
+
const AGENT_SELECT = `SELECT agent_definitions.*,
|
|
562
|
+
COALESCE(agent_definition_execution_limits.timeout_ms,
|
|
563
|
+
agent_definitions.timeout_ms) AS timeout_ms,
|
|
564
|
+
COALESCE(agent_definition_output_limits.max_output_tokens,
|
|
565
|
+
${DEFAULT_MAX_OUTPUT_TOKENS}) AS max_output_tokens
|
|
566
|
+
FROM agent_definitions LEFT JOIN agent_definition_execution_limits
|
|
567
|
+
ON agent_definition_execution_limits.agent_id = agent_definitions.id
|
|
568
|
+
LEFT JOIN agent_definition_output_limits
|
|
569
|
+
ON agent_definition_output_limits.agent_id = agent_definitions.id`;
|
|
570
|
+
const AGENT_REVISION_SELECT = `SELECT agent_definition_revisions.*,
|
|
571
|
+
agent_revision_ownership.module_id,
|
|
572
|
+
agent_revision_ownership.module_definition_revision
|
|
573
|
+
FROM agent_definition_revisions
|
|
574
|
+
LEFT JOIN agent_revision_ownership
|
|
575
|
+
ON agent_revision_ownership.tenant_id = agent_definition_revisions.tenant_id
|
|
576
|
+
AND agent_revision_ownership.agent_id = agent_definition_revisions.agent_id
|
|
577
|
+
AND agent_revision_ownership.revision = agent_definition_revisions.revision`;
|
|
578
|
+
|
|
579
|
+
export interface AgentsPersistenceStatements {
|
|
580
|
+
readonly procedureIds: string;
|
|
581
|
+
readonly procedureSnapshots: string;
|
|
582
|
+
readonly setAgentSkills1: string;
|
|
583
|
+
readonly setAgentSkills2: string;
|
|
584
|
+
readonly revisionSkills: string;
|
|
585
|
+
readonly retainAgentRevision1: string;
|
|
586
|
+
readonly retainAgentRevision2: string;
|
|
587
|
+
readonly listAgentsForRevisionAdoption: string;
|
|
588
|
+
readonly retainModuleAgentRevision1: string;
|
|
589
|
+
readonly retainModuleAgentRevision2: string;
|
|
590
|
+
readonly reconcileModuleAgents1: string;
|
|
591
|
+
readonly reconcileModuleAgents2: string;
|
|
592
|
+
readonly reconcileModuleAgents3: string;
|
|
593
|
+
readonly reconcileModuleAgents4: string;
|
|
594
|
+
readonly reconcileModuleAgents5: string;
|
|
595
|
+
readonly reconcileModuleAgents6: string;
|
|
596
|
+
readonly listModuleAgentBindings: string;
|
|
597
|
+
readonly getModuleAgentBinding: string;
|
|
598
|
+
readonly saveModuleAgentBinding1: string;
|
|
599
|
+
readonly saveModuleAgentBinding2: string;
|
|
600
|
+
readonly saveModuleAgentBinding3: string;
|
|
601
|
+
readonly listAgents: string;
|
|
602
|
+
readonly providerUsage1: string;
|
|
603
|
+
readonly providerUsage2: string;
|
|
604
|
+
readonly agentUsage: string;
|
|
605
|
+
readonly getAgent: string;
|
|
606
|
+
readonly getAgentRevision: string;
|
|
607
|
+
readonly listAgentRevisions: string;
|
|
608
|
+
readonly createAgent1: string;
|
|
609
|
+
readonly createAgent2: string;
|
|
610
|
+
readonly createAgent3: string;
|
|
611
|
+
readonly updateAgent1: string;
|
|
612
|
+
readonly updateAgent2: string;
|
|
613
|
+
readonly updateAgent3: string;
|
|
614
|
+
readonly deleteAgent: string;
|
|
615
|
+
readonly listProcedures: string;
|
|
616
|
+
readonly getProcedure: string;
|
|
617
|
+
readonly createProcedure: string;
|
|
618
|
+
readonly updateProcedure: string;
|
|
619
|
+
readonly procedureUsage: string;
|
|
620
|
+
readonly deleteProcedure: string;
|
|
621
|
+
readonly listRuns: string;
|
|
622
|
+
readonly getRun: string;
|
|
623
|
+
readonly listRunEvents: string;
|
|
624
|
+
readonly findRunByIdempotencyKey: string;
|
|
625
|
+
readonly enqueueRun1: string;
|
|
626
|
+
readonly enqueueRun2: string;
|
|
627
|
+
readonly enqueueRun3: string;
|
|
628
|
+
readonly enqueueRun4: string;
|
|
629
|
+
readonly enqueueRun5: string;
|
|
630
|
+
readonly enqueueRun6: string;
|
|
631
|
+
readonly listRecoverableRuns: string;
|
|
632
|
+
readonly claimRun1: string;
|
|
633
|
+
readonly claimRun2: string;
|
|
634
|
+
readonly renewLease: string;
|
|
635
|
+
readonly consumeRunGrant1: string;
|
|
636
|
+
readonly consumeRunGrant2: string;
|
|
637
|
+
readonly appendRunEvent: string;
|
|
638
|
+
readonly completeRun1: string;
|
|
639
|
+
readonly completeRun2: string;
|
|
640
|
+
readonly completeRun3: string;
|
|
641
|
+
readonly completeRun4: string;
|
|
642
|
+
readonly failRun: string;
|
|
643
|
+
readonly cancelRun1: string;
|
|
644
|
+
readonly cancelRun2: string;
|
|
645
|
+
readonly enqueueAction: string;
|
|
646
|
+
readonly getAction: string;
|
|
647
|
+
readonly findActionByIdempotencyKey: string;
|
|
648
|
+
readonly listRecoverableActions: string;
|
|
649
|
+
readonly claimAction: string;
|
|
650
|
+
readonly renewActionLease: string;
|
|
651
|
+
readonly completeAction: string;
|
|
652
|
+
readonly failAction: string;
|
|
653
|
+
readonly cancelAction: string;
|
|
654
|
+
readonly appendAuditEvent1: string;
|
|
655
|
+
readonly appendAuditEvent2: string;
|
|
656
|
+
readonly listAuditEvents: string;
|
|
657
|
+
readonly pageAuditEvents1: string;
|
|
658
|
+
readonly pageAuditEvents2: string;
|
|
659
|
+
readonly verifyAuditChainDetailed: string;
|
|
660
|
+
readonly usageByDay: string;
|
|
661
|
+
readonly usageByAgent: string;
|
|
662
|
+
readonly usageTotal1: string;
|
|
663
|
+
readonly usageTotal2: string;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
/* Every statement is PostgreSQL; the platform has no second dialect. */
|
|
667
|
+
export const AGENTS_SQL: AgentsPersistenceStatements = Object.freeze({
|
|
668
|
+
procedureIds: `SELECT skill_id FROM agent_skill_assignments
|
|
669
|
+
WHERE tenant_id = $1 AND agent_id = $2 ORDER BY skill_id`,
|
|
670
|
+
procedureSnapshots: `SELECT * FROM agent_run_skill_snapshots
|
|
671
|
+
WHERE tenant_id = $1 AND run_id = $2 ORDER BY skill_key, skill_id`,
|
|
672
|
+
setAgentSkills1: `DELETE FROM agent_skill_assignments WHERE agent_id = $1`,
|
|
673
|
+
setAgentSkills2: `INSERT INTO agent_skill_assignments (agent_id, skill_id, tenant_id)
|
|
674
|
+
VALUES ($1, $2, $3)`,
|
|
675
|
+
revisionSkills: `SELECT agent_skills.id, agent_skills.skill_key, agent_skills.name,
|
|
676
|
+
agent_skills.revision, agent_skills.instructions,
|
|
677
|
+
agent_skills.required_tools_json
|
|
678
|
+
FROM agent_skill_assignments JOIN agent_skills
|
|
679
|
+
ON agent_skills.id = agent_skill_assignments.skill_id
|
|
680
|
+
AND agent_skills.tenant_id = agent_skill_assignments.tenant_id
|
|
681
|
+
WHERE agent_skill_assignments.tenant_id = $1
|
|
682
|
+
AND agent_skill_assignments.agent_id = $2
|
|
683
|
+
ORDER BY agent_skills.skill_key, agent_skills.id`,
|
|
684
|
+
retainAgentRevision1: `INSERT INTO agent_definition_revisions
|
|
685
|
+
(tenant_id, agent_id, revision, agent_key, name, description,
|
|
686
|
+
instructions, provider, model, allowed_tools_json, skills_json,
|
|
687
|
+
max_steps, timeout_ms, temperature_milli, max_output_tokens,
|
|
688
|
+
status, retained_by, retained_at)
|
|
689
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18)
|
|
690
|
+
ON CONFLICT DO NOTHING`,
|
|
691
|
+
retainAgentRevision2: `INSERT INTO agent_definition_revisions
|
|
692
|
+
(tenant_id, agent_id, revision, agent_key, name, description,
|
|
693
|
+
instructions, provider, model, allowed_tools_json, skills_json,
|
|
694
|
+
max_steps, timeout_ms, temperature_milli, max_output_tokens,
|
|
695
|
+
status, retained_by, retained_at)
|
|
696
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18)`,
|
|
697
|
+
listAgentsForRevisionAdoption: `${AGENT_SELECT}
|
|
698
|
+
WHERE agent_definitions.tenant_id = $1
|
|
699
|
+
ORDER BY agent_definitions.tenant_id, agent_definitions.id`,
|
|
700
|
+
retainModuleAgentRevision1: `INSERT INTO agent_definition_revisions
|
|
701
|
+
(tenant_id, agent_id, revision, agent_key, name, description,
|
|
702
|
+
instructions, provider, model, allowed_tools_json, skills_json,
|
|
703
|
+
max_steps, timeout_ms, temperature_milli, max_output_tokens,
|
|
704
|
+
status, retained_by, retained_at)
|
|
705
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, '[]', $11, $12, $13, $14, 'active', $15, $16)`,
|
|
706
|
+
retainModuleAgentRevision2: `INSERT INTO agent_revision_ownership
|
|
707
|
+
(tenant_id, agent_id, revision, module_id, module_definition_revision)
|
|
708
|
+
VALUES ($1, $2, $3, $4, $5)`,
|
|
709
|
+
reconcileModuleAgents1: `SELECT * FROM module_agent_definitions WHERE agent_id = $1`,
|
|
710
|
+
reconcileModuleAgents2: `INSERT INTO agent_definitions
|
|
711
|
+
(id, tenant_id, agent_key, name, description, instructions,
|
|
712
|
+
provider, model, allowed_tools_json, max_steps, timeout_ms,
|
|
713
|
+
temperature_milli, status, revision, created_by, created_at,
|
|
714
|
+
updated_by, updated_at)
|
|
715
|
+
VALUES ($1, '__flowdular_module_agents__', $2, $3, $4, $5,
|
|
716
|
+
'local-simulation', 'deterministic-v1', $6, $7, $8, $9, 'archived',
|
|
717
|
+
$10, $11, $12, $13, $14)`,
|
|
718
|
+
reconcileModuleAgents3: `UPDATE agent_definitions SET name = $1, description = $2,
|
|
719
|
+
instructions = $3, allowed_tools_json = $4, max_steps = $5,
|
|
720
|
+
timeout_ms = $6, temperature_milli = $7, revision = $8,
|
|
721
|
+
updated_by = $9, updated_at = $10 WHERE id = $11`,
|
|
722
|
+
reconcileModuleAgents4: `INSERT INTO module_agent_definitions
|
|
723
|
+
(agent_id, module_id, agent_key, definition_revision, content_hash,
|
|
724
|
+
name, description, instructions, allowed_tools_json, max_steps,
|
|
725
|
+
timeout_ms, temperature_milli, max_output_tokens, registered_at)
|
|
726
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)
|
|
727
|
+
ON CONFLICT(agent_id) DO UPDATE SET
|
|
728
|
+
definition_revision = excluded.definition_revision,
|
|
729
|
+
content_hash = excluded.content_hash, name = excluded.name,
|
|
730
|
+
description = excluded.description, instructions = excluded.instructions,
|
|
731
|
+
allowed_tools_json = excluded.allowed_tools_json,
|
|
732
|
+
max_steps = excluded.max_steps, timeout_ms = excluded.timeout_ms,
|
|
733
|
+
temperature_milli = excluded.temperature_milli,
|
|
734
|
+
max_output_tokens = excluded.max_output_tokens,
|
|
735
|
+
registered_at = excluded.registered_at`,
|
|
736
|
+
reconcileModuleAgents5: `SELECT * FROM module_agent_bindings WHERE agent_id = $1`,
|
|
737
|
+
reconcileModuleAgents6: `UPDATE module_agent_bindings SET enabled_tools_json = $1,
|
|
738
|
+
module_definition_revision = $2, executable_revision = $3,
|
|
739
|
+
revision = $4, updated_by = $5, updated_at = $6
|
|
740
|
+
WHERE tenant_id = $7 AND agent_id = $8`,
|
|
741
|
+
listModuleAgentBindings: `SELECT * FROM module_agent_bindings WHERE tenant_id = $1
|
|
742
|
+
ORDER BY agent_id`,
|
|
743
|
+
getModuleAgentBinding: `SELECT * FROM module_agent_bindings WHERE tenant_id = $1 AND agent_id = $2`,
|
|
744
|
+
saveModuleAgentBinding1: `INSERT INTO module_agent_bindings
|
|
745
|
+
(tenant_id, agent_id, provider, model, enabled_tools_json, status,
|
|
746
|
+
module_definition_revision, executable_revision, revision,
|
|
747
|
+
updated_by, updated_at)
|
|
748
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)`,
|
|
749
|
+
saveModuleAgentBinding2: `UPDATE module_agent_bindings SET provider = $1, model = $2,
|
|
750
|
+
enabled_tools_json = $3, status = $4, module_definition_revision = $5,
|
|
751
|
+
executable_revision = $6, revision = $7, updated_by = $8, updated_at = $9
|
|
752
|
+
WHERE tenant_id = $10 AND agent_id = $11 AND revision = $12`,
|
|
753
|
+
saveModuleAgentBinding3: `SELECT 1 FROM agent_definition_revisions
|
|
754
|
+
WHERE tenant_id = $1 AND agent_id = $2 AND revision = $3`,
|
|
755
|
+
listAgents: `${AGENT_SELECT} WHERE agent_definitions.tenant_id = $1
|
|
756
|
+
ORDER BY lower(agent_definitions.name), agent_definitions.id`,
|
|
757
|
+
providerUsage1: `SELECT
|
|
758
|
+
(SELECT COUNT(*) FROM agent_definitions
|
|
759
|
+
WHERE tenant_id = $1 AND provider = $2 AND status <> 'archived') +
|
|
760
|
+
(SELECT COUNT(*) FROM module_agent_bindings
|
|
761
|
+
WHERE tenant_id = $3 AND provider = $4) AS count`,
|
|
762
|
+
providerUsage2: `SELECT COUNT(*) AS count FROM agent_runs
|
|
763
|
+
WHERE tenant_id = $1 AND provider = $2 AND status IN ('queued', 'running')`,
|
|
764
|
+
agentUsage: `SELECT
|
|
765
|
+
(SELECT COUNT(*) FROM agent_runs
|
|
766
|
+
WHERE tenant_id = $1 AND agent_id = $2) AS runs,
|
|
767
|
+
(SELECT COUNT(*) FROM agent_runs
|
|
768
|
+
WHERE tenant_id = $3 AND agent_id = $4
|
|
769
|
+
AND status IN ('queued', 'running')) AS pending_runs,
|
|
770
|
+
(SELECT COUNT(*) FROM agent_skill_assignments
|
|
771
|
+
WHERE tenant_id = $5 AND agent_id = $6) AS assignments`,
|
|
772
|
+
getAgent: `${AGENT_SELECT} WHERE agent_definitions.tenant_id = $1
|
|
773
|
+
AND agent_definitions.id = $2`,
|
|
774
|
+
getAgentRevision: `${AGENT_REVISION_SELECT}
|
|
775
|
+
WHERE agent_definition_revisions.tenant_id = $1
|
|
776
|
+
AND agent_definition_revisions.agent_id = $2
|
|
777
|
+
AND agent_definition_revisions.revision = $3`,
|
|
778
|
+
listAgentRevisions: `${AGENT_REVISION_SELECT}
|
|
779
|
+
WHERE agent_definition_revisions.tenant_id = $1
|
|
780
|
+
ORDER BY lower(agent_definition_revisions.name),
|
|
781
|
+
agent_definition_revisions.agent_id,
|
|
782
|
+
agent_definition_revisions.revision DESC`,
|
|
783
|
+
createAgent1: `INSERT INTO agent_definitions
|
|
784
|
+
(id, tenant_id, agent_key, name, description, instructions,
|
|
785
|
+
provider, model, allowed_tools_json, max_steps, timeout_ms,
|
|
786
|
+
temperature_milli, status, revision, created_by, created_at,
|
|
787
|
+
updated_by, updated_at)
|
|
788
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18)`,
|
|
789
|
+
createAgent2: `INSERT INTO agent_definition_execution_limits
|
|
790
|
+
(agent_id, tenant_id, timeout_ms) VALUES ($1, $2, $3)`,
|
|
791
|
+
createAgent3: `INSERT INTO agent_definition_output_limits
|
|
792
|
+
(agent_id, tenant_id, max_output_tokens) VALUES ($1, $2, $3)`,
|
|
793
|
+
updateAgent1: `UPDATE agent_definitions SET agent_key = $1, name = $2,
|
|
794
|
+
description = $3, instructions = $4, provider = $5, model = $6,
|
|
795
|
+
allowed_tools_json = $7, max_steps = $8, timeout_ms = $9,
|
|
796
|
+
temperature_milli = $10, status = $11, revision = $12, updated_by = $13,
|
|
797
|
+
updated_at = $14 WHERE tenant_id = $15 AND id = $16`,
|
|
798
|
+
updateAgent2: `INSERT INTO agent_definition_execution_limits
|
|
799
|
+
(agent_id, tenant_id, timeout_ms) VALUES ($1, $2, $3)
|
|
800
|
+
ON CONFLICT(agent_id) DO UPDATE SET timeout_ms = excluded.timeout_ms`,
|
|
801
|
+
updateAgent3: `INSERT INTO agent_definition_output_limits
|
|
802
|
+
(agent_id, tenant_id, max_output_tokens) VALUES ($1, $2, $3)
|
|
803
|
+
ON CONFLICT(agent_id) DO UPDATE SET max_output_tokens = excluded.max_output_tokens`,
|
|
804
|
+
deleteAgent: `DELETE FROM agent_definitions WHERE tenant_id = $1 AND id = $2`,
|
|
805
|
+
listProcedures: `SELECT * FROM agent_skills WHERE tenant_id = $1
|
|
806
|
+
ORDER BY lower(name), id`,
|
|
807
|
+
getProcedure: `SELECT * FROM agent_skills WHERE tenant_id = $1 AND id = $2`,
|
|
808
|
+
createProcedure: `INSERT INTO agent_skills
|
|
809
|
+
(id, tenant_id, skill_key, name, description, instructions,
|
|
810
|
+
required_tools_json, status, revision, created_by, created_at,
|
|
811
|
+
updated_by, updated_at)
|
|
812
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)`,
|
|
813
|
+
updateProcedure: `UPDATE agent_skills SET skill_key = $1, name = $2, description = $3,
|
|
814
|
+
instructions = $4, required_tools_json = $5, status = $6, revision = $7,
|
|
815
|
+
updated_by = $8, updated_at = $9 WHERE tenant_id = $10 AND id = $11`,
|
|
816
|
+
procedureUsage: `SELECT COUNT(*) AS assignments,
|
|
817
|
+
SUM(CASE WHEN agent_definitions.status = 'active' THEN 1 ELSE 0 END) AS active_definitions
|
|
818
|
+
FROM agent_skill_assignments
|
|
819
|
+
JOIN agent_definitions
|
|
820
|
+
ON agent_definitions.id = agent_skill_assignments.agent_id
|
|
821
|
+
AND agent_definitions.tenant_id = agent_skill_assignments.tenant_id
|
|
822
|
+
WHERE agent_skill_assignments.tenant_id = $1
|
|
823
|
+
AND agent_skill_assignments.skill_id = $2`,
|
|
824
|
+
deleteProcedure: `DELETE FROM agent_skills WHERE tenant_id = $1 AND id = $2`,
|
|
825
|
+
listRuns: `SELECT ${RUN_COLUMNS} FROM ${RUN_FROM} WHERE agent_runs.tenant_id = $1
|
|
826
|
+
ORDER BY queued_at DESC, agent_runs.id DESC LIMIT $2`,
|
|
827
|
+
getRun: `SELECT ${RUN_COLUMNS} FROM ${RUN_FROM} WHERE agent_runs.tenant_id = $1 AND agent_runs.id = $2`,
|
|
828
|
+
listRunEvents: `SELECT sequence, event_type, message, metadata_json, occurred_at
|
|
829
|
+
FROM agent_run_events WHERE tenant_id = $1 AND run_id = $2
|
|
830
|
+
AND sequence > $3 ORDER BY sequence`,
|
|
831
|
+
findRunByIdempotencyKey: `SELECT ${RUN_COLUMNS} FROM ${RUN_FROM}
|
|
832
|
+
WHERE agent_runs.tenant_id = $1 AND idempotency_key = $2`,
|
|
833
|
+
enqueueRun1: `INSERT INTO agent_runs
|
|
834
|
+
(id, tenant_id, agent_id, agent_name, agent_revision,
|
|
835
|
+
instructions_snapshot, provider, model, allowed_tools_json,
|
|
836
|
+
max_steps, timeout_ms, temperature_milli, trigger, status, input,
|
|
837
|
+
output, requested_by, permission_snapshot_json, tool_grants_json,
|
|
838
|
+
usage_json, failure_code, failure_message, idempotency_key, attempt,
|
|
839
|
+
queued_at, started_at, completed_at, lease_owner, lease_expires_at)
|
|
840
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, 'queued', $14, NULL,
|
|
841
|
+
$15, $16, $17, NULL, NULL, NULL, $18, 0, $19, NULL, NULL, NULL, NULL)`,
|
|
842
|
+
enqueueRun2: `INSERT INTO agent_run_execution_limits (run_id, tenant_id, timeout_ms)
|
|
843
|
+
VALUES ($1, $2, $3)`,
|
|
844
|
+
enqueueRun3: `INSERT INTO agent_run_output_limits (run_id, tenant_id, max_output_tokens)
|
|
845
|
+
VALUES ($1, $2, $3)`,
|
|
846
|
+
enqueueRun4: `INSERT INTO agent_run_skill_snapshots
|
|
847
|
+
(run_id, tenant_id, skill_id, skill_key, skill_name, skill_revision,
|
|
848
|
+
required_tools_json)
|
|
849
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7)`,
|
|
850
|
+
enqueueRun5: `INSERT INTO agent_run_contracts
|
|
851
|
+
(run_id, tenant_id, workflow_run_id, output_contract_json,
|
|
852
|
+
structured_output_json, request_hash)
|
|
853
|
+
VALUES ($1, $2, $3, $4, NULL, $5)`,
|
|
854
|
+
enqueueRun6: `INSERT INTO agent_run_actors
|
|
855
|
+
(run_id, tenant_id, actor_json, authorization_subject_json)
|
|
856
|
+
VALUES ($1, $2, $3, $4)`,
|
|
857
|
+
listRecoverableRuns: `SELECT tenant_id, id FROM agent_runs
|
|
858
|
+
WHERE status = 'queued'
|
|
859
|
+
OR (status = 'running' AND lease_expires_at < $1)
|
|
860
|
+
ORDER BY queued_at, id LIMIT $2`,
|
|
861
|
+
claimRun1: `UPDATE agent_runs SET status = 'running', lease_owner = $1,
|
|
862
|
+
lease_expires_at = $2, started_at = COALESCE(started_at, $3),
|
|
863
|
+
attempt = attempt + 1
|
|
864
|
+
WHERE tenant_id = $4 AND id = $5 AND
|
|
865
|
+
(status = 'queued' OR (status = 'running' AND lease_expires_at < $6))`,
|
|
866
|
+
claimRun2: `SELECT ${RUN_COLUMNS} FROM ${RUN_FROM} WHERE agent_runs.tenant_id = $1 AND agent_runs.id = $2`,
|
|
867
|
+
renewLease: `UPDATE agent_runs SET lease_expires_at = $1 WHERE tenant_id = $2
|
|
868
|
+
AND id = $3 AND status = 'running' AND lease_owner = $4`,
|
|
869
|
+
consumeRunGrant1: `DELETE FROM agent_run_grant_uses WHERE expires_at < $1`,
|
|
870
|
+
consumeRunGrant2: `INSERT INTO agent_run_grant_uses
|
|
871
|
+
(grant_id, token_hash, tenant_id, run_id, worker_id, provider_id,
|
|
872
|
+
model_id, issued_at, expires_at, consumed_at)
|
|
873
|
+
SELECT $1, $2, $3, $4, $5, $6, $7, $8, $9, $10
|
|
874
|
+
FROM agent_runs
|
|
875
|
+
WHERE tenant_id = $11 AND id = $12 AND status = 'running'
|
|
876
|
+
AND lease_owner = $13 AND lease_expires_at >= $14
|
|
877
|
+
ON CONFLICT DO NOTHING`,
|
|
878
|
+
appendRunEvent: `INSERT INTO agent_run_events
|
|
879
|
+
(run_id, tenant_id, sequence, event_type, message, metadata_json,
|
|
880
|
+
occurred_at)
|
|
881
|
+
SELECT $1, $2, COALESCE(MAX(sequence), 0) + 1, $3, $4, $5, $6
|
|
882
|
+
FROM agent_run_events WHERE run_id = $7 AND tenant_id = $8`,
|
|
883
|
+
completeRun1: `UPDATE agent_runs SET status = 'succeeded', output = $1, usage_json = $2,
|
|
884
|
+
completed_at = $3, lease_owner = NULL, lease_expires_at = NULL
|
|
885
|
+
WHERE tenant_id = $4 AND id = $5 AND status = 'running'
|
|
886
|
+
AND lease_owner = $6`,
|
|
887
|
+
completeRun2: `UPDATE agent_run_contracts SET structured_output_json = $1
|
|
888
|
+
WHERE tenant_id = $2 AND run_id = $3`,
|
|
889
|
+
completeRun3: `SELECT agent_id, agent_name, model FROM agent_runs
|
|
890
|
+
WHERE tenant_id = $1 AND id = $2`,
|
|
891
|
+
completeRun4: `INSERT INTO agent_run_costs
|
|
892
|
+
(run_id, tenant_id, agent_id, agent_name, model, day, input_tokens,
|
|
893
|
+
output_tokens, cost_micro_usd, completed_at)
|
|
894
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
|
|
895
|
+
ON CONFLICT(run_id) DO UPDATE SET
|
|
896
|
+
input_tokens = excluded.input_tokens,
|
|
897
|
+
output_tokens = excluded.output_tokens,
|
|
898
|
+
cost_micro_usd = excluded.cost_micro_usd,
|
|
899
|
+
day = excluded.day, completed_at = excluded.completed_at`,
|
|
900
|
+
failRun: `UPDATE agent_runs SET status = 'failed', failure_code = $1,
|
|
901
|
+
failure_message = $2, completed_at = $3, lease_owner = NULL,
|
|
902
|
+
lease_expires_at = NULL WHERE tenant_id = $4 AND id = $5
|
|
903
|
+
AND status = 'running' AND lease_owner = $6`,
|
|
904
|
+
cancelRun1: `SELECT status FROM agent_runs WHERE tenant_id = $1 AND id = $2`,
|
|
905
|
+
cancelRun2: `UPDATE agent_runs SET status = 'cancelled', failure_code = 'RUN_CANCELLED',
|
|
906
|
+
failure_message = $1, completed_at = $2, lease_owner = NULL,
|
|
907
|
+
lease_expires_at = NULL WHERE tenant_id = $3 AND id = $4`,
|
|
908
|
+
enqueueAction: `INSERT INTO agent_action_invocations
|
|
909
|
+
(id, tenant_id, workflow_run_id, node_run_id, action_id,
|
|
910
|
+
contract_version, actor_json, authorization_subject_json, permission_snapshot_json,
|
|
911
|
+
input_json, idempotency_key, request_hash, status, output_json,
|
|
912
|
+
failure_code, attempt, queued_at, started_at, completed_at,
|
|
913
|
+
lease_owner, lease_expires_at)
|
|
914
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, 'queued', NULL, NULL,
|
|
915
|
+
0, $13, NULL, NULL, NULL, NULL)`,
|
|
916
|
+
getAction: `SELECT * FROM agent_action_invocations
|
|
917
|
+
WHERE tenant_id = $1 AND id = $2`,
|
|
918
|
+
findActionByIdempotencyKey: `SELECT * FROM agent_action_invocations
|
|
919
|
+
WHERE tenant_id = $1 AND idempotency_key = $2`,
|
|
920
|
+
listRecoverableActions: `SELECT tenant_id, id FROM agent_action_invocations
|
|
921
|
+
WHERE status = 'queued'
|
|
922
|
+
OR (status = 'running' AND lease_expires_at < $1)
|
|
923
|
+
ORDER BY queued_at, id LIMIT $2`,
|
|
924
|
+
claimAction: `UPDATE agent_action_invocations SET status = 'running',
|
|
925
|
+
lease_owner = $1, lease_expires_at = $2,
|
|
926
|
+
started_at = COALESCE(started_at, $3), attempt = attempt + 1
|
|
927
|
+
WHERE tenant_id = $4 AND id = $5
|
|
928
|
+
AND (status = 'queued' OR
|
|
929
|
+
(status = 'running' AND lease_expires_at < $6))`,
|
|
930
|
+
renewActionLease: `UPDATE agent_action_invocations SET lease_expires_at = $1
|
|
931
|
+
WHERE tenant_id = $2 AND id = $3 AND status = 'running'
|
|
932
|
+
AND lease_owner = $4`,
|
|
933
|
+
completeAction: `UPDATE agent_action_invocations SET status = 'succeeded',
|
|
934
|
+
output_json = $1, completed_at = $2, lease_owner = NULL,
|
|
935
|
+
lease_expires_at = NULL WHERE tenant_id = $3 AND id = $4
|
|
936
|
+
AND status = 'running' AND lease_owner = $5`,
|
|
937
|
+
failAction: `UPDATE agent_action_invocations SET status = 'failed',
|
|
938
|
+
failure_code = $1, completed_at = $2, lease_owner = NULL,
|
|
939
|
+
lease_expires_at = NULL WHERE tenant_id = $3 AND id = $4
|
|
940
|
+
AND status = 'running' AND lease_owner = $5`,
|
|
941
|
+
cancelAction: `UPDATE agent_action_invocations SET status = 'cancelled',
|
|
942
|
+
failure_code = 'ACTION_CANCELLED', completed_at = $1,
|
|
943
|
+
lease_owner = NULL, lease_expires_at = NULL
|
|
944
|
+
WHERE tenant_id = $2 AND id = $3 AND status IN ('queued', 'running')`,
|
|
945
|
+
appendAuditEvent1: `SELECT sequence, event_hash FROM agent_audit_events_v4
|
|
946
|
+
WHERE tenant_id = $1 ORDER BY sequence DESC LIMIT 1`,
|
|
947
|
+
appendAuditEvent2: `INSERT INTO agent_audit_events_v4
|
|
948
|
+
(id, tenant_id, sequence, actor_id, action, subject_type,
|
|
949
|
+
subject_id, metadata_json, occurred_at, previous_hash, event_hash)
|
|
950
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)`,
|
|
951
|
+
listAuditEvents: `SELECT * FROM agent_audit_events_v4 WHERE tenant_id = $1
|
|
952
|
+
ORDER BY sequence DESC LIMIT $2`,
|
|
953
|
+
pageAuditEvents1: `SELECT * FROM agent_audit_events_v4 WHERE tenant_id = $1
|
|
954
|
+
AND (occurred_at < $2 OR (occurred_at = $3 AND sequence < $4))
|
|
955
|
+
ORDER BY occurred_at DESC, sequence DESC LIMIT $5`,
|
|
956
|
+
pageAuditEvents2: `SELECT * FROM agent_audit_events_v4 WHERE tenant_id = $1
|
|
957
|
+
ORDER BY occurred_at DESC, sequence DESC LIMIT $2`,
|
|
958
|
+
verifyAuditChainDetailed: `SELECT * FROM agent_audit_events_v4 WHERE tenant_id = $1
|
|
959
|
+
ORDER BY sequence`,
|
|
960
|
+
usageByDay: `SELECT day, ${USAGE_COLUMNS} FROM agent_run_costs
|
|
961
|
+
WHERE tenant_id = $1 AND day BETWEEN $2 AND $3
|
|
962
|
+
GROUP BY day ORDER BY day`,
|
|
963
|
+
usageByAgent: `SELECT agent_id, MAX(agent_name) AS agent_name, ${USAGE_COLUMNS}
|
|
964
|
+
FROM agent_run_costs WHERE tenant_id = $1 AND day BETWEEN $2 AND $3
|
|
965
|
+
GROUP BY agent_id ORDER BY cost_micro_usd DESC, agent_id`,
|
|
966
|
+
usageTotal1: `SELECT ${USAGE_COLUMNS} FROM agent_run_costs
|
|
967
|
+
WHERE tenant_id = $1 AND day >= $2`,
|
|
968
|
+
usageTotal2: `SELECT ${USAGE_COLUMNS} FROM agent_run_costs
|
|
969
|
+
WHERE tenant_id = $1 AND agent_id = $2 AND day >= $3`,
|
|
970
|
+
});
|
|
971
|
+
|
|
972
|
+
export async function migrateAgentsDatabase(
|
|
973
|
+
database: DatabaseHandle,
|
|
974
|
+
): Promise<void> {
|
|
975
|
+
await runDatabaseMigrations(database, 'agents.core', databaseMigrations);
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
export interface AgentsDatabaseHandles {
|
|
979
|
+
/** Tenant-scoped handle used by every request-time read and write. */
|
|
980
|
+
readonly runtime: DatabaseHandle;
|
|
981
|
+
/**
|
|
982
|
+
* Cross-tenant read handle for the worker recovery polls. It reads only what
|
|
983
|
+
* those tables' own FOR SELECT policy grants and writes nothing; the claim
|
|
984
|
+
* that follows runs under the tenant of the row it returned.
|
|
985
|
+
*/
|
|
986
|
+
readonly background: DatabaseHandle;
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
/** A dialect-neutral repository over platform-owned database handles. */
|
|
990
|
+
export class DatabaseAgentRepository implements AgentRepository {
|
|
991
|
+
constructor(
|
|
992
|
+
private readonly handles: AgentsDatabaseHandles,
|
|
993
|
+
private readonly readyPromise: Promise<void> = Promise.resolve(),
|
|
994
|
+
) {}
|
|
995
|
+
|
|
996
|
+
/* One unit of work under one tenant. Every multi-statement operation runs
|
|
997
|
+
inside a single transaction, so a partially written run is impossible. */
|
|
998
|
+
async #tx<T>(
|
|
999
|
+
tenantId: string,
|
|
1000
|
+
access: 'read' | 'write',
|
|
1001
|
+
body: (transaction: DatabaseTransaction) => Promise<T>,
|
|
1002
|
+
): Promise<T> {
|
|
1003
|
+
await this.readyPromise;
|
|
1004
|
+
return this.handles.runtime.transaction(body, { access, tenantId });
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
/* The recovery polls have to find work before they know whose it is. They
|
|
1008
|
+
read routing columns on the read-only background handle; the claim that
|
|
1009
|
+
follows runs under the tenant the row named. */
|
|
1010
|
+
async #crossTenant<T>(
|
|
1011
|
+
body: (transaction: DatabaseTransaction) => Promise<T>,
|
|
1012
|
+
): Promise<T> {
|
|
1013
|
+
await this.readyPromise;
|
|
1014
|
+
return this.handles.background.transaction(body, { access: 'read' });
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
async #query<Row extends object>(
|
|
1018
|
+
transaction: DatabaseTransaction,
|
|
1019
|
+
text: string,
|
|
1020
|
+
parameters: readonly unknown[],
|
|
1021
|
+
): Promise<readonly Row[]> {
|
|
1022
|
+
const result = await transaction.query<Row>({
|
|
1023
|
+
text,
|
|
1024
|
+
parameters: parameters as never,
|
|
1025
|
+
});
|
|
1026
|
+
return result.rows;
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
async #exec(
|
|
1030
|
+
transaction: DatabaseTransaction,
|
|
1031
|
+
text: string,
|
|
1032
|
+
parameters: readonly unknown[],
|
|
1033
|
+
): Promise<number> {
|
|
1034
|
+
const result = await transaction.execute({
|
|
1035
|
+
text,
|
|
1036
|
+
parameters: parameters as never,
|
|
1037
|
+
});
|
|
1038
|
+
return result.affectedRows;
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
async #procedureIds(
|
|
1042
|
+
transaction: DatabaseTransaction,
|
|
1043
|
+
tenantId: string,
|
|
1044
|
+
agentId: string,
|
|
1045
|
+
): Promise<readonly string[]> {
|
|
1046
|
+
return (
|
|
1047
|
+
(await this.#query(transaction, AGENTS_SQL.procedureIds, [
|
|
1048
|
+
tenantId,
|
|
1049
|
+
agentId,
|
|
1050
|
+
])) as unknown as { skill_id: string }[]
|
|
1051
|
+
).map((row) => row.skill_id);
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
async #procedureSnapshots(
|
|
1055
|
+
transaction: DatabaseTransaction,
|
|
1056
|
+
tenantId: string,
|
|
1057
|
+
runId: string,
|
|
1058
|
+
): Promise<readonly AgentProcedureSnapshot[]> {
|
|
1059
|
+
return (
|
|
1060
|
+
(await this.#query(transaction, AGENTS_SQL.procedureSnapshots, [
|
|
1061
|
+
tenantId,
|
|
1062
|
+
runId,
|
|
1063
|
+
])) as unknown as SkillSnapshotRow[]
|
|
1064
|
+
).map((row) => ({
|
|
1065
|
+
id: row.skill_id,
|
|
1066
|
+
key: row.skill_key,
|
|
1067
|
+
name: row.skill_name,
|
|
1068
|
+
revision: row.skill_revision,
|
|
1069
|
+
requiredTools: stringArray(row.required_tools_json),
|
|
1070
|
+
}));
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
async #setAgentSkills(
|
|
1074
|
+
transaction: DatabaseTransaction,
|
|
1075
|
+
agent: AgentDefinition,
|
|
1076
|
+
): Promise<void> {
|
|
1077
|
+
await this.#exec(transaction, AGENTS_SQL.setAgentSkills1, [agent.id]);
|
|
1078
|
+
for (const procedureId of agent.procedureIds) {
|
|
1079
|
+
await this.#exec(transaction, AGENTS_SQL.setAgentSkills2, [
|
|
1080
|
+
agent.id,
|
|
1081
|
+
procedureId,
|
|
1082
|
+
agent.tenantId,
|
|
1083
|
+
]);
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
async #revisionSkills(
|
|
1088
|
+
transaction: DatabaseTransaction,
|
|
1089
|
+
|
|
1090
|
+
tenantId: string,
|
|
1091
|
+
agentId: string,
|
|
1092
|
+
): Promise<readonly AgentRevisionProcedure[]> {
|
|
1093
|
+
return (
|
|
1094
|
+
(await this.#query(transaction, AGENTS_SQL.revisionSkills, [
|
|
1095
|
+
tenantId,
|
|
1096
|
+
agentId,
|
|
1097
|
+
])) as unknown as {
|
|
1098
|
+
id: string;
|
|
1099
|
+
skill_key: string;
|
|
1100
|
+
name: string;
|
|
1101
|
+
revision: number;
|
|
1102
|
+
instructions: string;
|
|
1103
|
+
required_tools_json: string;
|
|
1104
|
+
}[]
|
|
1105
|
+
).map((row) => ({
|
|
1106
|
+
id: row.id,
|
|
1107
|
+
key: row.skill_key,
|
|
1108
|
+
name: row.name,
|
|
1109
|
+
revision: row.revision,
|
|
1110
|
+
instructions: row.instructions,
|
|
1111
|
+
requiredTools: stringArray(row.required_tools_json),
|
|
1112
|
+
}));
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
async #retainAgentRevision(
|
|
1116
|
+
transaction: DatabaseTransaction,
|
|
1117
|
+
agent: AgentDefinition,
|
|
1118
|
+
ignoreExisting = false,
|
|
1119
|
+
): Promise<void> {
|
|
1120
|
+
await this.#exec(
|
|
1121
|
+
transaction,
|
|
1122
|
+
ignoreExisting
|
|
1123
|
+
? AGENTS_SQL.retainAgentRevision1
|
|
1124
|
+
: AGENTS_SQL.retainAgentRevision2,
|
|
1125
|
+
[
|
|
1126
|
+
agent.tenantId,
|
|
1127
|
+
agent.id,
|
|
1128
|
+
agent.revision,
|
|
1129
|
+
agent.key,
|
|
1130
|
+
agent.name,
|
|
1131
|
+
agent.description,
|
|
1132
|
+
agent.instructions,
|
|
1133
|
+
agent.provider,
|
|
1134
|
+
agent.model,
|
|
1135
|
+
JSON.stringify(agent.allowedTools),
|
|
1136
|
+
JSON.stringify(
|
|
1137
|
+
await this.#revisionSkills(transaction, agent.tenantId, agent.id),
|
|
1138
|
+
),
|
|
1139
|
+
agent.maxSteps,
|
|
1140
|
+
agent.timeoutMs,
|
|
1141
|
+
Math.round(agent.temperature * 1_000),
|
|
1142
|
+
agent.maxOutputTokens,
|
|
1143
|
+
agent.status,
|
|
1144
|
+
agent.updatedBy,
|
|
1145
|
+
agent.updatedAt,
|
|
1146
|
+
],
|
|
1147
|
+
);
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
async adoptCurrentAgentRevisions(): Promise<void> {
|
|
1151
|
+
let afterTenant = '';
|
|
1152
|
+
for (;;) {
|
|
1153
|
+
const page = await this.#crossTenant((transaction) =>
|
|
1154
|
+
this.#query<{ tenant_id: string }>(
|
|
1155
|
+
transaction,
|
|
1156
|
+
`SELECT DISTINCT tenant_id FROM agent_definitions
|
|
1157
|
+
WHERE tenant_id > $1 AND tenant_id <> '__flowdular_module_agents__'
|
|
1158
|
+
ORDER BY tenant_id LIMIT 100`,
|
|
1159
|
+
[afterTenant],
|
|
1160
|
+
),
|
|
1161
|
+
);
|
|
1162
|
+
if (page.length === 0) return;
|
|
1163
|
+
for (const { tenant_id: tenantId } of page)
|
|
1164
|
+
await this.#tx(tenantId, 'write', async (transaction) => {
|
|
1165
|
+
for (const agent of await this.#agentsForRevisionAdoption(
|
|
1166
|
+
transaction,
|
|
1167
|
+
tenantId,
|
|
1168
|
+
)) {
|
|
1169
|
+
await this.#retainAgentRevision(transaction, agent, true);
|
|
1170
|
+
}
|
|
1171
|
+
});
|
|
1172
|
+
afterTenant = page[page.length - 1]!.tenant_id;
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
/* Constructor-only helper. It avoids calling a public method while the
|
|
1177
|
+
repository is still adopting the pre-ledger current definitions. */
|
|
1178
|
+
async #agentsForRevisionAdoption(
|
|
1179
|
+
transaction: DatabaseTransaction,
|
|
1180
|
+
tenantId: string,
|
|
1181
|
+
): Promise<readonly AgentDefinition[]> {
|
|
1182
|
+
const rows = (await this.#query(
|
|
1183
|
+
transaction,
|
|
1184
|
+
AGENTS_SQL.listAgentsForRevisionAdoption,
|
|
1185
|
+
[tenantId],
|
|
1186
|
+
)) as unknown as AgentRow[];
|
|
1187
|
+
const agents: AgentDefinition[] = [];
|
|
1188
|
+
for (const row of rows) {
|
|
1189
|
+
const agent = fromAgentRow(row);
|
|
1190
|
+
agents.push({
|
|
1191
|
+
...agent,
|
|
1192
|
+
procedureIds: await this.#procedureIds(
|
|
1193
|
+
transaction,
|
|
1194
|
+
agent.tenantId,
|
|
1195
|
+
agent.id,
|
|
1196
|
+
),
|
|
1197
|
+
});
|
|
1198
|
+
}
|
|
1199
|
+
return agents;
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
async #retainModuleAgentRevision(
|
|
1203
|
+
transaction: DatabaseTransaction,
|
|
1204
|
+
|
|
1205
|
+
binding: ModuleAgentBinding,
|
|
1206
|
+
definition: ModuleAgentDefinition,
|
|
1207
|
+
): Promise<void> {
|
|
1208
|
+
await this.#exec(transaction, AGENTS_SQL.retainModuleAgentRevision1, [
|
|
1209
|
+
binding.tenantId,
|
|
1210
|
+
definition.id,
|
|
1211
|
+
binding.executableRevision,
|
|
1212
|
+
definition.key,
|
|
1213
|
+
definition.name,
|
|
1214
|
+
definition.description,
|
|
1215
|
+
definition.instructions,
|
|
1216
|
+
binding.provider,
|
|
1217
|
+
binding.model,
|
|
1218
|
+
JSON.stringify(binding.enabledTools),
|
|
1219
|
+
definition.limits.maxSteps,
|
|
1220
|
+
definition.limits.timeoutMs,
|
|
1221
|
+
Math.round(definition.limits.temperature * 1_000),
|
|
1222
|
+
definition.limits.maxOutputTokens,
|
|
1223
|
+
binding.updatedBy,
|
|
1224
|
+
binding.updatedAt,
|
|
1225
|
+
]);
|
|
1226
|
+
await this.#exec(transaction, AGENTS_SQL.retainModuleAgentRevision2, [
|
|
1227
|
+
binding.tenantId,
|
|
1228
|
+
definition.id,
|
|
1229
|
+
binding.executableRevision,
|
|
1230
|
+
definition.moduleId,
|
|
1231
|
+
definition.definitionRevision,
|
|
1232
|
+
]);
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
async reconcileModuleAgents(
|
|
1236
|
+
definitions: readonly ModuleAgentDefinition[],
|
|
1237
|
+
reconciledAt: number,
|
|
1238
|
+
): Promise<void> {
|
|
1239
|
+
await this.#tx(
|
|
1240
|
+
'__flowdular_module_agents__',
|
|
1241
|
+
'write',
|
|
1242
|
+
async (transaction) => {
|
|
1243
|
+
await transaction.query({
|
|
1244
|
+
text: "SELECT pg_advisory_xact_lock(hashtextextended('agents.core.module-catalog', 0))",
|
|
1245
|
+
});
|
|
1246
|
+
try {
|
|
1247
|
+
const seen = new Set<string>();
|
|
1248
|
+
for (const definition of definitions) {
|
|
1249
|
+
if (seen.has(definition.id)) {
|
|
1250
|
+
throw new Error(`MODULE_AGENT_DUPLICATE: ${definition.id}`);
|
|
1251
|
+
}
|
|
1252
|
+
seen.add(definition.id);
|
|
1253
|
+
const contentHash = moduleAgentDefinitionHash(definition);
|
|
1254
|
+
const stored = (
|
|
1255
|
+
await this.#query(
|
|
1256
|
+
transaction,
|
|
1257
|
+
AGENTS_SQL.reconcileModuleAgents1,
|
|
1258
|
+
[definition.id],
|
|
1259
|
+
)
|
|
1260
|
+
)[0] as unknown as ModuleAgentDefinitionRow | undefined;
|
|
1261
|
+
if (stored) {
|
|
1262
|
+
if (definition.definitionRevision < stored.definition_revision) {
|
|
1263
|
+
throw new Error(
|
|
1264
|
+
`MODULE_AGENT_REVISION_DOWNGRADE: ${definition.id} registered revision ${definition.definitionRevision} after ${stored.definition_revision}.`,
|
|
1265
|
+
);
|
|
1266
|
+
}
|
|
1267
|
+
if (
|
|
1268
|
+
definition.definitionRevision === stored.definition_revision
|
|
1269
|
+
) {
|
|
1270
|
+
if (contentHash !== stored.content_hash) {
|
|
1271
|
+
throw new Error(
|
|
1272
|
+
`MODULE_AGENT_REVISION_DRIFT: ${definition.id} changed without a definition revision bump.`,
|
|
1273
|
+
);
|
|
1274
|
+
}
|
|
1275
|
+
continue;
|
|
1276
|
+
}
|
|
1277
|
+
} else {
|
|
1278
|
+
/* The legacy run table references agent_definitions by id only. A
|
|
1279
|
+
retained internal parent keeps that foreign key valid across all
|
|
1280
|
+
tenant bindings without pretending the behavior is tenant-owned. */
|
|
1281
|
+
await this.#exec(transaction, AGENTS_SQL.reconcileModuleAgents2, [
|
|
1282
|
+
definition.id,
|
|
1283
|
+
definition.id,
|
|
1284
|
+
definition.name,
|
|
1285
|
+
definition.description,
|
|
1286
|
+
definition.instructions,
|
|
1287
|
+
JSON.stringify(definition.allowedTools),
|
|
1288
|
+
definition.limits.maxSteps,
|
|
1289
|
+
Math.min(definition.limits.timeoutMs, 300_000),
|
|
1290
|
+
Math.round(definition.limits.temperature * 1_000),
|
|
1291
|
+
definition.definitionRevision,
|
|
1292
|
+
`module:${definition.moduleId}`,
|
|
1293
|
+
reconciledAt,
|
|
1294
|
+
`module:${definition.moduleId}`,
|
|
1295
|
+
reconciledAt,
|
|
1296
|
+
]);
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
if (stored) {
|
|
1300
|
+
await this.#exec(transaction, AGENTS_SQL.reconcileModuleAgents3, [
|
|
1301
|
+
definition.name,
|
|
1302
|
+
definition.description,
|
|
1303
|
+
definition.instructions,
|
|
1304
|
+
JSON.stringify(definition.allowedTools),
|
|
1305
|
+
definition.limits.maxSteps,
|
|
1306
|
+
Math.min(definition.limits.timeoutMs, 300_000),
|
|
1307
|
+
Math.round(definition.limits.temperature * 1_000),
|
|
1308
|
+
definition.definitionRevision,
|
|
1309
|
+
`module:${definition.moduleId}`,
|
|
1310
|
+
reconciledAt,
|
|
1311
|
+
definition.id,
|
|
1312
|
+
]);
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
await this.#exec(transaction, AGENTS_SQL.reconcileModuleAgents4, [
|
|
1316
|
+
definition.id,
|
|
1317
|
+
definition.moduleId,
|
|
1318
|
+
definition.key,
|
|
1319
|
+
definition.definitionRevision,
|
|
1320
|
+
contentHash,
|
|
1321
|
+
definition.name,
|
|
1322
|
+
definition.description,
|
|
1323
|
+
definition.instructions,
|
|
1324
|
+
JSON.stringify(definition.allowedTools),
|
|
1325
|
+
definition.limits.maxSteps,
|
|
1326
|
+
definition.limits.timeoutMs,
|
|
1327
|
+
Math.round(definition.limits.temperature * 1_000),
|
|
1328
|
+
definition.limits.maxOutputTokens,
|
|
1329
|
+
reconciledAt,
|
|
1330
|
+
]);
|
|
1331
|
+
}
|
|
1332
|
+
} catch (error) {
|
|
1333
|
+
throw error;
|
|
1334
|
+
}
|
|
1335
|
+
},
|
|
1336
|
+
);
|
|
1337
|
+
// Retry stale bindings even when the durable catalog already has this revision.
|
|
1338
|
+
for (const definition of definitions)
|
|
1339
|
+
await this.#reconcileModuleBindings(definition, reconciledAt);
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
async #reconcileModuleBindings(
|
|
1343
|
+
definition: ModuleAgentDefinition,
|
|
1344
|
+
reconciledAt: number,
|
|
1345
|
+
): Promise<void> {
|
|
1346
|
+
let afterTenant = '';
|
|
1347
|
+
for (;;) {
|
|
1348
|
+
const page = await this.#crossTenant((transaction) =>
|
|
1349
|
+
this.#query<{ tenant_id: string }>(
|
|
1350
|
+
transaction,
|
|
1351
|
+
'SELECT tenant_id FROM module_agent_bindings WHERE agent_id = $1 AND tenant_id > $2 ORDER BY tenant_id LIMIT 100',
|
|
1352
|
+
[definition.id, afterTenant],
|
|
1353
|
+
),
|
|
1354
|
+
);
|
|
1355
|
+
if (page.length === 0) return;
|
|
1356
|
+
for (const { tenant_id: tenantId } of page)
|
|
1357
|
+
await this.#tx(tenantId, 'write', async (transaction) => {
|
|
1358
|
+
const catalog = (
|
|
1359
|
+
await this.#query<ModuleAgentDefinitionRow>(
|
|
1360
|
+
transaction,
|
|
1361
|
+
AGENTS_SQL.reconcileModuleAgents1 + ' FOR SHARE',
|
|
1362
|
+
[definition.id],
|
|
1363
|
+
)
|
|
1364
|
+
)[0];
|
|
1365
|
+
if (
|
|
1366
|
+
catalog?.definition_revision !== definition.definitionRevision ||
|
|
1367
|
+
catalog.content_hash !== moduleAgentDefinitionHash(definition)
|
|
1368
|
+
) {
|
|
1369
|
+
throw new Error(
|
|
1370
|
+
'MODULE_AGENT_REVISION_DRIFT: catalog changed during reconciliation.',
|
|
1371
|
+
);
|
|
1372
|
+
}
|
|
1373
|
+
const row = (
|
|
1374
|
+
await this.#query<ModuleAgentBindingRow>(
|
|
1375
|
+
transaction,
|
|
1376
|
+
AGENTS_SQL.getModuleAgentBinding + ' FOR UPDATE',
|
|
1377
|
+
[tenantId, definition.id],
|
|
1378
|
+
)
|
|
1379
|
+
)[0];
|
|
1380
|
+
if (
|
|
1381
|
+
!row ||
|
|
1382
|
+
row.module_definition_revision >= definition.definitionRevision
|
|
1383
|
+
)
|
|
1384
|
+
return;
|
|
1385
|
+
const previous = fromModuleBindingRow(row);
|
|
1386
|
+
const binding: ModuleAgentBinding = {
|
|
1387
|
+
...previous,
|
|
1388
|
+
enabledTools: previous.enabledTools.filter((tool) =>
|
|
1389
|
+
definition.allowedTools.includes(tool),
|
|
1390
|
+
),
|
|
1391
|
+
moduleDefinitionRevision: definition.definitionRevision,
|
|
1392
|
+
executableRevision: previous.executableRevision + 1,
|
|
1393
|
+
revision: previous.revision + 1,
|
|
1394
|
+
updatedBy: `module:${definition.moduleId}`,
|
|
1395
|
+
updatedAt: reconciledAt,
|
|
1396
|
+
};
|
|
1397
|
+
await this.#exec(transaction, AGENTS_SQL.reconcileModuleAgents6, [
|
|
1398
|
+
JSON.stringify(binding.enabledTools),
|
|
1399
|
+
binding.moduleDefinitionRevision,
|
|
1400
|
+
binding.executableRevision,
|
|
1401
|
+
binding.revision,
|
|
1402
|
+
binding.updatedBy,
|
|
1403
|
+
binding.updatedAt,
|
|
1404
|
+
binding.tenantId,
|
|
1405
|
+
binding.agentId,
|
|
1406
|
+
]);
|
|
1407
|
+
await this.#retainModuleAgentRevision(
|
|
1408
|
+
transaction,
|
|
1409
|
+
binding,
|
|
1410
|
+
definition,
|
|
1411
|
+
);
|
|
1412
|
+
await this.#appendAuditEvent(transaction, {
|
|
1413
|
+
tenantId: binding.tenantId,
|
|
1414
|
+
actorId: binding.updatedBy,
|
|
1415
|
+
action: 'module-agent.definition-reconciled',
|
|
1416
|
+
subjectType: 'agent',
|
|
1417
|
+
subjectId: definition.id,
|
|
1418
|
+
metadata: {
|
|
1419
|
+
moduleId: definition.moduleId,
|
|
1420
|
+
previousDefinitionRevision: previous.moduleDefinitionRevision,
|
|
1421
|
+
definitionRevision: definition.definitionRevision,
|
|
1422
|
+
executableRevision: binding.executableRevision,
|
|
1423
|
+
bindingRevision: binding.revision,
|
|
1424
|
+
removedTools:
|
|
1425
|
+
previous.enabledTools.length - binding.enabledTools.length,
|
|
1426
|
+
},
|
|
1427
|
+
occurredAt: reconciledAt,
|
|
1428
|
+
});
|
|
1429
|
+
});
|
|
1430
|
+
afterTenant = page[page.length - 1]!.tenant_id;
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
async listModuleAgentBindings(
|
|
1435
|
+
tenantId: string,
|
|
1436
|
+
): Promise<readonly ModuleAgentBinding[]> {
|
|
1437
|
+
return this.#tx(tenantId, 'read', async (transaction) => {
|
|
1438
|
+
return (
|
|
1439
|
+
(await this.#query(transaction, AGENTS_SQL.listModuleAgentBindings, [
|
|
1440
|
+
tenantId,
|
|
1441
|
+
])) as unknown as ModuleAgentBindingRow[]
|
|
1442
|
+
).map(fromModuleBindingRow);
|
|
1443
|
+
});
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
async getModuleAgentBinding(
|
|
1447
|
+
tenantId: string,
|
|
1448
|
+
agentId: string,
|
|
1449
|
+
): Promise<ModuleAgentBinding | null> {
|
|
1450
|
+
return this.#tx(tenantId, 'read', async (transaction) => {
|
|
1451
|
+
const row = (
|
|
1452
|
+
await this.#query(transaction, AGENTS_SQL.getModuleAgentBinding, [
|
|
1453
|
+
tenantId,
|
|
1454
|
+
agentId,
|
|
1455
|
+
])
|
|
1456
|
+
)[0] as unknown as ModuleAgentBindingRow | undefined;
|
|
1457
|
+
return row ? fromModuleBindingRow(row) : null;
|
|
1458
|
+
});
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
async saveModuleAgentBinding(
|
|
1462
|
+
binding: ModuleAgentBinding,
|
|
1463
|
+
definition: ModuleAgentDefinition,
|
|
1464
|
+
expectedRevision: number,
|
|
1465
|
+
audit: PendingAgentAuditEvent,
|
|
1466
|
+
): Promise<ModuleAgentBinding> {
|
|
1467
|
+
return this.#tx(binding.tenantId, 'write', async (transaction) => {
|
|
1468
|
+
try {
|
|
1469
|
+
if (expectedRevision === 0) {
|
|
1470
|
+
await this.#exec(transaction, AGENTS_SQL.saveModuleAgentBinding1, [
|
|
1471
|
+
binding.tenantId,
|
|
1472
|
+
binding.agentId,
|
|
1473
|
+
binding.provider,
|
|
1474
|
+
binding.model,
|
|
1475
|
+
JSON.stringify(binding.enabledTools),
|
|
1476
|
+
binding.status,
|
|
1477
|
+
binding.moduleDefinitionRevision,
|
|
1478
|
+
binding.executableRevision,
|
|
1479
|
+
binding.revision,
|
|
1480
|
+
binding.updatedBy,
|
|
1481
|
+
binding.updatedAt,
|
|
1482
|
+
]);
|
|
1483
|
+
} else {
|
|
1484
|
+
const result = await this.#exec(
|
|
1485
|
+
transaction,
|
|
1486
|
+
AGENTS_SQL.saveModuleAgentBinding2,
|
|
1487
|
+
[
|
|
1488
|
+
binding.provider,
|
|
1489
|
+
binding.model,
|
|
1490
|
+
JSON.stringify(binding.enabledTools),
|
|
1491
|
+
binding.status,
|
|
1492
|
+
binding.moduleDefinitionRevision,
|
|
1493
|
+
binding.executableRevision,
|
|
1494
|
+
binding.revision,
|
|
1495
|
+
binding.updatedBy,
|
|
1496
|
+
binding.updatedAt,
|
|
1497
|
+
binding.tenantId,
|
|
1498
|
+
binding.agentId,
|
|
1499
|
+
expectedRevision,
|
|
1500
|
+
],
|
|
1501
|
+
);
|
|
1502
|
+
if (result !== 1) throw new ModuleAgentBindingConflictError();
|
|
1503
|
+
}
|
|
1504
|
+
const existingRevision = (
|
|
1505
|
+
await this.#query(transaction, AGENTS_SQL.saveModuleAgentBinding3, [
|
|
1506
|
+
binding.tenantId,
|
|
1507
|
+
binding.agentId,
|
|
1508
|
+
binding.executableRevision,
|
|
1509
|
+
])
|
|
1510
|
+
)[0];
|
|
1511
|
+
if (!existingRevision)
|
|
1512
|
+
await this.#retainModuleAgentRevision(
|
|
1513
|
+
transaction,
|
|
1514
|
+
binding,
|
|
1515
|
+
definition,
|
|
1516
|
+
);
|
|
1517
|
+
await this.#appendAuditEvent(transaction, audit);
|
|
1518
|
+
} catch (error) {
|
|
1519
|
+
if (
|
|
1520
|
+
expectedRevision === 0 &&
|
|
1521
|
+
String(error).includes('module_agent_bindings_pkey')
|
|
1522
|
+
) {
|
|
1523
|
+
throw new ModuleAgentBindingConflictError();
|
|
1524
|
+
}
|
|
1525
|
+
throw error;
|
|
1526
|
+
}
|
|
1527
|
+
return binding;
|
|
1528
|
+
});
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
async listAgents(tenantId: string): Promise<readonly AgentDefinition[]> {
|
|
1532
|
+
return this.#tx(tenantId, 'read', async (transaction) => {
|
|
1533
|
+
const rows = (await this.#query(transaction, AGENTS_SQL.listAgents, [
|
|
1534
|
+
tenantId,
|
|
1535
|
+
])) as unknown as AgentRow[];
|
|
1536
|
+
const agents: AgentDefinition[] = [];
|
|
1537
|
+
for (const row of rows) {
|
|
1538
|
+
const agent = fromAgentRow(row);
|
|
1539
|
+
agents.push({
|
|
1540
|
+
...agent,
|
|
1541
|
+
procedureIds: await this.#procedureIds(
|
|
1542
|
+
transaction,
|
|
1543
|
+
agent.tenantId,
|
|
1544
|
+
agent.id,
|
|
1545
|
+
),
|
|
1546
|
+
});
|
|
1547
|
+
}
|
|
1548
|
+
return agents;
|
|
1549
|
+
});
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
providerUsage(
|
|
1553
|
+
tenantId: string,
|
|
1554
|
+
providerId: string,
|
|
1555
|
+
): Promise<{ readonly definitions: number; readonly pendingRuns: number }> {
|
|
1556
|
+
return this.#tx(tenantId, 'read', async (transaction) => {
|
|
1557
|
+
const definitions = (
|
|
1558
|
+
await this.#query(transaction, AGENTS_SQL.providerUsage1, [
|
|
1559
|
+
tenantId,
|
|
1560
|
+
providerId,
|
|
1561
|
+
tenantId,
|
|
1562
|
+
providerId,
|
|
1563
|
+
])
|
|
1564
|
+
)[0] as unknown as { count: number | string };
|
|
1565
|
+
const pendingRuns = (
|
|
1566
|
+
await this.#query(transaction, AGENTS_SQL.providerUsage2, [
|
|
1567
|
+
tenantId,
|
|
1568
|
+
providerId,
|
|
1569
|
+
])
|
|
1570
|
+
)[0] as unknown as { count: number | string };
|
|
1571
|
+
return {
|
|
1572
|
+
definitions: integer(definitions.count),
|
|
1573
|
+
pendingRuns: integer(pendingRuns.count),
|
|
1574
|
+
};
|
|
1575
|
+
});
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
agentUsage(
|
|
1579
|
+
tenantId: string,
|
|
1580
|
+
agentId: string,
|
|
1581
|
+
): Promise<{
|
|
1582
|
+
readonly runs: number;
|
|
1583
|
+
readonly pendingRuns: number;
|
|
1584
|
+
readonly assignments: number;
|
|
1585
|
+
}> {
|
|
1586
|
+
return this.#tx(tenantId, 'read', async (transaction) => {
|
|
1587
|
+
const counts = (
|
|
1588
|
+
await this.#query(transaction, AGENTS_SQL.agentUsage, [
|
|
1589
|
+
tenantId,
|
|
1590
|
+
agentId,
|
|
1591
|
+
tenantId,
|
|
1592
|
+
agentId,
|
|
1593
|
+
tenantId,
|
|
1594
|
+
agentId,
|
|
1595
|
+
])
|
|
1596
|
+
)[0] as unknown as {
|
|
1597
|
+
runs: number;
|
|
1598
|
+
pending_runs: number;
|
|
1599
|
+
assignments: number;
|
|
1600
|
+
};
|
|
1601
|
+
return {
|
|
1602
|
+
runs: counts.runs,
|
|
1603
|
+
pendingRuns: counts.pending_runs,
|
|
1604
|
+
assignments: counts.assignments,
|
|
1605
|
+
};
|
|
1606
|
+
});
|
|
1607
|
+
}
|
|
1608
|
+
|
|
1609
|
+
async getAgent(
|
|
1610
|
+
tenantId: string,
|
|
1611
|
+
agentId: string,
|
|
1612
|
+
): Promise<AgentDefinition | null> {
|
|
1613
|
+
return this.#tx(tenantId, 'read', async (transaction) => {
|
|
1614
|
+
const row = (
|
|
1615
|
+
await this.#query(transaction, AGENTS_SQL.getAgent, [tenantId, agentId])
|
|
1616
|
+
)[0] as unknown as AgentRow | undefined;
|
|
1617
|
+
if (!row) return null;
|
|
1618
|
+
const agent = fromAgentRow(row);
|
|
1619
|
+
return {
|
|
1620
|
+
...agent,
|
|
1621
|
+
procedureIds: await this.#procedureIds(
|
|
1622
|
+
transaction,
|
|
1623
|
+
agent.tenantId,
|
|
1624
|
+
agent.id,
|
|
1625
|
+
),
|
|
1626
|
+
};
|
|
1627
|
+
});
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1630
|
+
async getAgentRevision(
|
|
1631
|
+
tenantId: string,
|
|
1632
|
+
agentId: string,
|
|
1633
|
+
revision: number,
|
|
1634
|
+
): Promise<AgentDefinitionRevision | null> {
|
|
1635
|
+
return this.#tx(tenantId, 'read', async (transaction) => {
|
|
1636
|
+
const row = (
|
|
1637
|
+
await this.#query(transaction, AGENTS_SQL.getAgentRevision, [
|
|
1638
|
+
tenantId,
|
|
1639
|
+
agentId,
|
|
1640
|
+
revision,
|
|
1641
|
+
])
|
|
1642
|
+
)[0] as unknown as AgentRevisionRow | undefined;
|
|
1643
|
+
return row ? fromRevisionRow(row) : null;
|
|
1644
|
+
});
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
async listAgentRevisions(
|
|
1648
|
+
tenantId: string,
|
|
1649
|
+
): Promise<readonly AgentDefinitionRevision[]> {
|
|
1650
|
+
return this.#tx(tenantId, 'read', async (transaction) => {
|
|
1651
|
+
return (
|
|
1652
|
+
(await this.#query(transaction, AGENTS_SQL.listAgentRevisions, [
|
|
1653
|
+
tenantId,
|
|
1654
|
+
])) as unknown as AgentRevisionRow[]
|
|
1655
|
+
).map(fromRevisionRow);
|
|
1656
|
+
});
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1659
|
+
async createAgent(agent: AgentDefinition): Promise<AgentDefinition> {
|
|
1660
|
+
return this.#tx(agent.tenantId, 'write', async (transaction) => {
|
|
1661
|
+
try {
|
|
1662
|
+
await this.#exec(transaction, AGENTS_SQL.createAgent1, [
|
|
1663
|
+
agent.id,
|
|
1664
|
+
agent.tenantId,
|
|
1665
|
+
agent.key,
|
|
1666
|
+
agent.name,
|
|
1667
|
+
agent.description,
|
|
1668
|
+
agent.instructions,
|
|
1669
|
+
agent.provider,
|
|
1670
|
+
agent.model,
|
|
1671
|
+
JSON.stringify(agent.allowedTools),
|
|
1672
|
+
agent.maxSteps,
|
|
1673
|
+
Math.min(agent.timeoutMs, 300_000),
|
|
1674
|
+
Math.round(agent.temperature * 1_000),
|
|
1675
|
+
agent.status,
|
|
1676
|
+
agent.revision,
|
|
1677
|
+
agent.createdBy,
|
|
1678
|
+
agent.createdAt,
|
|
1679
|
+
agent.updatedBy,
|
|
1680
|
+
agent.updatedAt,
|
|
1681
|
+
]);
|
|
1682
|
+
await this.#exec(transaction, AGENTS_SQL.createAgent2, [
|
|
1683
|
+
agent.id,
|
|
1684
|
+
agent.tenantId,
|
|
1685
|
+
agent.timeoutMs,
|
|
1686
|
+
]);
|
|
1687
|
+
await this.#exec(transaction, AGENTS_SQL.createAgent3, [
|
|
1688
|
+
agent.id,
|
|
1689
|
+
agent.tenantId,
|
|
1690
|
+
agent.maxOutputTokens,
|
|
1691
|
+
]);
|
|
1692
|
+
await this.#setAgentSkills(transaction, agent);
|
|
1693
|
+
await this.#retainAgentRevision(transaction, agent);
|
|
1694
|
+
} catch (error) {
|
|
1695
|
+
if (
|
|
1696
|
+
String(error).includes('agent_definitions_tenant_id_agent_key_key')
|
|
1697
|
+
) {
|
|
1698
|
+
throw new DuplicateAgentKeyError();
|
|
1699
|
+
}
|
|
1700
|
+
throw error;
|
|
1701
|
+
}
|
|
1702
|
+
return agent;
|
|
1703
|
+
});
|
|
1704
|
+
}
|
|
1705
|
+
|
|
1706
|
+
async updateAgent(agent: AgentDefinition): Promise<AgentDefinition> {
|
|
1707
|
+
return this.#tx(agent.tenantId, 'write', async (transaction) => {
|
|
1708
|
+
try {
|
|
1709
|
+
const result = await this.#exec(transaction, AGENTS_SQL.updateAgent1, [
|
|
1710
|
+
agent.key,
|
|
1711
|
+
agent.name,
|
|
1712
|
+
agent.description,
|
|
1713
|
+
agent.instructions,
|
|
1714
|
+
agent.provider,
|
|
1715
|
+
agent.model,
|
|
1716
|
+
JSON.stringify(agent.allowedTools),
|
|
1717
|
+
agent.maxSteps,
|
|
1718
|
+
Math.min(agent.timeoutMs, 300_000),
|
|
1719
|
+
Math.round(agent.temperature * 1_000),
|
|
1720
|
+
agent.status,
|
|
1721
|
+
agent.revision,
|
|
1722
|
+
agent.updatedBy,
|
|
1723
|
+
agent.updatedAt,
|
|
1724
|
+
agent.tenantId,
|
|
1725
|
+
agent.id,
|
|
1726
|
+
]);
|
|
1727
|
+
if (result !== 1) throw new Error('Agent definition not found.');
|
|
1728
|
+
await this.#exec(transaction, AGENTS_SQL.updateAgent2, [
|
|
1729
|
+
agent.id,
|
|
1730
|
+
agent.tenantId,
|
|
1731
|
+
agent.timeoutMs,
|
|
1732
|
+
]);
|
|
1733
|
+
await this.#exec(transaction, AGENTS_SQL.updateAgent3, [
|
|
1734
|
+
agent.id,
|
|
1735
|
+
agent.tenantId,
|
|
1736
|
+
agent.maxOutputTokens,
|
|
1737
|
+
]);
|
|
1738
|
+
await this.#setAgentSkills(transaction, agent);
|
|
1739
|
+
await this.#retainAgentRevision(transaction, agent);
|
|
1740
|
+
} catch (error) {
|
|
1741
|
+
if (
|
|
1742
|
+
String(error).includes('agent_definitions_tenant_id_agent_key_key')
|
|
1743
|
+
) {
|
|
1744
|
+
throw new DuplicateAgentKeyError();
|
|
1745
|
+
}
|
|
1746
|
+
throw error;
|
|
1747
|
+
}
|
|
1748
|
+
return agent;
|
|
1749
|
+
});
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1752
|
+
async deleteAgent(tenantId: string, agentId: string): Promise<boolean> {
|
|
1753
|
+
return this.#tx(tenantId, 'write', async (transaction) => {
|
|
1754
|
+
return (
|
|
1755
|
+
(await this.#exec(transaction, AGENTS_SQL.deleteAgent, [
|
|
1756
|
+
tenantId,
|
|
1757
|
+
agentId,
|
|
1758
|
+
])) === 1
|
|
1759
|
+
);
|
|
1760
|
+
});
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
async listProcedures(tenantId: string): Promise<readonly AgentProcedure[]> {
|
|
1764
|
+
return this.#tx(tenantId, 'read', async (transaction) => {
|
|
1765
|
+
return (
|
|
1766
|
+
(await this.#query(transaction, AGENTS_SQL.listProcedures, [
|
|
1767
|
+
tenantId,
|
|
1768
|
+
])) as unknown as SkillRow[]
|
|
1769
|
+
).map(fromSkillRow);
|
|
1770
|
+
});
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1773
|
+
async getProcedure(
|
|
1774
|
+
tenantId: string,
|
|
1775
|
+
skillId: string,
|
|
1776
|
+
): Promise<AgentProcedure | null> {
|
|
1777
|
+
return this.#tx(tenantId, 'read', async (transaction) => {
|
|
1778
|
+
const row = (
|
|
1779
|
+
await this.#query(transaction, AGENTS_SQL.getProcedure, [
|
|
1780
|
+
tenantId,
|
|
1781
|
+
skillId,
|
|
1782
|
+
])
|
|
1783
|
+
)[0] as unknown as SkillRow | undefined;
|
|
1784
|
+
return row ? fromSkillRow(row) : null;
|
|
1785
|
+
});
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
async createProcedure(skill: AgentProcedure): Promise<AgentProcedure> {
|
|
1789
|
+
return this.#tx(skill.tenantId, 'write', async (transaction) => {
|
|
1790
|
+
try {
|
|
1791
|
+
await this.#exec(transaction, AGENTS_SQL.createProcedure, [
|
|
1792
|
+
skill.id,
|
|
1793
|
+
skill.tenantId,
|
|
1794
|
+
skill.key,
|
|
1795
|
+
skill.name,
|
|
1796
|
+
skill.description,
|
|
1797
|
+
skill.instructions,
|
|
1798
|
+
JSON.stringify(skill.requiredTools),
|
|
1799
|
+
skill.status,
|
|
1800
|
+
skill.revision,
|
|
1801
|
+
skill.createdBy,
|
|
1802
|
+
skill.createdAt,
|
|
1803
|
+
skill.updatedBy,
|
|
1804
|
+
skill.updatedAt,
|
|
1805
|
+
]);
|
|
1806
|
+
} catch (error) {
|
|
1807
|
+
if (String(error).includes('agent_skills_tenant_id_skill_key_key')) {
|
|
1808
|
+
throw new DuplicateAgentProcedureKeyError();
|
|
1809
|
+
}
|
|
1810
|
+
throw error;
|
|
1811
|
+
}
|
|
1812
|
+
return skill;
|
|
1813
|
+
});
|
|
1814
|
+
}
|
|
1815
|
+
|
|
1816
|
+
async updateProcedure(skill: AgentProcedure): Promise<AgentProcedure> {
|
|
1817
|
+
return this.#tx(skill.tenantId, 'write', async (transaction) => {
|
|
1818
|
+
try {
|
|
1819
|
+
const result = await this.#exec(
|
|
1820
|
+
transaction,
|
|
1821
|
+
AGENTS_SQL.updateProcedure,
|
|
1822
|
+
[
|
|
1823
|
+
skill.key,
|
|
1824
|
+
skill.name,
|
|
1825
|
+
skill.description,
|
|
1826
|
+
skill.instructions,
|
|
1827
|
+
JSON.stringify(skill.requiredTools),
|
|
1828
|
+
skill.status,
|
|
1829
|
+
skill.revision,
|
|
1830
|
+
skill.updatedBy,
|
|
1831
|
+
skill.updatedAt,
|
|
1832
|
+
skill.tenantId,
|
|
1833
|
+
skill.id,
|
|
1834
|
+
],
|
|
1835
|
+
);
|
|
1836
|
+
if (result !== 1) throw new Error('Agent skill not found.');
|
|
1837
|
+
} catch (error) {
|
|
1838
|
+
if (String(error).includes('agent_skills_tenant_id_skill_key_key')) {
|
|
1839
|
+
throw new DuplicateAgentProcedureKeyError();
|
|
1840
|
+
}
|
|
1841
|
+
throw error;
|
|
1842
|
+
}
|
|
1843
|
+
return skill;
|
|
1844
|
+
});
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1847
|
+
procedureUsage(
|
|
1848
|
+
tenantId: string,
|
|
1849
|
+
skillId: string,
|
|
1850
|
+
): Promise<{
|
|
1851
|
+
readonly assignments: number;
|
|
1852
|
+
readonly activeDefinitions: number;
|
|
1853
|
+
}> {
|
|
1854
|
+
return this.#tx(tenantId, 'read', async (transaction) => {
|
|
1855
|
+
const counts = (
|
|
1856
|
+
await this.#query(transaction, AGENTS_SQL.procedureUsage, [
|
|
1857
|
+
tenantId,
|
|
1858
|
+
skillId,
|
|
1859
|
+
])
|
|
1860
|
+
)[0] as unknown as {
|
|
1861
|
+
assignments: number;
|
|
1862
|
+
active_definitions: number | null;
|
|
1863
|
+
};
|
|
1864
|
+
return {
|
|
1865
|
+
assignments: counts.assignments,
|
|
1866
|
+
activeDefinitions: counts.active_definitions ?? 0,
|
|
1867
|
+
};
|
|
1868
|
+
});
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1871
|
+
async deleteProcedure(tenantId: string, skillId: string): Promise<boolean> {
|
|
1872
|
+
return this.#tx(tenantId, 'write', async (transaction) => {
|
|
1873
|
+
return (
|
|
1874
|
+
(await this.#exec(transaction, AGENTS_SQL.deleteProcedure, [
|
|
1875
|
+
tenantId,
|
|
1876
|
+
skillId,
|
|
1877
|
+
])) === 1
|
|
1878
|
+
);
|
|
1879
|
+
});
|
|
1880
|
+
}
|
|
1881
|
+
|
|
1882
|
+
async listRuns(
|
|
1883
|
+
tenantId: string,
|
|
1884
|
+
limit: number,
|
|
1885
|
+
): Promise<readonly AgentRun[]> {
|
|
1886
|
+
return this.#tx(tenantId, 'read', async (transaction) => {
|
|
1887
|
+
const rows = (await this.#query(transaction, AGENTS_SQL.listRuns, [
|
|
1888
|
+
tenantId,
|
|
1889
|
+
limit,
|
|
1890
|
+
])) as unknown as RunRow[];
|
|
1891
|
+
const runs: AgentRun[] = [];
|
|
1892
|
+
for (const row of rows) {
|
|
1893
|
+
const run = fromRunRow(row);
|
|
1894
|
+
runs.push({
|
|
1895
|
+
...run,
|
|
1896
|
+
procedureSnapshots: await this.#procedureSnapshots(
|
|
1897
|
+
transaction,
|
|
1898
|
+
tenantId,
|
|
1899
|
+
run.id,
|
|
1900
|
+
),
|
|
1901
|
+
});
|
|
1902
|
+
}
|
|
1903
|
+
return runs;
|
|
1904
|
+
});
|
|
1905
|
+
}
|
|
1906
|
+
|
|
1907
|
+
async getRun(
|
|
1908
|
+
tenantId: string,
|
|
1909
|
+
runId: string,
|
|
1910
|
+
): Promise<AgentRunDetail | null> {
|
|
1911
|
+
return this.#tx(tenantId, 'read', async (transaction) => {
|
|
1912
|
+
const row = (
|
|
1913
|
+
await this.#query(transaction, AGENTS_SQL.getRun, [tenantId, runId])
|
|
1914
|
+
)[0] as unknown as RunRow | undefined;
|
|
1915
|
+
if (!row) return null;
|
|
1916
|
+
const events = await this.#runEventsIn(transaction, tenantId, runId, 0);
|
|
1917
|
+
return {
|
|
1918
|
+
...fromRunRow(row),
|
|
1919
|
+
procedureSnapshots: await this.#procedureSnapshots(
|
|
1920
|
+
transaction,
|
|
1921
|
+
tenantId,
|
|
1922
|
+
row.id,
|
|
1923
|
+
),
|
|
1924
|
+
events,
|
|
1925
|
+
};
|
|
1926
|
+
});
|
|
1927
|
+
}
|
|
1928
|
+
|
|
1929
|
+
async #runEventsIn(
|
|
1930
|
+
transaction: DatabaseTransaction,
|
|
1931
|
+
tenantId: string,
|
|
1932
|
+
runId: string,
|
|
1933
|
+
afterSequence: number,
|
|
1934
|
+
): Promise<readonly AgentExecutionEvent[]> {
|
|
1935
|
+
{
|
|
1936
|
+
return (
|
|
1937
|
+
(await this.#query(transaction, AGENTS_SQL.listRunEvents, [
|
|
1938
|
+
tenantId,
|
|
1939
|
+
runId,
|
|
1940
|
+
afterSequence,
|
|
1941
|
+
])) as unknown as RunEventRow[]
|
|
1942
|
+
).map(
|
|
1943
|
+
(event): AgentExecutionEvent => ({
|
|
1944
|
+
sequence: integer(event.sequence),
|
|
1945
|
+
type: event.event_type,
|
|
1946
|
+
timestamp: integer(event.occurred_at),
|
|
1947
|
+
message: event.message,
|
|
1948
|
+
metadata: metadata(event.metadata_json),
|
|
1949
|
+
}),
|
|
1950
|
+
);
|
|
1951
|
+
}
|
|
1952
|
+
}
|
|
1953
|
+
|
|
1954
|
+
async listRunEvents(
|
|
1955
|
+
tenantId: string,
|
|
1956
|
+
runId: string,
|
|
1957
|
+
afterSequence: number,
|
|
1958
|
+
): Promise<readonly AgentExecutionEvent[]> {
|
|
1959
|
+
return this.#tx(tenantId, 'read', (transaction) =>
|
|
1960
|
+
this.#runEventsIn(transaction, tenantId, runId, afterSequence),
|
|
1961
|
+
);
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1964
|
+
async findRunByIdempotencyKey(
|
|
1965
|
+
tenantId: string,
|
|
1966
|
+
idempotencyKey: string,
|
|
1967
|
+
): Promise<AgentRun | null> {
|
|
1968
|
+
return this.#tx(tenantId, 'read', async (transaction) => {
|
|
1969
|
+
const row = (
|
|
1970
|
+
await this.#query(transaction, AGENTS_SQL.findRunByIdempotencyKey, [
|
|
1971
|
+
tenantId,
|
|
1972
|
+
idempotencyKey,
|
|
1973
|
+
])
|
|
1974
|
+
)[0] as unknown as RunRow | undefined;
|
|
1975
|
+
if (!row) return null;
|
|
1976
|
+
const run = fromRunRow(row);
|
|
1977
|
+
return {
|
|
1978
|
+
...run,
|
|
1979
|
+
procedureSnapshots: await this.#procedureSnapshots(
|
|
1980
|
+
transaction,
|
|
1981
|
+
tenantId,
|
|
1982
|
+
run.id,
|
|
1983
|
+
),
|
|
1984
|
+
};
|
|
1985
|
+
});
|
|
1986
|
+
}
|
|
1987
|
+
|
|
1988
|
+
async enqueueRun(
|
|
1989
|
+
execution: AgentRunExecution,
|
|
1990
|
+
idempotencyKey: string | null,
|
|
1991
|
+
audit: PendingAgentAuditEvent,
|
|
1992
|
+
): Promise<AgentRun> {
|
|
1993
|
+
return this.#tx(execution.run.tenantId, 'write', async (transaction) => {
|
|
1994
|
+
const { run, definition } = execution;
|
|
1995
|
+
try {
|
|
1996
|
+
await this.#exec(transaction, AGENTS_SQL.enqueueRun1, [
|
|
1997
|
+
run.id,
|
|
1998
|
+
run.tenantId,
|
|
1999
|
+
run.agentId,
|
|
2000
|
+
run.agentName,
|
|
2001
|
+
run.agentRevision,
|
|
2002
|
+
definition.instructions,
|
|
2003
|
+
run.provider,
|
|
2004
|
+
run.model,
|
|
2005
|
+
JSON.stringify(definition.allowedTools),
|
|
2006
|
+
definition.maxSteps,
|
|
2007
|
+
Math.min(definition.timeoutMs, 300_000),
|
|
2008
|
+
Math.round(definition.temperature * 1_000),
|
|
2009
|
+
run.trigger,
|
|
2010
|
+
run.input,
|
|
2011
|
+
run.requestedBy,
|
|
2012
|
+
JSON.stringify(run.permissionSnapshot),
|
|
2013
|
+
JSON.stringify(run.toolGrants),
|
|
2014
|
+
idempotencyKey,
|
|
2015
|
+
run.queuedAt,
|
|
2016
|
+
]);
|
|
2017
|
+
await this.#exec(transaction, AGENTS_SQL.enqueueRun2, [
|
|
2018
|
+
run.id,
|
|
2019
|
+
run.tenantId,
|
|
2020
|
+
definition.timeoutMs,
|
|
2021
|
+
]);
|
|
2022
|
+
await this.#exec(transaction, AGENTS_SQL.enqueueRun3, [
|
|
2023
|
+
run.id,
|
|
2024
|
+
run.tenantId,
|
|
2025
|
+
definition.maxOutputTokens ?? DEFAULT_MAX_OUTPUT_TOKENS,
|
|
2026
|
+
]);
|
|
2027
|
+
for (const skill of run.procedureSnapshots) {
|
|
2028
|
+
await this.#exec(transaction, AGENTS_SQL.enqueueRun4, [
|
|
2029
|
+
run.id,
|
|
2030
|
+
run.tenantId,
|
|
2031
|
+
skill.id,
|
|
2032
|
+
skill.key,
|
|
2033
|
+
skill.name,
|
|
2034
|
+
skill.revision,
|
|
2035
|
+
JSON.stringify(skill.requiredTools),
|
|
2036
|
+
]);
|
|
2037
|
+
}
|
|
2038
|
+
await this.#exec(transaction, AGENTS_SQL.enqueueRun5, [
|
|
2039
|
+
run.id,
|
|
2040
|
+
run.tenantId,
|
|
2041
|
+
run.workflowRunId,
|
|
2042
|
+
JSON.stringify(run.outputContract),
|
|
2043
|
+
createHash('sha256')
|
|
2044
|
+
.update(
|
|
2045
|
+
JSON.stringify([
|
|
2046
|
+
run.agentId,
|
|
2047
|
+
run.agentRevision,
|
|
2048
|
+
run.input,
|
|
2049
|
+
run.outputContract,
|
|
2050
|
+
run.workflowRunId,
|
|
2051
|
+
]),
|
|
2052
|
+
)
|
|
2053
|
+
.digest('hex'),
|
|
2054
|
+
]);
|
|
2055
|
+
await this.#exec(transaction, AGENTS_SQL.enqueueRun6, [
|
|
2056
|
+
run.id,
|
|
2057
|
+
run.tenantId,
|
|
2058
|
+
JSON.stringify(run.requestedActor),
|
|
2059
|
+
run.authorizationSubject
|
|
2060
|
+
? JSON.stringify(run.authorizationSubject)
|
|
2061
|
+
: null,
|
|
2062
|
+
]);
|
|
2063
|
+
await this.#appendAuditEvent(transaction, audit);
|
|
2064
|
+
} catch (error) {
|
|
2065
|
+
if (
|
|
2066
|
+
String(error).includes('agent_runs_tenant_id_idempotency_key_key')
|
|
2067
|
+
) {
|
|
2068
|
+
throw new DuplicateRunIdempotencyKeyError();
|
|
2069
|
+
}
|
|
2070
|
+
throw error;
|
|
2071
|
+
}
|
|
2072
|
+
return run;
|
|
2073
|
+
});
|
|
2074
|
+
}
|
|
2075
|
+
|
|
2076
|
+
async listRecoverableRuns(
|
|
2077
|
+
now: number,
|
|
2078
|
+
limit: number,
|
|
2079
|
+
): Promise<readonly RecoverableRun[]> {
|
|
2080
|
+
return this.#crossTenant(async (transaction) => {
|
|
2081
|
+
return (
|
|
2082
|
+
(await this.#query(transaction, AGENTS_SQL.listRecoverableRuns, [
|
|
2083
|
+
now,
|
|
2084
|
+
limit,
|
|
2085
|
+
])) as unknown as RecoverableRow[]
|
|
2086
|
+
).map((row) => ({ tenantId: row.tenant_id, runId: row.id }));
|
|
2087
|
+
});
|
|
2088
|
+
}
|
|
2089
|
+
|
|
2090
|
+
async claimRun(
|
|
2091
|
+
tenantId: string,
|
|
2092
|
+
runId: string,
|
|
2093
|
+
workerId: string,
|
|
2094
|
+
now: number,
|
|
2095
|
+
leaseExpiresAt: number,
|
|
2096
|
+
audit: PendingAgentAuditEvent,
|
|
2097
|
+
): Promise<AgentRunExecution | null> {
|
|
2098
|
+
return this.#tx(tenantId, 'write', async (transaction) => {
|
|
2099
|
+
try {
|
|
2100
|
+
const result = await this.#exec(transaction, AGENTS_SQL.claimRun1, [
|
|
2101
|
+
workerId,
|
|
2102
|
+
leaseExpiresAt,
|
|
2103
|
+
now,
|
|
2104
|
+
tenantId,
|
|
2105
|
+
runId,
|
|
2106
|
+
now,
|
|
2107
|
+
]);
|
|
2108
|
+
if (result !== 1) {
|
|
2109
|
+
return null;
|
|
2110
|
+
}
|
|
2111
|
+
const row = (
|
|
2112
|
+
await this.#query(transaction, AGENTS_SQL.claimRun2, [
|
|
2113
|
+
tenantId,
|
|
2114
|
+
runId,
|
|
2115
|
+
])
|
|
2116
|
+
)[0] as unknown as RunRow;
|
|
2117
|
+
const execution = executionFromRow(row);
|
|
2118
|
+
await this.#appendAuditEvent(transaction, {
|
|
2119
|
+
...audit,
|
|
2120
|
+
metadata: { ...audit.metadata, attempt: execution.run.attempt },
|
|
2121
|
+
});
|
|
2122
|
+
return {
|
|
2123
|
+
...execution,
|
|
2124
|
+
run: {
|
|
2125
|
+
...execution.run,
|
|
2126
|
+
procedureSnapshots: await this.#procedureSnapshots(
|
|
2127
|
+
transaction,
|
|
2128
|
+
execution.run.tenantId,
|
|
2129
|
+
execution.run.id,
|
|
2130
|
+
),
|
|
2131
|
+
},
|
|
2132
|
+
};
|
|
2133
|
+
} catch (error) {
|
|
2134
|
+
throw error;
|
|
2135
|
+
}
|
|
2136
|
+
});
|
|
2137
|
+
}
|
|
2138
|
+
|
|
2139
|
+
async renewLease(
|
|
2140
|
+
tenantId: string,
|
|
2141
|
+
runId: string,
|
|
2142
|
+
workerId: string,
|
|
2143
|
+
leaseExpiresAt: number,
|
|
2144
|
+
): Promise<boolean> {
|
|
2145
|
+
return this.#tx(tenantId, 'write', async (transaction) => {
|
|
2146
|
+
return (
|
|
2147
|
+
(await this.#exec(transaction, AGENTS_SQL.renewLease, [
|
|
2148
|
+
leaseExpiresAt,
|
|
2149
|
+
tenantId,
|
|
2150
|
+
runId,
|
|
2151
|
+
workerId,
|
|
2152
|
+
])) === 1
|
|
2153
|
+
);
|
|
2154
|
+
});
|
|
2155
|
+
}
|
|
2156
|
+
|
|
2157
|
+
async consumeRunGrant(input: {
|
|
2158
|
+
readonly grantId: string;
|
|
2159
|
+
readonly tokenHash: string;
|
|
2160
|
+
readonly tenantId: string;
|
|
2161
|
+
readonly runId: string;
|
|
2162
|
+
readonly workerId: string;
|
|
2163
|
+
readonly providerId: string;
|
|
2164
|
+
readonly modelId: string;
|
|
2165
|
+
readonly issuedAt: number;
|
|
2166
|
+
readonly expiresAt: number;
|
|
2167
|
+
readonly consumedAt: number;
|
|
2168
|
+
}): Promise<boolean> {
|
|
2169
|
+
return this.#tx(input.tenantId, 'write', async (transaction) => {
|
|
2170
|
+
await this.#exec(transaction, AGENTS_SQL.consumeRunGrant1, [
|
|
2171
|
+
input.consumedAt,
|
|
2172
|
+
]);
|
|
2173
|
+
const result = await this.#exec(
|
|
2174
|
+
transaction,
|
|
2175
|
+
AGENTS_SQL.consumeRunGrant2,
|
|
2176
|
+
[
|
|
2177
|
+
input.grantId,
|
|
2178
|
+
input.tokenHash,
|
|
2179
|
+
input.tenantId,
|
|
2180
|
+
input.runId,
|
|
2181
|
+
input.workerId,
|
|
2182
|
+
input.providerId,
|
|
2183
|
+
input.modelId,
|
|
2184
|
+
input.issuedAt,
|
|
2185
|
+
input.expiresAt,
|
|
2186
|
+
input.consumedAt,
|
|
2187
|
+
input.tenantId,
|
|
2188
|
+
input.runId,
|
|
2189
|
+
input.workerId,
|
|
2190
|
+
input.consumedAt,
|
|
2191
|
+
],
|
|
2192
|
+
);
|
|
2193
|
+
return result === 1;
|
|
2194
|
+
});
|
|
2195
|
+
}
|
|
2196
|
+
|
|
2197
|
+
async appendRunEvent(
|
|
2198
|
+
tenantId: string,
|
|
2199
|
+
runId: string,
|
|
2200
|
+
event: AgentExecutionEvent,
|
|
2201
|
+
): Promise<void> {
|
|
2202
|
+
return this.#tx(tenantId, 'write', async (transaction) => {
|
|
2203
|
+
// A server has multiple connections; MAX(sequence) needs a per-run lock.
|
|
2204
|
+
await transaction.query({
|
|
2205
|
+
text: 'SELECT id FROM agent_runs WHERE tenant_id = $1 AND id = $2 FOR UPDATE',
|
|
2206
|
+
parameters: [tenantId, runId],
|
|
2207
|
+
});
|
|
2208
|
+
await this.#exec(transaction, AGENTS_SQL.appendRunEvent, [
|
|
2209
|
+
runId,
|
|
2210
|
+
tenantId,
|
|
2211
|
+
event.type,
|
|
2212
|
+
event.message,
|
|
2213
|
+
stableMetadata(event.metadata ?? {}),
|
|
2214
|
+
event.timestamp,
|
|
2215
|
+
runId,
|
|
2216
|
+
tenantId,
|
|
2217
|
+
]);
|
|
2218
|
+
});
|
|
2219
|
+
}
|
|
2220
|
+
|
|
2221
|
+
/* Settling the run and projecting its cost share one transaction: a run that
|
|
2222
|
+
succeeded but is missing from the rollup would understate every budget
|
|
2223
|
+
check that follows it. */
|
|
2224
|
+
async completeRun(
|
|
2225
|
+
tenantId: string,
|
|
2226
|
+
runId: string,
|
|
2227
|
+
workerId: string,
|
|
2228
|
+
result: AgentExecutionResult,
|
|
2229
|
+
audit: PendingAgentAuditEvent,
|
|
2230
|
+
): Promise<void> {
|
|
2231
|
+
return this.#tx(tenantId, 'write', async (transaction) => {
|
|
2232
|
+
try {
|
|
2233
|
+
const update = await this.#exec(transaction, AGENTS_SQL.completeRun1, [
|
|
2234
|
+
result.output,
|
|
2235
|
+
JSON.stringify(result.usage),
|
|
2236
|
+
result.completedAt,
|
|
2237
|
+
tenantId,
|
|
2238
|
+
runId,
|
|
2239
|
+
workerId,
|
|
2240
|
+
]);
|
|
2241
|
+
if (update !== 1) throw new Error('Agent run lease was lost.');
|
|
2242
|
+
await this.#exec(transaction, AGENTS_SQL.completeRun2, [
|
|
2243
|
+
result.structuredOutput === undefined
|
|
2244
|
+
? null
|
|
2245
|
+
: JSON.stringify(result.structuredOutput),
|
|
2246
|
+
tenantId,
|
|
2247
|
+
runId,
|
|
2248
|
+
]);
|
|
2249
|
+
const run = (
|
|
2250
|
+
await this.#query(transaction, AGENTS_SQL.completeRun3, [
|
|
2251
|
+
tenantId,
|
|
2252
|
+
runId,
|
|
2253
|
+
])
|
|
2254
|
+
)[0] as unknown as {
|
|
2255
|
+
agent_id: string;
|
|
2256
|
+
agent_name: string;
|
|
2257
|
+
model: string;
|
|
2258
|
+
};
|
|
2259
|
+
await this.#exec(transaction, AGENTS_SQL.completeRun4, [
|
|
2260
|
+
runId,
|
|
2261
|
+
tenantId,
|
|
2262
|
+
run.agent_id,
|
|
2263
|
+
run.agent_name,
|
|
2264
|
+
run.model,
|
|
2265
|
+
usageDay(result.completedAt),
|
|
2266
|
+
Math.max(0, Math.trunc(result.usage.inputTokens)),
|
|
2267
|
+
Math.max(0, Math.trunc(result.usage.outputTokens)),
|
|
2268
|
+
usageCostMicros(run.model, result.usage),
|
|
2269
|
+
result.completedAt,
|
|
2270
|
+
]);
|
|
2271
|
+
await this.#appendAuditEvent(transaction, audit);
|
|
2272
|
+
} catch (error) {
|
|
2273
|
+
throw error;
|
|
2274
|
+
}
|
|
2275
|
+
});
|
|
2276
|
+
}
|
|
2277
|
+
|
|
2278
|
+
async failRun(
|
|
2279
|
+
tenantId: string,
|
|
2280
|
+
runId: string,
|
|
2281
|
+
workerId: string,
|
|
2282
|
+
code: string,
|
|
2283
|
+
message: string,
|
|
2284
|
+
completedAt: number,
|
|
2285
|
+
audit: PendingAgentAuditEvent,
|
|
2286
|
+
): Promise<void> {
|
|
2287
|
+
return this.#tx(tenantId, 'write', async (transaction) => {
|
|
2288
|
+
try {
|
|
2289
|
+
const update = await this.#exec(transaction, AGENTS_SQL.failRun, [
|
|
2290
|
+
code,
|
|
2291
|
+
message,
|
|
2292
|
+
completedAt,
|
|
2293
|
+
tenantId,
|
|
2294
|
+
runId,
|
|
2295
|
+
workerId,
|
|
2296
|
+
]);
|
|
2297
|
+
if (update !== 1) throw new Error('Agent run lease was lost.');
|
|
2298
|
+
await this.#appendAuditEvent(transaction, audit);
|
|
2299
|
+
} catch (error) {
|
|
2300
|
+
throw error;
|
|
2301
|
+
}
|
|
2302
|
+
});
|
|
2303
|
+
}
|
|
2304
|
+
|
|
2305
|
+
async cancelRun(
|
|
2306
|
+
tenantId: string,
|
|
2307
|
+
runId: string,
|
|
2308
|
+
message: string,
|
|
2309
|
+
completedAt: number,
|
|
2310
|
+
audit: PendingAgentAuditEvent,
|
|
2311
|
+
): Promise<AgentRun['status'] | null> {
|
|
2312
|
+
return this.#tx(tenantId, 'write', async (transaction) => {
|
|
2313
|
+
try {
|
|
2314
|
+
const current = (
|
|
2315
|
+
await this.#query(transaction, AGENTS_SQL.cancelRun1, [
|
|
2316
|
+
tenantId,
|
|
2317
|
+
runId,
|
|
2318
|
+
])
|
|
2319
|
+
)[0] as unknown as { status: AgentRun['status'] } | undefined;
|
|
2320
|
+
if (!current || !['queued', 'running'].includes(current.status)) {
|
|
2321
|
+
return null;
|
|
2322
|
+
}
|
|
2323
|
+
await this.#exec(transaction, AGENTS_SQL.cancelRun2, [
|
|
2324
|
+
message,
|
|
2325
|
+
completedAt,
|
|
2326
|
+
tenantId,
|
|
2327
|
+
runId,
|
|
2328
|
+
]);
|
|
2329
|
+
await this.#appendAuditEvent(transaction, {
|
|
2330
|
+
...audit,
|
|
2331
|
+
metadata: { ...audit.metadata, previousStatus: current.status },
|
|
2332
|
+
});
|
|
2333
|
+
return current.status;
|
|
2334
|
+
} catch (error) {
|
|
2335
|
+
throw error;
|
|
2336
|
+
}
|
|
2337
|
+
});
|
|
2338
|
+
}
|
|
2339
|
+
|
|
2340
|
+
async enqueueAction(
|
|
2341
|
+
invocation: AgentActionInvocation,
|
|
2342
|
+
audit: PendingAgentAuditEvent,
|
|
2343
|
+
): Promise<AgentActionInvocation> {
|
|
2344
|
+
return this.#tx(invocation.tenantId, 'write', async (transaction) => {
|
|
2345
|
+
try {
|
|
2346
|
+
await this.#exec(transaction, AGENTS_SQL.enqueueAction, [
|
|
2347
|
+
invocation.id,
|
|
2348
|
+
invocation.tenantId,
|
|
2349
|
+
invocation.workflowRunId,
|
|
2350
|
+
invocation.nodeRunId,
|
|
2351
|
+
invocation.actionId,
|
|
2352
|
+
invocation.contractVersion,
|
|
2353
|
+
JSON.stringify(invocation.actor),
|
|
2354
|
+
JSON.stringify(invocation.authorizationSubject),
|
|
2355
|
+
JSON.stringify(invocation.permissionSnapshot),
|
|
2356
|
+
JSON.stringify(invocation.input),
|
|
2357
|
+
invocation.idempotencyKey,
|
|
2358
|
+
invocation.requestHash,
|
|
2359
|
+
invocation.queuedAt,
|
|
2360
|
+
]);
|
|
2361
|
+
await this.#appendAuditEvent(transaction, audit);
|
|
2362
|
+
} catch (error) {
|
|
2363
|
+
if (
|
|
2364
|
+
String(error).includes(
|
|
2365
|
+
'agent_action_invocations_tenant_id_idempotency_key_key',
|
|
2366
|
+
)
|
|
2367
|
+
) {
|
|
2368
|
+
throw new DuplicateActionIdempotencyKeyError();
|
|
2369
|
+
}
|
|
2370
|
+
throw error;
|
|
2371
|
+
}
|
|
2372
|
+
return invocation;
|
|
2373
|
+
});
|
|
2374
|
+
}
|
|
2375
|
+
|
|
2376
|
+
async #actionIn(
|
|
2377
|
+
transaction: DatabaseTransaction,
|
|
2378
|
+
tenantId: string,
|
|
2379
|
+
invocationId: string,
|
|
2380
|
+
): Promise<AgentActionInvocation | null> {
|
|
2381
|
+
const row = (
|
|
2382
|
+
await this.#query(transaction, AGENTS_SQL.getAction, [
|
|
2383
|
+
tenantId,
|
|
2384
|
+
invocationId,
|
|
2385
|
+
])
|
|
2386
|
+
)[0] as unknown as ActionRow | undefined;
|
|
2387
|
+
return row ? fromActionRow(row) : null;
|
|
2388
|
+
}
|
|
2389
|
+
|
|
2390
|
+
async getAction(
|
|
2391
|
+
tenantId: string,
|
|
2392
|
+
invocationId: string,
|
|
2393
|
+
): Promise<AgentActionInvocation | null> {
|
|
2394
|
+
return this.#tx(tenantId, 'read', (transaction) =>
|
|
2395
|
+
this.#actionIn(transaction, tenantId, invocationId),
|
|
2396
|
+
);
|
|
2397
|
+
}
|
|
2398
|
+
|
|
2399
|
+
async findActionByIdempotencyKey(
|
|
2400
|
+
tenantId: string,
|
|
2401
|
+
idempotencyKey: string,
|
|
2402
|
+
): Promise<AgentActionInvocation | null> {
|
|
2403
|
+
return this.#tx(tenantId, 'read', async (transaction) => {
|
|
2404
|
+
const row = (
|
|
2405
|
+
await this.#query(transaction, AGENTS_SQL.findActionByIdempotencyKey, [
|
|
2406
|
+
tenantId,
|
|
2407
|
+
idempotencyKey,
|
|
2408
|
+
])
|
|
2409
|
+
)[0] as unknown as ActionRow | undefined;
|
|
2410
|
+
return row ? fromActionRow(row) : null;
|
|
2411
|
+
});
|
|
2412
|
+
}
|
|
2413
|
+
|
|
2414
|
+
listRecoverableActions(
|
|
2415
|
+
now: number,
|
|
2416
|
+
limit: number,
|
|
2417
|
+
): Promise<
|
|
2418
|
+
readonly { readonly tenantId: string; readonly invocationId: string }[]
|
|
2419
|
+
> {
|
|
2420
|
+
return this.#crossTenant(async (transaction) =>
|
|
2421
|
+
(
|
|
2422
|
+
(await this.#query(transaction, AGENTS_SQL.listRecoverableActions, [
|
|
2423
|
+
now,
|
|
2424
|
+
limit,
|
|
2425
|
+
])) as unknown as { tenant_id: string; id: string }[]
|
|
2426
|
+
).map((row) => ({ tenantId: row.tenant_id, invocationId: row.id })),
|
|
2427
|
+
);
|
|
2428
|
+
}
|
|
2429
|
+
|
|
2430
|
+
async claimAction(
|
|
2431
|
+
tenantId: string,
|
|
2432
|
+
invocationId: string,
|
|
2433
|
+
workerId: string,
|
|
2434
|
+
now: number,
|
|
2435
|
+
leaseExpiresAt: number,
|
|
2436
|
+
audit: PendingAgentAuditEvent,
|
|
2437
|
+
): Promise<AgentActionInvocation | null> {
|
|
2438
|
+
return this.#tx(tenantId, 'write', async (transaction) => {
|
|
2439
|
+
try {
|
|
2440
|
+
const updated = await this.#exec(transaction, AGENTS_SQL.claimAction, [
|
|
2441
|
+
workerId,
|
|
2442
|
+
leaseExpiresAt,
|
|
2443
|
+
now,
|
|
2444
|
+
tenantId,
|
|
2445
|
+
invocationId,
|
|
2446
|
+
now,
|
|
2447
|
+
]);
|
|
2448
|
+
if (updated !== 1) {
|
|
2449
|
+
return null;
|
|
2450
|
+
}
|
|
2451
|
+
const invocation = (await this.#actionIn(
|
|
2452
|
+
transaction,
|
|
2453
|
+
tenantId,
|
|
2454
|
+
invocationId,
|
|
2455
|
+
))!;
|
|
2456
|
+
await this.#appendAuditEvent(transaction, {
|
|
2457
|
+
...audit,
|
|
2458
|
+
metadata: { ...audit.metadata, attempt: invocation.attempt },
|
|
2459
|
+
});
|
|
2460
|
+
return invocation;
|
|
2461
|
+
} catch (error) {
|
|
2462
|
+
throw error;
|
|
2463
|
+
}
|
|
2464
|
+
});
|
|
2465
|
+
}
|
|
2466
|
+
|
|
2467
|
+
async renewActionLease(
|
|
2468
|
+
tenantId: string,
|
|
2469
|
+
invocationId: string,
|
|
2470
|
+
workerId: string,
|
|
2471
|
+
leaseExpiresAt: number,
|
|
2472
|
+
): Promise<boolean> {
|
|
2473
|
+
return this.#tx(tenantId, 'write', async (transaction) => {
|
|
2474
|
+
return (
|
|
2475
|
+
(await this.#exec(transaction, AGENTS_SQL.renewActionLease, [
|
|
2476
|
+
leaseExpiresAt,
|
|
2477
|
+
tenantId,
|
|
2478
|
+
invocationId,
|
|
2479
|
+
workerId,
|
|
2480
|
+
])) === 1
|
|
2481
|
+
);
|
|
2482
|
+
});
|
|
2483
|
+
}
|
|
2484
|
+
|
|
2485
|
+
async completeAction(
|
|
2486
|
+
tenantId: string,
|
|
2487
|
+
invocationId: string,
|
|
2488
|
+
workerId: string,
|
|
2489
|
+
output: JsonValue,
|
|
2490
|
+
completedAt: number,
|
|
2491
|
+
audit: PendingAgentAuditEvent,
|
|
2492
|
+
): Promise<boolean> {
|
|
2493
|
+
return this.#tx(tenantId, 'write', async (transaction) => {
|
|
2494
|
+
try {
|
|
2495
|
+
const changed =
|
|
2496
|
+
(await this.#exec(transaction, AGENTS_SQL.completeAction, [
|
|
2497
|
+
JSON.stringify(output),
|
|
2498
|
+
completedAt,
|
|
2499
|
+
tenantId,
|
|
2500
|
+
invocationId,
|
|
2501
|
+
workerId,
|
|
2502
|
+
])) === 1;
|
|
2503
|
+
if (changed) await this.#appendAuditEvent(transaction, audit);
|
|
2504
|
+
return changed;
|
|
2505
|
+
} catch (error) {
|
|
2506
|
+
throw error;
|
|
2507
|
+
}
|
|
2508
|
+
});
|
|
2509
|
+
}
|
|
2510
|
+
|
|
2511
|
+
async failAction(
|
|
2512
|
+
tenantId: string,
|
|
2513
|
+
invocationId: string,
|
|
2514
|
+
workerId: string,
|
|
2515
|
+
code: string,
|
|
2516
|
+
completedAt: number,
|
|
2517
|
+
audit: PendingAgentAuditEvent,
|
|
2518
|
+
): Promise<boolean> {
|
|
2519
|
+
return this.#tx(tenantId, 'write', async (transaction) => {
|
|
2520
|
+
try {
|
|
2521
|
+
const changed =
|
|
2522
|
+
(await this.#exec(transaction, AGENTS_SQL.failAction, [
|
|
2523
|
+
code,
|
|
2524
|
+
completedAt,
|
|
2525
|
+
tenantId,
|
|
2526
|
+
invocationId,
|
|
2527
|
+
workerId,
|
|
2528
|
+
])) === 1;
|
|
2529
|
+
if (changed) await this.#appendAuditEvent(transaction, audit);
|
|
2530
|
+
return changed;
|
|
2531
|
+
} catch (error) {
|
|
2532
|
+
throw error;
|
|
2533
|
+
}
|
|
2534
|
+
});
|
|
2535
|
+
}
|
|
2536
|
+
|
|
2537
|
+
async cancelAction(
|
|
2538
|
+
tenantId: string,
|
|
2539
|
+
invocationId: string,
|
|
2540
|
+
completedAt: number,
|
|
2541
|
+
audit: PendingAgentAuditEvent,
|
|
2542
|
+
): Promise<AgentActionInvocation['status'] | null> {
|
|
2543
|
+
return this.#tx(tenantId, 'write', async (transaction) => {
|
|
2544
|
+
try {
|
|
2545
|
+
const current = await this.#actionIn(
|
|
2546
|
+
transaction,
|
|
2547
|
+
tenantId,
|
|
2548
|
+
invocationId,
|
|
2549
|
+
);
|
|
2550
|
+
if (!current || !['queued', 'running'].includes(current.status)) {
|
|
2551
|
+
return null;
|
|
2552
|
+
}
|
|
2553
|
+
const changed = await this.#exec(transaction, AGENTS_SQL.cancelAction, [
|
|
2554
|
+
completedAt,
|
|
2555
|
+
tenantId,
|
|
2556
|
+
invocationId,
|
|
2557
|
+
]);
|
|
2558
|
+
if (changed !== 1) {
|
|
2559
|
+
return null;
|
|
2560
|
+
}
|
|
2561
|
+
await this.#appendAuditEvent(transaction, {
|
|
2562
|
+
...audit,
|
|
2563
|
+
metadata: { ...audit.metadata, previousStatus: current.status },
|
|
2564
|
+
});
|
|
2565
|
+
return current.status;
|
|
2566
|
+
} catch (error) {
|
|
2567
|
+
throw error;
|
|
2568
|
+
}
|
|
2569
|
+
});
|
|
2570
|
+
}
|
|
2571
|
+
|
|
2572
|
+
async #appendAuditEvent(
|
|
2573
|
+
transaction: DatabaseTransaction,
|
|
2574
|
+
event: PendingAgentAuditEvent,
|
|
2575
|
+
): Promise<AgentAuditEvent> {
|
|
2576
|
+
await transaction.query({
|
|
2577
|
+
text: 'SELECT pg_advisory_xact_lock(hashtextextended($1, 0))',
|
|
2578
|
+
parameters: [`agents.core.audit:${event.tenantId}`],
|
|
2579
|
+
});
|
|
2580
|
+
const previous = (
|
|
2581
|
+
await this.#query(transaction, AGENTS_SQL.appendAuditEvent1, [
|
|
2582
|
+
event.tenantId,
|
|
2583
|
+
])
|
|
2584
|
+
)[0] as unknown as
|
|
2585
|
+
| { sequence: number | string; event_hash: string }
|
|
2586
|
+
| undefined;
|
|
2587
|
+
/* count and every BIGINT arrive as a string from the server driver, so the
|
|
2588
|
+
next sequence must be added as a number. Without this the chain reads
|
|
2589
|
+
1, then "11", then "111". */
|
|
2590
|
+
const sequence = integer(previous?.sequence ?? 0) + 1;
|
|
2591
|
+
const previousHash = previous?.event_hash ?? null;
|
|
2592
|
+
const metadataJson = stableMetadata(event.metadata);
|
|
2593
|
+
const eventHash = auditHash({
|
|
2594
|
+
tenantId: event.tenantId,
|
|
2595
|
+
sequence,
|
|
2596
|
+
actorId: event.actorId,
|
|
2597
|
+
action: event.action,
|
|
2598
|
+
subjectType: event.subjectType,
|
|
2599
|
+
subjectId: event.subjectId,
|
|
2600
|
+
metadataJson,
|
|
2601
|
+
occurredAt: event.occurredAt,
|
|
2602
|
+
previousHash,
|
|
2603
|
+
});
|
|
2604
|
+
const created: AgentAuditEvent = {
|
|
2605
|
+
...event,
|
|
2606
|
+
id: randomUUID(),
|
|
2607
|
+
sequence,
|
|
2608
|
+
previousHash,
|
|
2609
|
+
eventHash,
|
|
2610
|
+
};
|
|
2611
|
+
await this.#exec(transaction, AGENTS_SQL.appendAuditEvent2, [
|
|
2612
|
+
created.id,
|
|
2613
|
+
created.tenantId,
|
|
2614
|
+
created.sequence,
|
|
2615
|
+
created.actorId,
|
|
2616
|
+
created.action,
|
|
2617
|
+
created.subjectType,
|
|
2618
|
+
created.subjectId,
|
|
2619
|
+
metadataJson,
|
|
2620
|
+
created.occurredAt,
|
|
2621
|
+
created.previousHash,
|
|
2622
|
+
created.eventHash,
|
|
2623
|
+
]);
|
|
2624
|
+
return created;
|
|
2625
|
+
}
|
|
2626
|
+
|
|
2627
|
+
async appendAuditEvent(
|
|
2628
|
+
event: PendingAgentAuditEvent,
|
|
2629
|
+
): Promise<AgentAuditEvent> {
|
|
2630
|
+
return this.#tx(event.tenantId, 'write', (transaction) =>
|
|
2631
|
+
this.#appendAuditEvent(transaction, event),
|
|
2632
|
+
);
|
|
2633
|
+
}
|
|
2634
|
+
|
|
2635
|
+
async listAuditEvents(
|
|
2636
|
+
tenantId: string,
|
|
2637
|
+
limit: number,
|
|
2638
|
+
): Promise<readonly AgentAuditEvent[]> {
|
|
2639
|
+
return this.#tx(tenantId, 'read', async (transaction) => {
|
|
2640
|
+
return (
|
|
2641
|
+
(await this.#query(transaction, AGENTS_SQL.listAuditEvents, [
|
|
2642
|
+
tenantId,
|
|
2643
|
+
limit,
|
|
2644
|
+
])) as unknown as AuditRow[]
|
|
2645
|
+
).map(fromAuditRow);
|
|
2646
|
+
});
|
|
2647
|
+
}
|
|
2648
|
+
|
|
2649
|
+
async pageAuditEvents(
|
|
2650
|
+
tenantId: string,
|
|
2651
|
+
cursor: { readonly occurredAt: number; readonly sequence: number } | null,
|
|
2652
|
+
limit: number,
|
|
2653
|
+
): Promise<AgentAuditPage> {
|
|
2654
|
+
return this.#tx(tenantId, 'read', async (transaction) => {
|
|
2655
|
+
const rows = (cursor
|
|
2656
|
+
? await this.#query(transaction, AGENTS_SQL.pageAuditEvents1, [
|
|
2657
|
+
tenantId,
|
|
2658
|
+
cursor.occurredAt,
|
|
2659
|
+
cursor.occurredAt,
|
|
2660
|
+
cursor.sequence,
|
|
2661
|
+
limit + 1,
|
|
2662
|
+
])
|
|
2663
|
+
: await this.#query(transaction, AGENTS_SQL.pageAuditEvents2, [
|
|
2664
|
+
tenantId,
|
|
2665
|
+
limit + 1,
|
|
2666
|
+
])) as unknown as AuditRow[];
|
|
2667
|
+
const page = rows.slice(0, limit).map(fromAuditRow);
|
|
2668
|
+
const last = page[page.length - 1];
|
|
2669
|
+
return {
|
|
2670
|
+
events: page,
|
|
2671
|
+
nextCursor:
|
|
2672
|
+
rows.length > limit && last
|
|
2673
|
+
? `${last.occurredAt}:${last.sequence}`
|
|
2674
|
+
: null,
|
|
2675
|
+
};
|
|
2676
|
+
});
|
|
2677
|
+
}
|
|
2678
|
+
|
|
2679
|
+
async verifyAuditChain(tenantId: string): Promise<boolean> {
|
|
2680
|
+
return (await this.verifyAuditChainDetailed(tenantId)).verified;
|
|
2681
|
+
}
|
|
2682
|
+
|
|
2683
|
+
async verifyAuditChainDetailed(
|
|
2684
|
+
tenantId: string,
|
|
2685
|
+
): Promise<AuditChainVerification> {
|
|
2686
|
+
return this.#tx(tenantId, 'read', async (transaction) => {
|
|
2687
|
+
const events = (
|
|
2688
|
+
(await this.#query(transaction, AGENTS_SQL.verifyAuditChainDetailed, [
|
|
2689
|
+
tenantId,
|
|
2690
|
+
])) as unknown as AuditRow[]
|
|
2691
|
+
).map(fromAuditRow);
|
|
2692
|
+
let previousHash: string | null = null;
|
|
2693
|
+
for (const event of events) {
|
|
2694
|
+
if (event.previousHash !== previousHash) {
|
|
2695
|
+
return { verified: false, brokenAt: event.id };
|
|
2696
|
+
}
|
|
2697
|
+
const expected = auditHash({
|
|
2698
|
+
tenantId: event.tenantId,
|
|
2699
|
+
sequence: event.sequence,
|
|
2700
|
+
actorId: event.actorId,
|
|
2701
|
+
action: event.action,
|
|
2702
|
+
subjectType: event.subjectType,
|
|
2703
|
+
subjectId: event.subjectId,
|
|
2704
|
+
metadataJson: stableMetadata(event.metadata),
|
|
2705
|
+
occurredAt: event.occurredAt,
|
|
2706
|
+
previousHash,
|
|
2707
|
+
});
|
|
2708
|
+
if (expected !== event.eventHash) {
|
|
2709
|
+
return { verified: false, brokenAt: event.id };
|
|
2710
|
+
}
|
|
2711
|
+
previousHash = event.eventHash;
|
|
2712
|
+
}
|
|
2713
|
+
return { verified: true, brokenAt: null };
|
|
2714
|
+
});
|
|
2715
|
+
}
|
|
2716
|
+
|
|
2717
|
+
async usageByDay(
|
|
2718
|
+
tenantId: string,
|
|
2719
|
+
fromDay: string,
|
|
2720
|
+
toDay: string,
|
|
2721
|
+
): Promise<readonly AgentUsageDay[]> {
|
|
2722
|
+
return this.#tx(tenantId, 'read', async (transaction) => {
|
|
2723
|
+
return (
|
|
2724
|
+
(await this.#query(transaction, AGENTS_SQL.usageByDay, [
|
|
2725
|
+
tenantId,
|
|
2726
|
+
fromDay,
|
|
2727
|
+
toDay,
|
|
2728
|
+
])) as unknown as UsageRow[]
|
|
2729
|
+
).map((row) => ({ day: row.day, ...fromUsageRow(row) }));
|
|
2730
|
+
});
|
|
2731
|
+
}
|
|
2732
|
+
|
|
2733
|
+
async usageByAgent(
|
|
2734
|
+
tenantId: string,
|
|
2735
|
+
fromDay: string,
|
|
2736
|
+
toDay: string,
|
|
2737
|
+
): Promise<readonly AgentUsageAgent[]> {
|
|
2738
|
+
return this.#tx(tenantId, 'read', async (transaction) => {
|
|
2739
|
+
return (
|
|
2740
|
+
(await this.#query(transaction, AGENTS_SQL.usageByAgent, [
|
|
2741
|
+
tenantId,
|
|
2742
|
+
fromDay,
|
|
2743
|
+
toDay,
|
|
2744
|
+
])) as unknown as UsageRow[]
|
|
2745
|
+
).map((row) => ({
|
|
2746
|
+
agentId: row.agent_id,
|
|
2747
|
+
agentName: row.agent_name,
|
|
2748
|
+
...fromUsageRow(row),
|
|
2749
|
+
}));
|
|
2750
|
+
});
|
|
2751
|
+
}
|
|
2752
|
+
|
|
2753
|
+
async usageTotal(
|
|
2754
|
+
tenantId: string,
|
|
2755
|
+
fromDay: string,
|
|
2756
|
+
agentId: string | null,
|
|
2757
|
+
): Promise<AgentUsageBucket> {
|
|
2758
|
+
return this.#tx(tenantId, 'read', async (transaction) => {
|
|
2759
|
+
const row = (agentId === null
|
|
2760
|
+
? (
|
|
2761
|
+
await this.#query(transaction, AGENTS_SQL.usageTotal1, [
|
|
2762
|
+
tenantId,
|
|
2763
|
+
fromDay,
|
|
2764
|
+
])
|
|
2765
|
+
)[0]
|
|
2766
|
+
: (
|
|
2767
|
+
await this.#query(transaction, AGENTS_SQL.usageTotal2, [
|
|
2768
|
+
tenantId,
|
|
2769
|
+
agentId,
|
|
2770
|
+
fromDay,
|
|
2771
|
+
])
|
|
2772
|
+
)[0]) as unknown as UsageRow | undefined;
|
|
2773
|
+
return row
|
|
2774
|
+
? fromUsageRow(row)
|
|
2775
|
+
: {
|
|
2776
|
+
runs: 0,
|
|
2777
|
+
inputTokens: 0,
|
|
2778
|
+
outputTokens: 0,
|
|
2779
|
+
costMicroUsd: 0,
|
|
2780
|
+
unpricedRuns: 0,
|
|
2781
|
+
};
|
|
2782
|
+
});
|
|
2783
|
+
}
|
|
2784
|
+
|
|
2785
|
+
async close(): Promise<void> {}
|
|
2786
|
+
}
|