@opengeni/db 3.7.4 → 4.0.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/automations.d.ts +4 -0
- package/dist/canonical-human-identities.js +3 -3
- package/dist/capability-integrations.d.ts +2 -0
- package/dist/{chunk-6DPJA36C.js → chunk-2XEZK4LF.js} +7 -1
- package/dist/chunk-2XEZK4LF.js.map +1 -0
- package/dist/{chunk-4NAR7FBA.js → chunk-3RI33YQN.js} +67 -1
- package/dist/chunk-3RI33YQN.js.map +1 -0
- package/dist/{chunk-SZAWDXQC.js → chunk-CJROYHSC.js} +3 -3
- package/dist/{chunk-DZCYW2WT.js → chunk-MX6V5F65.js} +2 -2
- package/dist/{chunk-S3TDDCS2.js → chunk-N5VXJ4I2.js} +151 -78
- package/dist/chunk-N5VXJ4I2.js.map +1 -0
- package/dist/{chunk-U4WPPEBH.js → chunk-NLFHMPUB.js} +2 -2
- package/dist/{chunk-5NNCGFQY.js → chunk-P6NSEG2S.js} +2 -2
- package/dist/{chunk-O56DM5GZ.js → chunk-QM6YOWHZ.js} +624 -57
- package/dist/chunk-QM6YOWHZ.js.map +1 -0
- package/dist/{chunk-US4IS6IV.js → chunk-RZNOSEMC.js} +2 -2
- package/dist/{chunk-F6PBS6WE.js → chunk-UFAMOUWL.js} +2 -2
- package/dist/codemode-operations.d.ts +5 -0
- package/dist/codex-token-resolver.d.ts +6 -2
- package/dist/connection-token-resolver.d.ts +8 -0
- package/dist/editable-artifact-durable-export.js +2 -2
- package/dist/editable-artifacts.js +3 -3
- package/dist/generated-images.d.ts +15 -0
- package/dist/index.d.ts +393 -91
- package/dist/index.js +9992 -6069
- package/dist/index.js.map +1 -1
- package/dist/insights.d.ts +9 -0
- package/dist/managed-auth-session-sets.js +3 -3
- package/dist/managed-user-setup.d.ts +3 -0
- package/dist/mcp-oauth.d.ts +80 -0
- package/dist/migrate.d.ts +1 -0
- package/dist/migrate.js +3 -1
- package/dist/model-catalog.d.ts +153 -0
- package/dist/model-context-snapshots.d.ts +20 -0
- package/dist/new-session-drafts.d.ts +12 -0
- package/dist/organization-membership-lifecycle.d.ts +8 -1
- package/dist/organization-model-providers.d.ts +101 -0
- package/dist/pack-components.d.ts +1 -0
- package/dist/pr-review.d.ts +9 -0
- package/dist/provision-roles.js +1 -1
- package/dist/runtime-posture.d.ts +8 -8
- package/dist/schema.d.ts +7708 -5050
- package/dist/schema.js +25 -1
- package/dist/session-background-commands.d.ts +18 -6
- package/dist/session-background-commands.js +15 -9
- package/dist/session-control.d.ts +37 -2
- package/dist/session-goal-pacing.d.ts +3 -6
- package/dist/session-queue-commands.d.ts +17 -0
- package/dist/session-tenancy.js +3 -3
- package/dist/tool-gateway-approvals.d.ts +31 -0
- package/dist/video-generation.js +3 -3
- package/dist/workspace-artifacts.d.ts +17 -3
- package/dist/xai-subscription.d.ts +8 -0
- package/drizzle/0387_bound_host_export_session_payloads.sql +165 -0
- package/drizzle/0388_sandbox_provider_deadline_interactions.sql +491 -0
- package/drizzle/0389_model_catalog_and_gateway_custom_models.sql +241 -0
- package/drizzle/0390_organization_model_provider_connections.sql +197 -0
- package/drizzle/0391_sandbox_provider_deadline_interaction_followup.sql +295 -0
- package/drizzle/0392_context_compaction_pending_observability.sql +198 -0
- package/drizzle/0393_workspace_memory_and_learning_defaults.sql +102 -0
- package/drizzle/0394_session_selected_skill_activation.sql +20 -0
- package/drizzle/0395_scheduled_task_unclaimed_occurrence_invalidation.sql +154 -0
- package/drizzle/0396_model_call_equivalent_credit_cost.sql +28 -0
- package/drizzle/0397_sandbox_deadline_rotation_preemption.sql +113 -0
- package/drizzle/0398_organization_workspace_management_entry.sql +206 -0
- package/drizzle/0399_additional_managed_organization_creation.sql +691 -0
- package/drizzle/0400_session_attempt_model_context_snapshots.sql +65 -0
- package/drizzle/0401_organization_user_setup_token_transport.sql +178 -0
- package/drizzle/0402_session_input_wait_and_background_command_results.sql +1023 -0
- package/drizzle/0403_codex_unconditional_credential_leasing.sql +181 -0
- package/drizzle/0404_mcp_oauth_authorization_server.sql +471 -0
- package/drizzle/0405_tool_gateway_approval_capabilities.sql +184 -0
- package/drizzle/0406_workspace_html_site_sources.sql +71 -0
- package/package.json +6 -6
- package/src/automations.ts +9 -1
- package/src/capability-integrations.ts +8 -0
- package/src/codemode-operations.ts +31 -21
- package/src/codex-token-resolver.ts +16 -6
- package/src/connection-token-resolver.ts +52 -3
- package/src/generated-images.ts +70 -6
- package/src/index.ts +3894 -994
- package/src/insights-model-bundle.ts +54 -5
- package/src/insights.ts +53 -7
- package/src/managed-user-setup.ts +14 -3
- package/src/mcp-oauth.ts +488 -0
- package/src/migrate.ts +9 -1
- package/src/model-catalog.ts +682 -0
- package/src/model-context-snapshots.ts +151 -0
- package/src/new-session-drafts.ts +66 -21
- package/src/organization-membership-lifecycle.ts +47 -5
- package/src/organization-model-providers.ts +614 -0
- package/src/pack-components.ts +15 -2
- package/src/pr-review.ts +19 -0
- package/src/provision-roles.ts +4 -0
- package/src/runtime-posture.ts +64 -0
- package/src/schema.ts +666 -61
- package/src/session-background-commands.ts +180 -78
- package/src/session-control.ts +181 -12
- package/src/session-goal-pacing.ts +4 -8
- package/src/session-queue-commands.ts +157 -82
- package/src/tool-gateway-approvals.ts +168 -0
- package/src/workspace-artifacts.ts +633 -178
- package/src/xai-subscription.ts +66 -14
- package/dist/chunk-4NAR7FBA.js.map +0 -1
- package/dist/chunk-6DPJA36C.js.map +0 -1
- package/dist/chunk-O56DM5GZ.js.map +0 -1
- package/dist/chunk-S3TDDCS2.js.map +0 -1
- /package/dist/{chunk-SZAWDXQC.js.map → chunk-CJROYHSC.js.map} +0 -0
- /package/dist/{chunk-DZCYW2WT.js.map → chunk-MX6V5F65.js.map} +0 -0
- /package/dist/{chunk-U4WPPEBH.js.map → chunk-NLFHMPUB.js.map} +0 -0
- /package/dist/{chunk-5NNCGFQY.js.map → chunk-P6NSEG2S.js.map} +0 -0
- /package/dist/{chunk-US4IS6IV.js.map → chunk-RZNOSEMC.js.map} +0 -0
- /package/dist/{chunk-F6PBS6WE.js.map → chunk-UFAMOUWL.js.map} +0 -0
|
@@ -0,0 +1,1023 @@
|
|
|
1
|
+
-- deployment-mode: maintenance
|
|
2
|
+
|
|
3
|
+
-- Move the durable out-of-turn wait from an active goal to its owning session.
|
|
4
|
+
-- This is an intentional clean break: the first-party tool is now
|
|
5
|
+
-- `wait_for_input`, it does not require a goal, and there is no compatibility
|
|
6
|
+
-- alias for `goal_wait`. Existing declarations keep their exact turn,
|
|
7
|
+
-- deadline, reason, and set time across the cutover. Existing explicit tool
|
|
8
|
+
-- selections replace `goal_wait` with `wait_for_input` in place across
|
|
9
|
+
-- sessions, workspace defaults, private drafts, automation definitions and
|
|
10
|
+
-- accepted runs, scheduled accepted-execution snapshots, and registered or
|
|
11
|
+
-- installed Pack manifests. Digest-bound snapshots are rewritten with their
|
|
12
|
+
-- exact native digest authority in the same transaction.
|
|
13
|
+
-- Stop every API, control worker, and turn worker before applying this
|
|
14
|
+
-- migration, and never restart a pre-0402 image after commit.
|
|
15
|
+
|
|
16
|
+
SET LOCAL lock_timeout = '5s';
|
|
17
|
+
SET LOCAL statement_timeout = '30min';
|
|
18
|
+
|
|
19
|
+
DO $session_input_wait_runtime_drain_before$
|
|
20
|
+
DECLARE
|
|
21
|
+
configured_roles_text text := nullif(
|
|
22
|
+
current_setting('opengeni.migration_application_roles', true), ''
|
|
23
|
+
);
|
|
24
|
+
configured_roles jsonb;
|
|
25
|
+
BEGIN
|
|
26
|
+
IF configured_roles_text IS NULL THEN
|
|
27
|
+
RAISE EXCEPTION
|
|
28
|
+
'0402 session input wait activation requires an explicit application database role list'
|
|
29
|
+
USING ERRCODE = '55000';
|
|
30
|
+
END IF;
|
|
31
|
+
BEGIN
|
|
32
|
+
configured_roles := configured_roles_text::jsonb;
|
|
33
|
+
EXCEPTION WHEN OTHERS THEN
|
|
34
|
+
RAISE EXCEPTION
|
|
35
|
+
'0402 session input wait activation received a malformed application database role list'
|
|
36
|
+
USING ERRCODE = '55000';
|
|
37
|
+
END;
|
|
38
|
+
IF jsonb_typeof(configured_roles) <> 'array'
|
|
39
|
+
OR jsonb_array_length(configured_roles) NOT BETWEEN 1 AND 16
|
|
40
|
+
OR EXISTS (
|
|
41
|
+
SELECT 1 FROM jsonb_array_elements(configured_roles) AS roles(value)
|
|
42
|
+
WHERE jsonb_typeof(value) <> 'string'
|
|
43
|
+
OR btrim(value #>> '{}') = ''
|
|
44
|
+
OR octet_length(value #>> '{}') > 63
|
|
45
|
+
)
|
|
46
|
+
OR (
|
|
47
|
+
SELECT count(*) FROM jsonb_array_elements_text(configured_roles)
|
|
48
|
+
) <> (
|
|
49
|
+
SELECT count(DISTINCT value)
|
|
50
|
+
FROM jsonb_array_elements_text(configured_roles) AS roles(value)
|
|
51
|
+
)
|
|
52
|
+
THEN
|
|
53
|
+
RAISE EXCEPTION
|
|
54
|
+
'0402 session input wait activation received an invalid application database role list'
|
|
55
|
+
USING ERRCODE = '55000';
|
|
56
|
+
END IF;
|
|
57
|
+
IF EXISTS (
|
|
58
|
+
SELECT 1 FROM pg_stat_activity activity
|
|
59
|
+
JOIN jsonb_array_elements_text(configured_roles) roles(role_name)
|
|
60
|
+
ON roles.role_name = activity.usename
|
|
61
|
+
WHERE activity.datname = current_database()
|
|
62
|
+
AND activity.pid <> pg_backend_pid()
|
|
63
|
+
)
|
|
64
|
+
THEN
|
|
65
|
+
RAISE EXCEPTION
|
|
66
|
+
'0402 session input wait activation requires all configured OpenGeni application database sessions to be stopped'
|
|
67
|
+
USING ERRCODE = '55000';
|
|
68
|
+
END IF;
|
|
69
|
+
END
|
|
70
|
+
$session_input_wait_runtime_drain_before$;
|
|
71
|
+
|
|
72
|
+
-- The runtime drain is a process fence. Hold every affected persistence
|
|
73
|
+
-- authority too, so no migration/admin writer can create a stale snapshot
|
|
74
|
+
-- between inventory, digest proof, and rewrite.
|
|
75
|
+
LOCK TABLE
|
|
76
|
+
"workspaces",
|
|
77
|
+
"sessions",
|
|
78
|
+
"session_goals",
|
|
79
|
+
"new_session_drafts",
|
|
80
|
+
"automation_trigger_revisions",
|
|
81
|
+
"automation_runs",
|
|
82
|
+
"scheduled_tasks",
|
|
83
|
+
"scheduled_task_revision_authorities",
|
|
84
|
+
"scheduled_task_personal_resource_authorities",
|
|
85
|
+
"scheduled_task_connection_authority_snapshots",
|
|
86
|
+
"scheduled_task_runs",
|
|
87
|
+
"workspace_packs",
|
|
88
|
+
"pack_installations",
|
|
89
|
+
"capability_operations"
|
|
90
|
+
IN ACCESS EXCLUSIVE MODE;
|
|
91
|
+
|
|
92
|
+
-- Preserve exact first-seen order. The rename may make an existing
|
|
93
|
+
-- wait_for_input entry collide with one or more historical goal_wait entries;
|
|
94
|
+
-- collapse only that replacement, leaving every unrelated entry byte-order
|
|
95
|
+
-- equivalent (including any unrelated duplicates).
|
|
96
|
+
CREATE FUNCTION opengeni_private.session_wait_translate_tool_array(value jsonb)
|
|
97
|
+
RETURNS jsonb
|
|
98
|
+
LANGUAGE plpgsql
|
|
99
|
+
IMMUTABLE
|
|
100
|
+
STRICT
|
|
101
|
+
PARALLEL SAFE
|
|
102
|
+
AS $translate$
|
|
103
|
+
DECLARE
|
|
104
|
+
translated jsonb;
|
|
105
|
+
BEGIN
|
|
106
|
+
IF jsonb_typeof(value) <> 'array' OR EXISTS (
|
|
107
|
+
SELECT 1
|
|
108
|
+
FROM jsonb_array_elements(value) AS entry(item)
|
|
109
|
+
WHERE jsonb_typeof(entry.item) <> 'string'
|
|
110
|
+
) THEN
|
|
111
|
+
RAISE EXCEPTION 'persisted first-party tool selection must be a string array'
|
|
112
|
+
USING ERRCODE = '23514';
|
|
113
|
+
END IF;
|
|
114
|
+
|
|
115
|
+
WITH mapped AS (
|
|
116
|
+
SELECT
|
|
117
|
+
CASE entry.value #>> '{}'
|
|
118
|
+
WHEN 'goal_wait' THEN 'wait_for_input'
|
|
119
|
+
ELSE entry.value #>> '{}'
|
|
120
|
+
END AS tool,
|
|
121
|
+
entry.ordinality
|
|
122
|
+
FROM jsonb_array_elements(value) WITH ORDINALITY AS entry(value, ordinality)
|
|
123
|
+
), ranked AS (
|
|
124
|
+
SELECT
|
|
125
|
+
mapped.tool,
|
|
126
|
+
mapped.ordinality,
|
|
127
|
+
row_number() OVER (
|
|
128
|
+
PARTITION BY mapped.tool
|
|
129
|
+
ORDER BY mapped.ordinality
|
|
130
|
+
) AS tool_ordinality
|
|
131
|
+
FROM mapped
|
|
132
|
+
)
|
|
133
|
+
SELECT coalesce(
|
|
134
|
+
jsonb_agg(to_jsonb(ranked.tool) ORDER BY ranked.ordinality),
|
|
135
|
+
'[]'::jsonb
|
|
136
|
+
)
|
|
137
|
+
INTO translated
|
|
138
|
+
FROM ranked
|
|
139
|
+
WHERE ranked.tool <> 'wait_for_input' OR ranked.tool_ordinality = 1;
|
|
140
|
+
|
|
141
|
+
RETURN translated;
|
|
142
|
+
END
|
|
143
|
+
$translate$;
|
|
144
|
+
|
|
145
|
+
CREATE FUNCTION opengeni_private.session_wait_rewrite_automation_template(value jsonb)
|
|
146
|
+
RETURNS jsonb
|
|
147
|
+
LANGUAGE plpgsql
|
|
148
|
+
IMMUTABLE
|
|
149
|
+
STRICT
|
|
150
|
+
PARALLEL SAFE
|
|
151
|
+
AS $rewrite_automation_template$
|
|
152
|
+
BEGIN
|
|
153
|
+
IF jsonb_typeof(value) <> 'object'
|
|
154
|
+
OR jsonb_typeof(value -> 'firstPartyMcpTools') <> 'array'
|
|
155
|
+
THEN
|
|
156
|
+
RAISE EXCEPTION 'persisted automation session template has invalid tool selection'
|
|
157
|
+
USING ERRCODE = '23514';
|
|
158
|
+
END IF;
|
|
159
|
+
IF value -> 'firstPartyMcpTools' @> '["goal_wait"]'::jsonb THEN
|
|
160
|
+
RETURN jsonb_set(
|
|
161
|
+
value,
|
|
162
|
+
'{firstPartyMcpTools}',
|
|
163
|
+
opengeni_private.session_wait_translate_tool_array(
|
|
164
|
+
value -> 'firstPartyMcpTools'
|
|
165
|
+
),
|
|
166
|
+
false
|
|
167
|
+
);
|
|
168
|
+
END IF;
|
|
169
|
+
RETURN value;
|
|
170
|
+
END
|
|
171
|
+
$rewrite_automation_template$;
|
|
172
|
+
|
|
173
|
+
CREATE FUNCTION opengeni_private.session_wait_rewrite_pack(value jsonb)
|
|
174
|
+
RETURNS jsonb
|
|
175
|
+
LANGUAGE plpgsql
|
|
176
|
+
IMMUTABLE
|
|
177
|
+
STRICT
|
|
178
|
+
PARALLEL SAFE
|
|
179
|
+
AS $rewrite_pack$
|
|
180
|
+
DECLARE
|
|
181
|
+
templates jsonb;
|
|
182
|
+
BEGIN
|
|
183
|
+
IF jsonb_typeof(value) <> 'object'
|
|
184
|
+
OR NOT (value ? 'automationTemplates')
|
|
185
|
+
OR jsonb_typeof(value -> 'automationTemplates') <> 'array'
|
|
186
|
+
THEN
|
|
187
|
+
RETURN value;
|
|
188
|
+
END IF;
|
|
189
|
+
|
|
190
|
+
SELECT coalesce(
|
|
191
|
+
jsonb_agg(
|
|
192
|
+
CASE
|
|
193
|
+
WHEN template.value #> '{sessionTemplate,firstPartyMcpTools}'
|
|
194
|
+
@> '["goal_wait"]'::jsonb
|
|
195
|
+
THEN jsonb_set(
|
|
196
|
+
template.value,
|
|
197
|
+
'{sessionTemplate}',
|
|
198
|
+
opengeni_private.session_wait_rewrite_automation_template(
|
|
199
|
+
template.value -> 'sessionTemplate'
|
|
200
|
+
),
|
|
201
|
+
false
|
|
202
|
+
)
|
|
203
|
+
ELSE template.value
|
|
204
|
+
END
|
|
205
|
+
ORDER BY template.ordinality
|
|
206
|
+
),
|
|
207
|
+
'[]'::jsonb
|
|
208
|
+
)
|
|
209
|
+
INTO templates
|
|
210
|
+
FROM jsonb_array_elements(value -> 'automationTemplates')
|
|
211
|
+
WITH ORDINALITY AS template(value, ordinality);
|
|
212
|
+
|
|
213
|
+
RETURN jsonb_set(value, '{automationTemplates}', templates, false);
|
|
214
|
+
END
|
|
215
|
+
$rewrite_pack$;
|
|
216
|
+
|
|
217
|
+
CREATE FUNCTION opengeni_private.session_wait_rewrite_scheduled_agent_config(value jsonb)
|
|
218
|
+
RETURNS jsonb
|
|
219
|
+
LANGUAGE plpgsql
|
|
220
|
+
IMMUTABLE
|
|
221
|
+
STRICT
|
|
222
|
+
PARALLEL SAFE
|
|
223
|
+
AS $rewrite_scheduled_agent_config$
|
|
224
|
+
DECLARE
|
|
225
|
+
rewritten jsonb := value;
|
|
226
|
+
BEGIN
|
|
227
|
+
IF jsonb_typeof(value) <> 'object' THEN
|
|
228
|
+
RAISE EXCEPTION 'persisted scheduled agent config must be an object'
|
|
229
|
+
USING ERRCODE = '23514';
|
|
230
|
+
END IF;
|
|
231
|
+
|
|
232
|
+
IF rewritten #> '{incidentTelemetryPreflight,requiredFirstPartyMcpTools}'
|
|
233
|
+
@> '["goal_wait"]'::jsonb
|
|
234
|
+
THEN
|
|
235
|
+
rewritten := jsonb_set(
|
|
236
|
+
rewritten,
|
|
237
|
+
'{incidentTelemetryPreflight,requiredFirstPartyMcpTools}',
|
|
238
|
+
opengeni_private.session_wait_translate_tool_array(
|
|
239
|
+
rewritten #> '{incidentTelemetryPreflight,requiredFirstPartyMcpTools}'
|
|
240
|
+
),
|
|
241
|
+
false
|
|
242
|
+
);
|
|
243
|
+
END IF;
|
|
244
|
+
IF rewritten #>> '{incidentTelemetryPreflight,dataSource,route,kind}' = 'first_party'
|
|
245
|
+
AND rewritten #>> '{incidentTelemetryPreflight,dataSource,route,tool}' = 'goal_wait'
|
|
246
|
+
THEN
|
|
247
|
+
rewritten := jsonb_set(
|
|
248
|
+
rewritten,
|
|
249
|
+
'{incidentTelemetryPreflight,dataSource,route,tool}',
|
|
250
|
+
to_jsonb('wait_for_input'::text),
|
|
251
|
+
false
|
|
252
|
+
);
|
|
253
|
+
END IF;
|
|
254
|
+
RETURN rewritten;
|
|
255
|
+
END
|
|
256
|
+
$rewrite_scheduled_agent_config$;
|
|
257
|
+
|
|
258
|
+
CREATE FUNCTION opengeni_private.session_wait_rewrite_scheduled_execution(value jsonb)
|
|
259
|
+
RETURNS jsonb
|
|
260
|
+
LANGUAGE plpgsql
|
|
261
|
+
IMMUTABLE
|
|
262
|
+
STRICT
|
|
263
|
+
PARALLEL SAFE
|
|
264
|
+
AS $rewrite_scheduled_execution$
|
|
265
|
+
DECLARE
|
|
266
|
+
rewritten jsonb := value;
|
|
267
|
+
BEGIN
|
|
268
|
+
IF jsonb_typeof(value) <> 'object' THEN
|
|
269
|
+
RAISE EXCEPTION 'persisted scheduled accepted execution must be an object'
|
|
270
|
+
USING ERRCODE = '23514';
|
|
271
|
+
END IF;
|
|
272
|
+
|
|
273
|
+
IF rewritten -> 'resolvedFirstPartyMcpTools' @> '["goal_wait"]'::jsonb THEN
|
|
274
|
+
rewritten := jsonb_set(
|
|
275
|
+
rewritten,
|
|
276
|
+
'{resolvedFirstPartyMcpTools}',
|
|
277
|
+
opengeni_private.session_wait_translate_tool_array(
|
|
278
|
+
rewritten -> 'resolvedFirstPartyMcpTools'
|
|
279
|
+
),
|
|
280
|
+
false
|
|
281
|
+
);
|
|
282
|
+
END IF;
|
|
283
|
+
IF rewritten #> '{targetSessionExecution,firstPartyMcpTools}'
|
|
284
|
+
@> '["goal_wait"]'::jsonb
|
|
285
|
+
THEN
|
|
286
|
+
rewritten := jsonb_set(
|
|
287
|
+
rewritten,
|
|
288
|
+
'{targetSessionExecution,firstPartyMcpTools}',
|
|
289
|
+
opengeni_private.session_wait_translate_tool_array(
|
|
290
|
+
rewritten #> '{targetSessionExecution,firstPartyMcpTools}'
|
|
291
|
+
),
|
|
292
|
+
false
|
|
293
|
+
);
|
|
294
|
+
END IF;
|
|
295
|
+
IF rewritten #> '{task,agentConfig}' IS DISTINCT FROM
|
|
296
|
+
opengeni_private.session_wait_rewrite_scheduled_agent_config(
|
|
297
|
+
rewritten #> '{task,agentConfig}'
|
|
298
|
+
)
|
|
299
|
+
THEN
|
|
300
|
+
rewritten := jsonb_set(
|
|
301
|
+
rewritten,
|
|
302
|
+
'{task,agentConfig}',
|
|
303
|
+
opengeni_private.session_wait_rewrite_scheduled_agent_config(
|
|
304
|
+
rewritten #> '{task,agentConfig}'
|
|
305
|
+
),
|
|
306
|
+
false
|
|
307
|
+
);
|
|
308
|
+
END IF;
|
|
309
|
+
RETURN rewritten;
|
|
310
|
+
END
|
|
311
|
+
$rewrite_scheduled_execution$;
|
|
312
|
+
|
|
313
|
+
-- Pack manifests are hashed with contracts stableJson(), whose object-key
|
|
314
|
+
-- order uses the default en-US Intl comparator. Reproduce those exact bytes;
|
|
315
|
+
-- the old-digest precondition below aborts before mutation if this database's
|
|
316
|
+
-- ICU/scalar rendering cannot reproduce any affected stored digest.
|
|
317
|
+
CREATE COLLATION opengeni_private.session_wait_js_en_us (
|
|
318
|
+
provider = icu,
|
|
319
|
+
locale = 'en-US',
|
|
320
|
+
deterministic = false
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
CREATE FUNCTION opengeni_private.session_wait_canonical_json(value jsonb)
|
|
324
|
+
RETURNS text
|
|
325
|
+
LANGUAGE plpgsql
|
|
326
|
+
IMMUTABLE
|
|
327
|
+
STRICT
|
|
328
|
+
PARALLEL SAFE
|
|
329
|
+
AS $canonical_json$
|
|
330
|
+
DECLARE
|
|
331
|
+
rendered text;
|
|
332
|
+
BEGIN
|
|
333
|
+
CASE jsonb_typeof(value)
|
|
334
|
+
WHEN 'object' THEN
|
|
335
|
+
SELECT coalesce(
|
|
336
|
+
'{' || string_agg(
|
|
337
|
+
to_jsonb(entry.key)::text || ':' ||
|
|
338
|
+
opengeni_private.session_wait_canonical_json(entry.value),
|
|
339
|
+
',' ORDER BY
|
|
340
|
+
entry.key COLLATE opengeni_private.session_wait_js_en_us,
|
|
341
|
+
entry.ordinality
|
|
342
|
+
) || '}',
|
|
343
|
+
'{}'
|
|
344
|
+
)
|
|
345
|
+
INTO rendered
|
|
346
|
+
FROM jsonb_each(value) WITH ORDINALITY AS entry(key, value, ordinality);
|
|
347
|
+
RETURN rendered;
|
|
348
|
+
WHEN 'array' THEN
|
|
349
|
+
SELECT coalesce(
|
|
350
|
+
'[' || string_agg(
|
|
351
|
+
opengeni_private.session_wait_canonical_json(entry.value),
|
|
352
|
+
',' ORDER BY entry.ordinality
|
|
353
|
+
) || ']',
|
|
354
|
+
'[]'
|
|
355
|
+
)
|
|
356
|
+
INTO rendered
|
|
357
|
+
FROM jsonb_array_elements(value) WITH ORDINALITY AS entry(value, ordinality);
|
|
358
|
+
RETURN rendered;
|
|
359
|
+
ELSE
|
|
360
|
+
RETURN value::text;
|
|
361
|
+
END CASE;
|
|
362
|
+
END
|
|
363
|
+
$canonical_json$;
|
|
364
|
+
|
|
365
|
+
ALTER TABLE "sessions"
|
|
366
|
+
ADD COLUMN "input_wait_turn_id" uuid,
|
|
367
|
+
ADD COLUMN "input_wait_until" timestamptz,
|
|
368
|
+
ADD COLUMN "input_wait_reason" text,
|
|
369
|
+
ADD COLUMN "input_wait_set_at" timestamptz;
|
|
370
|
+
|
|
371
|
+
-- The production migration identity is a NOSUPERUSER/NOBYPASSRLS table owner.
|
|
372
|
+
-- Relax FORCE only for this drained owner backfill, then restore it before any
|
|
373
|
+
-- constraint or column cutover. The enclosing migration transaction makes a
|
|
374
|
+
-- failure rollback both posture changes.
|
|
375
|
+
ALTER TABLE "sessions" NO FORCE ROW LEVEL SECURITY;
|
|
376
|
+
ALTER TABLE "session_goals" NO FORCE ROW LEVEL SECURITY;
|
|
377
|
+
ALTER TABLE "new_session_drafts" NO FORCE ROW LEVEL SECURITY;
|
|
378
|
+
ALTER TABLE "automation_trigger_revisions" NO FORCE ROW LEVEL SECURITY;
|
|
379
|
+
ALTER TABLE "automation_runs" NO FORCE ROW LEVEL SECURITY;
|
|
380
|
+
ALTER TABLE "scheduled_tasks" NO FORCE ROW LEVEL SECURITY;
|
|
381
|
+
ALTER TABLE "scheduled_task_revision_authorities" NO FORCE ROW LEVEL SECURITY;
|
|
382
|
+
ALTER TABLE "scheduled_task_personal_resource_authorities" NO FORCE ROW LEVEL SECURITY;
|
|
383
|
+
ALTER TABLE "scheduled_task_connection_authority_snapshots" NO FORCE ROW LEVEL SECURITY;
|
|
384
|
+
ALTER TABLE "scheduled_task_runs" NO FORCE ROW LEVEL SECURITY;
|
|
385
|
+
ALTER TABLE "workspace_packs" NO FORCE ROW LEVEL SECURITY;
|
|
386
|
+
ALTER TABLE "pack_installations" NO FORCE ROW LEVEL SECURITY;
|
|
387
|
+
ALTER TABLE "capability_operations" NO FORCE ROW LEVEL SECURITY;
|
|
388
|
+
|
|
389
|
+
CREATE TEMP TABLE session_wait_scheduled_task_cutover ON COMMIT DROP AS
|
|
390
|
+
SELECT
|
|
391
|
+
task.id,
|
|
392
|
+
task.account_id,
|
|
393
|
+
task.workspace_id,
|
|
394
|
+
task.authority_revision,
|
|
395
|
+
task.execution_digest AS previous_execution_digest,
|
|
396
|
+
task.agent_config AS previous_agent_config,
|
|
397
|
+
opengeni_private.session_wait_rewrite_scheduled_agent_config(
|
|
398
|
+
task.agent_config
|
|
399
|
+
) AS agent_config
|
|
400
|
+
FROM scheduled_tasks task
|
|
401
|
+
WHERE task.agent_config IS DISTINCT FROM
|
|
402
|
+
opengeni_private.session_wait_rewrite_scheduled_agent_config(
|
|
403
|
+
task.agent_config
|
|
404
|
+
);
|
|
405
|
+
|
|
406
|
+
CREATE TEMP TABLE session_wait_scheduled_snapshot_cutover ON COMMIT DROP AS
|
|
407
|
+
SELECT
|
|
408
|
+
run.id,
|
|
409
|
+
run.workspace_id,
|
|
410
|
+
run.accepted_execution_snapshot AS previous_snapshot,
|
|
411
|
+
run.accepted_execution_digest AS previous_digest,
|
|
412
|
+
opengeni_private.session_wait_rewrite_scheduled_execution(
|
|
413
|
+
run.accepted_execution_snapshot
|
|
414
|
+
) AS accepted_execution_snapshot
|
|
415
|
+
FROM scheduled_task_runs run
|
|
416
|
+
WHERE run.accepted_execution_snapshot IS NOT NULL
|
|
417
|
+
AND run.accepted_execution_snapshot IS DISTINCT FROM
|
|
418
|
+
opengeni_private.session_wait_rewrite_scheduled_execution(
|
|
419
|
+
run.accepted_execution_snapshot
|
|
420
|
+
);
|
|
421
|
+
|
|
422
|
+
CREATE TEMP TABLE session_wait_pack_snapshot_cutover ON COMMIT DROP AS
|
|
423
|
+
SELECT
|
|
424
|
+
installation.id,
|
|
425
|
+
installation.workspace_id,
|
|
426
|
+
installation.pack_id,
|
|
427
|
+
installation.manifest_snapshot AS previous_manifest_snapshot,
|
|
428
|
+
installation.manifest_digest AS previous_manifest_digest,
|
|
429
|
+
opengeni_private.session_wait_rewrite_pack(
|
|
430
|
+
installation.manifest_snapshot
|
|
431
|
+
) AS manifest_snapshot,
|
|
432
|
+
encode(
|
|
433
|
+
digest(
|
|
434
|
+
convert_to(
|
|
435
|
+
opengeni_private.session_wait_canonical_json(
|
|
436
|
+
opengeni_private.session_wait_rewrite_pack(
|
|
437
|
+
installation.manifest_snapshot
|
|
438
|
+
)
|
|
439
|
+
),
|
|
440
|
+
'UTF8'
|
|
441
|
+
),
|
|
442
|
+
'sha256'
|
|
443
|
+
),
|
|
444
|
+
'hex'
|
|
445
|
+
) AS manifest_digest
|
|
446
|
+
FROM pack_installations installation
|
|
447
|
+
WHERE installation.manifest_snapshot IS NOT NULL
|
|
448
|
+
AND installation.manifest_snapshot IS DISTINCT FROM
|
|
449
|
+
opengeni_private.session_wait_rewrite_pack(
|
|
450
|
+
installation.manifest_snapshot
|
|
451
|
+
);
|
|
452
|
+
|
|
453
|
+
DO $session_wait_snapshot_preconditions$
|
|
454
|
+
BEGIN
|
|
455
|
+
IF EXISTS (
|
|
456
|
+
SELECT 1
|
|
457
|
+
FROM session_wait_scheduled_task_cutover migrated
|
|
458
|
+
JOIN scheduled_tasks task ON task.id = migrated.id
|
|
459
|
+
WHERE migrated.previous_execution_digest IS DISTINCT FROM
|
|
460
|
+
scheduled_task_execution_digest(task)
|
|
461
|
+
) THEN
|
|
462
|
+
RAISE EXCEPTION
|
|
463
|
+
'0402 cannot reproduce a stored scheduled-task execution digest'
|
|
464
|
+
USING ERRCODE = '23514';
|
|
465
|
+
END IF;
|
|
466
|
+
|
|
467
|
+
IF EXISTS (
|
|
468
|
+
SELECT 1
|
|
469
|
+
FROM session_wait_scheduled_task_cutover migrated
|
|
470
|
+
JOIN scheduled_task_revision_authorities authority
|
|
471
|
+
ON authority.task_id = migrated.id
|
|
472
|
+
AND authority.task_authority_revision = migrated.authority_revision
|
|
473
|
+
WHERE authority.execution_digest IS DISTINCT FROM
|
|
474
|
+
migrated.previous_execution_digest
|
|
475
|
+
) OR EXISTS (
|
|
476
|
+
SELECT 1
|
|
477
|
+
FROM session_wait_scheduled_task_cutover migrated
|
|
478
|
+
JOIN scheduled_task_personal_resource_authorities authority
|
|
479
|
+
ON authority.task_id = migrated.id
|
|
480
|
+
AND authority.task_authority_revision = migrated.authority_revision
|
|
481
|
+
WHERE authority.execution_digest IS DISTINCT FROM
|
|
482
|
+
migrated.previous_execution_digest
|
|
483
|
+
) OR EXISTS (
|
|
484
|
+
SELECT 1
|
|
485
|
+
FROM session_wait_scheduled_task_cutover migrated
|
|
486
|
+
JOIN scheduled_task_connection_authority_snapshots snapshot
|
|
487
|
+
ON snapshot.task_id = migrated.id
|
|
488
|
+
AND snapshot.task_authority_revision = migrated.authority_revision
|
|
489
|
+
WHERE snapshot.execution_digest IS DISTINCT FROM
|
|
490
|
+
migrated.previous_execution_digest
|
|
491
|
+
OR snapshot.canonical_snapshot ->> 'executionDigest' IS DISTINCT FROM
|
|
492
|
+
migrated.previous_execution_digest
|
|
493
|
+
OR snapshot.snapshot_digest IS DISTINCT FROM digest(
|
|
494
|
+
convert_to(snapshot.canonical_snapshot::text, 'UTF8'),
|
|
495
|
+
'sha256'
|
|
496
|
+
)
|
|
497
|
+
) THEN
|
|
498
|
+
RAISE EXCEPTION
|
|
499
|
+
'0402 scheduled-task authority digest evidence is inconsistent'
|
|
500
|
+
USING ERRCODE = '23514';
|
|
501
|
+
END IF;
|
|
502
|
+
|
|
503
|
+
IF EXISTS (
|
|
504
|
+
SELECT 1
|
|
505
|
+
FROM session_wait_scheduled_snapshot_cutover migrated
|
|
506
|
+
WHERE migrated.previous_digest IS DISTINCT FROM encode(
|
|
507
|
+
digest(convert_to(migrated.previous_snapshot::text, 'UTF8'), 'sha256'),
|
|
508
|
+
'hex'
|
|
509
|
+
)
|
|
510
|
+
) THEN
|
|
511
|
+
RAISE EXCEPTION
|
|
512
|
+
'0402 cannot reproduce a stored scheduled accepted-execution digest'
|
|
513
|
+
USING ERRCODE = '23514';
|
|
514
|
+
END IF;
|
|
515
|
+
|
|
516
|
+
IF EXISTS (
|
|
517
|
+
SELECT 1
|
|
518
|
+
FROM session_wait_pack_snapshot_cutover migrated
|
|
519
|
+
WHERE migrated.previous_manifest_digest IS DISTINCT FROM encode(
|
|
520
|
+
digest(
|
|
521
|
+
convert_to(
|
|
522
|
+
opengeni_private.session_wait_canonical_json(
|
|
523
|
+
migrated.previous_manifest_snapshot
|
|
524
|
+
),
|
|
525
|
+
'UTF8'
|
|
526
|
+
),
|
|
527
|
+
'sha256'
|
|
528
|
+
),
|
|
529
|
+
'hex'
|
|
530
|
+
)
|
|
531
|
+
) THEN
|
|
532
|
+
RAISE EXCEPTION
|
|
533
|
+
'0402 cannot reproduce a stored runtime Pack manifest digest'
|
|
534
|
+
USING ERRCODE = '23514';
|
|
535
|
+
END IF;
|
|
536
|
+
|
|
537
|
+
IF EXISTS (
|
|
538
|
+
SELECT 1
|
|
539
|
+
FROM capability_operations operation
|
|
540
|
+
JOIN (
|
|
541
|
+
SELECT pack.workspace_id, pack.pack_id
|
|
542
|
+
FROM workspace_packs pack
|
|
543
|
+
WHERE pack.manifest IS DISTINCT FROM
|
|
544
|
+
opengeni_private.session_wait_rewrite_pack(pack.manifest)
|
|
545
|
+
UNION
|
|
546
|
+
SELECT migrated.workspace_id, migrated.pack_id
|
|
547
|
+
FROM session_wait_pack_snapshot_cutover migrated
|
|
548
|
+
) affected
|
|
549
|
+
ON affected.workspace_id = operation.workspace_id
|
|
550
|
+
AND affected.pack_id = operation.target_id
|
|
551
|
+
WHERE operation.target_kind = 'pack'
|
|
552
|
+
AND operation.status IN ('pending', 'running')
|
|
553
|
+
) THEN
|
|
554
|
+
RAISE EXCEPTION
|
|
555
|
+
'0402 requires affected Pack operations to be settled before cutover'
|
|
556
|
+
USING ERRCODE = '55000';
|
|
557
|
+
END IF;
|
|
558
|
+
END
|
|
559
|
+
$session_wait_snapshot_preconditions$;
|
|
560
|
+
|
|
561
|
+
DO $session_input_wait_workspace_fences$
|
|
562
|
+
DECLARE
|
|
563
|
+
workspace_id_value uuid;
|
|
564
|
+
BEGIN
|
|
565
|
+
FOR workspace_id_value IN
|
|
566
|
+
SELECT affected."workspace_id"
|
|
567
|
+
FROM (
|
|
568
|
+
SELECT session."workspace_id"
|
|
569
|
+
FROM "sessions" AS session
|
|
570
|
+
JOIN "session_goals" AS goal
|
|
571
|
+
ON goal."workspace_id" = session."workspace_id"
|
|
572
|
+
AND goal."session_id" = session."id"
|
|
573
|
+
WHERE goal."continuation_hold_turn_id" IS NOT NULL
|
|
574
|
+
UNION
|
|
575
|
+
SELECT session."workspace_id"
|
|
576
|
+
FROM "sessions" AS session
|
|
577
|
+
WHERE session."first_party_mcp_tools" @> '["goal_wait"]'::jsonb
|
|
578
|
+
UNION
|
|
579
|
+
SELECT workspace.id
|
|
580
|
+
FROM workspaces workspace
|
|
581
|
+
WHERE workspace.settings #> '{sessionToolDefaults,firstPartyMcpTools}'
|
|
582
|
+
@> '["goal_wait"]'::jsonb
|
|
583
|
+
UNION
|
|
584
|
+
SELECT draft.workspace_id
|
|
585
|
+
FROM new_session_drafts draft
|
|
586
|
+
WHERE draft.session_options -> 'firstPartyMcpTools'
|
|
587
|
+
@> '["goal_wait"]'::jsonb
|
|
588
|
+
UNION
|
|
589
|
+
SELECT revision.workspace_id
|
|
590
|
+
FROM automation_trigger_revisions revision
|
|
591
|
+
WHERE revision.session_template -> 'firstPartyMcpTools'
|
|
592
|
+
@> '["goal_wait"]'::jsonb
|
|
593
|
+
UNION
|
|
594
|
+
SELECT run.workspace_id
|
|
595
|
+
FROM automation_runs run
|
|
596
|
+
WHERE run.accepted_execution #> '{sessionTemplate,firstPartyMcpTools}'
|
|
597
|
+
@> '["goal_wait"]'::jsonb
|
|
598
|
+
UNION
|
|
599
|
+
SELECT migrated.workspace_id
|
|
600
|
+
FROM session_wait_scheduled_task_cutover migrated
|
|
601
|
+
UNION
|
|
602
|
+
SELECT migrated.workspace_id
|
|
603
|
+
FROM session_wait_scheduled_snapshot_cutover migrated
|
|
604
|
+
UNION
|
|
605
|
+
SELECT pack.workspace_id
|
|
606
|
+
FROM workspace_packs pack
|
|
607
|
+
WHERE pack.manifest IS DISTINCT FROM
|
|
608
|
+
opengeni_private.session_wait_rewrite_pack(pack.manifest)
|
|
609
|
+
UNION
|
|
610
|
+
SELECT migrated.workspace_id
|
|
611
|
+
FROM session_wait_pack_snapshot_cutover migrated
|
|
612
|
+
) AS affected
|
|
613
|
+
ORDER BY affected."workspace_id"
|
|
614
|
+
LOOP
|
|
615
|
+
PERFORM acquire_session_tenancy_fence(workspace_id_value);
|
|
616
|
+
END LOOP;
|
|
617
|
+
END
|
|
618
|
+
$session_input_wait_workspace_fences$;
|
|
619
|
+
|
|
620
|
+
UPDATE "sessions" AS session SET
|
|
621
|
+
"input_wait_turn_id" = goal."continuation_hold_turn_id",
|
|
622
|
+
"input_wait_until" = goal."continuation_hold_until",
|
|
623
|
+
"input_wait_reason" = coalesce(nullif(btrim(goal."continuation_hold_reason"), ''), 'Waiting for external input'),
|
|
624
|
+
"input_wait_set_at" = goal."continuation_hold_set_at"
|
|
625
|
+
FROM "session_goals" AS goal
|
|
626
|
+
WHERE goal."workspace_id" = session."workspace_id"
|
|
627
|
+
AND goal."session_id" = session."id"
|
|
628
|
+
AND goal."continuation_hold_turn_id" IS NOT NULL
|
|
629
|
+
AND goal."continuation_hold_until" IS NOT NULL
|
|
630
|
+
AND goal."continuation_hold_set_at" IS NOT NULL;
|
|
631
|
+
|
|
632
|
+
-- Tool selection is an immutable per-session snapshot. Preserve every
|
|
633
|
+
-- selected tool and its first-seen order while translating the clean-break
|
|
634
|
+
-- rename; collapse the replacement when a snapshot already contains both.
|
|
635
|
+
UPDATE "sessions" AS session
|
|
636
|
+
SET "first_party_mcp_tools" =
|
|
637
|
+
opengeni_private.session_wait_translate_tool_array(
|
|
638
|
+
session."first_party_mcp_tools"
|
|
639
|
+
)
|
|
640
|
+
WHERE session."first_party_mcp_tools" @> '["goal_wait"]'::jsonb;
|
|
641
|
+
|
|
642
|
+
UPDATE workspaces workspace
|
|
643
|
+
SET settings = jsonb_set(
|
|
644
|
+
workspace.settings,
|
|
645
|
+
'{sessionToolDefaults,firstPartyMcpTools}',
|
|
646
|
+
opengeni_private.session_wait_translate_tool_array(
|
|
647
|
+
workspace.settings #> '{sessionToolDefaults,firstPartyMcpTools}'
|
|
648
|
+
),
|
|
649
|
+
false
|
|
650
|
+
)
|
|
651
|
+
WHERE workspace.settings #> '{sessionToolDefaults,firstPartyMcpTools}'
|
|
652
|
+
@> '["goal_wait"]'::jsonb;
|
|
653
|
+
|
|
654
|
+
UPDATE new_session_drafts draft
|
|
655
|
+
SET session_options = jsonb_set(
|
|
656
|
+
draft.session_options,
|
|
657
|
+
'{firstPartyMcpTools}',
|
|
658
|
+
opengeni_private.session_wait_translate_tool_array(
|
|
659
|
+
draft.session_options -> 'firstPartyMcpTools'
|
|
660
|
+
),
|
|
661
|
+
false
|
|
662
|
+
)
|
|
663
|
+
WHERE draft.session_options -> 'firstPartyMcpTools'
|
|
664
|
+
@> '["goal_wait"]'::jsonb;
|
|
665
|
+
|
|
666
|
+
UPDATE automation_trigger_revisions revision
|
|
667
|
+
SET session_template =
|
|
668
|
+
opengeni_private.session_wait_rewrite_automation_template(
|
|
669
|
+
revision.session_template
|
|
670
|
+
)
|
|
671
|
+
WHERE revision.session_template -> 'firstPartyMcpTools'
|
|
672
|
+
@> '["goal_wait"]'::jsonb;
|
|
673
|
+
|
|
674
|
+
UPDATE automation_runs run
|
|
675
|
+
SET accepted_execution = jsonb_set(
|
|
676
|
+
run.accepted_execution,
|
|
677
|
+
'{sessionTemplate}',
|
|
678
|
+
opengeni_private.session_wait_rewrite_automation_template(
|
|
679
|
+
run.accepted_execution -> 'sessionTemplate'
|
|
680
|
+
),
|
|
681
|
+
false
|
|
682
|
+
)
|
|
683
|
+
WHERE run.accepted_execution #> '{sessionTemplate,firstPartyMcpTools}'
|
|
684
|
+
@> '["goal_wait"]'::jsonb;
|
|
685
|
+
|
|
686
|
+
-- The protocol rename is authority-equivalent for an active scheduled-task
|
|
687
|
+
-- head. Preserve its exact revision while the normal digest trigger derives
|
|
688
|
+
-- the new execution digest, then move only the current-revision authority
|
|
689
|
+
-- headers and canonical Connection evidence to that digest. Ordinary runtime
|
|
690
|
+
-- updates still advance revisions through the two triggers disabled here.
|
|
691
|
+
ALTER TABLE scheduled_tasks
|
|
692
|
+
DISABLE TRIGGER scheduled_task_connection_authority_execution_revision;
|
|
693
|
+
ALTER TABLE scheduled_tasks
|
|
694
|
+
DISABLE TRIGGER scheduled_task_personal_resource_execution_revision;
|
|
695
|
+
|
|
696
|
+
UPDATE scheduled_tasks task
|
|
697
|
+
SET agent_config = migrated.agent_config
|
|
698
|
+
FROM session_wait_scheduled_task_cutover migrated
|
|
699
|
+
WHERE task.id = migrated.id;
|
|
700
|
+
|
|
701
|
+
UPDATE scheduled_task_revision_authorities authority
|
|
702
|
+
SET execution_digest = task.execution_digest
|
|
703
|
+
FROM session_wait_scheduled_task_cutover migrated
|
|
704
|
+
JOIN scheduled_tasks task ON task.id = migrated.id
|
|
705
|
+
WHERE authority.task_id = migrated.id
|
|
706
|
+
AND authority.task_authority_revision = migrated.authority_revision;
|
|
707
|
+
|
|
708
|
+
UPDATE scheduled_task_personal_resource_authorities authority
|
|
709
|
+
SET execution_digest = task.execution_digest
|
|
710
|
+
FROM session_wait_scheduled_task_cutover migrated
|
|
711
|
+
JOIN scheduled_tasks task ON task.id = migrated.id
|
|
712
|
+
WHERE authority.task_id = migrated.id
|
|
713
|
+
AND authority.task_authority_revision = migrated.authority_revision;
|
|
714
|
+
|
|
715
|
+
WITH rewritten AS (
|
|
716
|
+
SELECT
|
|
717
|
+
snapshot.task_id,
|
|
718
|
+
snapshot.task_authority_revision,
|
|
719
|
+
snapshot.server_id,
|
|
720
|
+
task.execution_digest,
|
|
721
|
+
jsonb_set(
|
|
722
|
+
snapshot.canonical_snapshot,
|
|
723
|
+
'{executionDigest}',
|
|
724
|
+
to_jsonb(task.execution_digest),
|
|
725
|
+
false
|
|
726
|
+
) AS canonical_snapshot
|
|
727
|
+
FROM scheduled_task_connection_authority_snapshots snapshot
|
|
728
|
+
JOIN session_wait_scheduled_task_cutover migrated
|
|
729
|
+
ON migrated.id = snapshot.task_id
|
|
730
|
+
AND migrated.authority_revision = snapshot.task_authority_revision
|
|
731
|
+
JOIN scheduled_tasks task ON task.id = migrated.id
|
|
732
|
+
)
|
|
733
|
+
UPDATE scheduled_task_connection_authority_snapshots snapshot
|
|
734
|
+
SET execution_digest = rewritten.execution_digest,
|
|
735
|
+
canonical_snapshot = rewritten.canonical_snapshot,
|
|
736
|
+
snapshot_digest = digest(
|
|
737
|
+
convert_to(rewritten.canonical_snapshot::text, 'UTF8'),
|
|
738
|
+
'sha256'
|
|
739
|
+
)
|
|
740
|
+
FROM rewritten
|
|
741
|
+
WHERE snapshot.task_id = rewritten.task_id
|
|
742
|
+
AND snapshot.task_authority_revision = rewritten.task_authority_revision
|
|
743
|
+
AND snapshot.server_id = rewritten.server_id;
|
|
744
|
+
|
|
745
|
+
ALTER TABLE scheduled_tasks
|
|
746
|
+
ENABLE TRIGGER scheduled_task_personal_resource_execution_revision;
|
|
747
|
+
ALTER TABLE scheduled_tasks
|
|
748
|
+
ENABLE TRIGGER scheduled_task_connection_authority_execution_revision;
|
|
749
|
+
|
|
750
|
+
-- Accepted scheduled execution is immutable during runtime. The drained
|
|
751
|
+
-- protocol migration is the one bounded exception: prove the previous digest,
|
|
752
|
+
-- disable only that immutable-update trigger, replace the typed paths, and
|
|
753
|
+
-- recompute the database-native JSONB digest atomically.
|
|
754
|
+
ALTER TABLE scheduled_task_runs
|
|
755
|
+
DISABLE TRIGGER scheduled_task_run_connection_session_identity_immutable;
|
|
756
|
+
|
|
757
|
+
UPDATE scheduled_task_runs run
|
|
758
|
+
SET accepted_execution_snapshot = migrated.accepted_execution_snapshot,
|
|
759
|
+
accepted_execution_digest = encode(
|
|
760
|
+
digest(
|
|
761
|
+
convert_to(migrated.accepted_execution_snapshot::text, 'UTF8'),
|
|
762
|
+
'sha256'
|
|
763
|
+
),
|
|
764
|
+
'hex'
|
|
765
|
+
)
|
|
766
|
+
FROM session_wait_scheduled_snapshot_cutover migrated
|
|
767
|
+
WHERE run.id = migrated.id;
|
|
768
|
+
|
|
769
|
+
ALTER TABLE scheduled_task_runs
|
|
770
|
+
ENABLE TRIGGER scheduled_task_run_connection_session_identity_immutable;
|
|
771
|
+
|
|
772
|
+
UPDATE workspace_packs pack
|
|
773
|
+
SET manifest = opengeni_private.session_wait_rewrite_pack(pack.manifest)
|
|
774
|
+
WHERE pack.manifest IS DISTINCT FROM
|
|
775
|
+
opengeni_private.session_wait_rewrite_pack(pack.manifest);
|
|
776
|
+
|
|
777
|
+
UPDATE pack_installations installation
|
|
778
|
+
SET manifest_snapshot = migrated.manifest_snapshot,
|
|
779
|
+
manifest_digest = migrated.manifest_digest
|
|
780
|
+
FROM session_wait_pack_snapshot_cutover migrated
|
|
781
|
+
WHERE installation.id = migrated.id;
|
|
782
|
+
|
|
783
|
+
DO $session_wait_selection_postcondition$
|
|
784
|
+
BEGIN
|
|
785
|
+
IF EXISTS (
|
|
786
|
+
SELECT 1 FROM sessions session
|
|
787
|
+
WHERE session.first_party_mcp_tools @> '["goal_wait"]'::jsonb
|
|
788
|
+
) OR EXISTS (
|
|
789
|
+
SELECT 1 FROM workspaces workspace
|
|
790
|
+
WHERE workspace.settings #> '{sessionToolDefaults,firstPartyMcpTools}'
|
|
791
|
+
@> '["goal_wait"]'::jsonb
|
|
792
|
+
) OR EXISTS (
|
|
793
|
+
SELECT 1 FROM new_session_drafts draft
|
|
794
|
+
WHERE draft.session_options -> 'firstPartyMcpTools'
|
|
795
|
+
@> '["goal_wait"]'::jsonb
|
|
796
|
+
) OR EXISTS (
|
|
797
|
+
SELECT 1 FROM automation_trigger_revisions revision
|
|
798
|
+
WHERE revision.session_template -> 'firstPartyMcpTools'
|
|
799
|
+
@> '["goal_wait"]'::jsonb
|
|
800
|
+
) OR EXISTS (
|
|
801
|
+
SELECT 1 FROM automation_runs run
|
|
802
|
+
WHERE run.accepted_execution #> '{sessionTemplate,firstPartyMcpTools}'
|
|
803
|
+
@> '["goal_wait"]'::jsonb
|
|
804
|
+
) OR EXISTS (
|
|
805
|
+
SELECT 1 FROM scheduled_tasks task
|
|
806
|
+
WHERE task.agent_config IS DISTINCT FROM
|
|
807
|
+
opengeni_private.session_wait_rewrite_scheduled_agent_config(
|
|
808
|
+
task.agent_config
|
|
809
|
+
)
|
|
810
|
+
) OR EXISTS (
|
|
811
|
+
SELECT 1 FROM scheduled_task_runs run
|
|
812
|
+
WHERE run.accepted_execution_snapshot -> 'resolvedFirstPartyMcpTools'
|
|
813
|
+
@> '["goal_wait"]'::jsonb
|
|
814
|
+
OR run.accepted_execution_snapshot
|
|
815
|
+
#> '{targetSessionExecution,firstPartyMcpTools}'
|
|
816
|
+
@> '["goal_wait"]'::jsonb
|
|
817
|
+
) OR EXISTS (
|
|
818
|
+
SELECT 1 FROM workspace_packs pack
|
|
819
|
+
WHERE pack.manifest IS DISTINCT FROM
|
|
820
|
+
opengeni_private.session_wait_rewrite_pack(pack.manifest)
|
|
821
|
+
) OR EXISTS (
|
|
822
|
+
SELECT 1 FROM pack_installations installation
|
|
823
|
+
WHERE installation.manifest_snapshot IS NOT NULL
|
|
824
|
+
AND installation.manifest_snapshot IS DISTINCT FROM
|
|
825
|
+
opengeni_private.session_wait_rewrite_pack(
|
|
826
|
+
installation.manifest_snapshot
|
|
827
|
+
)
|
|
828
|
+
) THEN
|
|
829
|
+
RAISE EXCEPTION '0402 persisted first-party tool migration did not converge'
|
|
830
|
+
USING ERRCODE = '23514';
|
|
831
|
+
END IF;
|
|
832
|
+
|
|
833
|
+
IF EXISTS (
|
|
834
|
+
SELECT 1
|
|
835
|
+
FROM session_wait_scheduled_task_cutover migrated
|
|
836
|
+
JOIN scheduled_tasks task ON task.id = migrated.id
|
|
837
|
+
WHERE task.agent_config IS DISTINCT FROM migrated.agent_config
|
|
838
|
+
OR task.authority_revision IS DISTINCT FROM migrated.authority_revision
|
|
839
|
+
OR task.execution_digest IS DISTINCT FROM scheduled_task_execution_digest(task)
|
|
840
|
+
) OR EXISTS (
|
|
841
|
+
SELECT 1
|
|
842
|
+
FROM session_wait_scheduled_task_cutover migrated
|
|
843
|
+
JOIN scheduled_tasks task ON task.id = migrated.id
|
|
844
|
+
JOIN scheduled_task_revision_authorities authority
|
|
845
|
+
ON authority.task_id = migrated.id
|
|
846
|
+
AND authority.task_authority_revision = migrated.authority_revision
|
|
847
|
+
WHERE authority.execution_digest IS DISTINCT FROM task.execution_digest
|
|
848
|
+
) OR EXISTS (
|
|
849
|
+
SELECT 1
|
|
850
|
+
FROM session_wait_scheduled_task_cutover migrated
|
|
851
|
+
JOIN scheduled_tasks task ON task.id = migrated.id
|
|
852
|
+
JOIN scheduled_task_personal_resource_authorities authority
|
|
853
|
+
ON authority.task_id = migrated.id
|
|
854
|
+
AND authority.task_authority_revision = migrated.authority_revision
|
|
855
|
+
WHERE authority.execution_digest IS DISTINCT FROM task.execution_digest
|
|
856
|
+
) OR EXISTS (
|
|
857
|
+
SELECT 1
|
|
858
|
+
FROM session_wait_scheduled_task_cutover migrated
|
|
859
|
+
JOIN scheduled_tasks task ON task.id = migrated.id
|
|
860
|
+
JOIN scheduled_task_connection_authority_snapshots snapshot
|
|
861
|
+
ON snapshot.task_id = migrated.id
|
|
862
|
+
AND snapshot.task_authority_revision = migrated.authority_revision
|
|
863
|
+
WHERE snapshot.execution_digest IS DISTINCT FROM task.execution_digest
|
|
864
|
+
OR snapshot.canonical_snapshot ->> 'executionDigest' IS DISTINCT FROM
|
|
865
|
+
task.execution_digest
|
|
866
|
+
OR snapshot.snapshot_digest IS DISTINCT FROM digest(
|
|
867
|
+
convert_to(snapshot.canonical_snapshot::text, 'UTF8'),
|
|
868
|
+
'sha256'
|
|
869
|
+
)
|
|
870
|
+
) THEN
|
|
871
|
+
RAISE EXCEPTION '0402 scheduled-task head migration did not converge'
|
|
872
|
+
USING ERRCODE = '23514';
|
|
873
|
+
END IF;
|
|
874
|
+
|
|
875
|
+
IF EXISTS (
|
|
876
|
+
SELECT 1
|
|
877
|
+
FROM session_wait_scheduled_snapshot_cutover migrated
|
|
878
|
+
JOIN scheduled_task_runs run ON run.id = migrated.id
|
|
879
|
+
WHERE run.accepted_execution_snapshot IS DISTINCT FROM
|
|
880
|
+
migrated.accepted_execution_snapshot
|
|
881
|
+
OR run.accepted_execution_digest IS DISTINCT FROM encode(
|
|
882
|
+
digest(
|
|
883
|
+
convert_to(migrated.accepted_execution_snapshot::text, 'UTF8'),
|
|
884
|
+
'sha256'
|
|
885
|
+
),
|
|
886
|
+
'hex'
|
|
887
|
+
)
|
|
888
|
+
) THEN
|
|
889
|
+
RAISE EXCEPTION '0402 scheduled accepted-execution migration did not converge'
|
|
890
|
+
USING ERRCODE = '23514';
|
|
891
|
+
END IF;
|
|
892
|
+
|
|
893
|
+
IF EXISTS (
|
|
894
|
+
SELECT 1
|
|
895
|
+
FROM session_wait_pack_snapshot_cutover migrated
|
|
896
|
+
JOIN pack_installations installation ON installation.id = migrated.id
|
|
897
|
+
WHERE installation.manifest_snapshot IS DISTINCT FROM migrated.manifest_snapshot
|
|
898
|
+
OR installation.manifest_digest IS DISTINCT FROM migrated.manifest_digest
|
|
899
|
+
) THEN
|
|
900
|
+
RAISE EXCEPTION '0402 Pack manifest migration did not converge'
|
|
901
|
+
USING ERRCODE = '23514';
|
|
902
|
+
END IF;
|
|
903
|
+
END
|
|
904
|
+
$session_wait_selection_postcondition$;
|
|
905
|
+
|
|
906
|
+
-- The snapshot rewrite queues ordinary deferred row constraints. Prove them
|
|
907
|
+
-- before ALTER TABLE restores the production RLS posture.
|
|
908
|
+
SET CONSTRAINTS ALL IMMEDIATE;
|
|
909
|
+
|
|
910
|
+
ALTER TABLE "capability_operations" FORCE ROW LEVEL SECURITY;
|
|
911
|
+
ALTER TABLE "pack_installations" FORCE ROW LEVEL SECURITY;
|
|
912
|
+
ALTER TABLE "workspace_packs" FORCE ROW LEVEL SECURITY;
|
|
913
|
+
ALTER TABLE "scheduled_task_runs" FORCE ROW LEVEL SECURITY;
|
|
914
|
+
ALTER TABLE "scheduled_task_connection_authority_snapshots" FORCE ROW LEVEL SECURITY;
|
|
915
|
+
ALTER TABLE "scheduled_task_personal_resource_authorities" FORCE ROW LEVEL SECURITY;
|
|
916
|
+
ALTER TABLE "scheduled_task_revision_authorities" FORCE ROW LEVEL SECURITY;
|
|
917
|
+
ALTER TABLE "scheduled_tasks" FORCE ROW LEVEL SECURITY;
|
|
918
|
+
ALTER TABLE "automation_runs" FORCE ROW LEVEL SECURITY;
|
|
919
|
+
ALTER TABLE "automation_trigger_revisions" FORCE ROW LEVEL SECURITY;
|
|
920
|
+
ALTER TABLE "new_session_drafts" FORCE ROW LEVEL SECURITY;
|
|
921
|
+
ALTER TABLE "session_goals" FORCE ROW LEVEL SECURITY;
|
|
922
|
+
ALTER TABLE "sessions" FORCE ROW LEVEL SECURITY;
|
|
923
|
+
|
|
924
|
+
ALTER TABLE "sessions"
|
|
925
|
+
ADD CONSTRAINT "sessions_input_wait_check" CHECK (
|
|
926
|
+
(
|
|
927
|
+
"input_wait_turn_id" IS NULL
|
|
928
|
+
AND "input_wait_until" IS NULL
|
|
929
|
+
AND "input_wait_reason" IS NULL
|
|
930
|
+
AND "input_wait_set_at" IS NULL
|
|
931
|
+
)
|
|
932
|
+
OR (
|
|
933
|
+
"input_wait_turn_id" IS NOT NULL
|
|
934
|
+
AND "input_wait_until" IS NOT NULL
|
|
935
|
+
AND "input_wait_reason" IS NOT NULL
|
|
936
|
+
AND octet_length(btrim("input_wait_reason")) BETWEEN 1 AND 2048
|
|
937
|
+
AND "input_wait_set_at" IS NOT NULL
|
|
938
|
+
)
|
|
939
|
+
);
|
|
940
|
+
|
|
941
|
+
COMMENT ON COLUMN "sessions"."input_wait_turn_id" IS
|
|
942
|
+
'Exact turn that declared wait_for_input; current only while it remains the latest finished turn.';
|
|
943
|
+
COMMENT ON COLUMN "sessions"."input_wait_until" IS
|
|
944
|
+
'Absolute timeout safety-wake deadline persisted from wait_for_input timeoutSeconds.';
|
|
945
|
+
COMMENT ON COLUMN "sessions"."input_wait_reason" IS
|
|
946
|
+
'Bounded agent-declared reason for the session-level wait.';
|
|
947
|
+
COMMENT ON COLUMN "sessions"."input_wait_set_at" IS
|
|
948
|
+
'Database time when the current wait_for_input obligation was recorded.';
|
|
949
|
+
|
|
950
|
+
ALTER TABLE "session_goals"
|
|
951
|
+
DROP CONSTRAINT "session_goals_continuation_hold_check",
|
|
952
|
+
DROP COLUMN "continuation_hold_turn_id",
|
|
953
|
+
DROP COLUMN "continuation_hold_until",
|
|
954
|
+
DROP COLUMN "continuation_hold_reason",
|
|
955
|
+
DROP COLUMN "continuation_hold_set_at";
|
|
956
|
+
|
|
957
|
+
-- A wait operation belongs to the target session and logical turn, not to one
|
|
958
|
+
-- replaceable physical attempt. The receipt still retains the first attempt FK
|
|
959
|
+
-- for audit, while this partial identity makes a recovered attempt replay the
|
|
960
|
+
-- original deadline/result instead of stamping a second wait.
|
|
961
|
+
CREATE UNIQUE INDEX "session_command_receipts_wait_for_input_operation_uq"
|
|
962
|
+
ON "session_command_receipts" (
|
|
963
|
+
"workspace_id", "action", "target_session_id", "operation_key"
|
|
964
|
+
)
|
|
965
|
+
WHERE "action" = 'session.wait_for_input';
|
|
966
|
+
|
|
967
|
+
-- Terminal command settlement and wait timeouts are model-visible machine
|
|
968
|
+
-- inputs. Their discriminated payloads remain constrained exactly like every
|
|
969
|
+
-- other durable session system update.
|
|
970
|
+
ALTER TABLE "session_system_updates"
|
|
971
|
+
DROP CONSTRAINT "system_updates_kind_check";
|
|
972
|
+
|
|
973
|
+
ALTER TABLE "session_system_updates"
|
|
974
|
+
ADD CONSTRAINT "system_updates_kind_check" CHECK (
|
|
975
|
+
"kind" IN (
|
|
976
|
+
'scheduled_occurrence',
|
|
977
|
+
'goal_continuation',
|
|
978
|
+
'agent_message',
|
|
979
|
+
'agent_steer_instruction',
|
|
980
|
+
'session_wait_timeout',
|
|
981
|
+
'background_command_result',
|
|
982
|
+
'child_terminal_result',
|
|
983
|
+
'media_generation_result',
|
|
984
|
+
'child_requires_action',
|
|
985
|
+
'child_requires_action_resolved',
|
|
986
|
+
'child_paused',
|
|
987
|
+
'child_waiting_capacity',
|
|
988
|
+
'child_progress'
|
|
989
|
+
)
|
|
990
|
+
);
|
|
991
|
+
|
|
992
|
+
DO $session_input_wait_runtime_drain_after$
|
|
993
|
+
DECLARE
|
|
994
|
+
configured_roles jsonb := current_setting(
|
|
995
|
+
'opengeni.migration_application_roles',
|
|
996
|
+
true
|
|
997
|
+
)::jsonb;
|
|
998
|
+
BEGIN
|
|
999
|
+
IF EXISTS (
|
|
1000
|
+
SELECT 1 FROM pg_stat_activity activity
|
|
1001
|
+
JOIN jsonb_array_elements_text(configured_roles) roles(role_name)
|
|
1002
|
+
ON roles.role_name = activity.usename
|
|
1003
|
+
WHERE activity.datname = current_database()
|
|
1004
|
+
AND activity.pid <> pg_backend_pid()
|
|
1005
|
+
)
|
|
1006
|
+
THEN
|
|
1007
|
+
RAISE EXCEPTION
|
|
1008
|
+
'0402 session input wait activation detected an application database session during cutover'
|
|
1009
|
+
USING ERRCODE = '55000';
|
|
1010
|
+
END IF;
|
|
1011
|
+
END
|
|
1012
|
+
$session_input_wait_runtime_drain_after$;
|
|
1013
|
+
|
|
1014
|
+
DROP FUNCTION opengeni_private.session_wait_rewrite_scheduled_execution(jsonb);
|
|
1015
|
+
DROP FUNCTION opengeni_private.session_wait_rewrite_scheduled_agent_config(jsonb);
|
|
1016
|
+
DROP FUNCTION opengeni_private.session_wait_rewrite_pack(jsonb);
|
|
1017
|
+
DROP FUNCTION opengeni_private.session_wait_rewrite_automation_template(jsonb);
|
|
1018
|
+
DROP FUNCTION opengeni_private.session_wait_translate_tool_array(jsonb);
|
|
1019
|
+
DROP FUNCTION opengeni_private.session_wait_canonical_json(jsonb);
|
|
1020
|
+
DROP COLLATION opengeni_private.session_wait_js_en_us;
|
|
1021
|
+
|
|
1022
|
+
RESET statement_timeout;
|
|
1023
|
+
RESET lock_timeout;
|