@m6d/cortex-server 1.8.0 → 2.0.0
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.
- package/README.md +8 -3
- package/contracts/README.md +23 -0
- package/contracts/graph/embed.ts +50 -0
- package/{src/lib → contracts}/graph/helpers.ts +4 -10
- package/{src/lib → contracts}/graph/neo4j.ts +14 -27
- package/contracts/graph/schema.ts +65 -0
- package/{src/lib → contracts}/graph/types.ts +2 -29
- package/contracts/graph.ts +36 -0
- package/contracts/runtime.ts +208 -0
- package/contracts/wire.ts +143 -0
- package/dist/contracts/graph/embed.d.ts +22 -0
- package/dist/{src/lib → contracts}/graph/helpers.d.ts +16 -14
- package/dist/{src/lib → contracts}/graph/neo4j.d.ts +5 -5
- package/dist/contracts/graph/schema.d.ts +62 -0
- package/dist/{src/lib → contracts}/graph/types.d.ts +1 -1
- package/dist/contracts/graph.d.ts +14 -0
- package/dist/contracts/runtime.d.ts +278 -0
- package/dist/contracts/wire.d.ts +120 -0
- package/dist/src/lib/adapters/database/index.d.ts +61 -0
- package/dist/src/lib/adapters/database/message-content.d.ts +30 -0
- package/dist/src/lib/adapters/database/mssql/attachments.d.ts +100 -0
- package/dist/src/lib/adapters/database/mssql/client.d.ts +8 -0
- package/dist/src/lib/adapters/database/mssql/index.d.ts +194 -0
- package/dist/src/lib/adapters/database/mssql/llm-requests.d.ts +17 -0
- package/dist/src/lib/adapters/database/mssql/messages.d.ts +37 -0
- package/dist/src/lib/adapters/database/mssql/threads.d.ts +50 -0
- package/dist/src/lib/adapters/database/postgres/attachments.d.ts +113 -0
- package/dist/src/lib/adapters/database/postgres/client.d.ts +8 -0
- package/dist/src/lib/adapters/database/postgres/index.d.ts +207 -0
- package/dist/src/lib/adapters/database/postgres/llm-requests.d.ts +17 -0
- package/dist/src/lib/adapters/database/postgres/messages.d.ts +37 -0
- package/dist/src/lib/adapters/database/postgres/threads.d.ts +50 -0
- package/{src/lib/adapters/storage.ts → dist/src/lib/adapters/storage/index.d.ts} +1 -1
- package/dist/src/lib/adapters/{minio.d.ts → storage/minio.d.ts} +1 -1
- package/dist/src/lib/ai/active-runs.d.ts +63 -0
- package/dist/src/lib/ai/attachments.d.ts +30 -0
- package/dist/src/lib/ai/backend-url.d.ts +16 -0
- package/dist/src/lib/ai/cc-runtime.d.ts +61 -0
- package/dist/src/lib/ai/commit-gate.d.ts +21 -0
- package/dist/src/lib/ai/context/builder.d.ts +6 -7
- package/dist/src/lib/ai/context/compression-middleware.d.ts +15 -0
- package/dist/src/lib/ai/context/compressor.d.ts +2 -13
- package/dist/src/lib/ai/context/intra-turn-compressor.d.ts +9 -9
- package/dist/src/lib/ai/context/optimize-thread-context.d.ts +9 -0
- package/dist/src/lib/ai/context/summarizer.d.ts +3 -3
- package/dist/src/lib/ai/context/token-estimator.d.ts +5 -8
- package/dist/src/lib/ai/fetch.d.ts +1 -1
- package/dist/src/lib/ai/finish-turn.d.ts +23 -0
- package/dist/src/lib/ai/helpers.d.ts +37 -4
- package/dist/src/lib/ai/index.d.ts +6 -3
- package/dist/src/lib/ai/inspector.d.ts +41 -0
- package/dist/src/lib/ai/interceptors/request-interceptor.d.ts +6 -5
- package/dist/src/lib/ai/prompt.d.ts +5 -4
- package/dist/src/lib/ai/redis-runs.d.ts +41 -0
- package/dist/src/lib/ai/redis-stream-log.d.ts +39 -0
- package/dist/src/lib/ai/tools/execute-code.tool.d.ts +18 -4
- package/dist/src/lib/ai/tools/query-graph.tool.d.ts +13 -5
- package/dist/src/lib/ai/tools/read-attachment.tool.d.ts +21 -0
- package/dist/src/lib/ai/tools/search-common.d.ts +17 -0
- package/dist/src/lib/ai/tools/search-knowledge.tool.d.ts +15 -0
- package/dist/src/lib/ai/tools/search-services.tool.d.ts +12 -0
- package/dist/src/lib/ai/tools/search-tools.tool.d.ts +12 -0
- package/dist/src/lib/ai/turn-tools.d.ts +39 -0
- package/dist/src/lib/ai/vision/rasterize-pdf.d.ts +26 -0
- package/dist/src/lib/ai/vision/rasterize-pdf.worker.d.ts +1 -0
- package/dist/src/lib/ai/vision/vision-reader.d.ts +45 -0
- package/dist/src/lib/cc/client.d.ts +183 -0
- package/dist/src/lib/cc/config-cache.d.ts +20 -0
- package/dist/src/lib/cc/format.d.ts +23 -0
- package/dist/src/lib/cc/registry.d.ts +34 -0
- package/dist/src/lib/cc/types.d.ts +27 -0
- package/dist/src/lib/config.d.ts +81 -64
- package/dist/src/lib/db/drizzle.config.mssql.d.ts +2 -0
- package/dist/src/lib/db/drizzle.config.pg.d.ts +2 -0
- package/dist/src/lib/db/migrate.d.ts +7 -1
- package/dist/src/lib/db/{schema.d.ts → schema.mssql.d.ts} +138 -29
- package/dist/src/lib/db/schema.pg.d.ts +546 -0
- package/dist/src/lib/factory.d.ts +2 -12
- package/dist/src/lib/graph/index.d.ts +10 -11
- package/dist/src/lib/graph/resolver.d.ts +2 -3
- package/dist/src/lib/index.d.ts +3 -3
- package/dist/src/lib/redis.d.ts +19 -0
- package/dist/src/lib/routes/chat.d.ts +1 -1
- package/dist/src/lib/routes/files.d.ts +1 -1
- package/dist/src/lib/routes/owned-thread.d.ts +17 -0
- package/dist/src/lib/routes/threads.d.ts +1 -1
- package/dist/src/lib/routes/ws.d.ts +1 -1
- package/dist/src/lib/types.d.ts +20 -37
- package/dist/src/lib/ws/connections.d.ts +2 -1
- package/package.json +33 -18
- package/src/lib/adapters/database/index.ts +78 -0
- package/src/lib/adapters/database/message-content.ts +39 -0
- package/src/lib/adapters/database/mssql/attachments.ts +90 -0
- package/src/lib/adapters/database/mssql/client.ts +11 -0
- package/src/lib/adapters/database/mssql/index.ts +23 -0
- package/src/lib/adapters/database/mssql/llm-requests.ts +43 -0
- package/src/lib/adapters/database/mssql/messages.ts +92 -0
- package/src/lib/adapters/database/mssql/threads.ts +83 -0
- package/src/lib/adapters/database/postgres/attachments.ts +88 -0
- package/src/lib/adapters/database/postgres/client.ts +11 -0
- package/src/lib/adapters/database/postgres/index.ts +23 -0
- package/src/lib/adapters/database/postgres/llm-requests.ts +45 -0
- package/src/lib/adapters/database/postgres/messages.ts +92 -0
- package/src/lib/adapters/database/postgres/threads.ts +84 -0
- package/{dist/src/lib/adapters/storage.d.ts → src/lib/adapters/storage/index.ts} +1 -1
- package/src/lib/adapters/{minio.ts → storage/minio.ts} +5 -5
- package/src/lib/ai/active-runs.ts +157 -0
- package/src/lib/ai/attachments.ts +144 -0
- package/src/lib/ai/backend-url.ts +27 -0
- package/src/lib/ai/cc-runtime.ts +63 -0
- package/src/lib/ai/commit-gate.ts +116 -0
- package/src/lib/ai/context/builder.ts +12 -14
- package/src/lib/ai/context/compression-middleware.ts +44 -0
- package/src/lib/ai/context/compressor.ts +67 -59
- package/src/lib/ai/context/intra-turn-compressor.ts +121 -204
- package/src/lib/ai/context/optimize-thread-context.ts +50 -0
- package/src/lib/ai/context/summarizer.ts +28 -30
- package/src/lib/ai/context/token-estimator.ts +35 -30
- package/src/lib/ai/fetch.ts +10 -5
- package/src/lib/ai/finish-turn.ts +75 -0
- package/src/lib/ai/helpers.ts +83 -15
- package/src/lib/ai/index.ts +359 -329
- package/src/lib/ai/inspector.ts +112 -0
- package/src/lib/ai/interceptors/request-interceptor.ts +70 -42
- package/src/lib/ai/prompt.ts +126 -125
- package/src/lib/ai/redis-runs.ts +167 -0
- package/src/lib/ai/redis-stream-log.ts +219 -0
- package/src/lib/ai/tools/execute-code.tool.ts +178 -67
- package/src/lib/ai/tools/query-graph.tool.ts +7 -8
- package/src/lib/ai/tools/read-attachment.tool.ts +59 -0
- package/src/lib/ai/tools/search-common.ts +15 -0
- package/src/lib/ai/tools/search-knowledge.tool.ts +33 -0
- package/src/lib/ai/tools/search-services.tool.ts +31 -0
- package/src/lib/ai/tools/search-tools.tool.ts +29 -0
- package/src/lib/ai/turn-tools.ts +154 -0
- package/src/lib/ai/vision/rasterize-pdf.ts +69 -0
- package/src/lib/ai/vision/rasterize-pdf.worker.ts +81 -0
- package/src/lib/ai/vision/vision-reader.ts +130 -0
- package/src/lib/auth/middleware.ts +5 -3
- package/src/lib/cc/client.ts +273 -0
- package/src/lib/cc/config-cache.ts +32 -0
- package/src/lib/cc/format.ts +96 -0
- package/src/lib/cc/registry.ts +62 -0
- package/src/lib/cc/types.ts +44 -0
- package/src/lib/config.ts +102 -71
- package/src/lib/db/drizzle.config.mssql.ts +9 -0
- package/src/lib/db/drizzle.config.pg.ts +9 -0
- package/src/lib/db/migrate.ts +45 -10
- package/src/lib/db/migrations/mssql/20260729092726_talented_wilson_fisk/migration.sql +20 -0
- package/src/lib/db/migrations/mssql/20260729092726_talented_wilson_fisk/snapshot.json +497 -0
- package/src/lib/db/migrations/mssql/20260801003652_perpetual_blue_shield/migration.sql +1 -0
- package/src/lib/db/migrations/mssql/20260801003652_perpetual_blue_shield/snapshot.json +516 -0
- package/src/lib/db/migrations/mssql/20260812174642_user_id_text/migration.sql +2 -0
- package/src/lib/db/migrations/mssql/20260812174642_user_id_text/snapshot.json +516 -0
- package/src/lib/db/migrations/pg/20260801084117_thick_ben_grimm/migration.sql +53 -0
- package/src/lib/db/migrations/pg/20260801084117_thick_ben_grimm/snapshot.json +584 -0
- package/src/lib/db/migrations/pg/20260812174622_user_id_text/migration.sql +2 -0
- package/src/lib/db/migrations/pg/20260812174622_user_id_text/snapshot.json +584 -0
- package/src/lib/db/{schema.ts → schema.mssql.ts} +29 -18
- package/src/lib/db/schema.pg.ts +95 -0
- package/src/lib/factory.ts +44 -89
- package/src/lib/graph/index.ts +12 -40
- package/src/lib/graph/resolver.ts +146 -116
- package/src/lib/index.ts +11 -4
- package/src/lib/redis.ts +44 -0
- package/src/lib/routes/chat.ts +91 -62
- package/src/lib/routes/files.ts +105 -83
- package/src/lib/routes/owned-thread.ts +17 -0
- package/src/lib/routes/threads.ts +14 -30
- package/src/lib/routes/ws.ts +9 -3
- package/src/lib/types.ts +37 -36
- package/src/lib/ws/connections.ts +9 -1
- package/tsconfig.json +48 -0
- package/dist/src/lib/adapters/database.d.ts +0 -45
- package/dist/src/lib/adapters/mssql.d.ts +0 -3
- package/dist/src/lib/ai/active-streams.d.ts +0 -14
- package/dist/src/lib/ai/context/index.d.ts +0 -16
- package/dist/src/lib/ai/tools/capture-files.tool.d.ts +0 -6
- package/dist/src/lib/cli/extract-endpoints.d.ts +0 -6
- package/dist/src/lib/graph/expand-domains.d.ts +0 -2
- package/dist/src/lib/graph/generate-cypher.d.ts +0 -22
- package/dist/src/lib/graph/seed.d.ts +0 -19
- package/dist/src/lib/graph/validate.d.ts +0 -2
- package/dist/src/lib/routes/index.d.ts +0 -4
- package/dist/src/lib/ws/events.d.ts +0 -39
- package/dist/src/lib/ws/index.d.ts +0 -3
- package/dist/src/lib/ws/notify.d.ts +0 -2
- package/src/lib/adapters/database.ts +0 -48
- package/src/lib/adapters/mssql.ts +0 -231
- package/src/lib/ai/active-streams.ts +0 -123
- package/src/lib/ai/context/index.ts +0 -80
- package/src/lib/ai/tools/capture-files.tool.ts +0 -20
- package/src/lib/cli/extract-endpoints.ts +0 -550
- package/src/lib/graph/expand-domains.ts +0 -276
- package/src/lib/graph/generate-cypher.ts +0 -192
- package/src/lib/graph/seed.ts +0 -162
- package/src/lib/graph/validate.ts +0 -78
- package/src/lib/routes/index.ts +0 -4
- package/src/lib/ws/events.ts +0 -39
- package/src/lib/ws/index.ts +0 -11
- package/src/lib/ws/notify.ts +0 -9
- package/src/sample/db/client.ts +0 -9
- package/src/sample/db/migrations/20260411023125_rich_purple_man/migration.sql +0 -5
- package/src/sample/db/migrations/20260411023125_rich_purple_man/snapshot.json +0 -50
- package/src/sample/db/schema.ts +0 -10
- package/src/sample/domains/account/concepts/session.concept.ts +0 -17
- package/src/sample/domains/account/endpoints/listCurrentSessions.endpoint.ts +0 -31
- package/src/sample/domains/account/endpoints/revokeAllOtherSessions.endpoint.ts +0 -22
- package/src/sample/domains/account/endpoints/revokeCurrentSession.endpoint.ts +0 -33
- package/src/sample/domains/account/index.ts +0 -18
- package/src/sample/domains/appraisals/concepts/appraisalCycle.concept.ts +0 -15
- package/src/sample/domains/appraisals/concepts/appraisalRecord.concept.ts +0 -20
- package/src/sample/domains/appraisals/concepts/appraisalRecordCompetency.concept.ts +0 -10
- package/src/sample/domains/appraisals/concepts/appraisalRecordFunctionalRequirement.concept.ts +0 -10
- package/src/sample/domains/appraisals/concepts/appraisalRecordGoal.concept.ts +0 -17
- package/src/sample/domains/appraisals/endpoints/getAppraisalRecordById.endpoint.ts +0 -321
- package/src/sample/domains/appraisals/endpoints/getAppraisalRecordCompetencies.endpoint.ts +0 -120
- package/src/sample/domains/appraisals/endpoints/getAppraisalRecordFunctionalRequirements.endpoint.ts +0 -126
- package/src/sample/domains/appraisals/endpoints/getAppraisalRecordGoals.endpoint.ts +0 -104
- package/src/sample/domains/appraisals/endpoints/getAppraisalRecordScore.endpoint.ts +0 -58
- package/src/sample/domains/appraisals/endpoints/listAppraisalCyclesSimple.endpoint.ts +0 -52
- package/src/sample/domains/appraisals/endpoints/listAppraisalRecords.endpoint.ts +0 -245
- package/src/sample/domains/appraisals/endpoints/listAppraisalTemplatesSimple.endpoint.ts +0 -52
- package/src/sample/domains/appraisals/index.ts +0 -40
- package/src/sample/domains/appraisals/rules/appraisalRecordScoping.rule.ts +0 -7
- package/src/sample/domains/attendance/concepts/attendancePermission.concept.ts +0 -17
- package/src/sample/domains/attendance/concepts/attendanceTransaction.concept.ts +0 -17
- package/src/sample/domains/attendance/concepts/publicHoliday.concept.ts +0 -10
- package/src/sample/domains/attendance/concepts/punch.concept.ts +0 -19
- package/src/sample/domains/attendance/endpoints/getAttendanceTransactionById.endpoint.ts +0 -444
- package/src/sample/domains/attendance/endpoints/getCurrentAttendanceProfile.endpoint.ts +0 -886
- package/src/sample/domains/attendance/endpoints/getCurrentAttendanceStatistics.endpoint.ts +0 -49
- package/src/sample/domains/attendance/endpoints/listAttendancePermissions.endpoint.ts +0 -176
- package/src/sample/domains/attendance/endpoints/listAttendanceTransactionStates.endpoint.ts +0 -26
- package/src/sample/domains/attendance/endpoints/listAttendanceTransactions.endpoint.ts +0 -373
- package/src/sample/domains/attendance/endpoints/listPublicHolidaysSimple.endpoint.ts +0 -52
- package/src/sample/domains/attendance/endpoints/listPunchTypes.endpoint.ts +0 -25
- package/src/sample/domains/attendance/endpoints/listPunches.endpoint.ts +0 -178
- package/src/sample/domains/attendance/index.ts +0 -41
- package/src/sample/domains/attendance/services/attendancePermissions.service.ts +0 -15
- package/src/sample/domains/employees/concepts/employee.concept.ts +0 -20
- package/src/sample/domains/employees/concepts/employeeBankAccount.concept.ts +0 -19
- package/src/sample/domains/employees/concepts/employeeChild.concept.ts +0 -19
- package/src/sample/domains/employees/concepts/employeeDocument.concept.ts +0 -21
- package/src/sample/domains/employees/concepts/employeeEvent.concept.ts +0 -21
- package/src/sample/domains/employees/concepts/employeeExperience.concept.ts +0 -18
- package/src/sample/domains/employees/concepts/employeeJobLevelChange.concept.ts +0 -21
- package/src/sample/domains/employees/concepts/employeeMedal.concept.ts +0 -20
- package/src/sample/domains/employees/concepts/employeeQualification.concept.ts +0 -20
- package/src/sample/domains/employees/concepts/employeeSpouse.concept.ts +0 -21
- package/src/sample/domains/employees/concepts/employeeViolation.concept.ts +0 -19
- package/src/sample/domains/employees/endpoints/getCurrentEmployee.endpoint.ts +0 -1651
- package/src/sample/domains/employees/endpoints/getCurrentIdentity.endpoint.ts +0 -197
- package/src/sample/domains/employees/endpoints/getCurrentManagers.endpoint.ts +0 -142
- package/src/sample/domains/employees/endpoints/getEmployeeById.endpoint.ts +0 -1659
- package/src/sample/domains/employees/endpoints/getEmployeeStatistics.endpoint.ts +0 -43
- package/src/sample/domains/employees/endpoints/listBankAccounts.endpoint.ts +0 -223
- package/src/sample/domains/employees/endpoints/listChildren.endpoint.ts +0 -211
- package/src/sample/domains/employees/endpoints/listDocuments.endpoint.ts +0 -222
- package/src/sample/domains/employees/endpoints/listEmployeesSimple.endpoint.ts +0 -156
- package/src/sample/domains/employees/endpoints/listEvents.endpoint.ts +0 -120
- package/src/sample/domains/employees/endpoints/listExperiences.endpoint.ts +0 -188
- package/src/sample/domains/employees/endpoints/listJobLevelChanges.endpoint.ts +0 -240
- package/src/sample/domains/employees/endpoints/listMedals.endpoint.ts +0 -266
- package/src/sample/domains/employees/endpoints/listQualifications.endpoint.ts +0 -265
- package/src/sample/domains/employees/endpoints/listSpouses.endpoint.ts +0 -278
- package/src/sample/domains/employees/endpoints/listViolations.endpoint.ts +0 -245
- package/src/sample/domains/employees/index.ts +0 -75
- package/src/sample/domains/employees/services/employees.service.ts +0 -181
- package/src/sample/domains/index.ts +0 -10
- package/src/sample/domains/leaves/concepts/leave.concept.ts +0 -21
- package/src/sample/domains/leaves/concepts/leaveBalance.concept.ts +0 -17
- package/src/sample/domains/leaves/concepts/leaveBalanceTransaction.concept.ts +0 -16
- package/src/sample/domains/leaves/concepts/leaveType.concept.ts +0 -13
- package/src/sample/domains/leaves/concepts/leaveTypes.concept.ts +0 -205
- package/src/sample/domains/leaves/endpoints/getBalance.endpoint.ts +0 -53
- package/src/sample/domains/leaves/endpoints/getLeaveById.endpoint.ts +0 -53
- package/src/sample/domains/leaves/endpoints/listBalanceTransactions.endpoint.ts +0 -196
- package/src/sample/domains/leaves/endpoints/listBalanceTypes.endpoint.ts +0 -26
- package/src/sample/domains/leaves/endpoints/listBalances.endpoint.ts +0 -201
- package/src/sample/domains/leaves/endpoints/listLeaveTypes.endpoint.ts +0 -28
- package/src/sample/domains/leaves/endpoints/listLeaves.endpoint.ts +0 -234
- package/src/sample/domains/leaves/index.ts +0 -38
- package/src/sample/domains/leaves/services/leaveRequests.service.ts +0 -232
- package/src/sample/domains/notifications/concepts/notification.concept.ts +0 -19
- package/src/sample/domains/notifications/endpoints/countMyNotifications.endpoint.ts +0 -21
- package/src/sample/domains/notifications/endpoints/getMyNotification.endpoint.ts +0 -57
- package/src/sample/domains/notifications/endpoints/listMyNotifications.endpoint.ts +0 -59
- package/src/sample/domains/notifications/endpoints/markMyNotificationAsRead.endpoint.ts +0 -32
- package/src/sample/domains/notifications/index.ts +0 -20
- package/src/sample/domains/payroll/concepts/payslip.concept.ts +0 -18
- package/src/sample/domains/payroll/concepts/salaryCertificate.concept.ts +0 -17
- package/src/sample/domains/payroll/concepts/salaryCertificateRequestingEntity.concept.ts +0 -8
- package/src/sample/domains/payroll/endpoints/getPayslipById.endpoint.ts +0 -238
- package/src/sample/domains/payroll/endpoints/listPayslips.endpoint.ts +0 -216
- package/src/sample/domains/payroll/endpoints/listSalaryCertificateLanguages.endpoint.ts +0 -25
- package/src/sample/domains/payroll/endpoints/listSalaryCertificateRequestingEntities.endpoint.ts +0 -62
- package/src/sample/domains/payroll/endpoints/listSalaryCertificateTypes.endpoint.ts +0 -24
- package/src/sample/domains/payroll/endpoints/listSalaryCertificates.endpoint.ts +0 -122
- package/src/sample/domains/payroll/endpoints/previewSalaryCertificate.endpoint.ts +0 -45
- package/src/sample/domains/payroll/index.ts +0 -32
- package/src/sample/domains/payroll/rules/payrollEmployeeContext.rule.ts +0 -7
- package/src/sample/domains/payroll/services/salaryCertificates.service.ts +0 -15
- package/src/sample/domains/servicing/concepts/service.concept.ts +0 -6
- package/src/sample/domains/servicing/concepts/serviceRequest.concept.ts +0 -12
- package/src/sample/domains/servicing/concepts/serviceRequestApproval.concept.ts +0 -9
- package/src/sample/domains/servicing/endpoints/cancelServiceRequest.endpoint.ts +0 -21
- package/src/sample/domains/servicing/endpoints/createServiceRequest.endpoint.ts +0 -511
- package/src/sample/domains/servicing/endpoints/getServiceRequest.endpoint.ts +0 -352
- package/src/sample/domains/servicing/endpoints/getServiceRequestFormItems.endpoint.ts +0 -219
- package/src/sample/domains/servicing/endpoints/getServiceRequestTransactionFormItems.endpoint.ts +0 -216
- package/src/sample/domains/servicing/endpoints/getServiceStates.endpoint.ts +0 -47
- package/src/sample/domains/servicing/endpoints/invokeServiceRequestAction.endpoint.ts +0 -139
- package/src/sample/domains/servicing/endpoints/listServiceRequests.endpoint.ts +0 -292
- package/src/sample/domains/servicing/endpoints/listServices.endpoint.ts +0 -108
- package/src/sample/domains/servicing/endpoints/updateServiceRequest.endpoint.ts +0 -355
- package/src/sample/domains/servicing/index.ts +0 -44
- package/src/sample/domains/servicing/rules/checkValidActions.rule.ts +0 -7
- package/src/sample/domains/servicing/rules/createServiceRequest.rule.ts +0 -7
- package/src/sample/domains/servicing/rules/filterServiceRequestsByState.rule.ts +0 -7
- package/src/sample/domains/servicing/rules/passingOptionFields.rule.ts +0 -7
- package/src/sample/domains/shared/rules/pagination.rule.ts +0 -7
- package/src/sample/domains/suggestions/concepts/suggestion.concept.ts +0 -19
- package/src/sample/domains/suggestions/concepts/suggestionCategory.concept.ts +0 -7
- package/src/sample/domains/suggestions/concepts/suggestionImpactLevel.concept.ts +0 -7
- package/src/sample/domains/suggestions/endpoints/createSuggestion.endpoint.ts +0 -705
- package/src/sample/domains/suggestions/endpoints/deleteSuggestion.endpoint.ts +0 -32
- package/src/sample/domains/suggestions/endpoints/getSuggestionById.endpoint.ts +0 -635
- package/src/sample/domains/suggestions/endpoints/listSuggestionCategories.endpoint.ts +0 -62
- package/src/sample/domains/suggestions/endpoints/listSuggestionImpactLevels.endpoint.ts +0 -62
- package/src/sample/domains/suggestions/endpoints/listSuggestionStates.endpoint.ts +0 -24
- package/src/sample/domains/suggestions/endpoints/listSuggestions.endpoint.ts +0 -132
- package/src/sample/domains/suggestions/endpoints/updateSuggestion.endpoint.ts +0 -690
- package/src/sample/domains/suggestions/endpoints/updateSuggestionState.endpoint.ts +0 -39
- package/src/sample/domains/suggestions/index.ts +0 -34
- package/src/sample/domains/suggestions/rules/suggestionScope.rule.ts +0 -7
- package/src/sample/domains/surveys/concepts/survey.concept.ts +0 -10
- package/src/sample/domains/surveys/concepts/surveyResponse.concept.ts +0 -14
- package/src/sample/domains/surveys/endpoints/getSurveyResponseById.endpoint.ts +0 -131
- package/src/sample/domains/surveys/endpoints/getTargetedSurvey.endpoint.ts +0 -129
- package/src/sample/domains/surveys/endpoints/listTargetedSurveys.endpoint.ts +0 -160
- package/src/sample/domains/surveys/endpoints/respondToSurvey.endpoint.ts +0 -144
- package/src/sample/domains/surveys/index.ts +0 -21
- package/src/sample/drizzle.config.ts +0 -11
- package/src/sample/index.bak.ts +0 -341
- package/src/sample/index.ts +0 -318
- package/src/sample/official-statements/defaults.ts +0 -57
- package/src/sample/official-statements/routes.ts +0 -137
- package/src/sample/official-statements/service.ts +0 -148
- package/src/sample/official-statements/types.ts +0 -23
- /package/src/lib/db/migrations/{20260326231647_nice_speedball → mssql/20260326231647_nice_speedball}/migration.sql +0 -0
- /package/src/lib/db/migrations/{20260326231647_nice_speedball → mssql/20260326231647_nice_speedball}/snapshot.json +0 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// fallow-ignore-file code-duplication -- mirrors ../mssql/attachments.ts by design;
|
|
2
|
+
// Drizzle types query builders per dialect. See DatabaseAdapter in ../index.ts.
|
|
3
|
+
import { and, asc, count, eq, isNull, or, sql } from "drizzle-orm";
|
|
4
|
+
import { attachments, threads } from "@/db/schema.pg";
|
|
5
|
+
import type { DatabaseAdapter } from "@/adapters/database/index";
|
|
6
|
+
import type { PostgresDb } from "./client";
|
|
7
|
+
|
|
8
|
+
export function createAttachmentsRepository(db: PostgresDb) {
|
|
9
|
+
return {
|
|
10
|
+
async createPending(row, limit) {
|
|
11
|
+
return await db.transaction(async function (tx) {
|
|
12
|
+
await tx.execute(
|
|
13
|
+
sql`SELECT 1 FROM ${threads} WHERE ${threads.id} = ${row.threadId} FOR UPDATE`,
|
|
14
|
+
);
|
|
15
|
+
const pending = await tx
|
|
16
|
+
.select({ value: count() })
|
|
17
|
+
.from(attachments)
|
|
18
|
+
.where(
|
|
19
|
+
and(
|
|
20
|
+
eq(attachments.threadId, row.threadId),
|
|
21
|
+
eq(attachments.userId, row.userId),
|
|
22
|
+
isNull(attachments.messageId),
|
|
23
|
+
),
|
|
24
|
+
)
|
|
25
|
+
.execute()
|
|
26
|
+
.then((rows) => rows[0]!.value);
|
|
27
|
+
if (pending >= limit) return undefined;
|
|
28
|
+
|
|
29
|
+
return await tx
|
|
30
|
+
.insert(attachments)
|
|
31
|
+
.values(row)
|
|
32
|
+
.returning()
|
|
33
|
+
.then((rows) => rows[0]!);
|
|
34
|
+
});
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
async getById(id, userId) {
|
|
38
|
+
return await db
|
|
39
|
+
.select()
|
|
40
|
+
.from(attachments)
|
|
41
|
+
.where(and(eq(attachments.id, id), eq(attachments.userId, userId)))
|
|
42
|
+
.limit(1)
|
|
43
|
+
.execute()
|
|
44
|
+
.then((rows) => rows[0]);
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
async listByThread(threadId, userId) {
|
|
48
|
+
return await db
|
|
49
|
+
.select()
|
|
50
|
+
.from(attachments)
|
|
51
|
+
.where(and(eq(attachments.threadId, threadId), eq(attachments.userId, userId)))
|
|
52
|
+
.orderBy(asc(attachments.createdAt), asc(attachments.id))
|
|
53
|
+
.execute();
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
async claimForMessage(threadId, userId, messageId) {
|
|
57
|
+
// ponytail: retries only this message's pending rows; add claim timestamps for cross-message recovery.
|
|
58
|
+
return await db
|
|
59
|
+
.update(attachments)
|
|
60
|
+
.set({ messageId })
|
|
61
|
+
.where(
|
|
62
|
+
and(
|
|
63
|
+
eq(attachments.threadId, threadId),
|
|
64
|
+
eq(attachments.userId, userId),
|
|
65
|
+
eq(attachments.status, "pending"),
|
|
66
|
+
or(isNull(attachments.messageId), eq(attachments.messageId, messageId)),
|
|
67
|
+
),
|
|
68
|
+
)
|
|
69
|
+
.returning();
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
async setDescription(id, userId, status, description) {
|
|
73
|
+
await db
|
|
74
|
+
.update(attachments)
|
|
75
|
+
.set(description === undefined ? { status } : { status, description })
|
|
76
|
+
.where(and(eq(attachments.id, id), eq(attachments.userId, userId)))
|
|
77
|
+
.execute();
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
async remove(id, userId) {
|
|
81
|
+
return await db
|
|
82
|
+
.delete(attachments)
|
|
83
|
+
.where(and(eq(attachments.id, id), eq(attachments.userId, userId)))
|
|
84
|
+
.returning()
|
|
85
|
+
.then((rows) => rows[0]);
|
|
86
|
+
},
|
|
87
|
+
} satisfies DatabaseAdapter["attachments"];
|
|
88
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { drizzle } from "drizzle-orm/node-postgres";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Global snake_case mapping means schema columns are never spelled out twice —
|
|
5
|
+
* the TypeScript name is the source of truth and Drizzle derives the column.
|
|
6
|
+
*/
|
|
7
|
+
export function createPostgresDb(connectionString: string) {
|
|
8
|
+
return drizzle(connectionString, { casing: "snake_case" });
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type PostgresDb = ReturnType<typeof createPostgresDb>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { DatabaseAdapter } from "@/adapters/database/index";
|
|
2
|
+
import type { StorageAdapter } from "@/adapters/storage/index";
|
|
3
|
+
import { createPostgresDb } from "./client";
|
|
4
|
+
import { createThreadsRepository } from "./threads";
|
|
5
|
+
import { createMessagesRepository } from "./messages";
|
|
6
|
+
import { createLlmRequestsRepository } from "./llm-requests";
|
|
7
|
+
import { createAttachmentsRepository } from "./attachments";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The Postgres implementation of the database contract. One repository per
|
|
11
|
+
* table; only threads takes storage, because deleting a thread is the one
|
|
12
|
+
* operation that also has to reach into object storage.
|
|
13
|
+
*/
|
|
14
|
+
export function createPostgresAdapter(connectionString: string, storage?: StorageAdapter) {
|
|
15
|
+
const db = createPostgresDb(connectionString);
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
threads: createThreadsRepository(db, storage),
|
|
19
|
+
messages: createMessagesRepository(db),
|
|
20
|
+
llmRequests: createLlmRequestsRepository(db),
|
|
21
|
+
attachments: createAttachmentsRepository(db),
|
|
22
|
+
} satisfies DatabaseAdapter;
|
|
23
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// fallow-ignore-file code-duplication -- mirrors ../mssql/llm-requests.ts by design;
|
|
2
|
+
// Drizzle types query builders per dialect. See DatabaseAdapter in ../index.ts.
|
|
3
|
+
import { asc, eq, type InferInsertModel } from "drizzle-orm";
|
|
4
|
+
import { llmRequests } from "@/db/schema.pg";
|
|
5
|
+
import type { DatabaseAdapter } from "@/adapters/database/index";
|
|
6
|
+
import type { PostgresDb } from "./client";
|
|
7
|
+
|
|
8
|
+
export function createLlmRequestsRepository(db: PostgresDb) {
|
|
9
|
+
return {
|
|
10
|
+
async insert(requests) {
|
|
11
|
+
if (!requests.length) return;
|
|
12
|
+
|
|
13
|
+
await db
|
|
14
|
+
.insert(llmRequests)
|
|
15
|
+
.values(
|
|
16
|
+
requests.map(
|
|
17
|
+
(r) =>
|
|
18
|
+
({
|
|
19
|
+
messageId: r.messageId,
|
|
20
|
+
stepNumber: r.stepNumber,
|
|
21
|
+
prompt: r.prompt,
|
|
22
|
+
output: r.output,
|
|
23
|
+
tokenUsage: r.tokenUsage,
|
|
24
|
+
}) satisfies InferInsertModel<typeof llmRequests>,
|
|
25
|
+
),
|
|
26
|
+
)
|
|
27
|
+
.execute();
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
/** Ordered by step so the inspector replays a turn in the order it ran. */
|
|
31
|
+
async listByMessageId(messageId) {
|
|
32
|
+
return await db
|
|
33
|
+
.select({
|
|
34
|
+
id: llmRequests.id,
|
|
35
|
+
prompt: llmRequests.prompt,
|
|
36
|
+
output: llmRequests.output,
|
|
37
|
+
tokenUsage: llmRequests.tokenUsage,
|
|
38
|
+
})
|
|
39
|
+
.from(llmRequests)
|
|
40
|
+
.where(eq(llmRequests.messageId, messageId))
|
|
41
|
+
.orderBy(asc(llmRequests.stepNumber))
|
|
42
|
+
.execute();
|
|
43
|
+
},
|
|
44
|
+
} satisfies DatabaseAdapter["llmRequests"];
|
|
45
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// fallow-ignore-file code-duplication -- mirrors ../mssql/messages.ts by design;
|
|
2
|
+
// Drizzle types query builders per dialect. See DatabaseAdapter in ../index.ts.
|
|
3
|
+
import { and, desc, eq, getColumns, inArray, type InferInsertModel } from "drizzle-orm";
|
|
4
|
+
import { threads, messages } from "@/db/schema.pg";
|
|
5
|
+
import type { ChatMessage } from "@/types";
|
|
6
|
+
import type { DatabaseAdapter } from "@/adapters/database/index";
|
|
7
|
+
import {
|
|
8
|
+
mergeStoredContent,
|
|
9
|
+
textOf,
|
|
10
|
+
withOwnedAttachments,
|
|
11
|
+
} from "@/adapters/database/message-content";
|
|
12
|
+
import type { PostgresDb } from "./client";
|
|
13
|
+
|
|
14
|
+
const DEFAULT_MESSAGE_LIMIT = 100;
|
|
15
|
+
|
|
16
|
+
export function createMessagesRepository(db: PostgresDb) {
|
|
17
|
+
return {
|
|
18
|
+
/**
|
|
19
|
+
* Fetches the newest N and reverses, so a limit keeps the most recent
|
|
20
|
+
* messages while callers still receive them oldest-first.
|
|
21
|
+
*/
|
|
22
|
+
async list(userId, threadId, opts) {
|
|
23
|
+
return await db
|
|
24
|
+
.select(getColumns(messages))
|
|
25
|
+
.from(messages)
|
|
26
|
+
.innerJoin(threads, eq(threads.id, messages.threadId))
|
|
27
|
+
.where(and(eq(threads.userId, userId), eq(threads.id, threadId)))
|
|
28
|
+
.orderBy(desc(messages.createdAt), desc(messages.ordinal))
|
|
29
|
+
.limit(opts?.limit ?? DEFAULT_MESSAGE_LIMIT)
|
|
30
|
+
.then((x) => x.reverse());
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Ids are client-generated, so a turn mixes new messages with edits to
|
|
35
|
+
* ones already stored. Splitting on existence lets the new ones go in as
|
|
36
|
+
* a single insert; the rest are updated individually.
|
|
37
|
+
*/
|
|
38
|
+
async upsert(
|
|
39
|
+
threadId: string,
|
|
40
|
+
messagesToUpsert: ChatMessage[],
|
|
41
|
+
options?: { replaceAttachments?: boolean },
|
|
42
|
+
) {
|
|
43
|
+
const incomingMessages = withOwnedAttachments(
|
|
44
|
+
messagesToUpsert,
|
|
45
|
+
options?.replaceAttachments,
|
|
46
|
+
);
|
|
47
|
+
const existingMessages = await db
|
|
48
|
+
.select({ id: messages.id, content: messages.content })
|
|
49
|
+
.from(messages)
|
|
50
|
+
.where(
|
|
51
|
+
inArray(
|
|
52
|
+
messages.id,
|
|
53
|
+
incomingMessages.map((x) => x.id),
|
|
54
|
+
),
|
|
55
|
+
)
|
|
56
|
+
.execute();
|
|
57
|
+
const existingById = new Map(
|
|
58
|
+
existingMessages.map((message) => [message.id, message.content]),
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
const newMessages = incomingMessages.filter((x) => !existingById.has(x.id));
|
|
62
|
+
if (newMessages.length) {
|
|
63
|
+
await db
|
|
64
|
+
.insert(messages)
|
|
65
|
+
.values(
|
|
66
|
+
newMessages.map(
|
|
67
|
+
(x, ordinal) =>
|
|
68
|
+
({
|
|
69
|
+
id: x.id,
|
|
70
|
+
role: x.role,
|
|
71
|
+
threadId,
|
|
72
|
+
content: x,
|
|
73
|
+
text: textOf(x),
|
|
74
|
+
ordinal,
|
|
75
|
+
}) satisfies InferInsertModel<typeof messages>,
|
|
76
|
+
),
|
|
77
|
+
)
|
|
78
|
+
.execute();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
for (const message of incomingMessages.filter((x) => existingById.has(x.id))) {
|
|
82
|
+
const content = mergeStoredContent(existingById.get(message.id)!, message);
|
|
83
|
+
|
|
84
|
+
await db
|
|
85
|
+
.update(messages)
|
|
86
|
+
.set({ content, text: textOf(content) })
|
|
87
|
+
.where(eq(messages.id, message.id))
|
|
88
|
+
.execute();
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
} satisfies DatabaseAdapter["messages"];
|
|
92
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// fallow-ignore-file code-duplication -- mirrors ../mssql/threads.ts by design;
|
|
2
|
+
// Drizzle types query builders per dialect. See DatabaseAdapter in ../index.ts.
|
|
3
|
+
import { and, desc, eq } from "drizzle-orm";
|
|
4
|
+
import { attachments, threads } from "@/db/schema.pg";
|
|
5
|
+
import type { Thread } from "@/types";
|
|
6
|
+
import type { ThreadContextMeta } from "@/ai/context/types";
|
|
7
|
+
import type { DatabaseAdapter } from "@/adapters/database/index";
|
|
8
|
+
import type { PostgresDb } from "./client";
|
|
9
|
+
import type { StorageAdapter } from "@/adapters/storage/index";
|
|
10
|
+
|
|
11
|
+
export function createThreadsRepository(db: PostgresDb, storage?: StorageAdapter) {
|
|
12
|
+
return {
|
|
13
|
+
async list(userId, agentId) {
|
|
14
|
+
return await db
|
|
15
|
+
.select()
|
|
16
|
+
.from(threads)
|
|
17
|
+
.where(and(eq(threads.userId, userId), eq(threads.agentId, agentId)))
|
|
18
|
+
.orderBy(desc(threads.updatedAt), desc(threads.createdAt));
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
async getById(userId, threadId) {
|
|
22
|
+
const result = await db
|
|
23
|
+
.select()
|
|
24
|
+
.from(threads)
|
|
25
|
+
.where(and(eq(threads.id, threadId), eq(threads.userId, userId)))
|
|
26
|
+
.limit(1)
|
|
27
|
+
.execute();
|
|
28
|
+
return result.length ? (result[0] as Thread) : null;
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
async create(userId, agentId) {
|
|
32
|
+
const result = await db.insert(threads).values({ userId, agentId }).returning();
|
|
33
|
+
return result[0] as Thread;
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
/** Object storage has no foreign keys, so attachment paths must be swept before row cascade. */
|
|
37
|
+
async delete(userId, threadId) {
|
|
38
|
+
const attachmentPaths = await db
|
|
39
|
+
.select({ storageKey: attachments.storageKey })
|
|
40
|
+
.from(attachments)
|
|
41
|
+
.where(and(eq(attachments.threadId, threadId), eq(attachments.userId, userId)))
|
|
42
|
+
.execute()
|
|
43
|
+
.then((rows) => rows.map((row) => row.storageKey));
|
|
44
|
+
|
|
45
|
+
if (storage && attachmentPaths.length) {
|
|
46
|
+
await storage.delete(attachmentPaths);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// attachments.message_id has no cascade, so those rows go first.
|
|
50
|
+
await db.delete(attachments).where(eq(attachments.threadId, threadId)).execute();
|
|
51
|
+
|
|
52
|
+
await db
|
|
53
|
+
.delete(threads)
|
|
54
|
+
.where(and(eq(threads.id, threadId), eq(threads.userId, userId)))
|
|
55
|
+
.execute();
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
async touch(threadId) {
|
|
59
|
+
const result = await db
|
|
60
|
+
.update(threads)
|
|
61
|
+
.set({ updatedAt: new Date() })
|
|
62
|
+
.where(eq(threads.id, threadId))
|
|
63
|
+
.returning();
|
|
64
|
+
|
|
65
|
+
return result[0] as Thread;
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
async updateTitle(threadId, title) {
|
|
69
|
+
await db.update(threads).set({ title }).where(eq(threads.id, threadId)).execute();
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
async updateSession(threadId, session) {
|
|
73
|
+
await db.update(threads).set({ session }).where(eq(threads.id, threadId)).execute();
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
async updateContextMeta(threadId, meta: ThreadContextMeta) {
|
|
77
|
+
await db
|
|
78
|
+
.update(threads)
|
|
79
|
+
.set({ contextMeta: meta })
|
|
80
|
+
.where(eq(threads.id, threadId))
|
|
81
|
+
.execute();
|
|
82
|
+
},
|
|
83
|
+
} satisfies DatabaseAdapter["threads"];
|
|
84
|
+
}
|
|
@@ -2,5 +2,5 @@ export type StorageAdapter = {
|
|
|
2
2
|
put(path: string, data: string): Promise<boolean>;
|
|
3
3
|
get(path: string): Promise<string | false>;
|
|
4
4
|
delete(paths: string[]): Promise<boolean>;
|
|
5
|
-
stream(path: string): Promise<ReadableStream
|
|
5
|
+
stream(path: string): Promise<ReadableStream<Uint8Array>>;
|
|
6
6
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as Minio from "minio";
|
|
2
2
|
import { Readable } from "node:stream";
|
|
3
|
-
import type { StorageAdapter } from "./
|
|
3
|
+
import type { StorageAdapter } from "./index";
|
|
4
4
|
|
|
5
5
|
export type MinioConfig = {
|
|
6
6
|
endPoint: string;
|
|
@@ -53,11 +53,11 @@ export function createMinioAdapter(config: MinioConfig) {
|
|
|
53
53
|
return await new Promise<string>((resolve, reject) => {
|
|
54
54
|
const chunks: Uint8Array[] = [];
|
|
55
55
|
|
|
56
|
-
stream.on("error", () => {
|
|
57
|
-
reject();
|
|
56
|
+
stream.on("error", (error: Error) => {
|
|
57
|
+
reject(error);
|
|
58
58
|
});
|
|
59
59
|
|
|
60
|
-
stream.on("data", (chunk) => chunks.push(chunk));
|
|
60
|
+
stream.on("data", (chunk: Buffer) => chunks.push(chunk));
|
|
61
61
|
stream.on("end", () => {
|
|
62
62
|
const buffer = Buffer.concat(chunks);
|
|
63
63
|
resolve(buffer.toString("base64"));
|
|
@@ -82,7 +82,7 @@ export function createMinioAdapter(config: MinioConfig) {
|
|
|
82
82
|
|
|
83
83
|
async stream(path: string) {
|
|
84
84
|
const nodeStream = await client.getObject(bucketName, path);
|
|
85
|
-
return Readable.toWeb(nodeStream) as
|
|
85
|
+
return Readable.toWeb(nodeStream) as ReadableStream<Uint8Array>;
|
|
86
86
|
},
|
|
87
87
|
};
|
|
88
88
|
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
// fallow-ignore-file duplicate-export -- coordinator-facing wrapper intentionally shares redis-stream-log's helper name
|
|
2
|
+
import { memoryStream, type StreamDurability } from "@tanstack/ai";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The live turn on a thread. Generation runs detached from the HTTP request that
|
|
6
|
+
* started it, so this registry — not the request — owns the run's lifetime: it is
|
|
7
|
+
* how abort reaches a producer and how a reconnecting client finds the run to
|
|
8
|
+
* rejoin.
|
|
9
|
+
*/
|
|
10
|
+
export type ActiveRun = {
|
|
11
|
+
runId: string;
|
|
12
|
+
abortController: AbortController;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* One backend owns both halves of a live run: the thread→run claim registry and
|
|
17
|
+
* the durability log the run streams through. In-memory is the single-process
|
|
18
|
+
* default; `createCortex({ redis })` swaps in the Redis coordinator so claims,
|
|
19
|
+
* aborts, and logs survive a producer restart and reach every instance.
|
|
20
|
+
*/
|
|
21
|
+
export type RunCoordinator = {
|
|
22
|
+
/** Claims the thread for a new run, aborting whatever was running on it. */
|
|
23
|
+
startRun: (threadId: string) => Promise<ActiveRun>;
|
|
24
|
+
getRunId: (threadId: string) => Promise<string | undefined>;
|
|
25
|
+
/** Which of `threadIds` have a live run — one round trip, for list views. */
|
|
26
|
+
runningThreadIds: (threadIds: string[]) => Promise<Set<string>>;
|
|
27
|
+
/** Aborts the thread's live run. False when there was none to abort — the
|
|
28
|
+
* caller must not report an abort that never happened. */
|
|
29
|
+
abortRun: (threadId: string) => Promise<boolean>;
|
|
30
|
+
/** Releases the thread, but only for the run that still holds it — a
|
|
31
|
+
* superseded run finishing late must not evict its replacement. */
|
|
32
|
+
endRun: (threadId: string, runId: string) => Promise<void>;
|
|
33
|
+
/** The producer's sink: `resumeFrom()` is null, so appends flow into the log. */
|
|
34
|
+
producerLog: (runId: string) => StreamDurability;
|
|
35
|
+
/** A reader on the run's log, replaying from `offset` and tailing until close.
|
|
36
|
+
* Takes the thread too: the thread's claim is how a reader can tell a live
|
|
37
|
+
* producer from a dead one. */
|
|
38
|
+
joinLog: (threadId: string, runId: string, offset?: string) => StreamDurability;
|
|
39
|
+
/**
|
|
40
|
+
* Whether a client-supplied resume offset belongs to `runId`. The offset is
|
|
41
|
+
* the adapter's own opaque token and names the log it replays — so an offset
|
|
42
|
+
* naming another run would replay that run's log to whoever presents it.
|
|
43
|
+
*/
|
|
44
|
+
offsetBelongsToRun: (offset: string, runId: string) => boolean;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* How long a joiner waits for a run's first chunk. The adapter arms this on any
|
|
49
|
+
* empty log, and it cannot tell "the producer died" from "the producer has not
|
|
50
|
+
* reached the model yet" — so it has to clear the worst case: a compression
|
|
51
|
+
* middleware's extra summarization call plus the model's time to first token.
|
|
52
|
+
* It is generous because it is only a backstop: a producer that fails writes its
|
|
53
|
+
* own terminal event into the log, and a run that ended is gone from the
|
|
54
|
+
* registry, so neither ever reaches this timer.
|
|
55
|
+
*/
|
|
56
|
+
export const JOIN_FIRST_CHUNK_TIMEOUT_MS = 5 * 60_000;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* `memoryStream` keys its log by the run id it reads off a request, so a
|
|
60
|
+
* synthetic request is how a detached producer names the log it writes to and
|
|
61
|
+
* how a joiner names the one it reads from. The URL is never fetched.
|
|
62
|
+
*/
|
|
63
|
+
function logRequest(runId: string, offset?: string) {
|
|
64
|
+
const query = offset === undefined ? "" : `&offset=${offset}`;
|
|
65
|
+
return new Request(`http://cortex.invalid/run?runId=${encodeURIComponent(runId)}${query}`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function createMemoryRuns() {
|
|
69
|
+
const runs = new Map<string, ActiveRun>();
|
|
70
|
+
|
|
71
|
+
function abort(threadId: string) {
|
|
72
|
+
const run = runs.get(threadId);
|
|
73
|
+
if (!run) return false;
|
|
74
|
+
runs.delete(threadId);
|
|
75
|
+
run.abortController.abort();
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
startRun(threadId) {
|
|
81
|
+
abort(threadId);
|
|
82
|
+
const run: ActiveRun = {
|
|
83
|
+
runId: crypto.randomUUID(),
|
|
84
|
+
abortController: new AbortController(),
|
|
85
|
+
};
|
|
86
|
+
runs.set(threadId, run);
|
|
87
|
+
return Promise.resolve(run);
|
|
88
|
+
},
|
|
89
|
+
getRunId(threadId) {
|
|
90
|
+
return Promise.resolve(runs.get(threadId)?.runId);
|
|
91
|
+
},
|
|
92
|
+
runningThreadIds(threadIds) {
|
|
93
|
+
return Promise.resolve(new Set(threadIds.filter((threadId) => runs.has(threadId))));
|
|
94
|
+
},
|
|
95
|
+
abortRun(threadId) {
|
|
96
|
+
return Promise.resolve(abort(threadId));
|
|
97
|
+
},
|
|
98
|
+
endRun(threadId, runId) {
|
|
99
|
+
if (runs.get(threadId)?.runId === runId) runs.delete(threadId);
|
|
100
|
+
return Promise.resolve();
|
|
101
|
+
},
|
|
102
|
+
producerLog(runId) {
|
|
103
|
+
return memoryStream(logRequest(runId));
|
|
104
|
+
},
|
|
105
|
+
joinLog(_threadId, runId, offset = "-1") {
|
|
106
|
+
return memoryStream(logRequest(runId, offset), {
|
|
107
|
+
firstChunkDeadlineMs: JOIN_FIRST_CHUNK_TIMEOUT_MS,
|
|
108
|
+
});
|
|
109
|
+
},
|
|
110
|
+
offsetBelongsToRun(offset, runId) {
|
|
111
|
+
return offset.startsWith(`memory:v1:${encodeURIComponent(runId)}:`);
|
|
112
|
+
},
|
|
113
|
+
} satisfies RunCoordinator;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
let coordinator: RunCoordinator = createMemoryRuns();
|
|
117
|
+
|
|
118
|
+
/** `createCortex` swaps the backend in once at startup; everything below delegates. */
|
|
119
|
+
export function configureRunCoordination(backend: RunCoordinator) {
|
|
120
|
+
coordinator = backend;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function startRun(threadId: string) {
|
|
124
|
+
return coordinator.startRun(threadId);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function getRunId(threadId: string) {
|
|
128
|
+
return coordinator.getRunId(threadId);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export async function isRunning(threadId: string) {
|
|
132
|
+
return (await coordinator.getRunId(threadId)) !== undefined;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function runningThreadIds(threadIds: string[]) {
|
|
136
|
+
return coordinator.runningThreadIds(threadIds);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function abortRun(threadId: string) {
|
|
140
|
+
return coordinator.abortRun(threadId);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function endRun(threadId: string, runId: string) {
|
|
144
|
+
return coordinator.endRun(threadId, runId);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function producerLog(runId: string) {
|
|
148
|
+
return coordinator.producerLog(runId);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function joinLog(threadId: string, runId: string, offset?: string) {
|
|
152
|
+
return coordinator.joinLog(threadId, runId, offset);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function offsetBelongsToRun(offset: string, runId: string) {
|
|
156
|
+
return coordinator.offsetBelongsToRun(offset, runId);
|
|
157
|
+
}
|