/** * DI 装配 —— `app/` 是**唯一组装层**(编码规范 §5.2)。 * 只有这里能同时认识多个模块:new 出 adapter、注入 port、把用例接起来。 * * 跨层协作一律经端口注入:`ledger` 要发数据事件 → 注入 `event` 的出口; * `event` 的三级消费下游(trigger L7 / message L2)在其**上**,同样经端口注入。 */ import { Pool } from 'pg'; import { drizzle } from 'drizzle-orm/node-postgres'; import type { Db } from '@shared/db.ts'; import type { EventService, TriggerMatcher } from '@modules/event'; import { createEventService, createEventStore } from '@modules/event'; import type { LedgerService } from '@modules/ledger'; import { createDraftStore, createLedgerService, createLedgerStore, DRAFT_DDL } from '@modules/ledger'; import type { OrgService, InFlightWorkProbe } from '@modules/org'; import { createGrantRepository, createOrgService, createPositionRepository, createStaffRepository, } from '@modules/org'; import type { LlmService, ModelGateway } from '@modules/llm'; import { createLlmInstanceRepository, createLlmService, createModelGateway, createProviderInvoker, createReplayStore, } from '@modules/llm'; import type { MemoryService } from '@modules/memory'; import { createActivityMemoryStore, createMemoryService, createTaskMemoryStore } from '@modules/memory'; import type { ToolboxService, ToolHandler, ToolInvoker } from '@modules/toolbox'; import { createSchemaValidator, createToolInvoker, createToolRegistry, createToolReplayStore, createToolRuntime, createToolboxService, } from '@modules/toolbox'; import type { MessageService } from '@modules/message'; import { createMessageRepository, createMessageService } from '@modules/message'; import type { ChannelService } from '@modules/channel'; import { createChannelRepository, createChannelService, createFileAttachmentArchive, createSimulatedMailTransport, } from '@modules/channel'; import type { AppConfig } from './config.ts'; import { createIdGenerator, systemClock } from './runtime.ts'; import { createSecretBox, loadSecretKey } from './secret-box.ts'; export type Container = { readonly config: AppConfig; readonly pool: Pool; readonly db: Db; readonly org: OrgService; readonly ledger: LedgerService; readonly event: EventService; readonly llm: LlmService; readonly modelGateway: ModelGateway; readonly memory: MemoryService; readonly toolbox: ToolboxService; readonly toolInvoker: ToolInvoker; readonly message: MessageService; readonly channel: ChannelService; close(): Promise; }; /** * 在途工作探针 —— 停用前置检查要问的是 task(L6)与 human-tool(L3),二者随 M3/M4 落地。 * 占位返回空集;M4 起接真实用例(docs/debt.md · M1-1)。 */ const emptyInFlightProbe: InFlightWorkProbe = { openTasksOf: async () => [], openCardsOf: async () => [], openApprovalsOf: async () => [], }; /** 触发器判定 —— trigger(L7)随 M5 落地,当下恒不命中(docs/debt.md · M1-1) */ const noTriggerMatcher: TriggerMatcher = { match: async () => [] }; /** S-FEEL 求值 —— @sfeel 随 M3 落地;在此之前监听只用类型 + 关联键过滤 */ const passthroughEvaluator = (): boolean => true; /** 第一方工具实现 —— 由 app 注册进 ToolRuntime;活动只见调用契约 */ export const firstPartyToolHandlers = new Map(); export async function createContainer(config: AppConfig): Promise { const pool = new Pool({ connectionString: config.databaseUrl, max: 10 }); const db = drizzle(pool); const ids = createIdGenerator(); const secrets = createSecretBox(loadSecretKey()); // 草稿层的建表:ledger schema 的唯一写者是 ledger adapter,DDL 在其出口给出 await pool.query(DRAFT_DDL); const org = createOrgService({ positions: createPositionRepository(db), staff: createStaffRepository(db), grants: createGrantRepository(db), inFlight: emptyInFlightProbe, ids, }); // message 是 event 的 `MessageFallback` 实现面 —— event(L1)不反向依赖它,由此处注入 const message = createMessageService({ repo: createMessageRepository(db), org: { staffOfPosition: async (positionId) => { const { staff } = await org.listStaff(); return staff.filter((s) => s.positionId === positionId).map((s) => ({ id: s.id })); }, governanceStaff: async () => { const { staff } = await org.listStaff(); const governing = await Promise.all( staff.map(async (s) => ({ s, ok: await org.authorize(s.id, { kind: 'governance', function: 'task' }, 'govern'), })), ); return governing.filter((g) => g.ok).map((g) => ({ id: g.s.id })); }, }, clock: systemClock, ids, }); const event = createEventService({ store: createEventStore(db, ids), clock: systemClock, ids, evaluate: passthroughEvaluator, triggers: noTriggerMatcher, messages: message, }); const ledger = createLedgerService({ store: createLedgerStore(pool), drafts: createDraftStore(pool), events: { publish: async (envelope) => void (await event.publish(envelope)) }, clock: systemClock, ids, }); const instances = createLlmInstanceRepository(db); const provider = createProviderInvoker(); const llm = createLlmService({ instances, provider, secrets, clock: systemClock, ids }); const modelGateway = createModelGateway({ instances, provider, replay: createReplayStore(db), secrets, clock: systemClock, mode: 'live', }); const memory = createMemoryService({ tasks: createTaskMemoryStore(db), activities: createActivityMemoryStore(db), model: { // 系统用途模型:叙述性小结 / 汇报生成 / 蒸馏钩子 —— 计量入系统账,不占活动预算 generate: async (input) => { const result = await modelGateway.generate({ model: input.model, prompt: input.prompt, ...(input.outputSchema === undefined ? {} : { outputSchema: input.outputSchema }), label: 'system-use', }); return { text: result.text, ...(result.object === undefined ? {} : { object: result.object }) }; }, systemModelName: async () => (await llm.systemUseBinding())?.name, }, clock: systemClock, ids, }); const toolRegistry = createToolRegistry(db); const toolRuntime = createToolRuntime(firstPartyToolHandlers); const schemas = createSchemaValidator(); const toolbox = createToolboxService({ registry: toolRegistry, runtime: toolRuntime, schemas, secrets, clock: systemClock, }); const toolInvoker = createToolInvoker({ registry: toolRegistry, runtime: toolRuntime, replay: createToolReplayStore(db), schemas, secrets, clock: systemClock, mode: 'live', }); const channel = createChannelService({ channels: createChannelRepository(db), events: { ingestInbound: (input) => event.ingestInbound(input), recordOutbound: (ref) => event.recordOutbound(ref), }, ledger: { systemWrite: (input) => ledger.systemWrite(input) }, mail: createSimulatedMailTransport(db, ids), archive: createFileAttachmentArchive(config.attachmentRoot), clock: systemClock, ids, }); return { config, pool, db, org, ledger, event, llm, modelGateway, memory, toolbox, toolInvoker, message, channel, async close() { await pool.end(); }, }; }