openclaw / apps /shared /OpenClawKit /Sources /OpenClawChatUI /ClientDatabases+StateMigrations.swift
Download apps/shared/OpenClawKit/Sources/OpenClawChatUI/ClientDatabases+StateMigrations.swift from SaylorTwift/openclaw: direct link, hf CLI and curl.
- Browser
- Download file 8.48 kB
-
https://huggingface.co/SaylorTwift/openclaw/resolve/main/apps/shared/OpenClawKit/Sources/OpenClawChatUI/ClientDatabases%2BStateMigrations.swift
- Command line
-
hf download hf://SaylorTwift/openclaw/apps/shared/OpenClawKit/Sources/OpenClawChatUI/ClientDatabases+StateMigrations.swift
-
curl -L -o ClientDatabases+StateMigrations.swift https://huggingface.co/SaylorTwift/openclaw/resolve/main/apps/shared/OpenClawKit/Sources/OpenClawChatUI/ClientDatabases%2BStateMigrations.swift
8.48 kB
| import GRDB | |
| extension OpenClawClientDatabases { | |
| static func registerClientStateMigrationsV1ThroughV5(_ migrator: inout DatabaseMigrator) { | |
| migrator.registerMigration("client-state-v1") { db in | |
| try db.execute(sql: """ | |
| CREATE TABLE forgotten_gateways( | |
| gateway_hash TEXT NOT NULL PRIMARY KEY, | |
| gateway_id TEXT, | |
| forgotten_at REAL NOT NULL, | |
| cleanup_phase INTEGER NOT NULL CHECK(cleanup_phase IN (0, 1, 2, 3)), | |
| restore_finalized INTEGER NOT NULL DEFAULT 0 | |
| CHECK(restore_finalized IN (0, 1)), | |
| CHECK((cleanup_phase IN (1, 2) AND gateway_id IS NOT NULL) OR | |
| (cleanup_phase IN (0, 3) AND gateway_id IS NULL AND restore_finalized = 0)) | |
| ); | |
| CREATE TABLE gateway_routing_identity( | |
| gateway_id TEXT NOT NULL PRIMARY KEY, | |
| scope TEXT NOT NULL, | |
| main_session_key TEXT NOT NULL, | |
| default_agent_id TEXT NOT NULL, | |
| updated_at REAL NOT NULL | |
| ); | |
| CREATE TABLE outbox_commands( | |
| enqueue_sequence INTEGER PRIMARY KEY AUTOINCREMENT, | |
| gateway_id TEXT NOT NULL, | |
| client_uuid TEXT NOT NULL, | |
| session_key TEXT NOT NULL, | |
| delivery_session_key TEXT NOT NULL, | |
| routing_contract TEXT NOT NULL, | |
| agent_id TEXT NOT NULL, | |
| text TEXT NOT NULL, | |
| thinking TEXT NOT NULL, | |
| created_at REAL NOT NULL, | |
| status TEXT NOT NULL CHECK(status IN ( | |
| 'queued', 'sending', 'awaiting_confirmation', 'failed' | |
| )), | |
| retry_count INTEGER NOT NULL DEFAULT 0, | |
| last_error TEXT NOT NULL DEFAULT '', | |
| attachment_bytes INTEGER NOT NULL DEFAULT 0, | |
| UNIQUE(gateway_id, client_uuid) | |
| ); | |
| CREATE INDEX outbox_commands_delivery_order | |
| ON outbox_commands(gateway_id, created_at, enqueue_sequence); | |
| CREATE TABLE outbox_attachments( | |
| gateway_id TEXT NOT NULL, | |
| command_id TEXT NOT NULL, | |
| position INTEGER NOT NULL, | |
| type TEXT NOT NULL, | |
| mime_type TEXT NOT NULL, | |
| file_name TEXT NOT NULL, | |
| payload BLOB NOT NULL, | |
| duration_seconds REAL, | |
| PRIMARY KEY(gateway_id, command_id, position), | |
| FOREIGN KEY(gateway_id, command_id) | |
| REFERENCES outbox_commands(gateway_id, client_uuid) | |
| ON DELETE CASCADE | |
| ON UPDATE CASCADE | |
| ); | |
| """) | |
| } | |
| // Additive branch ownership remains local client state. Older app | |
| // builds ignore these fields while newer builds fail replay closed. | |
| migrator.registerMigration("client-state-branch-ownership-v2") { db in | |
| try db.execute(sql: """ | |
| ALTER TABLE outbox_commands ADD COLUMN branch_epoch INTEGER NOT NULL DEFAULT 0; | |
| ALTER TABLE outbox_commands ADD COLUMN attempt_version INTEGER NOT NULL DEFAULT 1; | |
| ALTER TABLE outbox_commands ADD COLUMN parked_was_accepted INTEGER NOT NULL DEFAULT 0; | |
| CREATE TABLE outbox_branch_scopes( | |
| gateway_id TEXT NOT NULL, | |
| session_key TEXT NOT NULL, | |
| agent_id TEXT NOT NULL DEFAULT '', | |
| branch_epoch INTEGER NOT NULL DEFAULT 0, | |
| last_active_leaf_id TEXT, | |
| switch_pending_since REAL, | |
| needs_reconciliation INTEGER NOT NULL DEFAULT 0, | |
| PRIMARY KEY(gateway_id, session_key, agent_id) | |
| ); | |
| """) | |
| } | |
| migrator.registerMigration("client-state-branch-revision-v3") { db in | |
| try db.execute(sql: """ | |
| ALTER TABLE outbox_branch_scopes | |
| ADD COLUMN branch_state_revision INTEGER NOT NULL DEFAULT 0; | |
| """) | |
| } | |
| migrator.registerMigration("client-state-agent-id-v4") { db in | |
| try db.execute(sql: "UPDATE outbox_commands SET agent_id = '' WHERE agent_id IS NULL") | |
| try db.execute(sql: "UPDATE outbox_branch_scopes SET agent_id = '' WHERE agent_id IS NULL") | |
| } | |
| migrator.registerMigration("client-state-outbox-attempt-scope-v5") { db in | |
| try db | |
| .execute( | |
| sql: "ALTER TABLE outbox_commands ADD COLUMN had_unacknowledged_send INTEGER NOT NULL DEFAULT 0") | |
| // Legacy rows with prior attempts may have reached the gateway before a | |
| // transport failure; without this evidence a post-park retry would reuse an | |
| // idempotency key the old branch may already own. | |
| try db.execute( | |
| sql: """ | |
| UPDATE outbox_commands SET had_unacknowledged_send = 1 | |
| WHERE retry_count > 0 OR status IN ('sending', 'awaiting_confirmation') | |
| """) | |
| try db.execute(sql: """ | |
| INSERT OR IGNORE INTO outbox_branch_scopes( | |
| gateway_id, session_key, agent_id, branch_epoch, needs_reconciliation | |
| ) | |
| SELECT gateway_id, session_key, agent_id, 0, 1 FROM outbox_commands | |
| """) | |
| } | |
| } | |
| static func registerClientStateMigrationsV6ThroughV8(_ migrator: inout DatabaseMigrator) { | |
| migrator.registerMigration("client-state-outbox-attachment-rekey-v6") { db in | |
| try db.execute(sql: """ | |
| CREATE TABLE outbox_attachments_v6( | |
| gateway_id TEXT NOT NULL, | |
| command_id TEXT NOT NULL, | |
| position INTEGER NOT NULL, | |
| type TEXT NOT NULL, | |
| mime_type TEXT NOT NULL, | |
| file_name TEXT NOT NULL, | |
| payload BLOB NOT NULL, | |
| duration_seconds REAL, | |
| PRIMARY KEY(gateway_id, command_id, position), | |
| FOREIGN KEY(gateway_id, command_id) | |
| REFERENCES outbox_commands(gateway_id, client_uuid) | |
| ON DELETE CASCADE | |
| ON UPDATE CASCADE | |
| ); | |
| INSERT INTO outbox_attachments_v6( | |
| gateway_id, command_id, position, type, mime_type, file_name, payload, duration_seconds | |
| ) | |
| SELECT gateway_id, command_id, position, type, mime_type, file_name, payload, duration_seconds | |
| FROM outbox_attachments; | |
| DROP TABLE outbox_attachments; | |
| ALTER TABLE outbox_attachments_v6 RENAME TO outbox_attachments; | |
| """) | |
| } | |
| // A queued command owns the authority it was captured under. Legacy | |
| // rows remain NULL so CAS-capable replay can park them for review. | |
| migrator.registerMigration("client-state-outbox-settings-expectation-v7") { db in | |
| try db.execute(sql: """ | |
| ALTER TABLE outbox_commands ADD COLUMN expected_settings_json TEXT; | |
| """) | |
| } | |
| migrator.registerMigration("client-state-outbox-settings-claim-v8") { db in | |
| try db.execute(sql: """ | |
| ALTER TABLE outbox_commands ADD COLUMN settings_retry_authorization INTEGER; | |
| CREATE TRIGGER outbox_settings_claim_guard | |
| BEFORE UPDATE OF status ON outbox_commands | |
| WHEN OLD.status = 'queued' AND NEW.status = 'sending' | |
| AND COALESCE(NEW.settings_retry_authorization, 0) = | |
| COALESCE(OLD.settings_retry_authorization, 0) | |
| BEGIN | |
| UPDATE outbox_commands | |
| SET status = 'failed', last_error = 'settings_client_upgrade_required' | |
| WHERE gateway_id = OLD.gateway_id AND client_uuid = OLD.client_uuid | |
| AND status = 'queued'; | |
| SELECT RAISE(IGNORE); | |
| END; | |
| CREATE TRIGGER outbox_settings_retry_guard | |
| BEFORE UPDATE OF status ON outbox_commands | |
| WHEN OLD.status = 'failed' AND NEW.status = 'queued' | |
| AND COALESCE(NEW.settings_retry_authorization, 0) = | |
| COALESCE(OLD.settings_retry_authorization, 0) | |
| BEGIN | |
| SELECT RAISE(ABORT, 'settings-fenced outbox retry requires current client'); | |
| END; | |
| """) | |
| } | |
| } | |
| } | |