repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
public Clawd ADK gateway launch mirror
stars
latest
clone command
git clone gitlawb://did:key:z6Mkq5mY...iFZ5/my-project-publ...git clone gitlawb://did:key:z6Mkq5mY.../my-project-publ...2fa351d6docs: add automaton and perps launch sources16d ago| #1 | /** |
| #2 | * Automaton Database |
| #3 | * |
| #4 | * SQLite-backed persistent state for the automaton. |
| #5 | * Uses better-sqlite3 for synchronous, single-process access. |
| #6 | */ |
| #7 | |
| #8 | import Database from "better-sqlite3"; |
| #9 | import fs from "fs"; |
| #10 | import path from "path"; |
| #11 | import type { |
| #12 | AutomatonDatabase, |
| #13 | AgentTurn, |
| #14 | AgentState, |
| #15 | ToolCallResult, |
| #16 | HeartbeatEntry, |
| #17 | Transaction, |
| #18 | InstalledTool, |
| #19 | ModificationEntry, |
| #20 | Skill, |
| #21 | ChildAutomaton, |
| #22 | ChildStatus, |
| #23 | RegistryEntry, |
| #24 | ReputationEntry, |
| #25 | InboxMessage, |
| #26 | } from "../types.js"; |
| #27 | import { SCHEMA_VERSION, CREATE_TABLES, MIGRATION_V2, MIGRATION_V3 } from "./schema.js"; |
| #28 | |
| #29 | export function createDatabase(dbPath: string): AutomatonDatabase { |
| #30 | // Ensure directory exists |
| #31 | const dir = path.dirname(dbPath); |
| #32 | if (!fs.existsSync(dir)) { |
| #33 | fs.mkdirSync(dir, { recursive: true, mode: 0o700 }); |
| #34 | } |
| #35 | |
| #36 | const db = new Database(dbPath); |
| #37 | |
| #38 | // Enable WAL mode for better concurrent read performance |
| #39 | db.pragma("journal_mode = WAL"); |
| #40 | db.pragma("foreign_keys = ON"); |
| #41 | |
| #42 | // Initialize schema |
| #43 | db.exec(CREATE_TABLES); |
| #44 | |
| #45 | // Check and apply schema version |
| #46 | const versionRow = db |
| #47 | .prepare("SELECT MAX(version) as v FROM schema_version") |
| #48 | .get() as { v: number | null } | undefined; |
| #49 | const currentVersion = versionRow?.v ?? 0; |
| #50 | |
| #51 | if (currentVersion < 2) { |
| #52 | db.exec(MIGRATION_V2); |
| #53 | } |
| #54 | |
| #55 | if (currentVersion < 3) { |
| #56 | db.exec(MIGRATION_V3); |
| #57 | } |
| #58 | |
| #59 | if (currentVersion < SCHEMA_VERSION) { |
| #60 | db.prepare( |
| #61 | "INSERT OR REPLACE INTO schema_version (version, applied_at) VALUES (?, datetime('now'))", |
| #62 | ).run(SCHEMA_VERSION); |
| #63 | } |
| #64 | |
| #65 | // ─── Identity ──────────────────────────────────────────────── |
| #66 | |
| #67 | const getIdentity = (key: string): string | undefined => { |
| #68 | const row = db |
| #69 | .prepare("SELECT value FROM identity WHERE key = ?") |
| #70 | .get(key) as { value: string } | undefined; |
| #71 | return row?.value; |
| #72 | }; |
| #73 | |
| #74 | const setIdentity = (key: string, value: string): void => { |
| #75 | db.prepare( |
| #76 | "INSERT OR REPLACE INTO identity (key, value) VALUES (?, ?)", |
| #77 | ).run(key, value); |
| #78 | }; |
| #79 | |
| #80 | // ─── Turns ─────────────────────────────────────────────────── |
| #81 | |
| #82 | const insertTurn = (turn: AgentTurn): void => { |
| #83 | db.prepare( |
| #84 | `INSERT INTO turns (id, timestamp, state, input, input_source, thinking, tool_calls, token_usage, cost_cents) |
| #85 | VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, |
| #86 | ).run( |
| #87 | turn.id, |
| #88 | turn.timestamp, |
| #89 | turn.state, |
| #90 | turn.input ?? null, |
| #91 | turn.inputSource ?? null, |
| #92 | turn.thinking, |
| #93 | JSON.stringify(turn.toolCalls), |
| #94 | JSON.stringify(turn.tokenUsage), |
| #95 | turn.costCents, |
| #96 | ); |
| #97 | }; |
| #98 | |
| #99 | const getRecentTurns = (limit: number): AgentTurn[] => { |
| #100 | const rows = db |
| #101 | .prepare( |
| #102 | "SELECT * FROM turns ORDER BY timestamp DESC LIMIT ?", |
| #103 | ) |
| #104 | .all(limit) as any[]; |
| #105 | return rows.map(deserializeTurn).reverse(); |
| #106 | }; |
| #107 | |
| #108 | const getTurnById = (id: string): AgentTurn | undefined => { |
| #109 | const row = db |
| #110 | .prepare("SELECT * FROM turns WHERE id = ?") |
| #111 | .get(id) as any | undefined; |
| #112 | return row ? deserializeTurn(row) : undefined; |
| #113 | }; |
| #114 | |
| #115 | const getTurnCount = (): number => { |
| #116 | const row = db |
| #117 | .prepare("SELECT COUNT(*) as count FROM turns") |
| #118 | .get() as { count: number }; |
| #119 | return row.count; |
| #120 | }; |
| #121 | |
| #122 | // ─── Tool Calls ────────────────────────────────────────────── |
| #123 | |
| #124 | const insertToolCall = ( |
| #125 | turnId: string, |
| #126 | call: ToolCallResult, |
| #127 | ): void => { |
| #128 | db.prepare( |
| #129 | `INSERT INTO tool_calls (id, turn_id, name, arguments, result, duration_ms, error) |
| #130 | VALUES (?, ?, ?, ?, ?, ?, ?)`, |
| #131 | ).run( |
| #132 | call.id, |
| #133 | turnId, |
| #134 | call.name, |
| #135 | JSON.stringify(call.arguments), |
| #136 | call.result, |
| #137 | call.durationMs, |
| #138 | call.error ?? null, |
| #139 | ); |
| #140 | }; |
| #141 | |
| #142 | const getToolCallsForTurn = (turnId: string): ToolCallResult[] => { |
| #143 | const rows = db |
| #144 | .prepare("SELECT * FROM tool_calls WHERE turn_id = ?") |
| #145 | .all(turnId) as any[]; |
| #146 | return rows.map(deserializeToolCall); |
| #147 | }; |
| #148 | |
| #149 | // ─── Heartbeat ─────────────────────────────────────────────── |
| #150 | |
| #151 | const getHeartbeatEntries = (): HeartbeatEntry[] => { |
| #152 | const rows = db |
| #153 | .prepare("SELECT * FROM heartbeat_entries") |
| #154 | .all() as any[]; |
| #155 | return rows.map(deserializeHeartbeatEntry); |
| #156 | }; |
| #157 | |
| #158 | const upsertHeartbeatEntry = (entry: HeartbeatEntry): void => { |
| #159 | db.prepare( |
| #160 | `INSERT OR REPLACE INTO heartbeat_entries (name, schedule, task, enabled, last_run, next_run, params, updated_at) |
| #161 | VALUES (?, ?, ?, ?, ?, ?, ?, datetime('now'))`, |
| #162 | ).run( |
| #163 | entry.name, |
| #164 | entry.schedule, |
| #165 | entry.task, |
| #166 | entry.enabled ? 1 : 0, |
| #167 | entry.lastRun ?? null, |
| #168 | entry.nextRun ?? null, |
| #169 | JSON.stringify(entry.params ?? {}), |
| #170 | ); |
| #171 | }; |
| #172 | |
| #173 | const updateHeartbeatLastRun = ( |
| #174 | name: string, |
| #175 | timestamp: string, |
| #176 | ): void => { |
| #177 | db.prepare( |
| #178 | "UPDATE heartbeat_entries SET last_run = ?, updated_at = datetime('now') WHERE name = ?", |
| #179 | ).run(timestamp, name); |
| #180 | }; |
| #181 | |
| #182 | // ─── Transactions ──────────────────────────────────────────── |
| #183 | |
| #184 | const insertTransaction = (txn: Transaction): void => { |
| #185 | db.prepare( |
| #186 | `INSERT INTO transactions (id, type, amount_cents, balance_after_cents, description) |
| #187 | VALUES (?, ?, ?, ?, ?)`, |
| #188 | ).run( |
| #189 | txn.id, |
| #190 | txn.type, |
| #191 | txn.amountCents ?? null, |
| #192 | txn.balanceAfterCents ?? null, |
| #193 | txn.description, |
| #194 | ); |
| #195 | }; |
| #196 | |
| #197 | const getRecentTransactions = (limit: number): Transaction[] => { |
| #198 | const rows = db |
| #199 | .prepare( |
| #200 | "SELECT * FROM transactions ORDER BY created_at DESC LIMIT ?", |
| #201 | ) |
| #202 | .all(limit) as any[]; |
| #203 | return rows.map(deserializeTransaction).reverse(); |
| #204 | }; |
| #205 | |
| #206 | // ─── Installed Tools ───────────────────────────────────────── |
| #207 | |
| #208 | const getInstalledTools = (): InstalledTool[] => { |
| #209 | const rows = db |
| #210 | .prepare("SELECT * FROM installed_tools WHERE enabled = 1") |
| #211 | .all() as any[]; |
| #212 | return rows.map(deserializeInstalledTool); |
| #213 | }; |
| #214 | |
| #215 | const installTool = (tool: InstalledTool): void => { |
| #216 | db.prepare( |
| #217 | `INSERT OR REPLACE INTO installed_tools (id, name, type, config, installed_at, enabled) |
| #218 | VALUES (?, ?, ?, ?, ?, ?)`, |
| #219 | ).run( |
| #220 | tool.id, |
| #221 | tool.name, |
| #222 | tool.type, |
| #223 | JSON.stringify(tool.config ?? {}), |
| #224 | tool.installedAt, |
| #225 | tool.enabled ? 1 : 0, |
| #226 | ); |
| #227 | }; |
| #228 | |
| #229 | const removeTool = (id: string): void => { |
| #230 | db.prepare( |
| #231 | "UPDATE installed_tools SET enabled = 0 WHERE id = ?", |
| #232 | ).run(id); |
| #233 | }; |
| #234 | |
| #235 | // ─── Modifications ─────────────────────────────────────────── |
| #236 | |
| #237 | const insertModification = (mod: ModificationEntry): void => { |
| #238 | db.prepare( |
| #239 | `INSERT INTO modifications (id, timestamp, type, description, file_path, diff, reversible) |
| #240 | VALUES (?, ?, ?, ?, ?, ?, ?)`, |
| #241 | ).run( |
| #242 | mod.id, |
| #243 | mod.timestamp, |
| #244 | mod.type, |
| #245 | mod.description, |
| #246 | mod.filePath ?? null, |
| #247 | mod.diff ?? null, |
| #248 | mod.reversible ? 1 : 0, |
| #249 | ); |
| #250 | }; |
| #251 | |
| #252 | const getRecentModifications = ( |
| #253 | limit: number, |
| #254 | ): ModificationEntry[] => { |
| #255 | const rows = db |
| #256 | .prepare( |
| #257 | "SELECT * FROM modifications ORDER BY timestamp DESC LIMIT ?", |
| #258 | ) |
| #259 | .all(limit) as any[]; |
| #260 | return rows.map(deserializeModification).reverse(); |
| #261 | }; |
| #262 | |
| #263 | // ─── Key-Value Store ───────────────────────────────────────── |
| #264 | |
| #265 | const getKV = (key: string): string | undefined => { |
| #266 | const row = db |
| #267 | .prepare("SELECT value FROM kv WHERE key = ?") |
| #268 | .get(key) as { value: string } | undefined; |
| #269 | return row?.value; |
| #270 | }; |
| #271 | |
| #272 | const setKV = (key: string, value: string): void => { |
| #273 | db.prepare( |
| #274 | "INSERT OR REPLACE INTO kv (key, value, updated_at) VALUES (?, ?, datetime('now'))", |
| #275 | ).run(key, value); |
| #276 | }; |
| #277 | |
| #278 | const deleteKV = (key: string): void => { |
| #279 | db.prepare("DELETE FROM kv WHERE key = ?").run(key); |
| #280 | }; |
| #281 | |
| #282 | // ─── Skills ───────────────────────────────────────────────── |
| #283 | |
| #284 | const getSkills = (enabledOnly?: boolean): Skill[] => { |
| #285 | const query = enabledOnly |
| #286 | ? "SELECT * FROM skills WHERE enabled = 1" |
| #287 | : "SELECT * FROM skills"; |
| #288 | const rows = db.prepare(query).all() as any[]; |
| #289 | return rows.map(deserializeSkill); |
| #290 | }; |
| #291 | |
| #292 | const getSkillByName = (name: string): Skill | undefined => { |
| #293 | const row = db |
| #294 | .prepare("SELECT * FROM skills WHERE name = ?") |
| #295 | .get(name) as any | undefined; |
| #296 | return row ? deserializeSkill(row) : undefined; |
| #297 | }; |
| #298 | |
| #299 | const upsertSkill = (skill: Skill): void => { |
| #300 | db.prepare( |
| #301 | `INSERT OR REPLACE INTO skills (name, description, auto_activate, requires, instructions, source, path, enabled, installed_at) |
| #302 | VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, |
| #303 | ).run( |
| #304 | skill.name, |
| #305 | skill.description, |
| #306 | skill.autoActivate ? 1 : 0, |
| #307 | JSON.stringify(skill.requires ?? {}), |
| #308 | skill.instructions, |
| #309 | skill.source, |
| #310 | skill.path, |
| #311 | skill.enabled ? 1 : 0, |
| #312 | skill.installedAt, |
| #313 | ); |
| #314 | }; |
| #315 | |
| #316 | const removeSkill = (name: string): void => { |
| #317 | db.prepare("UPDATE skills SET enabled = 0 WHERE name = ?").run(name); |
| #318 | }; |
| #319 | |
| #320 | // ─── Children ────────────────────────────────────────────── |
| #321 | |
| #322 | const getChildren = (): ChildAutomaton[] => { |
| #323 | const rows = db |
| #324 | .prepare("SELECT * FROM children ORDER BY created_at DESC") |
| #325 | .all() as any[]; |
| #326 | return rows.map(deserializeChild); |
| #327 | }; |
| #328 | |
| #329 | const getChildById = (id: string): ChildAutomaton | undefined => { |
| #330 | const row = db |
| #331 | .prepare("SELECT * FROM children WHERE id = ?") |
| #332 | .get(id) as any | undefined; |
| #333 | return row ? deserializeChild(row) : undefined; |
| #334 | }; |
| #335 | |
| #336 | const insertChild = (child: ChildAutomaton): void => { |
| #337 | db.prepare( |
| #338 | `INSERT INTO children (id, name, address, sandbox_id, genesis_prompt, creator_message, funded_amount_cents, status, created_at) |
| #339 | VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, |
| #340 | ).run( |
| #341 | child.id, |
| #342 | child.name, |
| #343 | child.address, |
| #344 | child.sandboxId, |
| #345 | child.genesisPrompt, |
| #346 | child.creatorMessage ?? null, |
| #347 | child.fundedAmountCents, |
| #348 | child.status, |
| #349 | child.createdAt, |
| #350 | ); |
| #351 | }; |
| #352 | |
| #353 | const updateChildStatus = (id: string, status: ChildStatus): void => { |
| #354 | db.prepare( |
| #355 | "UPDATE children SET status = ?, last_checked = datetime('now') WHERE id = ?", |
| #356 | ).run(status, id); |
| #357 | }; |
| #358 | |
| #359 | // ─── Registry ────────────────────────────────────────────── |
| #360 | |
| #361 | const getRegistryEntry = (): RegistryEntry | undefined => { |
| #362 | const row = db |
| #363 | .prepare("SELECT * FROM registry LIMIT 1") |
| #364 | .get() as any | undefined; |
| #365 | return row ? deserializeRegistry(row) : undefined; |
| #366 | }; |
| #367 | |
| #368 | const setRegistryEntry = (entry: RegistryEntry): void => { |
| #369 | db.prepare( |
| #370 | `INSERT OR REPLACE INTO registry (agent_id, agent_uri, chain, contract_address, tx_hash, registered_at) |
| #371 | VALUES (?, ?, ?, ?, ?, ?)`, |
| #372 | ).run( |
| #373 | entry.agentId, |
| #374 | entry.agentURI, |
| #375 | entry.chain, |
| #376 | entry.contractAddress, |
| #377 | entry.txHash, |
| #378 | entry.registeredAt, |
| #379 | ); |
| #380 | }; |
| #381 | |
| #382 | // ─── Reputation ──────────────────────────────────────────── |
| #383 | |
| #384 | const insertReputation = (entry: ReputationEntry): void => { |
| #385 | db.prepare( |
| #386 | `INSERT INTO reputation (id, from_agent, to_agent, score, comment, tx_hash) |
| #387 | VALUES (?, ?, ?, ?, ?, ?)`, |
| #388 | ).run( |
| #389 | entry.id, |
| #390 | entry.fromAgent, |
| #391 | entry.toAgent, |
| #392 | entry.score, |
| #393 | entry.comment, |
| #394 | entry.txHash ?? null, |
| #395 | ); |
| #396 | }; |
| #397 | |
| #398 | const getReputation = (agentAddress?: string): ReputationEntry[] => { |
| #399 | const query = agentAddress |
| #400 | ? "SELECT * FROM reputation WHERE to_agent = ? ORDER BY created_at DESC" |
| #401 | : "SELECT * FROM reputation ORDER BY created_at DESC"; |
| #402 | const params = agentAddress ? [agentAddress] : []; |
| #403 | const rows = db.prepare(query).all(...params) as any[]; |
| #404 | return rows.map(deserializeReputation); |
| #405 | }; |
| #406 | |
| #407 | // ─── Inbox Messages ────────────────────────────────────────── |
| #408 | |
| #409 | const insertInboxMessage = (msg: InboxMessage): void => { |
| #410 | db.prepare( |
| #411 | `INSERT OR IGNORE INTO inbox_messages (id, from_address, content, received_at, reply_to) |
| #412 | VALUES (?, ?, ?, ?, ?)`, |
| #413 | ).run( |
| #414 | msg.id, |
| #415 | msg.from, |
| #416 | msg.content, |
| #417 | msg.createdAt || new Date().toISOString(), |
| #418 | msg.replyTo ?? null, |
| #419 | ); |
| #420 | }; |
| #421 | |
| #422 | const getUnprocessedInboxMessages = (limit: number): InboxMessage[] => { |
| #423 | const rows = db |
| #424 | .prepare( |
| #425 | "SELECT * FROM inbox_messages WHERE processed_at IS NULL ORDER BY received_at ASC LIMIT ?", |
| #426 | ) |
| #427 | .all(limit) as any[]; |
| #428 | return rows.map(deserializeInboxMessage); |
| #429 | }; |
| #430 | |
| #431 | const markInboxMessageProcessed = (id: string): void => { |
| #432 | db.prepare( |
| #433 | "UPDATE inbox_messages SET processed_at = datetime('now') WHERE id = ?", |
| #434 | ).run(id); |
| #435 | }; |
| #436 | |
| #437 | // ─── Agent State ───────────────────────────────────────────── |
| #438 | |
| #439 | const getAgentState = (): AgentState => { |
| #440 | return (getKV("agent_state") as AgentState) || "setup"; |
| #441 | }; |
| #442 | |
| #443 | const setAgentState = (state: AgentState): void => { |
| #444 | setKV("agent_state", state); |
| #445 | }; |
| #446 | |
| #447 | // ─── Close ─────────────────────────────────────────────────── |
| #448 | |
| #449 | const close = (): void => { |
| #450 | db.close(); |
| #451 | }; |
| #452 | |
| #453 | return { |
| #454 | getIdentity, |
| #455 | setIdentity, |
| #456 | insertTurn, |
| #457 | getRecentTurns, |
| #458 | getTurnById, |
| #459 | getTurnCount, |
| #460 | insertToolCall, |
| #461 | getToolCallsForTurn, |
| #462 | getHeartbeatEntries, |
| #463 | upsertHeartbeatEntry, |
| #464 | updateHeartbeatLastRun, |
| #465 | insertTransaction, |
| #466 | getRecentTransactions, |
| #467 | getInstalledTools, |
| #468 | installTool, |
| #469 | removeTool, |
| #470 | insertModification, |
| #471 | getRecentModifications, |
| #472 | getKV, |
| #473 | setKV, |
| #474 | deleteKV, |
| #475 | getSkills, |
| #476 | getSkillByName, |
| #477 | upsertSkill, |
| #478 | removeSkill, |
| #479 | getChildren, |
| #480 | getChildById, |
| #481 | insertChild, |
| #482 | updateChildStatus, |
| #483 | getRegistryEntry, |
| #484 | setRegistryEntry, |
| #485 | insertReputation, |
| #486 | getReputation, |
| #487 | insertInboxMessage, |
| #488 | getUnprocessedInboxMessages, |
| #489 | markInboxMessageProcessed, |
| #490 | getAgentState, |
| #491 | setAgentState, |
| #492 | close, |
| #493 | }; |
| #494 | } |
| #495 | |
| #496 | // ─── Deserializers ───────────────────────────────────────────── |
| #497 | |
| #498 | function deserializeTurn(row: any): AgentTurn { |
| #499 | return { |
| #500 | id: row.id, |
| #501 | timestamp: row.timestamp, |
| #502 | state: row.state, |
| #503 | input: row.input ?? undefined, |
| #504 | inputSource: row.input_source ?? undefined, |
| #505 | thinking: row.thinking, |
| #506 | toolCalls: JSON.parse(row.tool_calls || "[]"), |
| #507 | tokenUsage: JSON.parse(row.token_usage || "{}"), |
| #508 | costCents: row.cost_cents, |
| #509 | }; |
| #510 | } |
| #511 | |
| #512 | function deserializeToolCall(row: any): ToolCallResult { |
| #513 | return { |
| #514 | id: row.id, |
| #515 | name: row.name, |
| #516 | arguments: JSON.parse(row.arguments || "{}"), |
| #517 | result: row.result, |
| #518 | durationMs: row.duration_ms, |
| #519 | error: row.error ?? undefined, |
| #520 | }; |
| #521 | } |
| #522 | |
| #523 | function deserializeHeartbeatEntry(row: any): HeartbeatEntry { |
| #524 | return { |
| #525 | name: row.name, |
| #526 | schedule: row.schedule, |
| #527 | task: row.task, |
| #528 | enabled: !!row.enabled, |
| #529 | lastRun: row.last_run ?? undefined, |
| #530 | nextRun: row.next_run ?? undefined, |
| #531 | params: JSON.parse(row.params || "{}"), |
| #532 | }; |
| #533 | } |
| #534 | |
| #535 | function deserializeTransaction(row: any): Transaction { |
| #536 | return { |
| #537 | id: row.id, |
| #538 | type: row.type, |
| #539 | amountCents: row.amount_cents ?? undefined, |
| #540 | balanceAfterCents: row.balance_after_cents ?? undefined, |
| #541 | description: row.description, |
| #542 | timestamp: row.created_at, |
| #543 | }; |
| #544 | } |
| #545 | |
| #546 | function deserializeInstalledTool(row: any): InstalledTool { |
| #547 | return { |
| #548 | id: row.id, |
| #549 | name: row.name, |
| #550 | type: row.type, |
| #551 | config: JSON.parse(row.config || "{}"), |
| #552 | installedAt: row.installed_at, |
| #553 | enabled: !!row.enabled, |
| #554 | }; |
| #555 | } |
| #556 | |
| #557 | function deserializeModification(row: any): ModificationEntry { |
| #558 | return { |
| #559 | id: row.id, |
| #560 | timestamp: row.timestamp, |
| #561 | type: row.type, |
| #562 | description: row.description, |
| #563 | filePath: row.file_path ?? undefined, |
| #564 | diff: row.diff ?? undefined, |
| #565 | reversible: !!row.reversible, |
| #566 | }; |
| #567 | } |
| #568 | |
| #569 | function deserializeSkill(row: any): Skill { |
| #570 | return { |
| #571 | name: row.name, |
| #572 | description: row.description, |
| #573 | autoActivate: !!row.auto_activate, |
| #574 | requires: JSON.parse(row.requires || "{}"), |
| #575 | instructions: row.instructions, |
| #576 | source: row.source, |
| #577 | path: row.path, |
| #578 | enabled: !!row.enabled, |
| #579 | installedAt: row.installed_at, |
| #580 | }; |
| #581 | } |
| #582 | |
| #583 | function deserializeChild(row: any): ChildAutomaton { |
| #584 | return { |
| #585 | id: row.id, |
| #586 | name: row.name, |
| #587 | address: row.address, |
| #588 | sandboxId: row.sandbox_id, |
| #589 | genesisPrompt: row.genesis_prompt, |
| #590 | creatorMessage: row.creator_message ?? undefined, |
| #591 | fundedAmountCents: row.funded_amount_cents, |
| #592 | status: row.status, |
| #593 | createdAt: row.created_at, |
| #594 | lastChecked: row.last_checked ?? undefined, |
| #595 | }; |
| #596 | } |
| #597 | |
| #598 | function deserializeRegistry(row: any): RegistryEntry { |
| #599 | return { |
| #600 | agentId: row.agent_id, |
| #601 | agentURI: row.agent_uri, |
| #602 | chain: row.chain, |
| #603 | contractAddress: row.contract_address, |
| #604 | txHash: row.tx_hash, |
| #605 | registeredAt: row.registered_at, |
| #606 | }; |
| #607 | } |
| #608 | |
| #609 | function deserializeInboxMessage(row: any): InboxMessage { |
| #610 | return { |
| #611 | id: row.id, |
| #612 | from: row.from_address, |
| #613 | to: "", |
| #614 | content: row.content, |
| #615 | signedAt: row.received_at, |
| #616 | createdAt: row.received_at, |
| #617 | replyTo: row.reply_to ?? undefined, |
| #618 | }; |
| #619 | } |
| #620 | |
| #621 | function deserializeReputation(row: any): ReputationEntry { |
| #622 | return { |
| #623 | id: row.id, |
| #624 | fromAgent: row.from_agent, |
| #625 | toAgent: row.to_agent, |
| #626 | score: row.score, |
| #627 | comment: row.comment, |
| #628 | txHash: row.tx_hash ?? undefined, |
| #629 | timestamp: row.created_at, |
| #630 | }; |
| #631 | } |
| #632 |