@opengeni/db 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/dist/chunk-57MLICFR.js +121 -0
  2. package/dist/chunk-57MLICFR.js.map +1 -0
  3. package/dist/chunk-OGCE6O2X.js +52 -0
  4. package/dist/chunk-OGCE6O2X.js.map +1 -0
  5. package/dist/chunk-PSX56ZTL.js +1093 -0
  6. package/dist/chunk-PSX56ZTL.js.map +1 -0
  7. package/dist/chunk-PZ5AY32C.js +10 -0
  8. package/dist/chunk-PZ5AY32C.js.map +1 -0
  9. package/dist/index.d.ts +8 -0
  10. package/dist/index.js +5165 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/migrate.d.ts +40 -0
  13. package/dist/migrate.js +10 -0
  14. package/dist/migrate.js.map +1 -0
  15. package/dist/provision-roles.d.ts +2063 -0
  16. package/dist/provision-roles.js +8 -0
  17. package/dist/provision-roles.js.map +1 -0
  18. package/dist/schema-CaeZQAJQ.d.ts +9705 -0
  19. package/dist/schema.d.ts +3 -0
  20. package/dist/schema.js +110 -0
  21. package/dist/schema.js.map +1 -0
  22. package/drizzle/0000_initial.sql +179 -0
  23. package/drizzle/0001_workspace_auth_billing.sql +590 -0
  24. package/drizzle/0002_packs_and_social.sql +99 -0
  25. package/drizzle/0003_capability_catalog.sql +73 -0
  26. package/drizzle/0004_workspace_environments.sql +65 -0
  27. package/drizzle/0005_session_goals.sql +45 -0
  28. package/drizzle/0006_workspace_packs.sql +31 -0
  29. package/drizzle/0007_session_history_items.sql +66 -0
  30. package/drizzle/0008_session_first_party_mcp_permissions.sql +5 -0
  31. package/drizzle/0009_goal_sessions_first_party_goals_manage.sql +34 -0
  32. package/drizzle/0010_session_parent_linkage.sql +30 -0
  33. package/drizzle/0011_context_compaction.sql +33 -0
  34. package/drizzle/0012_compaction_summary_fractional_position.sql +19 -0
  35. package/drizzle/0013_session_compact_requested.sql +16 -0
  36. package/drizzle/0014_repair_orphaned_function_call_results.sql +125 -0
  37. package/drizzle/0015_workspace_agent_instructions.sql +17 -0
  38. package/drizzle/0016_session_create_idempotency.sql +27 -0
  39. package/drizzle/0017_sandbox_leases.sql +313 -0
  40. package/drizzle/0018_sandbox_os.sql +89 -0
  41. package/drizzle/0019_session_stream_acknowledgments.sql +94 -0
  42. package/drizzle/0020_session_recordings.sql +88 -0
  43. package/drizzle/0021_sandbox_pty_sessions.sql +70 -0
  44. package/drizzle/0022_sandbox_lease_terminal_url.sql +32 -0
  45. package/drizzle/0023_session_title.sql +19 -0
  46. package/drizzle/0024_codex_subscription_credentials.sql +51 -0
  47. package/drizzle/0024_sandboxes_enrollments_metrics.sql +262 -0
  48. package/drizzle/0025_device_enrollment_requests.sql +142 -0
  49. package/drizzle/0026_device_enrollment_user_code_resolver.sql +47 -0
  50. package/drizzle/0027_session_working_dir.sql +24 -0
  51. package/drizzle/0028_codex_multi_account.sql +85 -0
  52. package/drizzle/0029_session_history_item_producer.sql +31 -0
  53. package/drizzle/0030_agent_run_state_frozen_codex.sql +35 -0
  54. package/drizzle/0031_codex_usage_cache.sql +21 -0
  55. package/drizzle/0032_codex_account_cooldown.sql +18 -0
  56. package/drizzle/0033_codex_connector_cache.sql +20 -0
  57. package/drizzle/0034_sandbox_lease_image.sql +21 -0
  58. package/drizzle/meta/_journal.json +167 -0
  59. package/package.json +66 -0
  60. package/src/codex-token-resolver.ts +247 -0
  61. package/src/environment-crypto.ts +51 -0
  62. package/src/event-payload-sanitizer.ts +89 -0
  63. package/src/index.ts +7776 -0
  64. package/src/migrate.ts +95 -0
  65. package/src/provision-roles.ts +198 -0
  66. package/src/schema.ts +1110 -0
@@ -0,0 +1,99 @@
1
+ CREATE TABLE IF NOT EXISTS "pack_installations" (
2
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
3
+ "account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
4
+ "workspace_id" uuid NOT NULL REFERENCES "workspaces"("id") ON DELETE CASCADE,
5
+ "pack_id" text NOT NULL,
6
+ "status" text NOT NULL DEFAULT 'active',
7
+ "metadata" jsonb NOT NULL DEFAULT '{}'::jsonb,
8
+ "enabled_at" timestamptz NOT NULL DEFAULT now(),
9
+ "updated_at" timestamptz NOT NULL DEFAULT now()
10
+ );
11
+ CREATE UNIQUE INDEX IF NOT EXISTS "pack_installations_workspace_pack_idx" ON "pack_installations" ("workspace_id", "pack_id");
12
+ CREATE INDEX IF NOT EXISTS "pack_installations_workspace_status_idx" ON "pack_installations" ("workspace_id", "status");
13
+ ALTER TABLE "pack_installations" ENABLE ROW LEVEL SECURITY;
14
+ ALTER TABLE "pack_installations" FORCE ROW LEVEL SECURITY;
15
+ DO $$
16
+ BEGIN
17
+ IF EXISTS (
18
+ SELECT 1 FROM pg_policies
19
+ WHERE schemaname = current_schema() AND tablename = 'pack_installations' AND policyname = 'workspace_isolation'
20
+ ) THEN
21
+ DROP POLICY workspace_isolation ON "pack_installations";
22
+ END IF;
23
+ END $$;
24
+ CREATE POLICY workspace_isolation ON "pack_installations"
25
+ USING (opengeni_private.workspace_rls_visible(account_id, workspace_id))
26
+ WITH CHECK (opengeni_private.workspace_rls_visible(account_id, workspace_id));
27
+
28
+ CREATE TABLE IF NOT EXISTS "social_connections" (
29
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
30
+ "account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
31
+ "workspace_id" uuid NOT NULL REFERENCES "workspaces"("id") ON DELETE CASCADE,
32
+ "provider" text NOT NULL,
33
+ "account_handle" text NOT NULL,
34
+ "account_name" text,
35
+ "external_account_id" text,
36
+ "status" text NOT NULL DEFAULT 'connected',
37
+ "scopes" jsonb NOT NULL DEFAULT '[]'::jsonb,
38
+ "credential_ref" text,
39
+ "token_metadata" jsonb NOT NULL DEFAULT '{}'::jsonb,
40
+ "metadata" jsonb NOT NULL DEFAULT '{}'::jsonb,
41
+ "created_at" timestamptz NOT NULL DEFAULT now(),
42
+ "updated_at" timestamptz NOT NULL DEFAULT now()
43
+ );
44
+ CREATE UNIQUE INDEX IF NOT EXISTS "social_connections_workspace_provider_handle_idx" ON "social_connections" ("workspace_id", "provider", "account_handle");
45
+ CREATE INDEX IF NOT EXISTS "social_connections_workspace_provider_status_idx" ON "social_connections" ("workspace_id", "provider", "status");
46
+ ALTER TABLE "social_connections" ENABLE ROW LEVEL SECURITY;
47
+ ALTER TABLE "social_connections" FORCE ROW LEVEL SECURITY;
48
+ DO $$
49
+ BEGIN
50
+ IF EXISTS (
51
+ SELECT 1 FROM pg_policies
52
+ WHERE schemaname = current_schema() AND tablename = 'social_connections' AND policyname = 'workspace_isolation'
53
+ ) THEN
54
+ DROP POLICY workspace_isolation ON "social_connections";
55
+ END IF;
56
+ END $$;
57
+ CREATE POLICY workspace_isolation ON "social_connections"
58
+ USING (opengeni_private.workspace_rls_visible(account_id, workspace_id))
59
+ WITH CHECK (opengeni_private.workspace_rls_visible(account_id, workspace_id));
60
+
61
+ CREATE TABLE IF NOT EXISTS "social_posts" (
62
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
63
+ "account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
64
+ "workspace_id" uuid NOT NULL REFERENCES "workspaces"("id") ON DELETE CASCADE,
65
+ "connection_id" uuid NOT NULL REFERENCES "social_connections"("id") ON DELETE CASCADE,
66
+ "provider" text NOT NULL,
67
+ "external_post_id" text,
68
+ "url" text,
69
+ "author_handle" text,
70
+ "text" text NOT NULL,
71
+ "published_at" timestamptz NOT NULL,
72
+ "metrics" jsonb NOT NULL DEFAULT '{}'::jsonb,
73
+ "raw" jsonb NOT NULL DEFAULT '{}'::jsonb,
74
+ "created_at" timestamptz NOT NULL DEFAULT now()
75
+ );
76
+ CREATE UNIQUE INDEX IF NOT EXISTS "social_posts_workspace_connection_external_post_idx" ON "social_posts" ("workspace_id", "connection_id", "external_post_id");
77
+ CREATE INDEX IF NOT EXISTS "social_posts_workspace_connection_published_idx" ON "social_posts" ("workspace_id", "connection_id", "published_at");
78
+ CREATE INDEX IF NOT EXISTS "social_posts_workspace_provider_published_idx" ON "social_posts" ("workspace_id", "provider", "published_at");
79
+ ALTER TABLE "social_posts" ENABLE ROW LEVEL SECURITY;
80
+ ALTER TABLE "social_posts" FORCE ROW LEVEL SECURITY;
81
+ DO $$
82
+ BEGIN
83
+ IF EXISTS (
84
+ SELECT 1 FROM pg_policies
85
+ WHERE schemaname = current_schema() AND tablename = 'social_posts' AND policyname = 'workspace_isolation'
86
+ ) THEN
87
+ DROP POLICY workspace_isolation ON "social_posts";
88
+ END IF;
89
+ END $$;
90
+ CREATE POLICY workspace_isolation ON "social_posts"
91
+ USING (opengeni_private.workspace_rls_visible(account_id, workspace_id))
92
+ WITH CHECK (opengeni_private.workspace_rls_visible(account_id, workspace_id));
93
+
94
+ DO $$
95
+ BEGIN
96
+ IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
97
+ GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO opengeni_app;
98
+ END IF;
99
+ END $$;
@@ -0,0 +1,73 @@
1
+ CREATE TABLE IF NOT EXISTS "capability_catalog_items" (
2
+ "id" text NOT NULL,
3
+ "account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
4
+ "workspace_id" uuid NOT NULL REFERENCES "workspaces"("id") ON DELETE CASCADE,
5
+ "kind" text NOT NULL,
6
+ "source" text NOT NULL DEFAULT 'manual',
7
+ "name" text NOT NULL,
8
+ "description" text,
9
+ "category" text NOT NULL DEFAULT 'custom',
10
+ "tags" jsonb NOT NULL DEFAULT '[]'::jsonb,
11
+ "homepage_url" text,
12
+ "endpoint_url" text,
13
+ "install_url" text,
14
+ "auth_model" text,
15
+ "metadata" jsonb NOT NULL DEFAULT '{}'::jsonb,
16
+ "created_at" timestamptz NOT NULL DEFAULT now(),
17
+ "updated_at" timestamptz NOT NULL DEFAULT now()
18
+ );
19
+ CREATE UNIQUE INDEX IF NOT EXISTS "capability_catalog_items_workspace_capability_idx" ON "capability_catalog_items" ("workspace_id", "id");
20
+ CREATE INDEX IF NOT EXISTS "capability_catalog_items_workspace_kind_idx" ON "capability_catalog_items" ("workspace_id", "kind");
21
+ CREATE INDEX IF NOT EXISTS "capability_catalog_items_workspace_category_idx" ON "capability_catalog_items" ("workspace_id", "category");
22
+ CREATE INDEX IF NOT EXISTS "capability_catalog_items_workspace_source_idx" ON "capability_catalog_items" ("workspace_id", "source");
23
+ ALTER TABLE "capability_catalog_items" ENABLE ROW LEVEL SECURITY;
24
+ ALTER TABLE "capability_catalog_items" FORCE ROW LEVEL SECURITY;
25
+ DO $$
26
+ BEGIN
27
+ IF EXISTS (
28
+ SELECT 1 FROM pg_policies
29
+ WHERE schemaname = current_schema() AND tablename = 'capability_catalog_items' AND policyname = 'workspace_isolation'
30
+ ) THEN
31
+ DROP POLICY workspace_isolation ON "capability_catalog_items";
32
+ END IF;
33
+ END $$;
34
+ CREATE POLICY workspace_isolation ON "capability_catalog_items"
35
+ USING (opengeni_private.workspace_rls_visible(account_id, workspace_id))
36
+ WITH CHECK (opengeni_private.workspace_rls_visible(account_id, workspace_id));
37
+
38
+ CREATE TABLE IF NOT EXISTS "capability_installations" (
39
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
40
+ "account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
41
+ "workspace_id" uuid NOT NULL REFERENCES "workspaces"("id") ON DELETE CASCADE,
42
+ "capability_id" text NOT NULL,
43
+ "kind" text NOT NULL,
44
+ "status" text NOT NULL DEFAULT 'active',
45
+ "config" jsonb NOT NULL DEFAULT '{}'::jsonb,
46
+ "metadata" jsonb NOT NULL DEFAULT '{}'::jsonb,
47
+ "enabled_at" timestamptz NOT NULL DEFAULT now(),
48
+ "updated_at" timestamptz NOT NULL DEFAULT now()
49
+ );
50
+ CREATE UNIQUE INDEX IF NOT EXISTS "capability_installations_workspace_capability_idx" ON "capability_installations" ("workspace_id", "capability_id");
51
+ CREATE INDEX IF NOT EXISTS "capability_installations_workspace_kind_idx" ON "capability_installations" ("workspace_id", "kind");
52
+ CREATE INDEX IF NOT EXISTS "capability_installations_workspace_status_idx" ON "capability_installations" ("workspace_id", "status");
53
+ ALTER TABLE "capability_installations" ENABLE ROW LEVEL SECURITY;
54
+ ALTER TABLE "capability_installations" FORCE ROW LEVEL SECURITY;
55
+ DO $$
56
+ BEGIN
57
+ IF EXISTS (
58
+ SELECT 1 FROM pg_policies
59
+ WHERE schemaname = current_schema() AND tablename = 'capability_installations' AND policyname = 'workspace_isolation'
60
+ ) THEN
61
+ DROP POLICY workspace_isolation ON "capability_installations";
62
+ END IF;
63
+ END $$;
64
+ CREATE POLICY workspace_isolation ON "capability_installations"
65
+ USING (opengeni_private.workspace_rls_visible(account_id, workspace_id))
66
+ WITH CHECK (opengeni_private.workspace_rls_visible(account_id, workspace_id));
67
+
68
+ DO $$
69
+ BEGIN
70
+ IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
71
+ GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO opengeni_app;
72
+ END IF;
73
+ END $$;
@@ -0,0 +1,65 @@
1
+ CREATE TABLE IF NOT EXISTS "workspace_environments" (
2
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
3
+ "account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
4
+ "workspace_id" uuid NOT NULL REFERENCES "workspaces"("id") ON DELETE CASCADE,
5
+ "name" text NOT NULL,
6
+ "description" text,
7
+ "created_at" timestamptz NOT NULL DEFAULT now(),
8
+ "updated_at" timestamptz NOT NULL DEFAULT now()
9
+ );
10
+ CREATE UNIQUE INDEX IF NOT EXISTS "workspace_environments_workspace_name_idx" ON "workspace_environments" ("workspace_id", "name");
11
+ CREATE INDEX IF NOT EXISTS "workspace_environments_workspace_created_idx" ON "workspace_environments" ("workspace_id", "created_at");
12
+ ALTER TABLE "workspace_environments" ENABLE ROW LEVEL SECURITY;
13
+ ALTER TABLE "workspace_environments" FORCE ROW LEVEL SECURITY;
14
+ DO $$
15
+ BEGIN
16
+ IF EXISTS (
17
+ SELECT 1 FROM pg_policies
18
+ WHERE schemaname = current_schema() AND tablename = 'workspace_environments' AND policyname = 'workspace_isolation'
19
+ ) THEN
20
+ DROP POLICY workspace_isolation ON "workspace_environments";
21
+ END IF;
22
+ END $$;
23
+ CREATE POLICY workspace_isolation ON "workspace_environments"
24
+ USING (opengeni_private.workspace_rls_visible(account_id, workspace_id))
25
+ WITH CHECK (opengeni_private.workspace_rls_visible(account_id, workspace_id));
26
+
27
+ CREATE TABLE IF NOT EXISTS "workspace_environment_variables" (
28
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
29
+ "account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
30
+ "workspace_id" uuid NOT NULL REFERENCES "workspaces"("id") ON DELETE CASCADE,
31
+ "environment_id" uuid NOT NULL REFERENCES "workspace_environments"("id") ON DELETE CASCADE,
32
+ "name" text NOT NULL,
33
+ "value_encrypted" text NOT NULL,
34
+ "version" integer NOT NULL DEFAULT 1,
35
+ "created_at" timestamptz NOT NULL DEFAULT now(),
36
+ "updated_at" timestamptz NOT NULL DEFAULT now()
37
+ );
38
+ CREATE UNIQUE INDEX IF NOT EXISTS "workspace_environment_variables_env_name_idx" ON "workspace_environment_variables" ("workspace_id", "environment_id", "name");
39
+ CREATE INDEX IF NOT EXISTS "workspace_environment_variables_workspace_env_idx" ON "workspace_environment_variables" ("workspace_id", "environment_id");
40
+ ALTER TABLE "workspace_environment_variables" ENABLE ROW LEVEL SECURITY;
41
+ ALTER TABLE "workspace_environment_variables" FORCE ROW LEVEL SECURITY;
42
+ DO $$
43
+ BEGIN
44
+ IF EXISTS (
45
+ SELECT 1 FROM pg_policies
46
+ WHERE schemaname = current_schema() AND tablename = 'workspace_environment_variables' AND policyname = 'workspace_isolation'
47
+ ) THEN
48
+ DROP POLICY workspace_isolation ON "workspace_environment_variables";
49
+ END IF;
50
+ END $$;
51
+ CREATE POLICY workspace_isolation ON "workspace_environment_variables"
52
+ USING (opengeni_private.workspace_rls_visible(account_id, workspace_id))
53
+ WITH CHECK (opengeni_private.workspace_rls_visible(account_id, workspace_id));
54
+
55
+ ALTER TABLE "sessions" ADD COLUMN IF NOT EXISTS "environment_id" uuid REFERENCES "workspace_environments"("id") ON DELETE SET NULL;
56
+ ALTER TABLE "scheduled_tasks" ADD COLUMN IF NOT EXISTS "environment_id" uuid REFERENCES "workspace_environments"("id") ON DELETE RESTRICT;
57
+ CREATE INDEX IF NOT EXISTS "sessions_environment_idx" ON "sessions" ("workspace_id", "environment_id");
58
+ CREATE INDEX IF NOT EXISTS "scheduled_tasks_environment_idx" ON "scheduled_tasks" ("workspace_id", "environment_id");
59
+
60
+ DO $$
61
+ BEGIN
62
+ IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
63
+ GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO opengeni_app;
64
+ END IF;
65
+ END $$;
@@ -0,0 +1,45 @@
1
+ CREATE TABLE IF NOT EXISTS "session_goals" (
2
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
3
+ "account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
4
+ "workspace_id" uuid NOT NULL REFERENCES "workspaces"("id") ON DELETE CASCADE,
5
+ "session_id" uuid NOT NULL REFERENCES "sessions"("id") ON DELETE CASCADE,
6
+ "status" text NOT NULL DEFAULT 'active',
7
+ "text" text NOT NULL,
8
+ "success_criteria" text,
9
+ "evidence" text,
10
+ "rationale" text,
11
+ "paused_reason" text,
12
+ "created_by" text NOT NULL DEFAULT 'api',
13
+ "version" integer NOT NULL DEFAULT 1,
14
+ "auto_continuations" integer NOT NULL DEFAULT 0,
15
+ "no_progress_streak" integer NOT NULL DEFAULT 0,
16
+ "max_auto_continuations" integer,
17
+ "last_continuation_turn_id" uuid,
18
+ "version_at_last_continuation" integer,
19
+ "metadata" jsonb NOT NULL DEFAULT '{}'::jsonb,
20
+ "created_at" timestamptz NOT NULL DEFAULT now(),
21
+ "updated_at" timestamptz NOT NULL DEFAULT now()
22
+ );
23
+ CREATE UNIQUE INDEX IF NOT EXISTS "session_goals_workspace_session_idx" ON "session_goals" ("workspace_id", "session_id");
24
+ CREATE INDEX IF NOT EXISTS "session_goals_workspace_status_idx" ON "session_goals" ("workspace_id", "status");
25
+ ALTER TABLE "session_goals" ENABLE ROW LEVEL SECURITY;
26
+ ALTER TABLE "session_goals" FORCE ROW LEVEL SECURITY;
27
+ DO $$
28
+ BEGIN
29
+ IF EXISTS (
30
+ SELECT 1 FROM pg_policies
31
+ WHERE schemaname = current_schema() AND tablename = 'session_goals' AND policyname = 'workspace_isolation'
32
+ ) THEN
33
+ DROP POLICY workspace_isolation ON "session_goals";
34
+ END IF;
35
+ END $$;
36
+ CREATE POLICY workspace_isolation ON "session_goals"
37
+ USING (opengeni_private.workspace_rls_visible(account_id, workspace_id))
38
+ WITH CHECK (opengeni_private.workspace_rls_visible(account_id, workspace_id));
39
+
40
+ DO $$
41
+ BEGIN
42
+ IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
43
+ GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO opengeni_app;
44
+ END IF;
45
+ END $$;
@@ -0,0 +1,31 @@
1
+ CREATE TABLE IF NOT EXISTS "workspace_packs" (
2
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
3
+ "account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
4
+ "workspace_id" uuid NOT NULL REFERENCES "workspaces"("id") ON DELETE CASCADE,
5
+ "pack_id" text NOT NULL,
6
+ "manifest" jsonb NOT NULL,
7
+ "created_at" timestamptz NOT NULL DEFAULT now(),
8
+ "updated_at" timestamptz NOT NULL DEFAULT now()
9
+ );
10
+ CREATE UNIQUE INDEX IF NOT EXISTS "workspace_packs_workspace_pack_idx" ON "workspace_packs" ("workspace_id", "pack_id");
11
+ ALTER TABLE "workspace_packs" ENABLE ROW LEVEL SECURITY;
12
+ ALTER TABLE "workspace_packs" FORCE ROW LEVEL SECURITY;
13
+ DO $$
14
+ BEGIN
15
+ IF EXISTS (
16
+ SELECT 1 FROM pg_policies
17
+ WHERE schemaname = current_schema() AND tablename = 'workspace_packs' AND policyname = 'workspace_isolation'
18
+ ) THEN
19
+ DROP POLICY workspace_isolation ON "workspace_packs";
20
+ END IF;
21
+ END $$;
22
+ CREATE POLICY workspace_isolation ON "workspace_packs"
23
+ USING (opengeni_private.workspace_rls_visible(account_id, workspace_id))
24
+ WITH CHECK (opengeni_private.workspace_rls_visible(account_id, workspace_id));
25
+
26
+ DO $$
27
+ BEGIN
28
+ IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
29
+ GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO opengeni_app;
30
+ END IF;
31
+ END $$;
@@ -0,0 +1,66 @@
1
+ -- Conversation truth as ordered, verbatim SDK input items (issue #35).
2
+ -- The model-facing memory store: unredacted, replay-ready AgentInputItem JSON.
3
+ -- session_events stays the redacted human/audit timeline; agent_run_states
4
+ -- shrinks to mid-turn approval resume.
5
+ CREATE TABLE IF NOT EXISTS "session_history_items" (
6
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
7
+ "account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
8
+ "workspace_id" uuid NOT NULL REFERENCES "workspaces"("id") ON DELETE CASCADE,
9
+ "session_id" uuid NOT NULL REFERENCES "sessions"("id") ON DELETE CASCADE,
10
+ "turn_id" uuid REFERENCES "session_turns"("id") ON DELETE SET NULL,
11
+ "position" integer NOT NULL,
12
+ "item" jsonb NOT NULL,
13
+ "created_at" timestamptz NOT NULL DEFAULT now()
14
+ );
15
+ CREATE UNIQUE INDEX IF NOT EXISTS "session_history_items_position_idx"
16
+ ON "session_history_items" ("workspace_id", "session_id", "position");
17
+ ALTER TABLE "session_history_items" ENABLE ROW LEVEL SECURITY;
18
+ ALTER TABLE "session_history_items" FORCE ROW LEVEL SECURITY;
19
+ DO $$
20
+ BEGIN
21
+ IF EXISTS (
22
+ SELECT 1 FROM pg_policies
23
+ WHERE schemaname = current_schema() AND tablename = 'session_history_items' AND policyname = 'workspace_isolation'
24
+ ) THEN
25
+ DROP POLICY workspace_isolation ON "session_history_items";
26
+ END IF;
27
+ END $$;
28
+ CREATE POLICY workspace_isolation ON "session_history_items"
29
+ USING (opengeni_private.workspace_rls_visible(account_id, workspace_id))
30
+ WITH CHECK (opengeni_private.workspace_rls_visible(account_id, workspace_id));
31
+
32
+ -- Sandbox recovery descriptor, decoupled from the RunState blob: the small
33
+ -- versioned envelope (provider handle / snapshot ref / manifest) needed to
34
+ -- reattach, restore, or rebuild the sandbox for a session's next turn.
35
+ CREATE TABLE IF NOT EXISTS "sandbox_session_envelopes" (
36
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
37
+ "account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
38
+ "workspace_id" uuid NOT NULL REFERENCES "workspaces"("id") ON DELETE CASCADE,
39
+ "session_id" uuid NOT NULL REFERENCES "sessions"("id") ON DELETE CASCADE,
40
+ "envelope" jsonb NOT NULL,
41
+ "created_at" timestamptz NOT NULL DEFAULT now(),
42
+ "updated_at" timestamptz NOT NULL DEFAULT now()
43
+ );
44
+ CREATE UNIQUE INDEX IF NOT EXISTS "sandbox_session_envelopes_session_idx"
45
+ ON "sandbox_session_envelopes" ("workspace_id", "session_id");
46
+ ALTER TABLE "sandbox_session_envelopes" ENABLE ROW LEVEL SECURITY;
47
+ ALTER TABLE "sandbox_session_envelopes" FORCE ROW LEVEL SECURITY;
48
+ DO $$
49
+ BEGIN
50
+ IF EXISTS (
51
+ SELECT 1 FROM pg_policies
52
+ WHERE schemaname = current_schema() AND tablename = 'sandbox_session_envelopes' AND policyname = 'workspace_isolation'
53
+ ) THEN
54
+ DROP POLICY workspace_isolation ON "sandbox_session_envelopes";
55
+ END IF;
56
+ END $$;
57
+ CREATE POLICY workspace_isolation ON "sandbox_session_envelopes"
58
+ USING (opengeni_private.workspace_rls_visible(account_id, workspace_id))
59
+ WITH CHECK (opengeni_private.workspace_rls_visible(account_id, workspace_id));
60
+
61
+ DO $$
62
+ BEGIN
63
+ IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
64
+ GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO opengeni_app;
65
+ END IF;
66
+ END $$;
@@ -0,0 +1,5 @@
1
+ -- Per-session first-party MCP token permissions (manager-style sessions).
2
+ -- NULL means the fixed worker default permission set in @opengeni/runtime.
3
+ -- Values are validated at session creation: every permission must be held by
4
+ -- the creating grant, so a session can never out-rank its creator.
5
+ ALTER TABLE "sessions" ADD COLUMN IF NOT EXISTS "first_party_mcp_permissions" jsonb;
@@ -0,0 +1,34 @@
1
+ -- Goal-bearing sessions must always hold goals:manage in their first-party
2
+ -- MCP permission set. A session created with a goal plus an explicit
3
+ -- first_party_mcp_permissions list lacking goals:manage never sees the goal
4
+ -- tools (goal_complete/goal_pause/goal_set/goal_update) on its delegated
5
+ -- token, so the agent cannot stop its own goal and the continuation loop
6
+ -- runs until an operator intervenes. Session creation now unions
7
+ -- goals:manage into explicit lists for goal-bearing sessions; this backfills
8
+ -- the rows created before that fix.
9
+ --
10
+ -- The backfill is scoped to sessions with a non-completed goal and an
11
+ -- explicit permission list missing goals:manage, and is idempotent. NULL
12
+ -- permission lists (the default worker set) already include goals:manage at
13
+ -- token-signing time and are left untouched.
14
+ --
15
+ -- Migrations run as the table owner, which FORCE ROW LEVEL SECURITY would
16
+ -- otherwise subject to the workspace-scoped policies (matching zero rows
17
+ -- here, where no workspace GUCs are set). NO FORCE only affects the owner -
18
+ -- the app role stays policy-bound throughout - and FORCE is restored within
19
+ -- the same implicit transaction that runs this file.
20
+ ALTER TABLE "sessions" NO FORCE ROW LEVEL SECURITY;
21
+ ALTER TABLE "session_goals" NO FORCE ROW LEVEL SECURITY;
22
+ UPDATE "sessions" s
23
+ SET "first_party_mcp_permissions" = s."first_party_mcp_permissions" || '["goals:manage"]'::jsonb
24
+ WHERE s."first_party_mcp_permissions" IS NOT NULL
25
+ AND jsonb_typeof(s."first_party_mcp_permissions") = 'array'
26
+ AND NOT s."first_party_mcp_permissions" @> '"goals:manage"'::jsonb
27
+ AND EXISTS (
28
+ SELECT 1 FROM "session_goals" g
29
+ WHERE g."workspace_id" = s."workspace_id"
30
+ AND g."session_id" = s."id"
31
+ AND g."status" <> 'completed'
32
+ );
33
+ ALTER TABLE "sessions" FORCE ROW LEVEL SECURITY;
34
+ ALTER TABLE "session_goals" FORCE ROW LEVEL SECURITY;
@@ -0,0 +1,30 @@
1
+ -- Parent linkage for spawned worker sessions. When a session is created via
2
+ -- the first-party MCP session_create tool and the caller's grant carries a
3
+ -- worker-signed sessionId claim (i.e. a manager session spawning a worker),
4
+ -- the new worker records that manager as its parent_session_id. Direct API
5
+ -- creates and scheduled-task runs carry no such claim and leave this NULL.
6
+ --
7
+ -- The column powers event-driven completion wakeups: when a session that has
8
+ -- a parent reaches a terminal-for-now state (goal completed, agent/system
9
+ -- paused goal, idle with no active goal after doing work, or failed), the
10
+ -- parent is woken with a system-authored message so the manager resumes and
11
+ -- reads the worker's output instead of busy-polling or stalling.
12
+ --
13
+ -- Self-referencing FK with ON DELETE SET NULL: deleting a manager session must
14
+ -- never cascade into its spawned workers; the link simply clears.
15
+ ALTER TABLE "sessions" ADD COLUMN IF NOT EXISTS "parent_session_id" uuid;
16
+
17
+ DO $$
18
+ BEGIN
19
+ IF NOT EXISTS (
20
+ SELECT 1 FROM information_schema.table_constraints
21
+ WHERE constraint_name = 'sessions_parent_session_id_fkey'
22
+ AND table_name = 'sessions'
23
+ ) THEN
24
+ ALTER TABLE "sessions"
25
+ ADD CONSTRAINT "sessions_parent_session_id_fkey"
26
+ FOREIGN KEY ("parent_session_id") REFERENCES "sessions"("id") ON DELETE SET NULL;
27
+ END IF;
28
+ END $$;
29
+
30
+ CREATE INDEX IF NOT EXISTS "sessions_parent_idx" ON "sessions" ("workspace_id", "parent_session_id");
@@ -0,0 +1,33 @@
1
+ -- Provider-aware conversation context compaction (client-side path).
2
+ --
3
+ -- Long-lived sessions grow session_history_items unbounded until they overflow
4
+ -- the model context window and 400 every turn. On Azure the server-side
5
+ -- Responses-API compaction is unavailable, so OpenGeni runs its own
6
+ -- client-side compaction: it summarizes an old turn-boundary-aligned prefix
7
+ -- into one synthetic user message and supersedes (NOT deletes) the summarized
8
+ -- rows so the full transcript survives as an audit trail.
9
+ --
10
+ -- "active": the live-row flag. The read path selects only active rows ordered
11
+ -- by position => [active summary, ...active recent tail]. A compaction sets the
12
+ -- summarized prefix rows inactive and inserts one active summary row at the
13
+ -- boundary. Defaults true so all existing and normally-appended rows stay live.
14
+ ALTER TABLE "session_history_items"
15
+ ADD COLUMN IF NOT EXISTS "active" boolean NOT NULL DEFAULT true;
16
+
17
+ -- Fast active-row read per session (the live conversation-truth read path).
18
+ CREATE INDEX IF NOT EXISTS "session_history_items_active_idx"
19
+ ON "session_history_items" ("workspace_id", "session_id", "position")
20
+ WHERE "active";
21
+
22
+ -- Last model-call input tokens of the most recent turn: the pre-turn
23
+ -- client-side compaction trigger reads it as its budget signal (char/4 over the
24
+ -- active items is the same-turn fallback). Null until a turn with usage lands.
25
+ ALTER TABLE "sessions"
26
+ ADD COLUMN IF NOT EXISTS "last_input_tokens" integer;
27
+
28
+ DO $$
29
+ BEGIN
30
+ IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
31
+ GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO opengeni_app;
32
+ END IF;
33
+ END $$;
@@ -0,0 +1,19 @@
1
+ -- Audit-safe compaction summary placement.
2
+ --
3
+ -- The first cut of client-side compaction (0011) inserted the synthetic summary
4
+ -- at integer position `boundaryPosition - 1`. Because history positions are
5
+ -- always contiguous from 0, that position is ALWAYS occupied by a real prefix
6
+ -- row, and the upsert overwrote that row's item JSON — destroying one real
7
+ -- history row per compaction and violating the "supersede, never delete" audit
8
+ -- guarantee (it also stranded the summary under the prefix row's old turn_id).
9
+ --
10
+ -- Fix: store the summary at a FRACTIONAL position (boundaryPosition - 0.5) that
11
+ -- sorts immediately ahead of the kept tail and collides with nothing. That
12
+ -- requires `position` to be numeric rather than integer. Normal appends keep
13
+ -- whole-number positions; only the summary uses the half-step.
14
+ --
15
+ -- Safe in place: every existing position is a whole number, so the integer ->
16
+ -- numeric widening is loss-free and the unique index is rebuilt automatically by
17
+ -- the type change. No data is rewritten beyond the column representation.
18
+ ALTER TABLE "session_history_items"
19
+ ALTER COLUMN "position" TYPE numeric USING "position"::numeric;
@@ -0,0 +1,16 @@
1
+ -- Operator /compact request flag (slash-command palette).
2
+ --
3
+ -- /compact is a manual trigger for the client-side (Azure) context compaction
4
+ -- path. The API sets this flag true; the worker honors it BEFORE the next
5
+ -- turn's model call by forcing a compaction (bypassing the token-budget
6
+ -- trigger), then clears it. A durable column — not a transient signal — so the
7
+ -- request survives a worker restart and converges before the next turn.
8
+ ALTER TABLE "sessions"
9
+ ADD COLUMN IF NOT EXISTS "compact_requested" boolean NOT NULL DEFAULT false;
10
+
11
+ DO $$
12
+ BEGIN
13
+ IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
14
+ GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO opengeni_app;
15
+ END IF;
16
+ END $$;
@@ -0,0 +1,125 @@
1
+ -- One-time REPAIR of legacy orphaned tool-call RESULT rows (issue-61 self-heal).
2
+ --
3
+ -- Conversation truth is replayed verbatim into the model on every turn. The
4
+ -- Responses API rejects the whole request (HTTP 400 "No tool call found for
5
+ -- function call output with call_id <X>") when a tool-call RESULT row
6
+ -- (function_call_result / computer_call_result / shell_call_output /
7
+ -- apply_patch_call_output) has no matching CALL earlier in the active sequence.
8
+ -- Because the corrupt row is replayed every turn, one such orphan permanently
9
+ -- bricks the session across revival until the row is removed.
10
+ --
11
+ -- The read-path sanitizer (sanitizeHistoryItemsForModel) already filters these
12
+ -- in-memory so new turns survive, and the write-path watermark fix (seed from
13
+ -- the SANITIZED active length) stops new orphans from ever being persisted. But
14
+ -- sessions corrupted BEFORE those fixes still carry the orphaned row on disk;
15
+ -- the audit trail (session_get / session_events / exports) keeps surfacing a
16
+ -- result with no call, and the row needlessly re-triggers the sanitizer every
17
+ -- turn. This migration strips those already-persisted orphans once so corrupted
18
+ -- sessions self-heal on disk, paired and audited.
19
+ --
20
+ -- DEFINITION OF AN ORPHAN (mirrors the sanitizer's rule 1 exactly):
21
+ -- * The row is an ACTIVE result-type row (the live, model-facing sequence is
22
+ -- the only thing the read path replays; superseded prefix rows are audit
23
+ -- trail and never reach the model). active=false rows are left untouched.
24
+ -- * No ACTIVE row of the matching CALL type, with the same correlation id,
25
+ -- exists at a STRICTLY EARLIER position in the same (workspace, session).
26
+ -- * Correlation id is read from BOTH the SDK camelCase `callId` and the wire
27
+ -- snake_case `call_id`, matching the sanitizer's callIdOf().
28
+ --
29
+ -- We deliberately do NOT touch DANGLING CALLS (a call with no result yet): a
30
+ -- call awaiting a not-yet-settled result is valid mid-turn, not corruption; the
31
+ -- read-path sanitizer drops it transiently and it settles on the next pass.
32
+ --
33
+ -- Every deleted row is first copied verbatim into the permanent audit table
34
+ -- session_history_items_repair_audit, so the repair is reversible and auditable.
35
+
36
+ -- Permanent audit of every row this repair removed.
37
+ CREATE TABLE IF NOT EXISTS "session_history_items_repair_audit" (
38
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
39
+ -- The original session_history_items row, captured verbatim. No FK back to the
40
+ -- source row: it is being deleted, and the audit must outlive it.
41
+ "source_id" uuid NOT NULL,
42
+ "account_id" uuid NOT NULL,
43
+ "workspace_id" uuid NOT NULL,
44
+ "session_id" uuid NOT NULL,
45
+ "turn_id" uuid,
46
+ "position" numeric NOT NULL,
47
+ "item" jsonb NOT NULL,
48
+ "source_created_at" timestamptz NOT NULL,
49
+ "repair_reason" text NOT NULL,
50
+ "repaired_at" timestamptz NOT NULL DEFAULT now()
51
+ );
52
+
53
+ -- Result-item types and the CALL type that settles each, kept in sync with the
54
+ -- runtime sanitizer's RESULT_TYPE_BY_CALL_TYPE. Built once as a CTE so the
55
+ -- DELETE and the audit INSERT share one definition of an orphan.
56
+ WITH "result_call_pairs" ("result_type", "call_type") AS (
57
+ VALUES
58
+ ('function_call_result', 'function_call'),
59
+ ('computer_call_result', 'computer_call'),
60
+ ('shell_call_output', 'shell_call'),
61
+ ('apply_patch_call_output', 'apply_patch_call')
62
+ ),
63
+ -- Every ACTIVE result-type row, with its correlation id and the call type that
64
+ -- would settle it.
65
+ "active_results" AS (
66
+ SELECT
67
+ h."id",
68
+ h."account_id",
69
+ h."workspace_id",
70
+ h."session_id",
71
+ h."turn_id",
72
+ h."position",
73
+ h."item",
74
+ h."created_at",
75
+ p."call_type",
76
+ COALESCE(h."item" ->> 'callId', h."item" ->> 'call_id') AS "call_id"
77
+ FROM "session_history_items" h
78
+ JOIN "result_call_pairs" p
79
+ ON p."result_type" = (h."item" ->> 'type')
80
+ WHERE h."active" = true
81
+ AND COALESCE(h."item" ->> 'callId', h."item" ->> 'call_id') IS NOT NULL
82
+ ),
83
+ -- The orphans: an active result row with NO active matching call at a strictly
84
+ -- earlier position in the same session.
85
+ "orphans" AS (
86
+ SELECT r.*
87
+ FROM "active_results" r
88
+ WHERE NOT EXISTS (
89
+ SELECT 1
90
+ FROM "session_history_items" c
91
+ WHERE c."workspace_id" = r."workspace_id"
92
+ AND c."session_id" = r."session_id"
93
+ AND c."active" = true
94
+ AND (c."item" ->> 'type') = r."call_type"
95
+ AND COALESCE(c."item" ->> 'callId', c."item" ->> 'call_id') = r."call_id"
96
+ AND c."position" < r."position"
97
+ )
98
+ ),
99
+ -- Audit every orphan before deleting it.
100
+ "audited" AS (
101
+ INSERT INTO "session_history_items_repair_audit" (
102
+ "source_id", "account_id", "workspace_id", "session_id", "turn_id",
103
+ "position", "item", "source_created_at", "repair_reason"
104
+ )
105
+ SELECT
106
+ o."id", o."account_id", o."workspace_id", o."session_id", o."turn_id",
107
+ o."position", o."item", o."created_at",
108
+ 'orphaned_tool_call_result_no_matching_call'
109
+ FROM "orphans" o
110
+ RETURNING "source_id"
111
+ )
112
+ DELETE FROM "session_history_items" h
113
+ USING "audited" a
114
+ WHERE h."id" = a."source_id";
115
+
116
+ -- The audit table holds no workspace-scoped RLS (it is an operator/audit
117
+ -- artifact written only by this migration), but grant the app role the same
118
+ -- table access the rest of the schema gets so a later GRANT-ALL sweep is
119
+ -- idempotent and the role inventory stays uniform.
120
+ DO $$
121
+ BEGIN
122
+ IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
123
+ GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO opengeni_app;
124
+ END IF;
125
+ END $$;