【免费下载链接】trueforgeThe open-source agent harness - the runtime layer that turns an LLM into a working agent.项目地址https://gitcode.com/gh_mirrors/tr/trueforge点击查看免费下载本篇指南围绕 trueforge 开源仓库中 Postgres 持久层开发约定即packages/trueforge/src/db/postgres/AGENTS.md展开逐条拆解 trueforge 在时序列类型、UTC 时间戳序列化、批量查询、迁移锁超时与自定义 schema 上的硬性规则。读完你不仅能理解每条规则背后的数据库原理还能直接在仓库源码中找到对应实现并将其复用到自己的 Postgres 工程里——从写出一条合规的 Kysely 迁移到用pnpm migrate在非publicschema 中完成建表。trueforge 是一个把 LLM 变成可用 Agent的开源 agent harness其持久层同时支持 SQLitestandalone 模式与 Postgres生产模式并统一通过 Kysely 查询构建器访问数据库。Postgres 路径的全部代码集中在 packages/trueforge/src/db/postgres 目录内含连接客户端client.ts、迁移 CLImigrate-cli.ts、schema 引导逻辑schema.ts以及按业务域划分的多个 storeagent-store/、session-store/、schedule-store/等。该目录下的 AGENTS.md 是一份面向开发者的五条硬性编码约定本文即以其为骨架逐条结合源码展开。一、时序列必须使用timestamptztimestamp with time zone约定原文Temporal columns MUST usetimestamptz(timestamp with time zone). Do not usetimestampwithout time zone.Postgres 中的timestamp不带时区与timestamptz带时区行为差异巨大timestamp只存储墙上时间不含时区语义同一数值在不同timezone会话参数下会被解释成不同时刻跨地域部署或客户端时区不一致时极易产生错乱timestamptz底层以 UTC 存储展示时再按会话timezone转换语义唯一、可比较、可排序是分布式服务处理时间的唯一正确选择。该规则在 trueforge 中不是一句口号而是逐条落实在每个迁移文件里。以最核心的 session 存储迁移 为例session、turn、turn_thread、session_event、thread_context_log、thread_capability_state六张表的所有时间列created_at、updated_at一律声明为timestamptzawait db.schema .createTable(session) ... .addColumn(created_at, timestamptz, col col.notNull()) .addColumn(updated_at, timestamptz, col col.notNull())同样地agent 注册表迁移 中的agent.created_at/agent.updated_at、以及 init 迁移 之后的所有增量迁移均严格遵循timestamptz。在 trueforge 的仓库中搜索timestamptz可以确认没有任何一张业务表使用不带时区的timestamp。这条约定同时服务于下面第二条规则——只有列类型是timestamptz应用层以 UTC 瞬时写入的 ISO 字符串才能被无歧义地解析。二、应用时间戳必须视为 UTC 瞬时用toISOString()序列化约定原文Application timestamps MUST be treated as UTC instants. Serialize withDate.prototype.toISOString()(always...Zwith milliseconds).Date.prototype.toISOString()始终输出形如2026-10-09T06:47:53.123Z的字符串——带Z后缀、精确到毫秒、无时区歧义。trueforge 要求所有落在timestamptz列上的值都以这种格式序列化使得应用层写入格式与数据库存储语义保持同一套时间坐标系UTC 瞬时。该规则在 store 层的映射代码中反复出现。以 PostgresAgentStore.ts 为例读取行后向领域模型转换时直接调用toISOString()created_at: row.created_at.toISOString(), updated_at: row.updated_at.toISOString(),同样的模式还出现在 PostgresMcpServerStore.ts、PostgresModelProviderStore.ts 与 PostgresSandboxEnvironmentStore.ts 中。背后原理是node-postgres 驱动在解析timestamptz列时得到的是 JavaScriptDate对象而Date本质上就是 UTC 瞬时epoch millis向外序列化时若用toLocaleString()、toString()或手工拼接会引入本地时区偏移导致同一个值在不同机器上写出不同的字符串。toISOString()则保证任何环境下输出一致且与第一条约定的timestamptz完美配合。实践建议业务侧的时间对象在入库前统一调用toISOString()从库中读出后凡是需要对外暴露的时间字段也一律以toISOString()产出的 ISO-8601 UTC 字符串为准避免在领域层引入本地时区。三、禁止在循环内执行数据库查询N1改用批量查询 / JOIN / IN / ANY约定原文Do not run DB queries inside loops (N1). Prefer a single batched query, a join, or anIN/ANYlookup over per-item round-trips.N1 是 ORM/查询构建器项目中最典型的性能陷阱先查一个集合1 次查询再对每个元素单独查一次N 次查询网络往返与语句解析开销随 N 线性膨胀在 Agent 会话这类高频读写场景下会迅速拖垮吞吐。trueforge 的约定明确给出三条替代路径单条批量查询batched queryJOININ/ANY查找。源码中能找到直接印证。例如 PostgresAgentStore.ts 中按一组名字批量解析 agent 引用时使用了一条WHERE reference_name IN (...)的批量查询而非对每个名字单独 round-tripWHERE reference_name IN (${wanted})会话存储域则进一步封装了 Postgres 数组展开的辅助函数。在 session-store/sqlExpressions.ts 中可以看到unnest(ids::text[]) WITH ORDINALITY与LATERAL unnest(array_expr) WITH ORDINALITY两种形态——前者用于selectFrom场景把一次传入的 ID 数组展开成可参与 JOIN 的关系表后者用于 JOIN 场景实现一次查询拿到多个线程上下文的能力典型调用点见 session-store/queries/events.ts 与 session-store/queries/turns.ts。这些正是以单条语句替代循环查询的工程化落地把批量 ID 传进一条 SQL由数据库完成展开、关联与过滤。实践建议写任何需要先查集合、再逐项处理的逻辑前先自问能否把逐项处理合并进同一语句trueforge 的做法是优先用IN列表、ANY(array)或unnest WITH ORDINALITY与目标表做一次 JOIN让数据库在单轮往返内完成全部工作。四、迁移必须首行执行SET LOCAL lock_timeout 5s让等待中的 DDL 快速失败约定原文Postgres migrations MUST startup/downwithSET LOCAL lock_timeout 5sso waiting DDL fails fast instead of blocking later queries (includingSELECTs) behind it in the lock queue.这是本约定文件中工程味最浓的一条涉及 Postgres 的锁队列行为DDL如ALTER TABLE、CREATE INDEX需要获取排他锁若目标表正被长事务持有行锁/表锁DDL 会进入锁等待队列。默认lock_timeout为无限等待意味着这条 DDL 会一直挂着而排在它后面的普通查询包括SELECT也会被阻塞在锁队列里最终拖垮整个数据库。trueforge 的做法是在每个迁移的up/down函数体第一行执行await sqlSET LOCAL lock_timeout 5s.execute(db);SET LOCAL的作用域是当前事务事务结束自动失效不会污染后续语句5s则给 DDL 一个明确的等待上限——5 秒内拿不到锁就直接抛错、迁移失败而不是无限阻塞后续流量。仓库中每一个迁移文件都遵循这一模式例如 init 迁移 的up与down、session 存储迁移 的down中dropTable(...).cascade()之前以及 agent 迁移 的回滚分支。此外schema 引导事务 schema.ts 内部同样以SET LOCAL lock_timeout 5s开头并借助pg_advisory_xact_lock串行化多实例同时启动时的建 schema 竞争。实践建议凡是在线执行的迁移尤其是ALTER TABLE/CREATE INDEX/ADD CONSTRAINT这类会碰锁的语句一律在事务开头设置短lock_timeout同时保持迁移语句幂等IF NOT EXISTS/IF EXISTS这样 5 秒失败后重跑即可恢复不会留下半执行状态。五、所有业务表与 Kysely 迁移簿记都放在POSTGRES_SCHEMA默认trueforge非public约定原文All app tables and Kysely migration bookkeeping live in the configured Postgres schema (POSTGRES_SCHEMA, defaulttrueforge— notpublic). The init migration ownsCREATE SCHEMA(the Migrator also creates it formigrationTableSchema);createDbsetssearch_pathto that schema.这条规则回答了表建在哪里的问题可拆成四个机制点① schema 名来自环境变量默认trueforge。配置定义在 config.ts 中DEFAULT_POSTGRES_SCHEMA trueforge第 46 行并限定必须匹配小写标识符正则/^[a-z_][a-z0-9_]{0,62}$/第 48、253 行——schema 名必须是合法且可安全拼接进 SQL 的小写标识符防止注入与命名冲突。② init 迁移负责CREATE SCHEMA。仓库中编号最早20260727_000001的 init 迁移 在SET LOCAL lock_timeout之后执行await sqlCREATE SCHEMA IF NOT EXISTS ${sql.id(getTrueForgePostgresSchema())}.execute(db);同时其down被刻意设计为 no-op只执行SELECT 1——注释明确说明drop schema 会连 Kysely Migrator 自己的簿记表一起删掉因此不提供真正回滚。③ Kysely Migrator 的簿记表同样挂在自定义 schema 上。在 migratePostgres.ts 中Migrator 的migrationTableSchema显式传入getTrueForgePostgresSchema()因此kysely_migration与kysely_migration_lock这两张迁移状态表也落在trueforgeschema 而非public。迁移流程本身migrateToLatest会先调用ensureTrueforgeSchema引导 schema再执行migrateToLatest或按指定迁移名执行migrateTo。④createDb通过连接参数设置search_path。在 client.ts 中连接池创建时显式传入options: -c search_path${schema},这样同一条连接上所有的裸表名不带 schema 前缀的 SQL都会解析到trueforgeschema业务代码无需手工写trueforge.xxx前缀。此外schema.ts 中的ensureTrueforgeSchema还支持一个可配置项AUTOMATICALLY_MOVE_TRUEFORGE_TABLES_FROM_PUBLIC_TO_TRUEFORGE_SCHEMA默认开启见 config.ts 第 1005-1008 行首次引导时若发现旧版本遗留的public表列表见 schema.ts 的TABLES_TO_MOVE包括session、turn、agent、mcp_server、schedule、两张kysely_migration*簿记表等会自动ALTER TABLE ... SET SCHEMA迁入目标 schema让老实例平滑升级。本地实操在自定义 schema 上跑 Postgres 迁移真机验证这套机制的最快路径是仓库自带的编排文件 docker-compose.yml其中postgres服务使用postgres:17镜像第 7-8 行应用服务通过POSTGRES_HOST: postgres、POSTGRES_PORT: 5432等环境变量连接第 48-49 行。在packages/trueforge目录下执行迁移命令定义于 package.jsonpnpm migrate该脚本等价于cross-env NODE_OPTIONS--conditionstrueforge-dev STANDALONEfalse tsx --env-file.env src/db/postgres/migrate-cli.ts。关键约束见 migrate-cli.ts是必须设置STANDALONEfalse——standalone 模式下该脚本会直接抛错因为 standalone 模式走的是 SQLite其迁移在服务启动时自动执行需要提供DATABASE_URL或POSTGRES_USER/POSTGRES_PASSWORD/POSTGRES_DB/POSTGRES_HOST组合与必要的 Redis 环境变量连接参数由配置项驱动DATABASE_POOL_MAX、POSTGRES_STATEMENT_TIMEOUT_MS默认 60000ms见 config.ts 第 957-959 行、POSTGRES_IDLE_IN_TRANSACTION_SESSION_TIMEOUT_MS与DATABASE_SSL均会在 createDb 中应用到连接池包括 10 秒的连接超时、每连接的statement_timeout、idle_in_transaction_session_timeout以及search_path设置。迁移执行后你可以用如下 SQL 验证五条约定全部生效-- 1) schema 与迁移簿记表都在 trueforge 而非 public SELECT nspname FROM pg_namespace WHERE nspname trueforge; SELECT schemaname, tablename FROM pg_tables WHERE tablename LIKE kysely_migration%; -- 2) 所有时间列都是 timestamptz SELECT column_name, data_type FROM information_schema.columns WHERE table_schema trueforge AND column_name IN (created_at, updated_at);六、配套工程细节连接池的类型解析与错误匹配在深入以上五条约定时client.ts 还提供了两个值得借鉴的配套实现bigint 数组类型解析。node-postgres 默认只把标量int8OID 20解析为number而bigint[]OID 1016不在默认覆盖范围内。trueforge 通过 configurePgTypeParsers 额外注册了int8[]解析器把 Postgres 数组字面量如{1,2,3}解析为number[]并且特意声明其安全边界为Number.MAX_SAFE_INTEGER2^53——这正好服务于turn_thread.context_ids这类bigint[]上下文引用列见 session 存储迁移。按 SQLSTATE 匹配数据库错误。由于instanceof DatabaseError在同时加载两份 pg-protocolCJSESM 版本偏差时会静默失效trueforge 采用按错误code字段匹配的方式见 isPgErrorCode / isUniqueViolation / isPgConstraint分别对应23505唯一约束冲突与命名约束匹配。这让 store 层可以在迁移或写入冲突时做出确定性响应而不是依赖脆弱的类型判断。总结一条可迁移到任何 Postgres 工程的开发纪律trueforge 用一份仅五条的 AGENTS.md把 Postgres 持久层最关键的正确性问题一次性钉死timestamptz消灭时区歧义、toISOString()统一应用层序列化、批量查询消灭 N1、lock_timeout 5s让迁移在锁竞争下快速失败、自定义 schema 隔离业务表与迁移簿记。每一条都不是纸面规范而是散落在 migrations、store 各子目录与 client.ts / schema.ts 中可逐行核验的实现事实。对希望在自己的服务中复刻这套实践的人最直接的落地点是所有时间列一律timestamptz 出入库统一toISOString()、查询全部批量化为IN/ANY/unnestJOIN、每个迁移事务首行SET LOCAL lock_timeout 5s、为应用单独建 schema 并把search_path固化在连接池上。这四板斧即可让绝大多数多租户、高写入的 Postgres 服务规避最常踩的时区错乱、锁队列阻塞与 N1 性能退化三类问题。赞分享【免费下载链接】trueforgeThe open-source agent harness - the runtime layer that turns an LLM into a working agent.项目地址https://gitcode.com/gh_mirrors/tr/trueforge点击查看免费下载相关推荐GPUStack 开发工程指南解读架构、代码规范与数据库迁移实践GPUStack 开发工程指南解读架构、代码规范与数据库迁移实践 GPUStack 是一个开源的 GPU 集群管理器用于高性能 AI 模型推理vLLM、S后端人工智能模型推理服务集群管理可观测性Box3D 移植到 Rust 的工程规范makepad-box3d 的 1:1 移植约定与浮点确定性实践Box3D 移植到 Rust 的工程规范makepad box3d 的 1:1 移植约定与浮点确定性实践 本篇指南系统讲解 makepad 仓库中 libs/前端UI组件3D渲染跨平台游戏开发Velero 全解析备份、恢复与迁移 Kubernetes 集群和持久卷的工程实践Velero 全解析备份、恢复与迁移 Kubernetes 集群和持久卷的工程实践 Velero前身为 Heptio Ark是一个为 Kubernetes云原生灾备存储后端上一篇【免费下载】 IET期刊投稿LaTeX模板科研工作者的得力助手下一篇如何永久保存微信聊天记录三步实现数据自由与AI训练创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考