@opengeni/db 1.0.1 → 3.2.0-canary.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/attached-browser-devices.d.ts +7 -0
- package/dist/automations.d.ts +154 -0
- package/dist/canonical-human-identities.js +3 -3
- package/dist/capability-integrations.d.ts +13 -0
- package/dist/child-lifecycle-notices.d.ts +68 -0
- package/dist/{chunk-4SR4HKKA.js → chunk-2EH4WRHL.js} +19 -11
- package/dist/chunk-2EH4WRHL.js.map +1 -0
- package/dist/{chunk-CUPM3FGB.js → chunk-2PRS4J5Q.js} +3 -3
- package/dist/chunk-6HMM2R5T.js +390 -0
- package/dist/chunk-6HMM2R5T.js.map +1 -0
- package/dist/{chunk-ZWREYEWA.js → chunk-AZHW7R5V.js} +56 -11
- package/dist/chunk-AZHW7R5V.js.map +1 -0
- package/dist/{chunk-LTG3S6ZY.js → chunk-E6CLMKEE.js} +2 -2
- package/dist/{chunk-6ZYKCRFO.js → chunk-KRLPEMLH.js} +7591 -4417
- package/dist/chunk-KRLPEMLH.js.map +1 -0
- package/dist/chunk-NAB6FKFN.js +516 -0
- package/dist/chunk-NAB6FKFN.js.map +1 -0
- package/dist/{chunk-SK7YYHBI.js → chunk-SIBYBA2D.js} +46 -1
- package/dist/chunk-SIBYBA2D.js.map +1 -0
- package/dist/chunk-UZNXG44K.js +4508 -0
- package/dist/chunk-UZNXG44K.js.map +1 -0
- package/dist/codemode-operations.d.ts +1 -6
- package/dist/company-brain-context-selection-schema.d.ts +705 -0
- package/dist/company-brain-context-selection.d.ts +94 -0
- package/dist/company-brain-governed-writes.d.ts +24 -0
- package/dist/company-brain.d.ts +55 -0
- package/dist/company-profile-agent-admin.d.ts +15 -0
- package/dist/company-profile-schema.d.ts +619 -2
- package/dist/company-profile.d.ts +9 -4
- package/dist/connection-authority.d.ts +95 -0
- package/dist/connection-scopes.d.ts +8 -0
- package/dist/connection-tenancy-backfill.d.ts +85 -0
- package/dist/connection-token-resolver.d.ts +30 -1
- package/dist/database.d.ts +23 -4
- package/dist/editable-artifact-durable-export.js +2 -2
- package/dist/editable-artifacts.d.ts +2 -2
- package/dist/editable-artifacts.js +3 -3
- package/dist/governed-learning-activation-schema.d.ts +984 -0
- package/dist/governed-learning-activation.d.ts +98 -0
- package/dist/governed-learning-evaluator-schema.d.ts +633 -0
- package/dist/governed-learning-evaluator.d.ts +28 -0
- package/dist/index.d.ts +1606 -81
- package/dist/index.js +21898 -8147
- package/dist/index.js.map +1 -1
- package/dist/insights.d.ts +18 -0
- package/dist/integration-bindings.d.ts +1 -0
- package/dist/integration-facets.d.ts +30 -0
- package/dist/interaction-placement-loss.d.ts +22 -0
- package/dist/managed-human-provisioning.d.ts +25 -0
- package/dist/memory-domain.d.ts +3 -3
- package/dist/migrate.d.ts +11 -1
- package/dist/migrate.js +1 -1
- package/dist/new-session-drafts.d.ts +43 -5
- package/dist/organization-membership-backfill.d.ts +174 -0
- package/dist/organization-membership-lifecycle.d.ts +162 -0
- package/dist/pr-review.d.ts +107 -0
- package/dist/preference-registry-schema.d.ts +2 -0
- package/dist/preference-registry.d.ts +2 -0
- package/dist/provision-roles.js +1 -1
- package/dist/runtime-posture.d.ts +29 -8
- package/dist/schema.d.ts +24914 -13703
- package/dist/schema.js +99 -1
- package/dist/scoped-knowledge-schema.d.ts +52 -1
- package/dist/session-background-commands.d.ts +125 -0
- package/dist/session-background-commands.js +34 -0
- package/dist/session-background-commands.js.map +1 -0
- package/dist/session-control.d.ts +156 -3
- package/dist/session-goal-pacing.d.ts +68 -0
- package/dist/session-queue-commands.d.ts +43 -4
- package/dist/session-realtime-ledger.d.ts +2 -0
- package/dist/session-tenancy.d.ts +71 -1
- package/dist/session-tenancy.js +25 -3
- package/dist/session-tool-call-settlement.d.ts +9 -4
- package/dist/slack-routing-personal-workspace.d.ts +23 -0
- package/dist/slack-routing.d.ts +268 -0
- package/dist/slack-task-policy-schema.d.ts +34 -0
- package/dist/slack-task-policy.d.ts +8 -0
- package/dist/slack-user-link-access.d.ts +28 -0
- package/dist/task-notes-schema.d.ts +594 -0
- package/dist/task-notes.d.ts +39 -0
- package/dist/turn-initiator.d.ts +2 -0
- package/dist/user-resource-authority.d.ts +109 -0
- package/dist/video-generation.js +3 -3
- package/dist/workspace-authority.d.ts +81 -0
- package/dist/workspace-instruction-policies-schema.d.ts +279 -0
- package/dist/workspace-instruction-policies.d.ts +62 -0
- package/dist/workspace-learning-policy.d.ts +1 -0
- package/dist/workspace-membership-permissions.d.ts +2 -0
- package/drizzle/0240_enrollment_connection_authority.sql +39 -0
- package/drizzle/0241_atomic_personal_resource_delegation.sql +1000 -0
- package/drizzle/0241_enrollment_agent_runtime.sql +70 -0
- package/drizzle/0244_slack_app_home_refresh_queue.sql +120 -0
- package/drizzle/0245_model_context_contribution_facts.sql +88 -0
- package/drizzle/0246_integration_personal_instance_authority.sql +70 -0
- package/drizzle/0247_terraform_stacks_provenance_repair.sql +428 -0
- package/drizzle/0248_terraform_stacks_component_resolution_fence.sql +83 -0
- package/drizzle/0249_personal_resource_delegation_authority_correction.sql +662 -0
- package/drizzle/0250_direct_retained_process_owner_liveness.sql +199 -0
- package/drizzle/0251_connected_machine_operation_policy.sql +45 -0
- package/drizzle/0252_scheduled_personal_resource_delegation.sql +1867 -0
- package/drizzle/0253_common_user_resource_authority_lifecycle.sql +1555 -0
- package/drizzle/0254_scoped_variable_set_authority.sql +1255 -0
- package/drizzle/0255_company_brain_governed_write_proposals.sql +524 -0
- package/drizzle/0256_connection_authority_delegation.sql +703 -0
- package/drizzle/0257_goal_revision_decisions_and_root_constraints.sql +436 -0
- package/drizzle/0258_three_scope_document_knowledge_authority.sql +1273 -0
- package/drizzle/0259_company_brain_context_selection_receipts.sql +869 -0
- package/drizzle/0260_task_note_knowledge_promotion.sql +820 -0
- package/drizzle/0261_preference_knowledge_proposal_actor_binding.sql +471 -0
- package/drizzle/0262_scoped_connected_machines_and_rigs.sql +1700 -0
- package/drizzle/0263_organization_membership_lifecycle.sql +3284 -0
- package/drizzle/0264_connection_authority_runtime_activation.sql +1084 -0
- package/drizzle/0266_company_brain_context_receipt_inspection.sql +156 -0
- package/drizzle/0268_governed_learning_decision_receipts.sql +825 -0
- package/drizzle/0269_governed_learning_activation_controller.sql +1874 -0
- package/drizzle/0270_governed_learning_history_inspection.sql +170 -0
- package/drizzle/0271_company_brain_retrieval_only_default.sql +524 -0
- package/drizzle/0272_human_confirmed_learning_activation.sql +591 -0
- package/drizzle/0273_scheduled_variable_set_materialization.sql +268 -0
- package/drizzle/0274_human_confirmed_knowledge_review.sql +310 -0
- package/drizzle/0275_scheduled_connection_authority.sql +5527 -0
- package/drizzle/0276_onboarding_proposal_initiating_human_guc.sql +198 -0
- package/drizzle/0277_workspace_writer_authority_attribution.sql +393 -0
- package/drizzle/0278_workspace_membership_removal_fencing.sql +1174 -0
- package/drizzle/0279_workspace_connection_use_lane.sql +343 -0
- package/drizzle/0280_connection_and_variable_set_audit_attribution.sql +773 -0
- package/drizzle/0281_viewer_holder_authority_claims.sql +52 -0
- package/drizzle/0282_variable_set_session_attach_attribution.sql +178 -0
- package/drizzle/0283_editable_spreadsheet_authored_state.sql +82 -0
- package/drizzle/0284_truthful_human_confirmed_review_reason.sql +930 -0
- package/drizzle/0285_organization_tenancy_inventory.sql +329 -0
- package/drizzle/0286_widen_task_note_expiry_ceiling.sql +391 -0
- package/drizzle/0287_open_suffix_pending_tool_calls.sql +18 -0
- package/drizzle/0288_attached_browser_reenrollment.sql +64 -0
- package/drizzle/0289_session_composer_policy_authority.sql +597 -0
- package/drizzle/0290_organization_membership_backfill.sql +268 -0
- package/drizzle/0291_resource_authority_classification_assertion.sql +371 -0
- package/drizzle/0292_truthful_tenancy_inventory_counters.sql +291 -0
- package/drizzle/0293_confirm_time_rule_rebaseline.sql +615 -0
- package/drizzle/0294_preference_activation_authority.sql +237 -0
- package/drizzle/0295_retire_legacy_standing_memory_mode.sql +476 -0
- package/drizzle/0296_force_rls_backfill_noop_repair.sql +215 -0
- package/drizzle/0297_session_ownership_classification_and_backfill.sql +752 -0
- package/drizzle/0298_organization_tenancy_parity.sql +609 -0
- package/drizzle/0299_organization_membership_lock_order.sql +291 -0
- package/drizzle/0300_tenancy_backfill_ledger.sql +459 -0
- package/drizzle/0301_session_snapshot_and_pin_visibility.sql +181 -0
- package/drizzle/0302_personal_workspace_session_ownership.sql +303 -0
- package/drizzle/0303_session_tenancy_product_activation.sql +919 -0
- package/drizzle/0304_personal_workspace_private_session_reads.sql +97 -0
- package/drizzle/0305_personal_resource_grant_management.sql +584 -0
- package/drizzle/0306_atomic_personal_resource_attachments.sql +1374 -0
- package/drizzle/0307_session_attention_state.sql +51 -0
- package/drizzle/0308_session_archives.sql +35 -0
- package/drizzle/0309_channel_project_pins.sql +6 -0
- package/drizzle/0310_channel_project_order.sql +27 -0
- package/drizzle/0311_company_scope_and_private_session_create.sql +656 -0
- package/drizzle/0312_quiescent_session_tree_deletion.sql +39 -0
- package/drizzle/0313_private_child_session_authority.sql +365 -0
- package/drizzle/0314_unregistered_organization_invitations.sql +606 -0
- package/drizzle/0315_personal_github_repository_selection.sql +624 -0
- package/drizzle/0316_human_confirmed_activation_resumed_generation.sql +869 -0
- package/drizzle/0317_session_goal_continuation_hold.sql +64 -0
- package/drizzle/0318_session_turn_startup_milestones.sql +115 -0
- package/drizzle/0319_event_triggered_automations.sql +254 -0
- package/drizzle/0320_pr_review_pack.sql +113 -0
- package/drizzle/0321_slack_bot_environment_display_name.sql +15 -0
- package/drizzle/0322_session_turns_unclaimed_prompt_trigger_index.sql +5 -0
- package/drizzle/0323_organization_private_session_enablement.sql +489 -0
- package/drizzle/0324_human_confirmed_company_profile_agent_admin.sql +856 -0
- package/drizzle/0325_child_lifecycle_notices.sql +44 -0
- package/drizzle/0326_interaction_operation_error_codes.sql +62 -0
- package/drizzle/0327_slack_first_task_hint.sql +29 -0
- package/drizzle/0328_session_background_commands.sql +590 -0
- package/drizzle/0329_slack_orchestration_delivery_events.sql +91 -0
- package/drizzle/0330_api_key_descriptions.sql +20 -0
- package/drizzle/0331_managed_organization_creation.sql +163 -0
- package/drizzle/0332_organization_shared_workspace_control_plane.sql +539 -0
- package/drizzle/0333_session_turn_prompt_routing.sql +45 -0
- package/drizzle/0334_connected_machine_workspace_root.sql +99 -0
- package/drizzle/0335_slack_workspace_routing.sql +460 -0
- package/drizzle/0336_atomic_session_fork_visibility.sql +667 -0
- package/drizzle/0337_slack_routed_action_handles.sql +189 -0
- package/drizzle/0338_atomic_connected_machine_attachments.sql +410 -0
- package/drizzle/0339_document_authority_reclassification.sql +1153 -0
- package/drizzle/0340_tenancy_backfill_activation_evidence.sql +1347 -0
- package/drizzle/0341_slack_routing_probe_organization_fence.sql +109 -0
- package/drizzle/0342_slack_route_prompt_single_pending.sql +32 -0
- package/drizzle/0343_personal_document_force_rls_lock_repair.sql +146 -0
- package/drizzle/0344_private_session_visibility_transition_gate.sql +85 -0
- package/drizzle/0345_tenant_scoped_session_tenancy_fence.sql +2839 -0
- package/drizzle/0346_document_migration_audit_surface.sql +454 -0
- package/drizzle/0347_connection_authority_convergence_evidence.sql +396 -0
- package/package.json +10 -6
- package/src/attached-browser-devices.ts +233 -5
- package/src/automations.ts +911 -0
- package/src/browser-sessions.ts +10 -0
- package/src/capability-integrations.ts +175 -1
- package/src/child-lifecycle-notices.ts +241 -0
- package/src/codemode-operations.ts +1 -35
- package/src/company-brain-context-selection-schema.ts +100 -0
- package/src/company-brain-context-selection.ts +359 -0
- package/src/company-brain-governed-writes.ts +1170 -0
- package/src/company-brain.ts +309 -0
- package/src/company-profile-agent-admin.ts +225 -0
- package/src/company-profile-schema.ts +121 -1
- package/src/company-profile.ts +21 -0
- package/src/computer-sessions.ts +10 -1
- package/src/connection-authority.ts +290 -0
- package/src/connection-scopes.ts +20 -0
- package/src/connection-tenancy-backfill.ts +167 -0
- package/src/connection-token-resolver.ts +263 -31
- package/src/database.ts +87 -2
- package/src/editable-artifacts-schema.ts +10 -5
- package/src/editable-artifacts.ts +21 -11
- package/src/governed-learning-activation-schema.ts +121 -0
- package/src/governed-learning-activation.ts +588 -0
- package/src/governed-learning-evaluator-schema.ts +72 -0
- package/src/governed-learning-evaluator.ts +217 -0
- package/src/index.ts +11676 -1550
- package/src/insights.ts +107 -0
- package/src/integration-bindings.ts +88 -6
- package/src/integration-facets.ts +287 -84
- package/src/interaction-placement-loss.ts +234 -0
- package/src/managed-human-provisioning.ts +116 -0
- package/src/memory-domain.ts +27 -32
- package/src/migrate.ts +77 -1
- package/src/new-session-drafts.ts +229 -35
- package/src/organization-membership-backfill.ts +735 -0
- package/src/organization-membership-lifecycle.ts +995 -0
- package/src/pr-review.ts +890 -0
- package/src/preference-registry.ts +31 -1
- package/src/provision-roles.ts +905 -6
- package/src/runtime-posture-cli.ts +2 -0
- package/src/runtime-posture.ts +1317 -72
- package/src/schema.ts +3316 -428
- package/src/scoped-knowledge-schema.ts +16 -8
- package/src/scoped-knowledge.ts +1 -1
- package/src/session-background-commands.ts +759 -0
- package/src/session-control.ts +640 -74
- package/src/session-goal-pacing.ts +126 -0
- package/src/session-queue-commands.ts +441 -85
- package/src/session-realtime-context.ts +4 -6
- package/src/session-realtime-ledger.ts +28 -14
- package/src/session-realtime-mirror.ts +1 -1
- package/src/session-tenancy.ts +410 -49
- package/src/session-tool-call-settlement.ts +38 -29
- package/src/slack-routing-personal-workspace.ts +67 -0
- package/src/slack-routing.ts +867 -0
- package/src/slack-task-policy-schema.ts +5 -0
- package/src/slack-task-policy.ts +18 -0
- package/src/slack-user-link-access.ts +138 -11
- package/src/task-notes-schema.ts +74 -0
- package/src/task-notes.ts +124 -2
- package/src/turn-initiator.ts +8 -0
- package/src/user-resource-authority.ts +377 -0
- package/src/workspace-authority.ts +160 -0
- package/src/workspace-instruction-policies-schema.ts +53 -1
- package/src/workspace-instruction-policies.ts +528 -77
- package/src/workspace-learning-policy.ts +21 -5
- package/src/workspace-membership-permissions.ts +9 -0
- package/dist/chunk-4SR4HKKA.js.map +0 -1
- package/dist/chunk-6ZYKCRFO.js.map +0 -1
- package/dist/chunk-NXAFLCQX.js +0 -2468
- package/dist/chunk-NXAFLCQX.js.map +0 -1
- package/dist/chunk-SK7YYHBI.js.map +0 -1
- package/dist/chunk-WD5ROSLL.js +0 -117
- package/dist/chunk-WD5ROSLL.js.map +0 -1
- package/dist/chunk-ZWREYEWA.js.map +0 -1
- /package/dist/{chunk-CUPM3FGB.js.map → chunk-2PRS4J5Q.js.map} +0 -0
- /package/dist/{chunk-LTG3S6ZY.js.map → chunk-E6CLMKEE.js.map} +0 -0
package/src/browser-sessions.ts
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
type NetworkRouteConsistency as NetworkRouteConsistencyValue,
|
|
24
24
|
} from "@opengeni/contracts";
|
|
25
25
|
import { and, desc, eq, inArray, isNull, sql } from "drizzle-orm";
|
|
26
|
+
import { attachedDeviceGenerationMatches } from "./attached-browser-devices";
|
|
26
27
|
import { type Database, withRlsContext } from "./database";
|
|
27
28
|
import {
|
|
28
29
|
advanceWorkspaceInteractionRevision,
|
|
@@ -2194,6 +2195,15 @@ export async function touchBrowserSessionController(
|
|
|
2194
2195
|
)
|
|
2195
2196
|
.limit(1);
|
|
2196
2197
|
if (!observed) return false;
|
|
2198
|
+
if (observed.placementKind === "attached_device") {
|
|
2199
|
+
if (!observed.deviceId || !observed.placementInstanceId) return false;
|
|
2200
|
+
const current = await attachedDeviceGenerationMatches(tx, {
|
|
2201
|
+
workspaceId: input.workspaceId,
|
|
2202
|
+
deviceId: observed.deviceId,
|
|
2203
|
+
placementInstanceId: observed.placementInstanceId,
|
|
2204
|
+
});
|
|
2205
|
+
if (!current) return false;
|
|
2206
|
+
}
|
|
2197
2207
|
if (observed.controllerHostSandboxGroupId) {
|
|
2198
2208
|
// Match the reaper's exact lease -> holder -> BrowserSession lock
|
|
2199
2209
|
// order. The pre-lock observation is only a locator; every authority
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
withWorkspaceSubjectRls,
|
|
16
16
|
type Database,
|
|
17
17
|
} from "./database";
|
|
18
|
+
import { connectionScopeKey } from "./connection-scopes";
|
|
18
19
|
import {
|
|
19
20
|
ensureIntegrationFacetDefinition,
|
|
20
21
|
integrationBindingKey,
|
|
@@ -639,6 +640,176 @@ export async function listInstalledApiIntegrations(
|
|
|
639
640
|
);
|
|
640
641
|
}
|
|
641
642
|
|
|
643
|
+
type ApiIntegrationServerAuthorityMetadata = {
|
|
644
|
+
serverId: string;
|
|
645
|
+
connectionId: string | null;
|
|
646
|
+
providerDomain: string;
|
|
647
|
+
connectionKind: string | null;
|
|
648
|
+
subjectScope: "workspace" | "subject";
|
|
649
|
+
};
|
|
650
|
+
|
|
651
|
+
async function listInstalledApiIntegrationServerAuthorityMetadataInRlsContext(
|
|
652
|
+
scopedDb: Database,
|
|
653
|
+
workspaceId: string,
|
|
654
|
+
subjectId?: string,
|
|
655
|
+
): Promise<ApiIntegrationServerAuthorityMetadata[]> {
|
|
656
|
+
const rows = await scopedDb
|
|
657
|
+
.select({
|
|
658
|
+
serverId: schema.integrationFacetBindings.runtimeKey,
|
|
659
|
+
connectionId: schema.integrationFacetBindings.connectionId,
|
|
660
|
+
providerDomain: schema.capabilityIntegrationFacets.providerDomain,
|
|
661
|
+
connectionKind: sql<
|
|
662
|
+
string | null
|
|
663
|
+
>`${schema.integrationFacetBindings.config} ->> 'connectionKind'`,
|
|
664
|
+
subjectScope: sql<
|
|
665
|
+
string | null
|
|
666
|
+
>`${schema.integrationFacetBindings.config} ->> 'subjectScope'`,
|
|
667
|
+
})
|
|
668
|
+
.from(schema.integrationFacetBindings)
|
|
669
|
+
.innerJoin(
|
|
670
|
+
schema.integrationFacetDefinitions,
|
|
671
|
+
eq(schema.integrationFacetDefinitions.id, schema.integrationFacetBindings.facetDefinitionId),
|
|
672
|
+
)
|
|
673
|
+
.innerJoin(
|
|
674
|
+
schema.capabilityIntegrationFacets,
|
|
675
|
+
eq(
|
|
676
|
+
schema.capabilityIntegrationFacets.facetId,
|
|
677
|
+
schema.integrationFacetDefinitions.integrationFacetId,
|
|
678
|
+
),
|
|
679
|
+
)
|
|
680
|
+
.innerJoin(
|
|
681
|
+
schema.capabilityFacetInstallations,
|
|
682
|
+
eq(
|
|
683
|
+
schema.capabilityFacetInstallations.id,
|
|
684
|
+
schema.integrationFacetBindings.integrationFacetInstallationId,
|
|
685
|
+
),
|
|
686
|
+
)
|
|
687
|
+
.innerJoin(
|
|
688
|
+
schema.capabilityPluginInstallations,
|
|
689
|
+
eq(
|
|
690
|
+
schema.capabilityPluginInstallations.id,
|
|
691
|
+
schema.capabilityFacetInstallations.pluginInstallationId,
|
|
692
|
+
),
|
|
693
|
+
)
|
|
694
|
+
.innerJoin(
|
|
695
|
+
schema.capabilityApiFacets,
|
|
696
|
+
eq(schema.capabilityApiFacets.integrationFacetId, schema.capabilityIntegrationFacets.facetId),
|
|
697
|
+
)
|
|
698
|
+
.where(
|
|
699
|
+
and(
|
|
700
|
+
eq(schema.capabilityPluginInstallations.workspaceId, workspaceId),
|
|
701
|
+
eq(schema.capabilityPluginInstallations.status, "active"),
|
|
702
|
+
eq(schema.capabilityFacetInstallations.status, "active"),
|
|
703
|
+
eq(schema.integrationFacetDefinitions.kind, "tools"),
|
|
704
|
+
eq(schema.integrationFacetBindings.status, "active"),
|
|
705
|
+
sql`${schema.integrationFacetBindings.runtimeKey} is not null`,
|
|
706
|
+
sql`exists (
|
|
707
|
+
select 1 from ${schema.capabilityComponentOwners} owner
|
|
708
|
+
where owner.facet_installation_id = ${schema.capabilityFacetInstallations.id}
|
|
709
|
+
and ${effectiveCapabilityOwnerSql(sql`owner.owner_kind`, sql`owner.owner_id`)}
|
|
710
|
+
)`,
|
|
711
|
+
sql`exists (
|
|
712
|
+
select 1 from ${schema.integrationFacetBindingOwners} owner
|
|
713
|
+
where owner.binding_id = ${schema.integrationFacetBindings.id}
|
|
714
|
+
and ${effectiveCapabilityOwnerSql(sql`owner.owner_kind`, sql`owner.owner_id`)}
|
|
715
|
+
)`,
|
|
716
|
+
sql`exists (
|
|
717
|
+
select 1 from ${schema.capabilityFacetInstallations} api_installation
|
|
718
|
+
where api_installation.plugin_installation_id = ${schema.capabilityPluginInstallations.id}
|
|
719
|
+
and api_installation.facet_id = ${schema.capabilityApiFacets.facetId}
|
|
720
|
+
and api_installation.status = 'active'
|
|
721
|
+
)`,
|
|
722
|
+
subjectId
|
|
723
|
+
? sql`(
|
|
724
|
+
${schema.integrationFacetBindings.connectionId} is null
|
|
725
|
+
or exists (
|
|
726
|
+
select 1 from ${schema.connections} connection
|
|
727
|
+
where connection.id = ${schema.integrationFacetBindings.connectionId}
|
|
728
|
+
and (connection.subject_id is null or connection.subject_id = ${subjectId})
|
|
729
|
+
)
|
|
730
|
+
)`
|
|
731
|
+
: sql`(
|
|
732
|
+
${schema.integrationFacetBindings.connectionId} is null
|
|
733
|
+
or exists (
|
|
734
|
+
select 1 from ${schema.connections} connection
|
|
735
|
+
where connection.id = ${schema.integrationFacetBindings.connectionId}
|
|
736
|
+
and connection.subject_id is null
|
|
737
|
+
)
|
|
738
|
+
)`,
|
|
739
|
+
),
|
|
740
|
+
);
|
|
741
|
+
return rows.flatMap((row) =>
|
|
742
|
+
row.serverId
|
|
743
|
+
? [
|
|
744
|
+
{
|
|
745
|
+
serverId: row.serverId,
|
|
746
|
+
connectionId: row.connectionId,
|
|
747
|
+
providerDomain: row.providerDomain,
|
|
748
|
+
connectionKind: row.connectionKind,
|
|
749
|
+
subjectScope: row.subjectScope === "subject" ? "subject" : "workspace",
|
|
750
|
+
},
|
|
751
|
+
]
|
|
752
|
+
: [],
|
|
753
|
+
);
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
/**
|
|
757
|
+
* Exact runnable API-integration server ids for a scheduled service run.
|
|
758
|
+
* Only runtime ids and the minimum delegation-matching metadata are selected;
|
|
759
|
+
* no integration definition, credential, token, endpoint, or tool schema is
|
|
760
|
+
* materialized before incident admission.
|
|
761
|
+
*/
|
|
762
|
+
export async function listInstalledApiIntegrationServerIdsForDelegations(
|
|
763
|
+
db: Database,
|
|
764
|
+
workspaceId: string,
|
|
765
|
+
delegations: readonly {
|
|
766
|
+
serverId: string;
|
|
767
|
+
connectionId: string;
|
|
768
|
+
providerDomain: string;
|
|
769
|
+
ownerSubjectId: string;
|
|
770
|
+
kind?: string | undefined;
|
|
771
|
+
}[],
|
|
772
|
+
): Promise<string[]> {
|
|
773
|
+
const workspace = await withWorkspaceRls(
|
|
774
|
+
db,
|
|
775
|
+
workspaceId,
|
|
776
|
+
async (scopedDb) =>
|
|
777
|
+
await listInstalledApiIntegrationServerAuthorityMetadataInRlsContext(scopedDb, workspaceId),
|
|
778
|
+
);
|
|
779
|
+
const byServerId = new Set(workspace.map((entry) => entry.serverId));
|
|
780
|
+
const owners = [...new Set(delegations.map((delegation) => delegation.ownerSubjectId))];
|
|
781
|
+
for (const ownerSubjectId of owners) {
|
|
782
|
+
const ownerEntries = await withWorkspaceSubjectRls(
|
|
783
|
+
db,
|
|
784
|
+
workspaceId,
|
|
785
|
+
ownerSubjectId,
|
|
786
|
+
async (scopedDb) =>
|
|
787
|
+
await listInstalledApiIntegrationServerAuthorityMetadataInRlsContext(
|
|
788
|
+
scopedDb,
|
|
789
|
+
workspaceId,
|
|
790
|
+
ownerSubjectId,
|
|
791
|
+
),
|
|
792
|
+
);
|
|
793
|
+
const exact = delegations.filter((delegation) => delegation.ownerSubjectId === ownerSubjectId);
|
|
794
|
+
for (const entry of ownerEntries) {
|
|
795
|
+
if (
|
|
796
|
+
entry.subjectScope === "subject" &&
|
|
797
|
+
entry.connectionId &&
|
|
798
|
+
exact.some(
|
|
799
|
+
(delegation) =>
|
|
800
|
+
delegation.serverId === entry.serverId &&
|
|
801
|
+
delegation.connectionId === entry.connectionId &&
|
|
802
|
+
delegation.providerDomain.toLowerCase() === entry.providerDomain.toLowerCase() &&
|
|
803
|
+
(delegation.kind ?? "") === (entry.connectionKind ?? ""),
|
|
804
|
+
)
|
|
805
|
+
) {
|
|
806
|
+
byServerId.add(entry.serverId);
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
return [...byServerId];
|
|
811
|
+
}
|
|
812
|
+
|
|
642
813
|
/**
|
|
643
814
|
* Read installed API Integrations from a transaction that already carries the
|
|
644
815
|
* workspace RLS context. This is intentionally separate from the public
|
|
@@ -1180,8 +1351,11 @@ async function loadInstallConnection(
|
|
|
1180
1351
|
throw new Error("API Integration connection provider does not match the destination");
|
|
1181
1352
|
}
|
|
1182
1353
|
assertConnectionKindMatchesAuth(input.authScheme, connection.kind);
|
|
1354
|
+
const grantedScopes = new Set(
|
|
1355
|
+
connection.grantedScopes.map((scope) => connectionScopeKey(connection.providerDomain, scope)),
|
|
1356
|
+
);
|
|
1183
1357
|
const missing = normalizedStrings(input.requiredScopes ?? [], 256).filter(
|
|
1184
|
-
(scope) => !
|
|
1358
|
+
(scope) => !grantedScopes.has(connectionScopeKey(connection.providerDomain, scope)),
|
|
1185
1359
|
);
|
|
1186
1360
|
if (missing.length > 0) {
|
|
1187
1361
|
throw new Error("API Integration connection is missing required scopes");
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CHILD_PAUSED_REASON_MAX_BYTES,
|
|
3
|
+
CHILD_PROGRESS_NOTE_MAX_BYTES,
|
|
4
|
+
CHILD_REQUIRES_ACTION_MAX_REQUESTS,
|
|
5
|
+
CHILD_REQUIRES_ACTION_PAYLOAD_MAX_BYTES,
|
|
6
|
+
CHILD_REQUIRES_ACTION_QUESTION_PREVIEW_MAX_BYTES,
|
|
7
|
+
approvalIdentifier,
|
|
8
|
+
type ChildPausedPayload,
|
|
9
|
+
type ChildProgressPayload,
|
|
10
|
+
type ChildRequiresActionPayload,
|
|
11
|
+
type ChildRequiresActionRequest,
|
|
12
|
+
type ChildRequiresActionResolvedPayload,
|
|
13
|
+
type ChildWaitingCapacityPayload,
|
|
14
|
+
type HumanInputQuestion,
|
|
15
|
+
} from "@opengeni/contracts";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Child lifecycle notices (`child_requires_action`,
|
|
19
|
+
* `child_requires_action_resolved`, `child_paused`, `child_waiting_capacity`,
|
|
20
|
+
* `child_progress`) are produced only while this process-global flag is on.
|
|
21
|
+
* The deployment value is `OPENGENI_CHILD_LIFECYCLE_NOTICES_ENABLED`, parsed
|
|
22
|
+
* once at boot by `@opengeni/config` (`settings.childLifecycleNoticesEnabled`)
|
|
23
|
+
* and installed here by the API app and both worker roles. Rolling hazard: a
|
|
24
|
+
* worker from before these kinds existed throws in `mapSessionSystemUpdate`
|
|
25
|
+
* on an unknown kind, so the flag stays off until the whole fleet runs a new
|
|
26
|
+
* image. Delivery and consumption of an already committed notice never read
|
|
27
|
+
* the flag; only production does.
|
|
28
|
+
*/
|
|
29
|
+
let childLifecycleNoticesEnabledFlag = false;
|
|
30
|
+
|
|
31
|
+
export function configureChildLifecycleNotices(input: { enabled: boolean }): void {
|
|
32
|
+
childLifecycleNoticesEnabledFlag = input.enabled === true;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function childLifecycleNoticesEnabled(): boolean {
|
|
36
|
+
return childLifecycleNoticesEnabledFlag;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Bounded UTF-8 prefix with an explicit marker; never splits a code point. */
|
|
40
|
+
export function boundedChildNoticeText(
|
|
41
|
+
value: string,
|
|
42
|
+
maxBytes: number,
|
|
43
|
+
): { text: string; truncated: boolean } {
|
|
44
|
+
const encoder = new TextEncoder();
|
|
45
|
+
const bytes = encoder.encode(value);
|
|
46
|
+
if (bytes.byteLength <= maxBytes) return { text: value, truncated: false };
|
|
47
|
+
const marker = "…";
|
|
48
|
+
const budget = Math.max(0, maxBytes - encoder.encode(marker).byteLength);
|
|
49
|
+
let end = Math.min(budget, bytes.byteLength);
|
|
50
|
+
while (end > 0 && end < bytes.byteLength && (bytes[end]! & 0xc0) === 0x80) end -= 1;
|
|
51
|
+
return { text: `${new TextDecoder().decode(bytes.subarray(0, end))}${marker}`, truncated: true };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const CHILD_LIFECYCLE_DEDUPE_PREFIX = {
|
|
55
|
+
requiresAction: "child-requires-action",
|
|
56
|
+
requiresActionResolved: "child-requires-action-resolved",
|
|
57
|
+
paused: "child-paused",
|
|
58
|
+
waitingCapacity: "child-waiting-capacity",
|
|
59
|
+
progress: "child-progress",
|
|
60
|
+
} as const;
|
|
61
|
+
|
|
62
|
+
export function childRequiresActionDedupeKey(input: {
|
|
63
|
+
childSessionId: string;
|
|
64
|
+
turnId: string;
|
|
65
|
+
turnGeneration: number;
|
|
66
|
+
}): string {
|
|
67
|
+
return `${CHILD_LIFECYCLE_DEDUPE_PREFIX.requiresAction}:${input.childSessionId}:${input.turnId}:${input.turnGeneration}`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function childRequiresActionResolvedDedupeKey(input: {
|
|
71
|
+
childSessionId: string;
|
|
72
|
+
turnId: string;
|
|
73
|
+
turnGeneration: number;
|
|
74
|
+
requestId: string | null;
|
|
75
|
+
approvalId: string | null;
|
|
76
|
+
}): string {
|
|
77
|
+
return `${CHILD_LIFECYCLE_DEDUPE_PREFIX.requiresActionResolved}:${input.childSessionId}:${input.turnId}:${input.turnGeneration}:${input.requestId ?? input.approvalId ?? "unknown"}`;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function childPausedDedupeKey(input: { childSessionId: string; receiptId: string }): string {
|
|
81
|
+
return `${CHILD_LIFECYCLE_DEDUPE_PREFIX.paused}:${input.childSessionId}:${input.receiptId}`;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function childWaitingCapacityDedupeKey(input: {
|
|
85
|
+
childSessionId: string;
|
|
86
|
+
waiterId: string;
|
|
87
|
+
}): string {
|
|
88
|
+
return `${CHILD_LIFECYCLE_DEDUPE_PREFIX.waitingCapacity}:${input.childSessionId}:${input.waiterId}`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function childProgressDedupeKey(input: {
|
|
92
|
+
childSessionId: string;
|
|
93
|
+
receiptId: string;
|
|
94
|
+
}): string {
|
|
95
|
+
return `${CHILD_LIFECYCLE_DEDUPE_PREFIX.progress}:${input.childSessionId}:${input.receiptId}`;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Bounded, secret-free tool name of a serialized SDK approval interruption. */
|
|
99
|
+
function approvalToolName(value: unknown): string | null {
|
|
100
|
+
if (!value || typeof value !== "object") return null;
|
|
101
|
+
const approval = value as Record<string, unknown>;
|
|
102
|
+
const rawItem =
|
|
103
|
+
approval.rawItem && typeof approval.rawItem === "object"
|
|
104
|
+
? (approval.rawItem as Record<string, unknown>)
|
|
105
|
+
: null;
|
|
106
|
+
const candidate = rawItem?.name ?? approval.name;
|
|
107
|
+
return typeof candidate === "string" && candidate.length > 0
|
|
108
|
+
? boundedChildNoticeText(candidate, 128).text
|
|
109
|
+
: null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Build the bounded child_requires_action payload from the child's frozen
|
|
114
|
+
* human-input requests and pending approvals. Only typed, content-free facts
|
|
115
|
+
* plus one bounded first-question preview per request cross to the parent:
|
|
116
|
+
* never subject ids, credentials, or raw tool arguments. The whole payload
|
|
117
|
+
* stays within CHILD_REQUIRES_ACTION_PAYLOAD_MAX_BYTES by dropping trailing
|
|
118
|
+
* requests and recording `truncated`.
|
|
119
|
+
*/
|
|
120
|
+
export function buildChildRequiresActionPayload(input: {
|
|
121
|
+
childSessionId: string;
|
|
122
|
+
childTurnId: string;
|
|
123
|
+
childTurnGeneration: number;
|
|
124
|
+
humanInputRequests: ReadonlyArray<{
|
|
125
|
+
id: string;
|
|
126
|
+
questions: readonly HumanInputQuestion[];
|
|
127
|
+
allowSkip: boolean;
|
|
128
|
+
expiresAt?: Date | null;
|
|
129
|
+
}>;
|
|
130
|
+
pendingApprovals: readonly unknown[];
|
|
131
|
+
}): ChildRequiresActionPayload {
|
|
132
|
+
const requests: ChildRequiresActionRequest[] = [];
|
|
133
|
+
for (const request of input.humanInputRequests) {
|
|
134
|
+
const first = request.questions[0];
|
|
135
|
+
requests.push({
|
|
136
|
+
kind: "human_input",
|
|
137
|
+
requestId: request.id,
|
|
138
|
+
questionCount: request.questions.length,
|
|
139
|
+
firstQuestion: boundedChildNoticeText(
|
|
140
|
+
typeof first?.prompt === "string" ? first.prompt : "",
|
|
141
|
+
CHILD_REQUIRES_ACTION_QUESTION_PREVIEW_MAX_BYTES,
|
|
142
|
+
).text,
|
|
143
|
+
allowSkip: request.allowSkip,
|
|
144
|
+
expiresAt: request.expiresAt ? request.expiresAt.toISOString() : null,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
const seenApprovals = new Set<string>();
|
|
148
|
+
for (const pending of input.pendingApprovals) {
|
|
149
|
+
const approvalId = approvalIdentifier(pending);
|
|
150
|
+
if (!approvalId || seenApprovals.has(approvalId)) continue;
|
|
151
|
+
seenApprovals.add(approvalId);
|
|
152
|
+
requests.push({
|
|
153
|
+
kind: "approval",
|
|
154
|
+
approvalId: boundedChildNoticeText(approvalId, 256).text,
|
|
155
|
+
toolName: approvalToolName(pending),
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
let truncated = requests.length > CHILD_REQUIRES_ACTION_MAX_REQUESTS;
|
|
159
|
+
let bounded = requests.slice(0, CHILD_REQUIRES_ACTION_MAX_REQUESTS);
|
|
160
|
+
const build = (): ChildRequiresActionPayload => ({
|
|
161
|
+
type: "child_requires_action",
|
|
162
|
+
childSessionId: input.childSessionId,
|
|
163
|
+
childTurnId: input.childTurnId,
|
|
164
|
+
childTurnGeneration: input.childTurnGeneration,
|
|
165
|
+
requests: bounded,
|
|
166
|
+
truncated,
|
|
167
|
+
});
|
|
168
|
+
let payload = build();
|
|
169
|
+
while (
|
|
170
|
+
bounded.length > 0 &&
|
|
171
|
+
Buffer.byteLength(JSON.stringify(payload)) > CHILD_REQUIRES_ACTION_PAYLOAD_MAX_BYTES
|
|
172
|
+
) {
|
|
173
|
+
bounded = bounded.slice(0, -1);
|
|
174
|
+
truncated = true;
|
|
175
|
+
payload = build();
|
|
176
|
+
}
|
|
177
|
+
return payload;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export function childRequiresActionSummary(
|
|
181
|
+
childSessionId: string,
|
|
182
|
+
payload: ChildRequiresActionPayload,
|
|
183
|
+
): string {
|
|
184
|
+
const humanInputs = payload.requests.filter((request) => request.kind === "human_input");
|
|
185
|
+
const approvals = payload.requests.filter((request) => request.kind === "approval");
|
|
186
|
+
const first = humanInputs[0];
|
|
187
|
+
const lines = [
|
|
188
|
+
`Worker ${childSessionId} is blocked and needs input (turn ${payload.childTurnId}).`,
|
|
189
|
+
];
|
|
190
|
+
if (first && first.kind === "human_input") {
|
|
191
|
+
lines.push(
|
|
192
|
+
`It asked: ${first.firstQuestion}${first.questionCount > 1 ? ` (+${first.questionCount - 1} more question${first.questionCount > 2 ? "s" : ""})` : ""}${humanInputs.length > 1 ? ` [${humanInputs.length} open requests]` : ""}.`,
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
if (approvals.length > 0) {
|
|
196
|
+
const names = approvals
|
|
197
|
+
.map((request) => (request.kind === "approval" ? request.toolName : null))
|
|
198
|
+
.filter((name): name is string => name !== null);
|
|
199
|
+
lines.push(
|
|
200
|
+
`${approvals.length} tool approval${approvals.length > 1 ? "s are" : " is"} waiting for a human${names.length > 0 ? ` (${names.join(", ")})` : ""}.`,
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
if (payload.truncated) lines.push("The request list was truncated.");
|
|
204
|
+
return lines.join(" ");
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export function childRequiresActionResolvedSummary(
|
|
208
|
+
childSessionId: string,
|
|
209
|
+
payload: ChildRequiresActionResolvedPayload,
|
|
210
|
+
): string {
|
|
211
|
+
const subject = payload.requestId ? "input request" : "approval";
|
|
212
|
+
return `Worker ${childSessionId}: its ${subject} was ${payload.outcome} (by ${payload.respondedByKind.replace("_", " ")}); the worker is no longer blocked on it.`;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export function childPausedSummary(childSessionId: string, payload: ChildPausedPayload): string {
|
|
216
|
+
const base = `Worker ${childSessionId} was paused by ${payload.actorKind === "agent" ? "an agent" : payload.actorKind === "api" ? "the API" : "a human"}.`;
|
|
217
|
+
return payload.reason ? `${base} Reason: ${payload.reason}` : base;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export function childWaitingCapacitySummary(
|
|
221
|
+
childSessionId: string,
|
|
222
|
+
payload: ChildWaitingCapacityPayload,
|
|
223
|
+
): string {
|
|
224
|
+
return `Worker ${childSessionId} is waiting for ${payload.provider === "codex" ? "Codex" : "xAI"} provider capacity${payload.nextCheckAt ? ` (next check ${payload.nextCheckAt})` : ""}; its turn resumes automatically.`;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export function childProgressSummary(
|
|
228
|
+
childSessionId: string,
|
|
229
|
+
payload: ChildProgressPayload,
|
|
230
|
+
): string {
|
|
231
|
+
return `Worker ${childSessionId} progress: ${payload.progressNote}`;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export function boundedChildPausedReason(reason: string | null | undefined): string | null {
|
|
235
|
+
if (reason === null || reason === undefined || reason.length === 0) return null;
|
|
236
|
+
return boundedChildNoticeText(reason, CHILD_PAUSED_REASON_MAX_BYTES).text;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
export function boundedChildProgressNote(note: string): string {
|
|
240
|
+
return boundedChildNoticeText(note, CHILD_PROGRESS_NOTE_MAX_BYTES).text;
|
|
241
|
+
}
|
|
@@ -55,15 +55,6 @@ export class CodemodeToolApprovalRequiredError extends Error {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
export class CodemodeCallBudgetExceededError extends Error {
|
|
59
|
-
readonly code = "codemode_call_budget_exhausted";
|
|
60
|
-
|
|
61
|
-
constructor() {
|
|
62
|
-
super("Codemode call budget is exhausted for this turn");
|
|
63
|
-
this.name = "CodemodeCallBudgetExceededError";
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
58
|
export class CodemodePayloadTooLargeError extends Error {
|
|
68
59
|
readonly code = "codemode_payload_too_large";
|
|
69
60
|
|
|
@@ -81,13 +72,12 @@ export type SubmitCodemodeOperationInput = {
|
|
|
81
72
|
attemptId: string;
|
|
82
73
|
executionGeneration: number;
|
|
83
74
|
call: AttemptToolCallValue;
|
|
84
|
-
callLimit: number;
|
|
85
75
|
};
|
|
86
76
|
|
|
87
77
|
/**
|
|
88
78
|
* Bind one caller-provided operation id to one exact catalog call. Duplicate
|
|
89
79
|
* submission of identical bytes is free and returns the same row; repurposing
|
|
90
|
-
* the id fails. Admission
|
|
80
|
+
* the id fails. Admission and insert share one turn lock.
|
|
91
81
|
*/
|
|
92
82
|
export async function submitCodemodeOperation(
|
|
93
83
|
db: Database,
|
|
@@ -120,7 +110,6 @@ export async function submitCodemodeOperation(
|
|
|
120
110
|
status: schema.sessionTurns.status,
|
|
121
111
|
activeAttemptId: schema.sessionTurns.activeAttemptId,
|
|
122
112
|
executionGeneration: schema.sessionTurns.executionGeneration,
|
|
123
|
-
callCount: schema.sessionTurns.codemodeCallCount,
|
|
124
113
|
})
|
|
125
114
|
.from(schema.sessionTurns)
|
|
126
115
|
.where(
|
|
@@ -141,10 +130,6 @@ export async function submitCodemodeOperation(
|
|
|
141
130
|
) {
|
|
142
131
|
throw new CodemodeOperationNotExecutableError();
|
|
143
132
|
}
|
|
144
|
-
if (!Number.isInteger(input.callLimit) || input.callLimit < 1) {
|
|
145
|
-
throw new CodemodeCallBudgetExceededError();
|
|
146
|
-
}
|
|
147
|
-
if (turn.callCount >= input.callLimit) throw new CodemodeCallBudgetExceededError();
|
|
148
133
|
|
|
149
134
|
const [catalogRow] = await tx
|
|
150
135
|
.select({ catalog: schema.sessionAttemptToolCatalogs.catalog })
|
|
@@ -180,25 +165,6 @@ export async function submitCodemodeOperation(
|
|
|
180
165
|
throw new CodemodeToolApprovalRequiredError();
|
|
181
166
|
}
|
|
182
167
|
|
|
183
|
-
const [counter] = await tx
|
|
184
|
-
.update(schema.sessionTurns)
|
|
185
|
-
.set({
|
|
186
|
-
codemodeCallCount: sql`${schema.sessionTurns.codemodeCallCount} + 1`,
|
|
187
|
-
updatedAt: new Date(),
|
|
188
|
-
})
|
|
189
|
-
.where(
|
|
190
|
-
and(
|
|
191
|
-
eq(schema.sessionTurns.workspaceId, input.workspaceId),
|
|
192
|
-
eq(schema.sessionTurns.id, input.turnId),
|
|
193
|
-
eq(schema.sessionTurns.status, "running"),
|
|
194
|
-
eq(schema.sessionTurns.activeAttemptId, input.attemptId),
|
|
195
|
-
eq(schema.sessionTurns.executionGeneration, input.executionGeneration),
|
|
196
|
-
sql`${schema.sessionTurns.codemodeCallCount} < ${input.callLimit}`,
|
|
197
|
-
),
|
|
198
|
-
)
|
|
199
|
-
.returning({ count: schema.sessionTurns.codemodeCallCount });
|
|
200
|
-
if (!counter) throw new CodemodeCallBudgetExceededError();
|
|
201
|
-
|
|
202
168
|
const [created] = await tx
|
|
203
169
|
.insert(schema.sessionAttemptCodemodeCalls)
|
|
204
170
|
.values({
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import {
|
|
2
|
+
boolean,
|
|
3
|
+
index,
|
|
4
|
+
integer,
|
|
5
|
+
jsonb,
|
|
6
|
+
pgTable,
|
|
7
|
+
text,
|
|
8
|
+
timestamp,
|
|
9
|
+
uniqueIndex,
|
|
10
|
+
uuid,
|
|
11
|
+
} from "drizzle-orm/pg-core";
|
|
12
|
+
import type { CompanyBrainMemorySelectionReference } from "./company-brain-context-selection";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Content-free accepted-logical-turn selection receipt. Migration 0259 owns
|
|
16
|
+
* the exact-attempt writer, immutable trigger, FORCE-RLS policy, and grants.
|
|
17
|
+
*/
|
|
18
|
+
export const companyBrainContextSelectionReceipts = pgTable(
|
|
19
|
+
"company_brain_context_selection_receipts",
|
|
20
|
+
{
|
|
21
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
22
|
+
accountId: uuid("account_id").notNull(),
|
|
23
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
24
|
+
sessionId: uuid("session_id").notNull(),
|
|
25
|
+
rootSessionId: uuid("root_session_id").notNull(),
|
|
26
|
+
turnId: uuid("turn_id").notNull(),
|
|
27
|
+
createdByAttemptId: uuid("created_by_attempt_id").notNull(),
|
|
28
|
+
createdByExecutionGeneration: integer("created_by_execution_generation").notNull(),
|
|
29
|
+
acceptedAt: timestamp("accepted_at", { withTimezone: true }).notNull(),
|
|
30
|
+
sessionRole: text("session_role").notNull(),
|
|
31
|
+
memoryEnabled: boolean("memory_enabled").notNull(),
|
|
32
|
+
memoryPromptMode: text("memory_prompt_mode").notNull(),
|
|
33
|
+
companyProfileIncluded: boolean("company_profile_included").notNull(),
|
|
34
|
+
instructionPolicyEntryHash: text("instruction_policy_entry_hash").notNull(),
|
|
35
|
+
preferenceDescriptorHash: text("preference_descriptor_hash"),
|
|
36
|
+
companyProfileSnapshotHash: text("company_profile_snapshot_hash").notNull(),
|
|
37
|
+
turnContextSnapshotId: uuid("turn_context_snapshot_id").notNull(),
|
|
38
|
+
turnContextSnapshotHash: text("turn_context_snapshot_hash").notNull(),
|
|
39
|
+
turnContextSnapshotSource: text("turn_context_snapshot_source").notNull(),
|
|
40
|
+
memorySelections: jsonb("memory_selections")
|
|
41
|
+
.$type<readonly CompanyBrainMemorySelectionReference[]>()
|
|
42
|
+
.notNull(),
|
|
43
|
+
renderedMemorySelections: jsonb("rendered_memory_selections")
|
|
44
|
+
.$type<readonly CompanyBrainMemorySelectionReference[]>()
|
|
45
|
+
.notNull(),
|
|
46
|
+
selectionHash: text("selection_hash").notNull(),
|
|
47
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
48
|
+
},
|
|
49
|
+
(table) => ({
|
|
50
|
+
logicalTurn: uniqueIndex("company_brain_context_selection_turn_uq").on(
|
|
51
|
+
table.workspaceId,
|
|
52
|
+
table.turnId,
|
|
53
|
+
),
|
|
54
|
+
workspaceTimeline: index("company_brain_context_selection_workspace_time_idx").on(
|
|
55
|
+
table.workspaceId,
|
|
56
|
+
table.createdAt,
|
|
57
|
+
table.id,
|
|
58
|
+
),
|
|
59
|
+
}),
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Exact bounded accepted-turn authority that may contain the legacy workspace
|
|
64
|
+
* instruction fallback. It is deliberately separate from the content-free
|
|
65
|
+
* selection receipt and has no direct runtime table privileges.
|
|
66
|
+
*/
|
|
67
|
+
export const companyBrainTurnContextSnapshots = pgTable(
|
|
68
|
+
"company_brain_turn_context_snapshots",
|
|
69
|
+
{
|
|
70
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
71
|
+
accountId: uuid("account_id").notNull(),
|
|
72
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
73
|
+
sessionId: uuid("session_id").notNull(),
|
|
74
|
+
rootSessionId: uuid("root_session_id").notNull(),
|
|
75
|
+
turnId: uuid("turn_id").notNull(),
|
|
76
|
+
acceptedAt: timestamp("accepted_at", { withTimezone: true }).notNull(),
|
|
77
|
+
memoryEnabled: boolean("memory_enabled").notNull(),
|
|
78
|
+
memoryPromptMode: text("memory_prompt_mode").notNull(),
|
|
79
|
+
legacyWorkspaceInstructions: text("legacy_workspace_instructions"),
|
|
80
|
+
legacyWorkspaceInstructionsOriginalUtf8Bytes: integer(
|
|
81
|
+
"legacy_workspace_instructions_original_utf8_bytes",
|
|
82
|
+
),
|
|
83
|
+
legacyWorkspaceInstructionsTruncated: boolean(
|
|
84
|
+
"legacy_workspace_instructions_truncated",
|
|
85
|
+
).notNull(),
|
|
86
|
+
snapshotSource: text("snapshot_source").notNull(),
|
|
87
|
+
snapshotHash: text("snapshot_hash").notNull(),
|
|
88
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
89
|
+
},
|
|
90
|
+
(table) => ({
|
|
91
|
+
logicalTurn: uniqueIndex("company_brain_turn_context_snapshot_turn_uq").on(
|
|
92
|
+
table.workspaceId,
|
|
93
|
+
table.turnId,
|
|
94
|
+
),
|
|
95
|
+
workspaceIdentity: uniqueIndex("company_brain_turn_context_snapshot_workspace_id_uq").on(
|
|
96
|
+
table.workspaceId,
|
|
97
|
+
table.id,
|
|
98
|
+
),
|
|
99
|
+
}),
|
|
100
|
+
);
|