@relayfx/sdk 0.7.10 → 0.7.11

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 (71) hide show
  1. package/dist/http-server.js +1 -1
  2. package/dist/{index-gwgea1te.js → index-d1je4njg.js} +4088 -3764
  3. package/dist/{index-nb078xsy.js → index-j8k41y47.js} +26 -4
  4. package/dist/{index-m7dpw880.js → index-skcp0xvt.js} +1 -1
  5. package/dist/index.js +2 -2
  6. package/dist/migrations/20260723190000_transactional_event_head/migration.sql +22 -0
  7. package/dist/migrations/20260724010000_execution_event_archive_manifests/migration.sql +66 -0
  8. package/dist/migrations/20260724120000_execution_event_identity_directory/migration.sql +15 -0
  9. package/dist/migrations/20260724230000_idempotent_steering/migration.sql +7 -0
  10. package/dist/migrations/mysql/0015_transactional_event_head.sql +32 -0
  11. package/dist/migrations/mysql/0016_execution_event_archive_manifests.sql +65 -0
  12. package/dist/migrations/mysql/0017_execution_event_identity_directory.sql +20 -0
  13. package/dist/migrations/mysql/0018_idempotent_steering.sql +7 -0
  14. package/dist/migrations/pg/20260723190000_transactional_event_head/migration.sql +22 -0
  15. package/dist/migrations/pg/20260724010000_execution_event_archive_manifests/migration.sql +66 -0
  16. package/dist/migrations/pg/20260724120000_execution_event_identity_directory/migration.sql +15 -0
  17. package/dist/migrations/pg/20260724230000_idempotent_steering/migration.sql +7 -0
  18. package/dist/migrations/sqlite/0015_transactional_event_head.sql +22 -0
  19. package/dist/migrations/sqlite/0016_execution_event_archive_manifests.sql +45 -0
  20. package/dist/migrations/sqlite/0017_execution_event_identity_directory.sql +13 -0
  21. package/dist/migrations/sqlite/0018_idempotent_steering.sql +5 -0
  22. package/dist/mysql.js +49 -8
  23. package/dist/postgres.js +135 -13
  24. package/dist/sqlite.js +115 -4
  25. package/dist/types/relay/client-public-executions.d.ts +1 -1
  26. package/dist/types/relay/client-public.d.ts +2 -2
  27. package/dist/types/relay/http-server.d.ts +2 -2
  28. package/dist/types/relay/mysql-migrations.d.ts +1 -1
  29. package/dist/types/relay/operation.d.ts +9 -0
  30. package/dist/types/relay/sqlite-migrations.d.ts +21 -1
  31. package/dist/types/runtime/agent/agent-loop-events.d.ts +10 -9
  32. package/dist/types/runtime/agent/agent-loop-service.d.ts +1 -0
  33. package/dist/types/runtime/agent/emission-ordinal-allocator.d.ts +7 -0
  34. package/dist/types/runtime/agent/relay-permissions.d.ts +4 -7
  35. package/dist/types/runtime/agent/relay-steering.d.ts +5 -5
  36. package/dist/types/runtime/agent/relay-tool-executor.d.ts +3 -2
  37. package/dist/types/runtime/envelope/envelope-service.d.ts +2 -1
  38. package/dist/types/runtime/execution/event-log-service.d.ts +5 -4
  39. package/dist/types/runtime/execution/execution-service.d.ts +1 -1
  40. package/dist/types/runtime/inbox/inbox-service.d.ts +6 -6
  41. package/dist/types/runtime/schedule/scheduler-service.d.ts +3 -4
  42. package/dist/types/runtime/state/execution-state-service.d.ts +2 -2
  43. package/dist/types/runtime/tool/tool-runtime-contract.d.ts +2 -0
  44. package/dist/types/runtime/tool/tool-runtime-identifiers.d.ts +6 -0
  45. package/dist/types/runtime/wait/wait-service.d.ts +5 -5
  46. package/dist/types/runtime/workflow/execution-workflow.d.ts +2 -3
  47. package/dist/types/runtime/workspace/workspace-planner-service.d.ts +2 -0
  48. package/dist/types/schema/workflow-schema.d.ts +1 -0
  49. package/dist/types/store-sql/execution/archive-compression.d.ts +11 -0
  50. package/dist/types/store-sql/execution/event-history-file-system.d.ts +7 -0
  51. package/dist/types/store-sql/execution/event-history-store.d.ts +93 -0
  52. package/dist/types/store-sql/execution/execution-event-archive-codec.d.ts +69 -0
  53. package/dist/types/store-sql/execution/execution-event-archive-repository-memory.d.ts +28 -0
  54. package/dist/types/store-sql/execution/execution-event-archive-repository-sql.d.ts +19 -0
  55. package/dist/types/store-sql/execution/execution-event-archive-repository.d.ts +175 -0
  56. package/dist/types/store-sql/execution/execution-event-head-memory.d.ts +13 -0
  57. package/dist/types/store-sql/execution/execution-event-head.d.ts +40 -0
  58. package/dist/types/store-sql/execution/execution-event-identity-directory.d.ts +26 -0
  59. package/dist/types/store-sql/execution/execution-event-repository-archive-aware.d.ts +7 -0
  60. package/dist/types/store-sql/execution/execution-event-repository-memory.d.ts +6 -1
  61. package/dist/types/store-sql/execution/execution-event-repository.d.ts +6 -4
  62. package/dist/types/store-sql/inbox/inbox-repository.d.ts +6 -2
  63. package/dist/types/store-sql/schema/communication-schema.d.ts +15 -0
  64. package/dist/types/store-sql/schema/execution-schema.d.ts +583 -0
  65. package/dist/types/store-sql/schema/relay-schema.d.ts +1 -1
  66. package/dist/types/store-sql/state/execution-state-repository.d.ts +2 -1
  67. package/dist/types/store-sql/steering/steering-model.d.ts +60 -0
  68. package/dist/types/store-sql/steering/steering-repository.d.ts +5 -50
  69. package/package.json +3 -3
  70. package/dist/types/relay/client-event-sequence.d.ts +0 -3
  71. package/dist/types/runtime/agent/sequence-allocator.d.ts +0 -9
@@ -1343,10 +1343,26 @@ var Classification = Schema18.Union([
1343
1343
  var scopedToolCallId = (waitId, namespace) => {
1344
1344
  const scope = waitId.slice(namespace.length);
1345
1345
  const separator = scope.indexOf(":");
1346
- return ToolCallId.make(decodeURIComponent(scope.slice(separator + 1)));
1346
+ const toolScope = scope.slice(separator + 1);
1347
+ if (!toolScope.startsWith("operation:"))
1348
+ return ToolCallId.make(decodeURIComponent(toolScope));
1349
+ const operationSeparator = toolScope.indexOf(":tool-call:", "operation:".length);
1350
+ return ToolCallId.make(decodeURIComponent(toolScope.slice(operationSeparator + 11)));
1351
+ };
1352
+ var currentPermissionToolCallId = (waitId) => {
1353
+ const encoded = waitId.slice("relay-permission-wait-v2:".length);
1354
+ const identity = JSON.parse(decodeURIComponent(encoded));
1355
+ return ToolCallId.make(identity[2]);
1347
1356
  };
1348
1357
  var classify = (input) => {
1349
1358
  const waitId = input.wait_id;
1359
+ if (waitId.startsWith("relay-permission-wait-v2:")) {
1360
+ return {
1361
+ kind: "permission",
1362
+ wait_id: waitId,
1363
+ tool_call_id: currentPermissionToolCallId(waitId)
1364
+ };
1365
+ }
1350
1366
  if (waitId.startsWith("wait:permission:")) {
1351
1367
  return {
1352
1368
  kind: "permission",
@@ -1415,6 +1431,7 @@ var resolverFor = (classification) => {
1415
1431
  var externallyResolvable = (classification) => resolverFor(classification) !== undefined;
1416
1432
  var exports_workflow_schema = {};
1417
1433
  __export2(exports_workflow_schema, {
1434
+ sha256String: () => sha256String,
1418
1435
  digestDefinition: () => digestDefinition,
1419
1436
  canonicalDefinition: () => canonicalDefinition,
1420
1437
  ToolOperation: () => ToolOperation,
@@ -1743,7 +1760,7 @@ var sha256Constants = [
1743
1760
  3329325298
1744
1761
  ];
1745
1762
  var rotateRight = (value, count) => value >>> count | value << 32 - count;
1746
- var sha256 = (value) => {
1763
+ var sha256String = (value) => {
1747
1764
  const encoded = Encoding.encodeHex(value);
1748
1765
  const bytes = Array.from({ length: encoded.length / 2 }, (_, index) => Number.parseInt(encoded.slice(index * 2, index * 2 + 2), 16));
1749
1766
  const bitLength = bytes.length * 8;
@@ -1782,7 +1799,7 @@ var sha256 = (value) => {
1782
1799
  }
1783
1800
  return hash.map((part) => (part >>> 0).toString(16).padStart(8, "0")).join("");
1784
1801
  };
1785
- var digestDefinition = (definition) => Schema19.decodeUnknownSync(DefinitionDigest)(`sha256:${sha256(canonicalDefinition(definition))}`);
1802
+ var digestDefinition = (definition) => Schema19.decodeUnknownSync(DefinitionDigest)(`sha256:${sha256String(canonicalDefinition(definition))}`);
1786
1803
  var DefinitionRevisionRecord3 = Schema19.Struct({
1787
1804
  id: WorkflowDefinitionId,
1788
1805
  revision: DefinitionRevision3,
@@ -1965,6 +1982,7 @@ __export(exports_operation, {
1965
1982
  StreamSessionInput: () => StreamSessionInput,
1966
1983
  StreamExecutionInput: () => StreamExecutionInput,
1967
1984
  SteeringKind: () => SteeringKind,
1985
+ SteeringIdempotencyConflict: () => SteeringIdempotencyConflict,
1968
1986
  SteerInput: () => SteerInput,
1969
1987
  SteerAccepted: () => SteerAccepted,
1970
1988
  StartExecutionResult: () => StartExecutionResult,
@@ -2146,10 +2164,14 @@ var SteeringKind = Schema23.Literals(["steering", "follow_up"]).annotate({
2146
2164
  });
2147
2165
  var SteerInput = Schema23.Struct({
2148
2166
  execution_id: exports_ids_schema.ExecutionId,
2167
+ idempotency_key: exports_shared_schema.NonEmptyString.check(Schema23.isMaxLength(191), Schema23.makeFilter((value) => !value.startsWith("relay:"))),
2149
2168
  kind: SteeringKind,
2150
2169
  content: Schema23.Array(exports_content_schema.Part),
2151
2170
  created_at: exports_shared_schema.TimestampMillis
2152
2171
  }).annotate({ identifier: "Relay.Operation.SteerInput" });
2172
+
2173
+ class SteeringIdempotencyConflict extends Schema23.TaggedErrorClass()("SteeringIdempotencyConflict", { execution_id: exports_ids_schema.ExecutionId, idempotency_key: exports_shared_schema.NonEmptyString }) {
2174
+ }
2153
2175
  var SteerAccepted = Schema23.Struct({
2154
2176
  execution_id: exports_ids_schema.ExecutionId,
2155
2177
  kind: SteeringKind,
@@ -2747,4 +2769,4 @@ class Service2 extends Context2.Service()("@relayfx/runtime/presence/presence-co
2747
2769
  }
2748
2770
  var PresenceIdentity = Context2.Reference("@relayfx/runtime/PresenceIdentity", { defaultValue: () => ({}) });
2749
2771
 
2750
- export { exports_address_schema, exports_ids_schema, exports_shared_schema, exports_agent_schema, exports_tool_schema, exports_child_orchestration_schema, exports_execution_schema, exports_content_schema, exports_envelope_schema, exports_resident_schema, exports_inbox_schema, exports_pagination_schema, exports_presence_schema, exports_schedule_schema, exports_skill_schema, exports_state_schema, exports_wait_schema, exports_workflow_schema, exports_workspace_schema, StateVersionConflict, EventLogCursorNotFound, exports_operation, ClientError, ExecutionNotFound, ResidentNamespaceReserved, WaitKindMismatch, Service, followExecutionFrom, PresenceError, Service2 as Service1, PresenceIdentity };
2772
+ export { exports_address_schema, exports_ids_schema, exports_shared_schema, exports_agent_schema, exports_tool_schema, exports_child_orchestration_schema, exports_execution_schema, exports_content_schema, exports_envelope_schema, exports_resident_schema, exports_inbox_schema, exports_pagination_schema, exports_presence_schema, exports_schedule_schema, exports_skill_schema, exports_state_schema, exports_wait_schema, exports_workflow_schema, exports_workspace_schema, StateVersionConflict, SteerInput, SteeringIdempotencyConflict, EventLogCursorNotFound, exports_operation, ClientError, ExecutionNotFound, ResidentNamespaceReserved, WaitKindMismatch, Service, followExecutionFrom, PresenceError, Service2 as Service1, PresenceIdentity };
@@ -8,7 +8,7 @@ import {
8
8
  SqlFailure,
9
9
  make,
10
10
  normalizeAcquisitionCause
11
- } from "./index-gwgea1te.js";
11
+ } from "./index-d1je4njg.js";
12
12
 
13
13
  // src/migration-errors.ts
14
14
  import { Cause, Effect, Function } from "effect";
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ import {
14
14
  exports_tool_runtime,
15
15
  exports_workflow_definition_host,
16
16
  makeDatabaseIdentity
17
- } from "./index-gwgea1te.js";
17
+ } from "./index-d1je4njg.js";
18
18
  import {
19
19
  exports_context_overflow,
20
20
  exports_model_registry
@@ -47,7 +47,7 @@ import {
47
47
  exports_wait_schema,
48
48
  exports_workflow_schema,
49
49
  followExecutionFrom
50
- } from "./index-nb078xsy.js";
50
+ } from "./index-j8k41y47.js";
51
51
  import {
52
52
  __export
53
53
  } from "./index-nb39b5ae.js";
@@ -0,0 +1,22 @@
1
+ CREATE TABLE "relay_execution_event_heads" (
2
+ "tenant_id" text DEFAULT 'system' NOT NULL,
3
+ "execution_id" text NOT NULL,
4
+ "next_sequence" integer DEFAULT 0 NOT NULL,
5
+ "max_sequence" integer,
6
+ "event_count" integer DEFAULT 0 NOT NULL,
7
+ "usage_tokens" bigint DEFAULT 0 NOT NULL,
8
+ CONSTRAINT "pk_relay_execution_event_heads" PRIMARY KEY("tenant_id","execution_id")
9
+ );
10
+ --> statement-breakpoint
11
+ -- Drizzle runs this migration in one transaction. SHARE ROW EXCLUSIVE blocks
12
+ -- legacy INSERT/UPDATE/DELETE writers while allowing ACCESS SHARE readers, so
13
+ -- the backfill and the newly created head rows become visible atomically.
14
+ LOCK TABLE "relay_executions", "relay_execution_events", "relay_execution_event_heads"
15
+ IN SHARE ROW EXCLUSIVE MODE;
16
+ --> statement-breakpoint
17
+ INSERT INTO "relay_execution_event_heads" ("tenant_id", "execution_id", "next_sequence", "max_sequence", "event_count", "usage_tokens")
18
+ SELECT execution."tenant_id", execution."id", COALESCE(MAX(event."sequence") + 1, 0), MAX(event."sequence"), COUNT(event."id"), COALESCE(SUM(CASE WHEN event."type" = 'model.usage.reported' THEN CASE WHEN jsonb_typeof(event."data_json" -> 'input_tokens') = 'number' THEN trunc((event."data_json" ->> 'input_tokens')::numeric)::bigint ELSE 0 END + CASE WHEN jsonb_typeof(event."data_json" -> 'output_tokens') = 'number' THEN trunc((event."data_json" ->> 'output_tokens')::numeric)::bigint ELSE 0 END ELSE 0 END), 0)
19
+ FROM "relay_executions" execution
20
+ LEFT JOIN "relay_execution_events" event
21
+ ON event."tenant_id" = execution."tenant_id" AND event."execution_id" = execution."id"
22
+ GROUP BY execution."tenant_id", execution."id";
@@ -0,0 +1,66 @@
1
+ ALTER TABLE "relay_execution_event_heads" ADD COLUMN "archived_through" integer;
2
+ --> statement-breakpoint
3
+ ALTER TABLE "relay_execution_event_heads" ADD COLUMN "archive_generation" integer;
4
+ --> statement-breakpoint
5
+ ALTER TABLE "relay_execution_event_heads" ADD CONSTRAINT "ck_relay_execution_event_heads_archive_pointer" CHECK (("archived_through" IS NULL) = ("archive_generation" IS NULL));
6
+ --> statement-breakpoint
7
+ CREATE TABLE "relay_execution_event_archive_manifests" (
8
+ "tenant_id" text DEFAULT 'system' NOT NULL,
9
+ "execution_id" text NOT NULL,
10
+ "generation" integer NOT NULL,
11
+ "archived_through" integer NOT NULL,
12
+ "event_count" integer NOT NULL,
13
+ "max_sequence" integer NOT NULL,
14
+ "usage_tokens" bigint NOT NULL,
15
+ "schema_version" integer NOT NULL,
16
+ CONSTRAINT "pk_relay_execution_event_archive_manifests" PRIMARY KEY("tenant_id","execution_id","generation"),
17
+ CONSTRAINT "ck_relay_execution_event_archive_manifests_generation" CHECK ("generation" > 0),
18
+ CONSTRAINT "ck_relay_execution_event_archive_manifests_frontier" CHECK ("archived_through" >= 0),
19
+ CONSTRAINT "ck_relay_execution_event_archive_manifests_count" CHECK ("event_count" > 0),
20
+ CONSTRAINT "ck_relay_execution_event_archive_manifests_max" CHECK ("max_sequence" = "archived_through"),
21
+ CONSTRAINT "ck_relay_execution_event_archive_manifests_gaps" CHECK ("event_count" <= "archived_through" + 1),
22
+ CONSTRAINT "ck_relay_execution_event_archive_manifests_usage" CHECK ("usage_tokens" >= 0),
23
+ CONSTRAINT "ck_relay_execution_event_archive_manifests_schema" CHECK ("schema_version" = 1)
24
+ );
25
+ --> statement-breakpoint
26
+ CREATE TABLE "relay_execution_event_archive_blocks" (
27
+ "tenant_id" text DEFAULT 'system' NOT NULL,
28
+ "execution_id" text NOT NULL,
29
+ "generation" integer NOT NULL,
30
+ "block_index" integer NOT NULL,
31
+ "first_sequence" integer NOT NULL,
32
+ "last_sequence" integer NOT NULL,
33
+ "event_count" integer NOT NULL,
34
+ "object_key" text NOT NULL,
35
+ "object_checksum" text NOT NULL,
36
+ "object_size" integer NOT NULL,
37
+ "codec_version" integer NOT NULL,
38
+ "encoding" text NOT NULL,
39
+ "compression" text NOT NULL,
40
+ "payload_checksum" text NOT NULL,
41
+ "stored_payload_bytes" integer NOT NULL,
42
+ "uncompressed_bytes" integer NOT NULL,
43
+ CONSTRAINT "pk_relay_execution_event_archive_blocks" PRIMARY KEY("tenant_id","execution_id","generation","block_index"),
44
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_index" CHECK ("block_index" >= 0),
45
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_first" CHECK ("first_sequence" >= 0),
46
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_bounds" CHECK ("last_sequence" >= "first_sequence"),
47
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_count" CHECK ("event_count" > 0),
48
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_count_limit" CHECK ("event_count" <= 4096),
49
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_gaps" CHECK ("event_count" <= "last_sequence" - "first_sequence" + 1),
50
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_object_size" CHECK ("object_size" > 0 AND "object_size" <= 16777216),
51
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_stored_payload_size" CHECK ("stored_payload_bytes" > 0 AND "stored_payload_bytes" <= 15728640),
52
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_uncompressed_size" CHECK ("uncompressed_bytes" > 0 AND "uncompressed_bytes" <= 15728640),
53
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_stored_size" CHECK ("stored_payload_bytes" < "object_size"),
54
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_expansion" CHECK ("stored_payload_bytes" <= "uncompressed_bytes"),
55
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_codec" CHECK ("codec_version" IN (1, 2)),
56
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_encoding" CHECK ("encoding" = 'json'),
57
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_compression" CHECK (("codec_version" = 1 AND "compression" = 'none' AND "stored_payload_bytes" = "uncompressed_bytes") OR ("codec_version" = 2 AND "compression" = 'gzip')),
58
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_object_key" CHECK (length("object_key") <= 80),
59
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_checksum" CHECK (length("object_checksum") = 64),
60
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_payload_checksum" CHECK (length("payload_checksum") = 64),
61
+ CONSTRAINT "uq_relay_execution_event_archive_blocks_first" UNIQUE("tenant_id","execution_id","generation","first_sequence")
62
+ );
63
+ --> statement-breakpoint
64
+ ALTER TABLE "relay_execution_event_archive_manifests" ADD CONSTRAINT "fk_relay_execution_event_archive_manifests_execution" FOREIGN KEY ("tenant_id","execution_id") REFERENCES "relay_executions"("tenant_id","id") ON DELETE no action ON UPDATE no action;
65
+ --> statement-breakpoint
66
+ ALTER TABLE "relay_execution_event_archive_blocks" ADD CONSTRAINT "fk_relay_execution_event_archive_blocks_manifest" FOREIGN KEY ("tenant_id","execution_id","generation") REFERENCES "relay_execution_event_archive_manifests"("tenant_id","execution_id","generation") ON DELETE no action ON UPDATE no action;
@@ -0,0 +1,15 @@
1
+ CREATE TABLE "relay_execution_event_identity_directory" (
2
+ "tenant_id" text NOT NULL,
3
+ "cursor" text NOT NULL,
4
+ "event_id" text NOT NULL,
5
+ "execution_id" text NOT NULL,
6
+ "sequence" integer NOT NULL,
7
+ CONSTRAINT "pk_relay_execution_event_identity_directory" PRIMARY KEY("tenant_id","cursor"),
8
+ CONSTRAINT "uq_relay_execution_event_identity_directory_event" UNIQUE("tenant_id","event_id"),
9
+ CONSTRAINT "uq_relay_execution_event_identity_directory_sequence" UNIQUE("tenant_id","execution_id","sequence")
10
+ );
11
+ --> statement-breakpoint
12
+ LOCK TABLE "relay_execution_events" IN SHARE ROW EXCLUSIVE MODE;
13
+ --> statement-breakpoint
14
+ INSERT INTO "relay_execution_event_identity_directory" ("tenant_id", "cursor", "event_id", "execution_id", "sequence")
15
+ SELECT "tenant_id", "cursor", "id", "execution_id", "sequence" FROM "relay_execution_events";
@@ -0,0 +1,7 @@
1
+ ALTER TABLE "relay_steering_messages" ADD COLUMN "idempotency_key" text;
2
+ --> statement-breakpoint
3
+ UPDATE "relay_steering_messages" SET "idempotency_key" = 'relay:legacy:' || "kind" || ':' || "sequence"::text;
4
+ --> statement-breakpoint
5
+ ALTER TABLE "relay_steering_messages" ALTER COLUMN "idempotency_key" SET NOT NULL;
6
+ --> statement-breakpoint
7
+ CREATE UNIQUE INDEX "uq_relay_steering_messages_idempotency" ON "relay_steering_messages" ("tenant_id", "execution_id", "idempotency_key");
@@ -0,0 +1,32 @@
1
+ ALTER TABLE `relay_execution_events`
2
+ MODIFY `id` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
3
+ MODIFY `cursor` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;
4
+ --> statement-breakpoint
5
+ CREATE TABLE IF NOT EXISTS `relay_execution_event_heads` (
6
+ `tenant_id` VARCHAR(191) NOT NULL DEFAULT 'system',
7
+ `execution_id` VARCHAR(191) NOT NULL,
8
+ `next_sequence` INT NOT NULL DEFAULT 0,
9
+ `max_sequence` INT NULL,
10
+ `event_count` INT NOT NULL DEFAULT 0,
11
+ `usage_tokens` BIGINT NOT NULL DEFAULT 0,
12
+ CONSTRAINT `pk_relay_execution_event_heads` PRIMARY KEY (`tenant_id`, `execution_id`)
13
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
14
+ --> statement-breakpoint
15
+ -- Relay pins this migration to one reserved connection. These WRITE locks
16
+ -- block legacy execution creation and event appends until every head has been
17
+ -- backfilled and migration 15 is recorded. The runner guarantees UNLOCK TABLES
18
+ -- on success or failure.
19
+ LOCK TABLES
20
+ `relay_executions` WRITE,
21
+ `relay_execution_events` WRITE,
22
+ `relay_execution_event_heads` WRITE,
23
+ `relay_migrations` WRITE;
24
+ --> statement-breakpoint
25
+ DELETE FROM `relay_execution_event_heads`;
26
+ --> statement-breakpoint
27
+ INSERT INTO `relay_execution_event_heads` (`tenant_id`, `execution_id`, `next_sequence`, `max_sequence`, `event_count`, `usage_tokens`)
28
+ SELECT `relay_executions`.`tenant_id`, `relay_executions`.`id`, COALESCE(MAX(`relay_execution_events`.`sequence`) + 1, 0), MAX(`relay_execution_events`.`sequence`), COUNT(`relay_execution_events`.`id`), COALESCE(SUM(CASE WHEN `relay_execution_events`.`type` = 'model.usage.reported' THEN COALESCE(CAST(JSON_EXTRACT(`relay_execution_events`.`data_json`, '$.input_tokens') AS SIGNED), 0) + COALESCE(CAST(JSON_EXTRACT(`relay_execution_events`.`data_json`, '$.output_tokens') AS SIGNED), 0) ELSE 0 END), 0)
29
+ FROM `relay_executions`
30
+ LEFT JOIN `relay_execution_events`
31
+ ON `relay_execution_events`.`tenant_id` = `relay_executions`.`tenant_id` AND `relay_execution_events`.`execution_id` = `relay_executions`.`id`
32
+ GROUP BY `relay_executions`.`tenant_id`, `relay_executions`.`id`;
@@ -0,0 +1,65 @@
1
+ ALTER TABLE `relay_execution_event_heads`
2
+ ADD COLUMN `archived_through` INT NULL;
3
+ --> statement-breakpoint
4
+ ALTER TABLE `relay_execution_event_heads`
5
+ ADD COLUMN `archive_generation` INT NULL;
6
+ --> statement-breakpoint
7
+ ALTER TABLE `relay_execution_event_heads`
8
+ ADD CONSTRAINT `ck_relay_execution_event_heads_archive_pointer`
9
+ CHECK ((`archived_through` IS NULL) = (`archive_generation` IS NULL));
10
+ --> statement-breakpoint
11
+ CREATE TABLE IF NOT EXISTS `relay_execution_event_archive_manifests` (
12
+ `tenant_id` VARCHAR(191) NOT NULL DEFAULT 'system',
13
+ `execution_id` VARCHAR(191) NOT NULL,
14
+ `generation` INT NOT NULL,
15
+ `archived_through` INT NOT NULL,
16
+ `event_count` INT NOT NULL,
17
+ `max_sequence` INT NOT NULL,
18
+ `usage_tokens` BIGINT NOT NULL,
19
+ `schema_version` INT NOT NULL,
20
+ CONSTRAINT `pk_relay_execution_event_archive_manifests` PRIMARY KEY (`tenant_id`, `execution_id`, `generation`),
21
+ CONSTRAINT `fk_relay_execution_event_archive_manifests_execution` FOREIGN KEY (`tenant_id`, `execution_id`) REFERENCES `relay_executions` (`tenant_id`, `id`),
22
+ CONSTRAINT `ck_relay_execution_event_archive_manifests_generation` CHECK (`generation` > 0),
23
+ CONSTRAINT `ck_relay_execution_event_archive_manifests_frontier` CHECK (`archived_through` >= 0),
24
+ CONSTRAINT `ck_relay_execution_event_archive_manifests_count` CHECK (`event_count` > 0),
25
+ CONSTRAINT `ck_relay_execution_event_archive_manifests_max` CHECK (`max_sequence` = `archived_through`),
26
+ CONSTRAINT `ck_relay_execution_event_archive_manifests_gaps` CHECK (`event_count` <= `archived_through` + 1),
27
+ CONSTRAINT `ck_relay_execution_event_archive_manifests_usage` CHECK (`usage_tokens` >= 0),
28
+ CONSTRAINT `ck_relay_execution_event_archive_manifests_schema` CHECK (`schema_version` = 1)
29
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
30
+ --> statement-breakpoint
31
+ CREATE TABLE IF NOT EXISTS `relay_execution_event_archive_blocks` (
32
+ `tenant_id` VARCHAR(191) NOT NULL DEFAULT 'system',
33
+ `execution_id` VARCHAR(191) NOT NULL,
34
+ `generation` INT NOT NULL,
35
+ `block_index` INT NOT NULL,
36
+ `first_sequence` INT NOT NULL,
37
+ `last_sequence` INT NOT NULL,
38
+ `event_count` INT NOT NULL,
39
+ `object_key` VARCHAR(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
40
+ `object_checksum` CHAR(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
41
+ `object_size` INT NOT NULL,
42
+ `codec_version` INT NOT NULL,
43
+ `encoding` VARCHAR(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
44
+ `compression` VARCHAR(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
45
+ `payload_checksum` CHAR(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
46
+ `stored_payload_bytes` INT NOT NULL,
47
+ `uncompressed_bytes` INT NOT NULL,
48
+ CONSTRAINT `pk_relay_execution_event_archive_blocks` PRIMARY KEY (`tenant_id`, `execution_id`, `generation`, `block_index`),
49
+ CONSTRAINT `fk_relay_execution_event_archive_blocks_manifest` FOREIGN KEY (`tenant_id`, `execution_id`, `generation`) REFERENCES `relay_execution_event_archive_manifests` (`tenant_id`, `execution_id`, `generation`),
50
+ CONSTRAINT `uq_relay_execution_event_archive_blocks_first` UNIQUE (`tenant_id`, `execution_id`, `generation`, `first_sequence`),
51
+ CONSTRAINT `ck_relay_execution_event_archive_blocks_index` CHECK (`block_index` >= 0),
52
+ CONSTRAINT `ck_relay_execution_event_archive_blocks_first` CHECK (`first_sequence` >= 0),
53
+ CONSTRAINT `ck_relay_execution_event_archive_blocks_bounds` CHECK (`last_sequence` >= `first_sequence`),
54
+ CONSTRAINT `ck_relay_execution_event_archive_blocks_count` CHECK (`event_count` > 0),
55
+ CONSTRAINT `ck_relay_execution_event_archive_blocks_count_limit` CHECK (`event_count` <= 4096),
56
+ CONSTRAINT `ck_relay_execution_event_archive_blocks_gaps` CHECK (`event_count` <= `last_sequence` - `first_sequence` + 1),
57
+ CONSTRAINT `ck_relay_execution_event_archive_blocks_object_size` CHECK (`object_size` > 0 AND `object_size` <= 16777216),
58
+ CONSTRAINT `ck_relay_execution_event_archive_blocks_stored_payload_size` CHECK (`stored_payload_bytes` > 0 AND `stored_payload_bytes` <= 15728640),
59
+ CONSTRAINT `ck_relay_execution_event_archive_blocks_uncompressed_size` CHECK (`uncompressed_bytes` > 0 AND `uncompressed_bytes` <= 15728640),
60
+ CONSTRAINT `ck_relay_execution_event_archive_blocks_stored_size` CHECK (`stored_payload_bytes` < `object_size`),
61
+ CONSTRAINT `ck_relay_execution_event_archive_blocks_expansion` CHECK (`stored_payload_bytes` <= `uncompressed_bytes`),
62
+ CONSTRAINT `ck_relay_execution_event_archive_blocks_codec` CHECK (`codec_version` IN (1, 2)),
63
+ CONSTRAINT `ck_relay_execution_event_archive_blocks_encoding` CHECK (`encoding` = 'json'),
64
+ CONSTRAINT `ck_relay_execution_event_archive_blocks_compression` CHECK ((`codec_version` = 1 AND `compression` = 'none' AND `stored_payload_bytes` = `uncompressed_bytes`) OR (`codec_version` = 2 AND `compression` = 'gzip'))
65
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
@@ -0,0 +1,20 @@
1
+ CREATE TABLE IF NOT EXISTS `relay_execution_event_identity_directory` (
2
+ `tenant_id` varchar(191) NOT NULL,
3
+ `cursor` varchar(512) COLLATE utf8mb4_bin NOT NULL,
4
+ `event_id` varchar(512) COLLATE utf8mb4_bin NOT NULL,
5
+ `execution_id` varchar(191) NOT NULL,
6
+ `sequence` int NOT NULL,
7
+ CONSTRAINT `pk_relay_execution_event_identity_directory` PRIMARY KEY (`tenant_id`, `cursor`),
8
+ CONSTRAINT `uq_relay_execution_event_identity_directory_event` UNIQUE (`tenant_id`, `event_id`),
9
+ CONSTRAINT `uq_relay_execution_event_identity_directory_sequence` UNIQUE (`tenant_id`, `execution_id`, `sequence`)
10
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
11
+ --> statement-breakpoint
12
+ LOCK TABLES
13
+ `relay_execution_events` WRITE,
14
+ `relay_execution_event_identity_directory` WRITE,
15
+ `relay_migrations` WRITE;
16
+ --> statement-breakpoint
17
+ DELETE FROM `relay_execution_event_identity_directory`;
18
+ --> statement-breakpoint
19
+ INSERT INTO `relay_execution_event_identity_directory` (`tenant_id`, `cursor`, `event_id`, `execution_id`, `sequence`)
20
+ SELECT `tenant_id`, `cursor`, `id`, `execution_id`, `sequence` FROM `relay_execution_events`;
@@ -0,0 +1,7 @@
1
+ ALTER TABLE `relay_steering_messages` ADD COLUMN `idempotency_key` varchar(191) COLLATE utf8mb4_bin;
2
+ --> statement-breakpoint
3
+ UPDATE `relay_steering_messages` SET `idempotency_key` = CONCAT('relay:legacy:', `kind`, ':', `sequence`);
4
+ --> statement-breakpoint
5
+ ALTER TABLE `relay_steering_messages` MODIFY COLUMN `idempotency_key` varchar(191) COLLATE utf8mb4_bin NOT NULL;
6
+ --> statement-breakpoint
7
+ CREATE UNIQUE INDEX `uq_relay_steering_messages_idempotency` ON `relay_steering_messages` (`tenant_id`, `execution_id`, `idempotency_key`);
@@ -0,0 +1,22 @@
1
+ CREATE TABLE "relay_execution_event_heads" (
2
+ "tenant_id" text DEFAULT 'system' NOT NULL,
3
+ "execution_id" text NOT NULL,
4
+ "next_sequence" integer DEFAULT 0 NOT NULL,
5
+ "max_sequence" integer,
6
+ "event_count" integer DEFAULT 0 NOT NULL,
7
+ "usage_tokens" bigint DEFAULT 0 NOT NULL,
8
+ CONSTRAINT "pk_relay_execution_event_heads" PRIMARY KEY("tenant_id","execution_id")
9
+ );
10
+ --> statement-breakpoint
11
+ -- Drizzle runs this migration in one transaction. SHARE ROW EXCLUSIVE blocks
12
+ -- legacy INSERT/UPDATE/DELETE writers while allowing ACCESS SHARE readers, so
13
+ -- the backfill and the newly created head rows become visible atomically.
14
+ LOCK TABLE "relay_executions", "relay_execution_events", "relay_execution_event_heads"
15
+ IN SHARE ROW EXCLUSIVE MODE;
16
+ --> statement-breakpoint
17
+ INSERT INTO "relay_execution_event_heads" ("tenant_id", "execution_id", "next_sequence", "max_sequence", "event_count", "usage_tokens")
18
+ SELECT execution."tenant_id", execution."id", COALESCE(MAX(event."sequence") + 1, 0), MAX(event."sequence"), COUNT(event."id"), COALESCE(SUM(CASE WHEN event."type" = 'model.usage.reported' THEN CASE WHEN jsonb_typeof(event."data_json" -> 'input_tokens') = 'number' THEN trunc((event."data_json" ->> 'input_tokens')::numeric)::bigint ELSE 0 END + CASE WHEN jsonb_typeof(event."data_json" -> 'output_tokens') = 'number' THEN trunc((event."data_json" ->> 'output_tokens')::numeric)::bigint ELSE 0 END ELSE 0 END), 0)
19
+ FROM "relay_executions" execution
20
+ LEFT JOIN "relay_execution_events" event
21
+ ON event."tenant_id" = execution."tenant_id" AND event."execution_id" = execution."id"
22
+ GROUP BY execution."tenant_id", execution."id";
@@ -0,0 +1,66 @@
1
+ ALTER TABLE "relay_execution_event_heads" ADD COLUMN "archived_through" integer;
2
+ --> statement-breakpoint
3
+ ALTER TABLE "relay_execution_event_heads" ADD COLUMN "archive_generation" integer;
4
+ --> statement-breakpoint
5
+ ALTER TABLE "relay_execution_event_heads" ADD CONSTRAINT "ck_relay_execution_event_heads_archive_pointer" CHECK (("archived_through" IS NULL) = ("archive_generation" IS NULL));
6
+ --> statement-breakpoint
7
+ CREATE TABLE "relay_execution_event_archive_manifests" (
8
+ "tenant_id" text DEFAULT 'system' NOT NULL,
9
+ "execution_id" text NOT NULL,
10
+ "generation" integer NOT NULL,
11
+ "archived_through" integer NOT NULL,
12
+ "event_count" integer NOT NULL,
13
+ "max_sequence" integer NOT NULL,
14
+ "usage_tokens" bigint NOT NULL,
15
+ "schema_version" integer NOT NULL,
16
+ CONSTRAINT "pk_relay_execution_event_archive_manifests" PRIMARY KEY("tenant_id","execution_id","generation"),
17
+ CONSTRAINT "ck_relay_execution_event_archive_manifests_generation" CHECK ("generation" > 0),
18
+ CONSTRAINT "ck_relay_execution_event_archive_manifests_frontier" CHECK ("archived_through" >= 0),
19
+ CONSTRAINT "ck_relay_execution_event_archive_manifests_count" CHECK ("event_count" > 0),
20
+ CONSTRAINT "ck_relay_execution_event_archive_manifests_max" CHECK ("max_sequence" = "archived_through"),
21
+ CONSTRAINT "ck_relay_execution_event_archive_manifests_gaps" CHECK ("event_count" <= "archived_through" + 1),
22
+ CONSTRAINT "ck_relay_execution_event_archive_manifests_usage" CHECK ("usage_tokens" >= 0),
23
+ CONSTRAINT "ck_relay_execution_event_archive_manifests_schema" CHECK ("schema_version" = 1)
24
+ );
25
+ --> statement-breakpoint
26
+ CREATE TABLE "relay_execution_event_archive_blocks" (
27
+ "tenant_id" text DEFAULT 'system' NOT NULL,
28
+ "execution_id" text NOT NULL,
29
+ "generation" integer NOT NULL,
30
+ "block_index" integer NOT NULL,
31
+ "first_sequence" integer NOT NULL,
32
+ "last_sequence" integer NOT NULL,
33
+ "event_count" integer NOT NULL,
34
+ "object_key" text NOT NULL,
35
+ "object_checksum" text NOT NULL,
36
+ "object_size" integer NOT NULL,
37
+ "codec_version" integer NOT NULL,
38
+ "encoding" text NOT NULL,
39
+ "compression" text NOT NULL,
40
+ "payload_checksum" text NOT NULL,
41
+ "stored_payload_bytes" integer NOT NULL,
42
+ "uncompressed_bytes" integer NOT NULL,
43
+ CONSTRAINT "pk_relay_execution_event_archive_blocks" PRIMARY KEY("tenant_id","execution_id","generation","block_index"),
44
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_index" CHECK ("block_index" >= 0),
45
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_first" CHECK ("first_sequence" >= 0),
46
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_bounds" CHECK ("last_sequence" >= "first_sequence"),
47
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_count" CHECK ("event_count" > 0),
48
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_count_limit" CHECK ("event_count" <= 4096),
49
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_gaps" CHECK ("event_count" <= "last_sequence" - "first_sequence" + 1),
50
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_object_size" CHECK ("object_size" > 0 AND "object_size" <= 16777216),
51
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_stored_payload_size" CHECK ("stored_payload_bytes" > 0 AND "stored_payload_bytes" <= 15728640),
52
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_uncompressed_size" CHECK ("uncompressed_bytes" > 0 AND "uncompressed_bytes" <= 15728640),
53
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_stored_size" CHECK ("stored_payload_bytes" < "object_size"),
54
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_expansion" CHECK ("stored_payload_bytes" <= "uncompressed_bytes"),
55
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_codec" CHECK ("codec_version" IN (1, 2)),
56
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_encoding" CHECK ("encoding" = 'json'),
57
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_compression" CHECK (("codec_version" = 1 AND "compression" = 'none' AND "stored_payload_bytes" = "uncompressed_bytes") OR ("codec_version" = 2 AND "compression" = 'gzip')),
58
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_object_key" CHECK (length("object_key") <= 80),
59
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_checksum" CHECK (length("object_checksum") = 64),
60
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_payload_checksum" CHECK (length("payload_checksum") = 64),
61
+ CONSTRAINT "uq_relay_execution_event_archive_blocks_first" UNIQUE("tenant_id","execution_id","generation","first_sequence")
62
+ );
63
+ --> statement-breakpoint
64
+ ALTER TABLE "relay_execution_event_archive_manifests" ADD CONSTRAINT "fk_relay_execution_event_archive_manifests_execution" FOREIGN KEY ("tenant_id","execution_id") REFERENCES "relay_executions"("tenant_id","id") ON DELETE no action ON UPDATE no action;
65
+ --> statement-breakpoint
66
+ ALTER TABLE "relay_execution_event_archive_blocks" ADD CONSTRAINT "fk_relay_execution_event_archive_blocks_manifest" FOREIGN KEY ("tenant_id","execution_id","generation") REFERENCES "relay_execution_event_archive_manifests"("tenant_id","execution_id","generation") ON DELETE no action ON UPDATE no action;
@@ -0,0 +1,15 @@
1
+ CREATE TABLE "relay_execution_event_identity_directory" (
2
+ "tenant_id" text NOT NULL,
3
+ "cursor" text NOT NULL,
4
+ "event_id" text NOT NULL,
5
+ "execution_id" text NOT NULL,
6
+ "sequence" integer NOT NULL,
7
+ CONSTRAINT "pk_relay_execution_event_identity_directory" PRIMARY KEY("tenant_id","cursor"),
8
+ CONSTRAINT "uq_relay_execution_event_identity_directory_event" UNIQUE("tenant_id","event_id"),
9
+ CONSTRAINT "uq_relay_execution_event_identity_directory_sequence" UNIQUE("tenant_id","execution_id","sequence")
10
+ );
11
+ --> statement-breakpoint
12
+ LOCK TABLE "relay_execution_events" IN SHARE ROW EXCLUSIVE MODE;
13
+ --> statement-breakpoint
14
+ INSERT INTO "relay_execution_event_identity_directory" ("tenant_id", "cursor", "event_id", "execution_id", "sequence")
15
+ SELECT "tenant_id", "cursor", "id", "execution_id", "sequence" FROM "relay_execution_events";
@@ -0,0 +1,7 @@
1
+ ALTER TABLE "relay_steering_messages" ADD COLUMN "idempotency_key" text;
2
+ --> statement-breakpoint
3
+ UPDATE "relay_steering_messages" SET "idempotency_key" = 'relay:legacy:' || "kind" || ':' || "sequence"::text;
4
+ --> statement-breakpoint
5
+ ALTER TABLE "relay_steering_messages" ALTER COLUMN "idempotency_key" SET NOT NULL;
6
+ --> statement-breakpoint
7
+ CREATE UNIQUE INDEX "uq_relay_steering_messages_idempotency" ON "relay_steering_messages" ("tenant_id", "execution_id", "idempotency_key");
@@ -0,0 +1,22 @@
1
+ CREATE TABLE "relay_execution_event_heads" (
2
+ "tenant_id" TEXT NOT NULL DEFAULT 'system',
3
+ "execution_id" TEXT NOT NULL,
4
+ "next_sequence" INTEGER NOT NULL DEFAULT 0,
5
+ "max_sequence" INTEGER,
6
+ "event_count" INTEGER NOT NULL DEFAULT 0,
7
+ "usage_tokens" INTEGER NOT NULL DEFAULT 0,
8
+ CONSTRAINT "pk_relay_execution_event_heads" PRIMARY KEY ("tenant_id", "execution_id")
9
+ );
10
+ --> statement-breakpoint
11
+ INSERT INTO "relay_execution_event_heads" ("tenant_id", "execution_id", "next_sequence", "max_sequence", "event_count", "usage_tokens")
12
+ SELECT execution."tenant_id", execution."id", COALESCE(MAX(event."sequence") + 1, 0), MAX(event."sequence"), COUNT(event."id"),
13
+ COALESCE(SUM(CASE WHEN event."type" = 'model.usage.reported' AND json_valid(event."data_json") THEN
14
+ CASE WHEN json_type(event."data_json", '$.input_tokens') IN ('integer', 'real')
15
+ THEN CAST(json_extract(event."data_json", '$.input_tokens') AS INTEGER) ELSE 0 END +
16
+ CASE WHEN json_type(event."data_json", '$.output_tokens') IN ('integer', 'real')
17
+ THEN CAST(json_extract(event."data_json", '$.output_tokens') AS INTEGER) ELSE 0 END
18
+ ELSE 0 END), 0)
19
+ FROM "relay_executions" execution
20
+ LEFT JOIN "relay_execution_events" event
21
+ ON event."tenant_id" = execution."tenant_id" AND event."execution_id" = execution."id"
22
+ GROUP BY execution."tenant_id", execution."id";
@@ -0,0 +1,45 @@
1
+ ALTER TABLE "relay_execution_event_heads" ADD COLUMN "archived_through" INTEGER;
2
+ --> statement-breakpoint
3
+ ALTER TABLE "relay_execution_event_heads" ADD COLUMN "archive_generation" INTEGER;
4
+ --> statement-breakpoint
5
+ CREATE TABLE "relay_execution_event_archive_manifests" (
6
+ "tenant_id" TEXT NOT NULL DEFAULT 'system',
7
+ "execution_id" TEXT NOT NULL,
8
+ "generation" INTEGER NOT NULL CHECK ("generation" > 0),
9
+ "archived_through" INTEGER NOT NULL CHECK ("archived_through" >= 0),
10
+ "event_count" INTEGER NOT NULL CHECK ("event_count" > 0),
11
+ "max_sequence" INTEGER NOT NULL,
12
+ "usage_tokens" INTEGER NOT NULL CHECK ("usage_tokens" >= 0),
13
+ "schema_version" INTEGER NOT NULL CHECK ("schema_version" = 1),
14
+ CONSTRAINT "pk_relay_execution_event_archive_manifests" PRIMARY KEY ("tenant_id", "execution_id", "generation"),
15
+ CONSTRAINT "fk_relay_execution_event_archive_manifests_execution" FOREIGN KEY ("tenant_id", "execution_id") REFERENCES "relay_executions" ("tenant_id", "id"),
16
+ CONSTRAINT "ck_relay_execution_event_archive_manifests_max" CHECK ("max_sequence" = "archived_through"),
17
+ CONSTRAINT "ck_relay_execution_event_archive_manifests_gaps" CHECK ("event_count" <= "archived_through" + 1)
18
+ );
19
+ --> statement-breakpoint
20
+ CREATE TABLE "relay_execution_event_archive_blocks" (
21
+ "tenant_id" TEXT NOT NULL DEFAULT 'system',
22
+ "execution_id" TEXT NOT NULL,
23
+ "generation" INTEGER NOT NULL,
24
+ "block_index" INTEGER NOT NULL CHECK ("block_index" >= 0),
25
+ "first_sequence" INTEGER NOT NULL CHECK ("first_sequence" >= 0),
26
+ "last_sequence" INTEGER NOT NULL,
27
+ "event_count" INTEGER NOT NULL CHECK ("event_count" > 0 AND "event_count" <= 4096),
28
+ "object_key" TEXT NOT NULL CHECK (length("object_key") <= 80),
29
+ "object_checksum" TEXT NOT NULL CHECK (length("object_checksum") = 64),
30
+ "object_size" INTEGER NOT NULL CHECK ("object_size" > 0 AND "object_size" <= 16777216),
31
+ "codec_version" INTEGER NOT NULL CHECK ("codec_version" IN (1, 2)),
32
+ "encoding" TEXT NOT NULL CHECK ("encoding" = 'json'),
33
+ "compression" TEXT NOT NULL,
34
+ "payload_checksum" TEXT NOT NULL CHECK (length("payload_checksum") = 64),
35
+ "stored_payload_bytes" INTEGER NOT NULL CHECK ("stored_payload_bytes" > 0 AND "stored_payload_bytes" <= 15728640),
36
+ "uncompressed_bytes" INTEGER NOT NULL CHECK ("uncompressed_bytes" > 0 AND "uncompressed_bytes" <= 15728640),
37
+ CONSTRAINT "pk_relay_execution_event_archive_blocks" PRIMARY KEY ("tenant_id", "execution_id", "generation", "block_index"),
38
+ CONSTRAINT "fk_relay_execution_event_archive_blocks_manifest" FOREIGN KEY ("tenant_id", "execution_id", "generation") REFERENCES "relay_execution_event_archive_manifests" ("tenant_id", "execution_id", "generation"),
39
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_bounds" CHECK ("last_sequence" >= "first_sequence"),
40
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_gaps" CHECK ("event_count" <= "last_sequence" - "first_sequence" + 1),
41
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_stored_size" CHECK ("stored_payload_bytes" < "object_size"),
42
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_expansion" CHECK ("stored_payload_bytes" <= "uncompressed_bytes"),
43
+ CONSTRAINT "ck_relay_execution_event_archive_blocks_compression" CHECK (("codec_version" = 1 AND "compression" = 'none' AND "stored_payload_bytes" = "uncompressed_bytes") OR ("codec_version" = 2 AND "compression" = 'gzip')),
44
+ CONSTRAINT "uq_relay_execution_event_archive_blocks_first" UNIQUE ("tenant_id", "execution_id", "generation", "first_sequence")
45
+ );
@@ -0,0 +1,13 @@
1
+ CREATE TABLE "relay_execution_event_identity_directory" (
2
+ "tenant_id" text NOT NULL,
3
+ "cursor" text NOT NULL,
4
+ "event_id" text NOT NULL,
5
+ "execution_id" text NOT NULL,
6
+ "sequence" integer NOT NULL,
7
+ CONSTRAINT "pk_relay_execution_event_identity_directory" PRIMARY KEY("tenant_id", "cursor"),
8
+ CONSTRAINT "uq_relay_execution_event_identity_directory_event" UNIQUE("tenant_id", "event_id"),
9
+ CONSTRAINT "uq_relay_execution_event_identity_directory_sequence" UNIQUE("tenant_id", "execution_id", "sequence")
10
+ );
11
+ --> statement-breakpoint
12
+ INSERT INTO "relay_execution_event_identity_directory" ("tenant_id", "cursor", "event_id", "execution_id", "sequence")
13
+ SELECT "tenant_id", "cursor", "id", "execution_id", "sequence" FROM "relay_execution_events";
@@ -0,0 +1,5 @@
1
+ ALTER TABLE "relay_steering_messages" ADD COLUMN "idempotency_key" text NOT NULL DEFAULT '';
2
+ --> statement-breakpoint
3
+ UPDATE "relay_steering_messages" SET "idempotency_key" = 'relay:legacy:' || "kind" || ':' || CAST("sequence" AS text);
4
+ --> statement-breakpoint
5
+ CREATE UNIQUE INDEX "uq_relay_steering_messages_idempotency" ON "relay_steering_messages" ("tenant_id", "execution_id", "idempotency_key");