@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
package/src/lib/ai/index.ts
CHANGED
|
@@ -1,324 +1,363 @@
|
|
|
1
1
|
import {
|
|
2
|
+
chat,
|
|
3
|
+
chatParamsFromRequest,
|
|
4
|
+
convertMessagesToModelMessages,
|
|
5
|
+
generateMessageId,
|
|
6
|
+
maxIterations,
|
|
7
|
+
mergeAgentTools,
|
|
8
|
+
normalizeToUIMessage,
|
|
9
|
+
resumeServerSentEventsResponse,
|
|
10
|
+
toServerSentEventsResponse,
|
|
2
11
|
type UIMessage,
|
|
3
|
-
|
|
4
|
-
convertToModelMessages,
|
|
5
|
-
generateId,
|
|
6
|
-
generateText,
|
|
7
|
-
safeValidateUIMessages,
|
|
8
|
-
stepCountIs,
|
|
9
|
-
streamText,
|
|
10
|
-
wrapLanguageModel,
|
|
11
|
-
} from "ai";
|
|
12
|
+
} from "@tanstack/ai";
|
|
12
13
|
import { HTTPException } from "hono/http-exception";
|
|
13
|
-
import type { ResolvedCortexAgentConfig } from "
|
|
14
|
-
import type { MessageMetadata, Thread
|
|
15
|
-
import { createModel
|
|
16
|
-
import { buildSystemPrompt, resolveSession } from "./prompt
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import { createNeo4jClient } from "
|
|
22
|
-
import { resolveFromGraph } from "
|
|
23
|
-
import { notify } from "
|
|
24
|
-
import { buildContextMessages } from "./context/builder
|
|
25
|
-
import {
|
|
14
|
+
import type { ResolvedCortexAgentConfig, ToolSet } from "@/config";
|
|
15
|
+
import type { ChatMessage, MessageMetadata, Thread } from "@/types";
|
|
16
|
+
import { createModel } from "./helpers";
|
|
17
|
+
import { buildSystemPrompt, resolveSession } from "./prompt";
|
|
18
|
+
import { ControlCenterClient } from "@/cc/client";
|
|
19
|
+
import { getControlCenterConfig } from "@/cc/config-cache";
|
|
20
|
+
import { buildPromptVariables } from "@/cc/format";
|
|
21
|
+
import { getRecentCcTools } from "@/cc/registry";
|
|
22
|
+
import { createEmbedder, createNeo4jClient } from "@cortex/contracts/graph";
|
|
23
|
+
import { resolveFromGraph } from "@/graph/resolver";
|
|
24
|
+
import { notify } from "@/ws/connections";
|
|
25
|
+
import { buildContextMessages, trimMessagesToFit } from "./context/builder";
|
|
26
|
+
import { estimateTokens } from "./context/token-estimator";
|
|
27
|
+
import { createCompressionMiddleware } from "./context/compression-middleware";
|
|
28
|
+
import { createCcRuntime } from "./cc-runtime";
|
|
26
29
|
import {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
} from "./
|
|
31
|
-
import {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
} from "./
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
export
|
|
40
|
-
|
|
30
|
+
buildTurnTools,
|
|
31
|
+
createToolInstrumentation,
|
|
32
|
+
hasDefaultAttachmentInterceptor,
|
|
33
|
+
} from "./turn-tools";
|
|
34
|
+
import { createInspector } from "./inspector";
|
|
35
|
+
import { commitBeforeTerminal } from "./commit-gate";
|
|
36
|
+
import { finishTurn } from "./finish-turn";
|
|
37
|
+
import { endRun, isRunning, joinLog, producerLog, startRun } from "./active-runs";
|
|
38
|
+
import { toThreadSummary } from "@/types";
|
|
39
|
+
import { buildAttachmentListing, prepareAttachmentsForTurn } from "./attachments";
|
|
40
|
+
|
|
41
|
+
/** The AG-UI request body, as the route parsed it. */
|
|
42
|
+
export type TurnParams = Awaited<ReturnType<typeof chatParamsFromRequest>>;
|
|
43
|
+
|
|
44
|
+
/** Cortex's agentic loop cap; the SDK's own default is 5. */
|
|
45
|
+
const MAX_ITERATIONS = 25;
|
|
46
|
+
|
|
47
|
+
export async function startTurn(
|
|
48
|
+
params: TurnParams,
|
|
41
49
|
thread: Thread,
|
|
42
50
|
userId: string,
|
|
43
51
|
token: string,
|
|
44
52
|
requestContext: Record<string, unknown>,
|
|
45
53
|
config: ResolvedCortexAgentConfig,
|
|
46
54
|
) {
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
const run = await startRun(thread.id);
|
|
56
|
+
try {
|
|
57
|
+
// The client owns its own messages, and the assistant turn it sends back
|
|
58
|
+
// once a client-side tool has answered — without that answer stored, the
|
|
59
|
+
// next turn replays an assistant message whose tool calls nothing ever
|
|
60
|
+
// resolved, and the provider rejects the thread from there on. Everything
|
|
61
|
+
// else the server generated stays the server's; the repository keeps the
|
|
62
|
+
// usage and model id only it ever knew.
|
|
63
|
+
const incoming = params.messages
|
|
64
|
+
.map((message) => toChatMessage(normalizeToUIMessage(message, generateMessageId)))
|
|
65
|
+
.filter((message) => message.role === "user" || answersToolCalls(message));
|
|
66
|
+
await config.db.messages.upsert(thread.id, incoming);
|
|
67
|
+
|
|
68
|
+
const lastUserMessage = incoming.findLast((message) => message.role === "user");
|
|
69
|
+
const prompt = textOf(lastUserMessage);
|
|
70
|
+
if (thread.title === null && prompt) {
|
|
71
|
+
void generateTitle(thread.id, prompt, userId, config);
|
|
72
|
+
}
|
|
57
73
|
|
|
58
|
-
|
|
74
|
+
const updatedThread = await config.db.threads.touch(thread.id);
|
|
59
75
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
76
|
+
// A stop can land while the claim exists but before the run is
|
|
77
|
+
// announced; announcing anyway would put run-started after the abort's
|
|
78
|
+
// run-finished and pin the thread as running on every other tab. No
|
|
79
|
+
// await sits between this check and the notify, so once it passes the
|
|
80
|
+
// abort's run-finished can only follow the announcement.
|
|
81
|
+
if (run.abortController.signal.aborted) {
|
|
82
|
+
releaseRun(thread.id, run.runId);
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
64
85
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
// Run independent operations in parallel
|
|
78
|
-
const [contextResult, resolved, session] = await Promise.all([
|
|
79
|
-
// Branch A: Load messages + build token-aware context window
|
|
80
|
-
buildContextMessages(userId, thread, config.db, config.context),
|
|
81
|
-
// Branch B: Resolve graph context (400-2000ms, the bottleneck)
|
|
82
|
-
neo4j
|
|
83
|
-
? resolveFromGraph(prompt, {
|
|
84
|
-
neo4j,
|
|
85
|
-
embeddingModel,
|
|
86
|
-
reranker: config.reranker,
|
|
86
|
+
notify(userId, thread.agentId, {
|
|
87
|
+
type: "thread:run-started",
|
|
88
|
+
payload: { thread: toThreadSummary(updatedThread, true) },
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const threadAttachments = lastUserMessage
|
|
92
|
+
? await prepareAttachmentsForTurn({
|
|
93
|
+
config,
|
|
94
|
+
threadId: thread.id,
|
|
95
|
+
userId,
|
|
96
|
+
message: lastUserMessage,
|
|
97
|
+
abortSignal: run.abortController.signal,
|
|
87
98
|
})
|
|
88
|
-
:
|
|
89
|
-
// Branch C: Resolve session data
|
|
90
|
-
resolveSession(config, thread, token),
|
|
91
|
-
]);
|
|
99
|
+
: await config.db.attachments.listByThread(thread.id, userId);
|
|
92
100
|
|
|
93
|
-
|
|
101
|
+
// Claiming rewrites the message the user just sent, and the tabs that did
|
|
102
|
+
// not send it are already showing that message — with the run underway,
|
|
103
|
+
// this is their only chance to learn which files it carries.
|
|
104
|
+
if (threadAttachments.some((attachment) => attachment.messageId === lastUserMessage?.id)) {
|
|
105
|
+
notify(userId, thread.agentId, {
|
|
106
|
+
type: "thread:messages-updated",
|
|
107
|
+
payload: { threadId: thread.id, thread: toThreadSummary(updatedThread, true) },
|
|
108
|
+
});
|
|
109
|
+
}
|
|
94
110
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
111
|
+
const turnKey = lastUserMessage?.id ?? "0";
|
|
112
|
+
|
|
113
|
+
const inspector = createInspector();
|
|
114
|
+
const { model, embed, neo4j, ccClient } = createTurnProviders(config, inspector.fetch);
|
|
115
|
+
|
|
116
|
+
// Run independent operations in parallel
|
|
117
|
+
const [contextResult, resolved, session, ccConfig, ccResolved] = await Promise.all([
|
|
118
|
+
// Branch A: Load messages + build token-aware context window
|
|
119
|
+
buildContextMessages(userId, thread, config.db, config.context),
|
|
120
|
+
// Branch B: Resolve graph context (400-2000ms, the bottleneck)
|
|
121
|
+
neo4j && embed
|
|
122
|
+
? resolveFromGraph(prompt, { neo4j, embed, reranker: config.reranker })
|
|
123
|
+
: Promise.resolve(null),
|
|
124
|
+
// Branch C: Resolve session data
|
|
125
|
+
resolveSession(config, thread, token),
|
|
126
|
+
// Branch D: Control Center config (ETag-revalidated, last-known-good on outage)
|
|
127
|
+
ccClient
|
|
128
|
+
? getControlCenterConfig(ccClient, config.agentId, run.abortController.signal)
|
|
129
|
+
: Promise.resolve(null),
|
|
130
|
+
// Branch E: Control Center /resolve — on failure the turn degrades to
|
|
131
|
+
// the search meta-tools, it never blocks
|
|
132
|
+
ccClient && prompt
|
|
133
|
+
? ccClient.resolve(
|
|
134
|
+
config.agentId,
|
|
135
|
+
{
|
|
136
|
+
query: prompt,
|
|
137
|
+
hints: {
|
|
138
|
+
threadId: thread.id,
|
|
139
|
+
recentToolNames: getRecentCcTools(thread.id),
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
run.abortController.signal,
|
|
143
|
+
)
|
|
144
|
+
: Promise.resolve(null),
|
|
145
|
+
]);
|
|
146
|
+
|
|
147
|
+
const cc = createCcRuntime({
|
|
148
|
+
ccClient,
|
|
149
|
+
ccConfig,
|
|
150
|
+
ccResolved,
|
|
151
|
+
config,
|
|
152
|
+
thread,
|
|
153
|
+
userId,
|
|
154
|
+
token,
|
|
155
|
+
turnKey,
|
|
156
|
+
abortSignal: run.abortController.signal,
|
|
157
|
+
getStepIndex: () => inspector.steps.length,
|
|
158
|
+
onToolProgress: (toolName, toolCallId, status) =>
|
|
159
|
+
emitToolProgress(userId, thread, toolName, toolCallId, status),
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
const { messages: contextMessages, allMessages } = contextResult;
|
|
163
|
+
|
|
164
|
+
const turnToolsOptions = {
|
|
165
|
+
config,
|
|
166
|
+
cc,
|
|
167
|
+
neo4j,
|
|
168
|
+
thread,
|
|
169
|
+
userId,
|
|
170
|
+
token,
|
|
171
|
+
session,
|
|
172
|
+
requestContext,
|
|
173
|
+
threadAttachments,
|
|
174
|
+
};
|
|
175
|
+
const tools = buildTurnTools(turnToolsOptions);
|
|
176
|
+
const instrumentation = createToolInstrumentation({
|
|
177
|
+
...turnToolsOptions,
|
|
178
|
+
onToolStart: (toolName, toolCallId) =>
|
|
179
|
+
emitToolProgress(userId, thread, toolName, toolCallId, "started"),
|
|
180
|
+
onToolFinish: (toolName, toolCallId) =>
|
|
181
|
+
emitToolProgress(userId, thread, toolName, toolCallId, "finished"),
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
const systemPrompt = await buildSystemPrompt(
|
|
185
|
+
config,
|
|
186
|
+
resolved,
|
|
187
|
+
{ session, requestContext },
|
|
188
|
+
cc
|
|
189
|
+
? {
|
|
190
|
+
config: cc.config,
|
|
191
|
+
resolved: ccResolved,
|
|
192
|
+
variables: buildPromptVariables(cc.config.promptVariables, {
|
|
193
|
+
...session,
|
|
194
|
+
...requestContext,
|
|
195
|
+
locale: cc.locale,
|
|
196
|
+
}),
|
|
197
|
+
}
|
|
198
|
+
: undefined,
|
|
199
|
+
buildAttachmentListing(threadAttachments, lastUserMessage?.id, {
|
|
200
|
+
readAttachment: tools.some((tool) => tool.name === "readAttachment"),
|
|
201
|
+
attachmentSentinels: hasDefaultAttachmentInterceptor(config),
|
|
202
|
+
}),
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
const stream = chat({
|
|
206
|
+
adapter: model,
|
|
207
|
+
// Client tool declarations ride in on every request, so the server
|
|
208
|
+
// never re-declares them.
|
|
209
|
+
tools: mergeAgentTools(tools, params.tools),
|
|
210
|
+
messages: convertMessagesToModelMessages(
|
|
211
|
+
fitToContextWindow(contextMessages, systemPrompt, tools, config),
|
|
212
|
+
),
|
|
213
|
+
systemPrompts: [systemPrompt],
|
|
214
|
+
agentLoopStrategy: maxIterations(MAX_ITERATIONS),
|
|
215
|
+
abortController: run.abortController,
|
|
216
|
+
middleware: [
|
|
217
|
+
createCompressionMiddleware(config),
|
|
218
|
+
...(instrumentation ? [instrumentation] : []),
|
|
219
|
+
inspector.middleware,
|
|
220
|
+
],
|
|
221
|
+
threadId: thread.id,
|
|
222
|
+
runId: run.runId,
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
const producer = toServerSentEventsResponse(
|
|
226
|
+
commitBeforeTerminal(stream, {
|
|
227
|
+
isAborted: () => run.abortController.signal.aborted,
|
|
228
|
+
commit: async function (produced) {
|
|
229
|
+
const messages = produced.map(toChatMessage).map(withTurnMetadata);
|
|
230
|
+
await finishTurn({
|
|
231
|
+
messages,
|
|
232
|
+
// Summarization and the consumer hook judge the thread, not
|
|
233
|
+
// the turn — the run's own output is only its tail.
|
|
234
|
+
threadMessages: [...allMessages, ...messages],
|
|
235
|
+
isAborted: run.abortController.signal.aborted,
|
|
236
|
+
assistantMessageId: messages.at(-1)?.id,
|
|
237
|
+
thread,
|
|
238
|
+
userId,
|
|
239
|
+
capturedSteps: inspector.steps,
|
|
240
|
+
config,
|
|
241
|
+
});
|
|
242
|
+
},
|
|
243
|
+
}),
|
|
244
|
+
{
|
|
245
|
+
// Append per chunk rather than per batch of 32: a client joining
|
|
246
|
+
// the log is waiting on real tokens, not on a buffer filling up.
|
|
247
|
+
durability: { adapter: producerLog(run.runId), batch: 1 },
|
|
248
|
+
abortController: run.abortController,
|
|
249
|
+
},
|
|
250
|
+
);
|
|
251
|
+
|
|
252
|
+
function withTurnMetadata(message: ChatMessage, index: number, all: ChatMessage[]) {
|
|
253
|
+
if (index !== all.length - 1 || message.role !== "assistant") return message;
|
|
254
|
+
|
|
255
|
+
return {
|
|
256
|
+
...message,
|
|
257
|
+
metadata: {
|
|
258
|
+
modelId: inspector.modelId,
|
|
259
|
+
isAborted: run.abortController.signal.aborted,
|
|
260
|
+
tokenUsage: inspector.tokenUsage,
|
|
261
|
+
} satisfies MessageMetadata,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
99
264
|
|
|
100
|
-
|
|
101
|
-
|
|
265
|
+
// Generation outlives the request that started it, so a reload mid-turn
|
|
266
|
+
// rejoins the log instead of restarting the model. Draining into a sink
|
|
267
|
+
// that never cancels is what detaches the producer from this response;
|
|
268
|
+
// the client gets a reader on the same log.
|
|
269
|
+
void producer
|
|
270
|
+
.body!.pipeTo(new WritableStream())
|
|
271
|
+
.catch(() => undefined)
|
|
272
|
+
.finally(() => releaseRun(thread.id, run.runId));
|
|
273
|
+
|
|
274
|
+
return resumeServerSentEventsResponse({ adapter: joinLog(thread.id, run.runId) });
|
|
275
|
+
} catch (error) {
|
|
276
|
+
releaseRun(thread.id, run.runId);
|
|
277
|
+
throw error;
|
|
102
278
|
}
|
|
279
|
+
}
|
|
103
280
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
config.db,
|
|
111
|
-
config.storage,
|
|
112
|
-
config.backendFetch.interceptor,
|
|
113
|
-
),
|
|
114
|
-
};
|
|
281
|
+
/** Releasing the claim must never mask the turn's own error or reject unhandled. */
|
|
282
|
+
function releaseRun(threadId: string, runId: string) {
|
|
283
|
+
endRun(threadId, runId).catch((error: unknown) =>
|
|
284
|
+
console.error("[cortex-server] Failed to release run claim:", error),
|
|
285
|
+
);
|
|
286
|
+
}
|
|
115
287
|
|
|
116
|
-
|
|
117
|
-
|
|
288
|
+
/** Drops the SDK's transport shape into the envelope cortex persists and serves. */
|
|
289
|
+
function toChatMessage(message: UIMessage) {
|
|
290
|
+
return { id: message.id, role: message.role, parts: message.parts } satisfies ChatMessage;
|
|
291
|
+
}
|
|
118
292
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
293
|
+
/**
|
|
294
|
+
* An assistant turn the client is sending back because it resolved a tool call.
|
|
295
|
+
*
|
|
296
|
+
* The wire fans that turn out into a `role: "tool"` message per result, and each
|
|
297
|
+
* of those normalizes back into an assistant message carrying only the result,
|
|
298
|
+
* under a freshly generated id. Stored as rows of their own they would replay as
|
|
299
|
+
* assistant turns answering calls that no message makes, so the turn is picked
|
|
300
|
+
* out by holding both halves of the exchange.
|
|
301
|
+
*/
|
|
302
|
+
function answersToolCalls(message: ChatMessage) {
|
|
303
|
+
return (
|
|
304
|
+
message.role === "assistant" &&
|
|
305
|
+
message.parts.some((part) => part.type === "tool-call") &&
|
|
306
|
+
message.parts.some((part) => part.type === "tool-result")
|
|
307
|
+
);
|
|
308
|
+
}
|
|
123
309
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
310
|
+
function textOf(message: ChatMessage | undefined) {
|
|
311
|
+
const part = message?.parts.find((candidate) => candidate.type === "text");
|
|
312
|
+
return part?.type === "text" ? part.content : "";
|
|
313
|
+
}
|
|
128
314
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
315
|
+
/**
|
|
316
|
+
* Builds the clients one turn needs. Neo4j runs vector search through an embedding
|
|
317
|
+
* model, so configuring a graph without one is a misconfiguration we surface
|
|
318
|
+
* loudly rather than quietly serving every turn with no graph context.
|
|
319
|
+
*/
|
|
320
|
+
function createTurnProviders(config: ResolvedCortexAgentConfig, fetch: typeof globalThis.fetch) {
|
|
321
|
+
if (config.neo4j && !config.embedding) {
|
|
322
|
+
throw new HTTPException(500, {
|
|
323
|
+
message: "embedding config is required when neo4j is configured",
|
|
324
|
+
});
|
|
325
|
+
}
|
|
133
326
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
327
|
+
const embed = config.embedding ? createEmbedder(config.embedding) : undefined;
|
|
328
|
+
|
|
329
|
+
return {
|
|
330
|
+
// The inspector's fetch is per-turn, so the model is too.
|
|
331
|
+
model: createModel(config.model, { fetch }),
|
|
332
|
+
embed,
|
|
333
|
+
neo4j: config.neo4j && embed ? createNeo4jClient(config.neo4j, embed) : undefined,
|
|
334
|
+
ccClient: config.controlCenter ? new ControlCenterClient(config.controlCenter) : null,
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* The context builder reserved a static token budget for the system prompt and
|
|
340
|
+
* tools before either existed. Now that both are real, drop the oldest messages
|
|
341
|
+
* if the reserve fell short.
|
|
342
|
+
*/
|
|
343
|
+
function fitToContextWindow(
|
|
344
|
+
contextMessages: ChatMessage[],
|
|
345
|
+
systemPrompt: string,
|
|
346
|
+
tools: ToolSet,
|
|
347
|
+
config: ResolvedCortexAgentConfig,
|
|
348
|
+
) {
|
|
137
349
|
const actualFixedCost = estimateTokens(systemPrompt) + estimateTokens(JSON.stringify(tools));
|
|
138
350
|
const { reservedTokenBudget, maxContextTokens } = config.context;
|
|
139
|
-
|
|
140
|
-
actualFixedCost > reservedTokenBudget
|
|
141
|
-
? trimMessagesToFit(contextMessages, maxContextTokens - actualFixedCost)
|
|
142
|
-
: contextMessages;
|
|
143
|
-
|
|
144
|
-
const recentMessages = await convertToModelMessages(trimmedMessages);
|
|
145
|
-
|
|
146
|
-
const { context: contextConfig } = config;
|
|
147
|
-
|
|
148
|
-
const capturedSteps: {
|
|
149
|
-
prompt: string;
|
|
150
|
-
output: string | null;
|
|
151
|
-
tokenUsage: TokenUsage | null;
|
|
152
|
-
}[] = [];
|
|
153
|
-
|
|
154
|
-
const result = streamText({
|
|
155
|
-
model: wrapLanguageModel({
|
|
156
|
-
model,
|
|
157
|
-
middleware: {
|
|
158
|
-
specificationVersion: "v3",
|
|
159
|
-
transformParams: async ({ params }) => {
|
|
160
|
-
// Strategy 1: Compress older step tool results to one-liners
|
|
161
|
-
let optimizedPrompt = compressIntraTurnToolResults(
|
|
162
|
-
params.prompt,
|
|
163
|
-
contextConfig.toolResultMaxTokens,
|
|
164
|
-
);
|
|
165
|
-
|
|
166
|
-
// Strategy 5: If still over threshold, summarize with LLM
|
|
167
|
-
const summarizationModel = contextConfig.summarizationModel ?? config.model;
|
|
168
|
-
const toolTokens = estimateToolResultTokens(optimizedPrompt);
|
|
169
|
-
|
|
170
|
-
if (toolTokens > contextConfig.intraTurnSummarizationThresholdTokens) {
|
|
171
|
-
try {
|
|
172
|
-
optimizedPrompt = await summarizeOldStepResults(
|
|
173
|
-
optimizedPrompt,
|
|
174
|
-
contextConfig.intraTurnSummarizationThresholdTokens,
|
|
175
|
-
summarizationModel,
|
|
176
|
-
);
|
|
177
|
-
} catch (err) {
|
|
178
|
-
console.error("[cortex-server] Intra-turn summarization failed:", err);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
return { ...params, prompt: optimizedPrompt };
|
|
183
|
-
},
|
|
184
|
-
},
|
|
185
|
-
}),
|
|
186
|
-
system: systemPrompt,
|
|
187
|
-
tools,
|
|
188
|
-
messages: recentMessages,
|
|
189
|
-
abortSignal: abortController.signal,
|
|
190
|
-
stopWhen: stepCountIs(25),
|
|
191
|
-
onStepFinish: (step) => {
|
|
192
|
-
const usage = step.usage;
|
|
193
|
-
capturedSteps.push({
|
|
194
|
-
prompt: JSON.stringify(step.request.body),
|
|
195
|
-
output: JSON.stringify({
|
|
196
|
-
text: step.text,
|
|
197
|
-
content: step.content,
|
|
198
|
-
finishReason: step.finishReason,
|
|
199
|
-
response: {
|
|
200
|
-
id: step.response.id,
|
|
201
|
-
modelId: step.response.modelId,
|
|
202
|
-
messages: step.response.messages,
|
|
203
|
-
},
|
|
204
|
-
providerMetadata: step.providerMetadata,
|
|
205
|
-
}),
|
|
206
|
-
tokenUsage: {
|
|
207
|
-
input: {
|
|
208
|
-
noCache: usage.inputTokenDetails.noCacheTokens ?? 0,
|
|
209
|
-
cacheRead: usage.inputTokenDetails.cacheReadTokens ?? 0,
|
|
210
|
-
cacheWrite: usage.inputTokenDetails.cacheWriteTokens ?? 0,
|
|
211
|
-
total: usage.inputTokens ?? 0,
|
|
212
|
-
},
|
|
213
|
-
output: {
|
|
214
|
-
reasoning: usage.outputTokenDetails.reasoningTokens ?? 0,
|
|
215
|
-
text: usage.outputTokenDetails.textTokens ?? 0,
|
|
216
|
-
total: usage.outputTokens ?? 0,
|
|
217
|
-
},
|
|
218
|
-
total: usage.totalTokens ?? 0,
|
|
219
|
-
},
|
|
220
|
-
});
|
|
221
|
-
},
|
|
222
|
-
});
|
|
351
|
+
if (actualFixedCost <= reservedTokenBudget) return contextMessages;
|
|
223
352
|
|
|
224
|
-
return
|
|
225
|
-
|
|
226
|
-
generateMessageId: generateId,
|
|
227
|
-
consumeSseStream: ({ stream: sseStream }) => {
|
|
228
|
-
attachSseStream(thread.id, sseStream);
|
|
229
|
-
},
|
|
230
|
-
onFinish: async ({ messages: finishedMessages, isAborted }) => {
|
|
231
|
-
if (isAborted) {
|
|
232
|
-
finalizeAbortedMessages(finishedMessages);
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
// Record token usage (result promises reject on abort, so skip)
|
|
236
|
-
const lastAssistantMessage = finishedMessages
|
|
237
|
-
.filter((x) => x.role === "assistant")
|
|
238
|
-
.at(-1);
|
|
239
|
-
if (lastAssistantMessage && !isAborted) {
|
|
240
|
-
const providerMetadata = await result.providerMetadata;
|
|
241
|
-
const response = await result.response;
|
|
242
|
-
const usage = await result.totalUsage;
|
|
243
|
-
let metadata: MessageMetadata = {
|
|
244
|
-
isAborted,
|
|
245
|
-
providerMetadata,
|
|
246
|
-
modelId: response.modelId,
|
|
247
|
-
tokenUsage: {
|
|
248
|
-
input: {
|
|
249
|
-
noCache: usage.inputTokenDetails.noCacheTokens ?? 0,
|
|
250
|
-
cacheRead: usage.inputTokenDetails.cacheReadTokens ?? 0,
|
|
251
|
-
cacheWrite: usage.inputTokenDetails.cacheWriteTokens ?? 0,
|
|
252
|
-
total: usage.inputTokens ?? 0,
|
|
253
|
-
},
|
|
254
|
-
output: {
|
|
255
|
-
reasoning: usage.outputTokenDetails.reasoningTokens ?? 0,
|
|
256
|
-
text: usage.outputTokenDetails.textTokens ?? 0,
|
|
257
|
-
total: usage.outputTokens ?? 0,
|
|
258
|
-
},
|
|
259
|
-
total: usage.totalTokens ?? 0,
|
|
260
|
-
},
|
|
261
|
-
};
|
|
262
|
-
|
|
263
|
-
lastAssistantMessage.metadata = metadata;
|
|
264
|
-
} else if (lastAssistantMessage) {
|
|
265
|
-
lastAssistantMessage.metadata = {
|
|
266
|
-
isAborted,
|
|
267
|
-
modelId: "",
|
|
268
|
-
providerMetadata: undefined,
|
|
269
|
-
};
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
const persistedThread = await config.db.threads.getById(userId, thread.id);
|
|
273
|
-
if (!persistedThread) {
|
|
274
|
-
removeStream(thread.id);
|
|
275
|
-
return;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
await config.db.messages.upsert(thread.id, finishedMessages);
|
|
279
|
-
|
|
280
|
-
// Persist captured LLM request/response data per step
|
|
281
|
-
if (capturedSteps.length > 0 && lastAssistantMessage) {
|
|
282
|
-
const llmRequestInserts = capturedSteps.map((step, index) => ({
|
|
283
|
-
messageId: lastAssistantMessage.id,
|
|
284
|
-
stepNumber: index,
|
|
285
|
-
prompt: step.prompt,
|
|
286
|
-
output: step.output,
|
|
287
|
-
tokenUsage: step.tokenUsage,
|
|
288
|
-
}));
|
|
289
|
-
|
|
290
|
-
try {
|
|
291
|
-
await config.db.llmRequests.insert(llmRequestInserts);
|
|
292
|
-
} catch (err) {
|
|
293
|
-
console.error("[cortex-server] Failed to persist AI requests:", err);
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
config.onStreamFinish?.({ messages: finishedMessages, isAborted });
|
|
298
|
-
|
|
299
|
-
// XXX: we need to notify the user so that the client can
|
|
300
|
-
// fetch new messages. The client can't fetch messages
|
|
301
|
-
// immediately because messages may not have been saved yet.
|
|
302
|
-
notify(userId, persistedThread.agentId, {
|
|
303
|
-
type: "thread:messages-updated",
|
|
304
|
-
payload: {
|
|
305
|
-
threadId: thread.id,
|
|
306
|
-
thread: toThreadSummary(persistedThread, false),
|
|
307
|
-
},
|
|
308
|
-
});
|
|
353
|
+
return trimMessagesToFit(contextMessages, maxContextTokens - actualFixedCost);
|
|
354
|
+
}
|
|
309
355
|
|
|
310
|
-
|
|
356
|
+
const TITLE_SYSTEM_PROMPT = `You are an expert in generating titles for threads of chats
|
|
357
|
+
given the first message in that thread.
|
|
311
358
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
try {
|
|
315
|
-
optimizeThreadContext(thread, finishedMessages, config);
|
|
316
|
-
} catch (err) {
|
|
317
|
-
console.error("[cortex-server] Context optimization failed:", err);
|
|
318
|
-
}
|
|
319
|
-
},
|
|
320
|
-
});
|
|
321
|
-
}
|
|
359
|
+
When asked, only respond with the title without saying you're
|
|
360
|
+
going to do so or any other speech. Spit out only the title.`;
|
|
322
361
|
|
|
323
362
|
export async function generateTitle(
|
|
324
363
|
threadId: string,
|
|
@@ -326,53 +365,44 @@ export async function generateTitle(
|
|
|
326
365
|
userId: string,
|
|
327
366
|
config: ResolvedCortexAgentConfig,
|
|
328
367
|
) {
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
368
|
+
const title = await chat({
|
|
369
|
+
adapter: createModel(config.model, { name: "title" }),
|
|
370
|
+
stream: false,
|
|
371
|
+
systemPrompts: [TITLE_SYSTEM_PROMPT],
|
|
372
|
+
messages: [
|
|
373
|
+
{
|
|
374
|
+
id: generateMessageId(),
|
|
375
|
+
role: "user",
|
|
376
|
+
parts: [{ type: "text", content: `Generate a title for this prompt: ${prompt}` }],
|
|
377
|
+
},
|
|
378
|
+
],
|
|
339
379
|
});
|
|
340
380
|
|
|
341
|
-
|
|
381
|
+
// A failed generation resolves to empty text rather than throwing, and the
|
|
382
|
+
// only trigger for a retry is the title still being null — so writing "" here
|
|
383
|
+
// would leave the thread permanently unnamed.
|
|
384
|
+
if (!title) return;
|
|
385
|
+
|
|
386
|
+
await config.db.threads.updateTitle(threadId, title);
|
|
342
387
|
|
|
343
388
|
const thread = await config.db.threads.getById(userId, threadId);
|
|
344
389
|
if (!thread) return;
|
|
345
390
|
|
|
346
391
|
notify(userId, thread.agentId, {
|
|
347
392
|
type: "thread:title-updated",
|
|
348
|
-
payload: { thread: toThreadSummary(thread,
|
|
393
|
+
payload: { thread: toThreadSummary(thread, await isRunning(thread.id)) },
|
|
349
394
|
});
|
|
350
395
|
}
|
|
351
396
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
if ("toolCallId" in part && "state" in part) {
|
|
364
|
-
const toolState = part.state;
|
|
365
|
-
if (!TERMINAL_TOOL_STATES.has(toolState)) {
|
|
366
|
-
const { approval: _, ...rest } = part;
|
|
367
|
-
return {
|
|
368
|
-
...rest,
|
|
369
|
-
state: "output-error" as const,
|
|
370
|
-
errorText: "Generation was aborted",
|
|
371
|
-
output: undefined,
|
|
372
|
-
};
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
return part;
|
|
397
|
+
function emitToolProgress(
|
|
398
|
+
userId: string,
|
|
399
|
+
thread: Thread,
|
|
400
|
+
toolName: string,
|
|
401
|
+
toolCallId: string,
|
|
402
|
+
status: "started" | "finished",
|
|
403
|
+
) {
|
|
404
|
+
notify(userId, thread.agentId, {
|
|
405
|
+
type: "thread:tool-progress",
|
|
406
|
+
payload: { threadId: thread.id, toolCallId, toolName, status },
|
|
377
407
|
});
|
|
378
408
|
}
|