@m6d/cortex-server 1.8.0 → 2.0.1
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/rich-text.ts +207 -0
- package/contracts/runtime.ts +243 -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/rich-text.d.ts +32 -0
- package/dist/contracts/runtime.d.ts +310 -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 +366 -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 +92 -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
|
@@ -1,132 +1,56 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
} from "
|
|
6
|
-
import {
|
|
7
|
-
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
|
|
8
|
-
import { estimateTokens } from "./token-estimator.ts";
|
|
9
|
-
import { summarizeValue } from "./compressor.ts";
|
|
10
|
-
import type { ContextConfig } from "./types.ts";
|
|
11
|
-
|
|
12
|
-
type ToolRoleMessage = LanguageModelV3Message & { role: "tool" };
|
|
1
|
+
import { chat } from "@tanstack/ai";
|
|
2
|
+
import type { ModelMessage } from "@tanstack/ai";
|
|
3
|
+
import { createModel } from "@/ai/helpers";
|
|
4
|
+
import { estimateTokens } from "./token-estimator";
|
|
5
|
+
import { summarizeValue } from "./compressor";
|
|
6
|
+
import type { ContextConfig } from "./types";
|
|
13
7
|
|
|
14
8
|
type SummarizationModelConfig = NonNullable<ContextConfig["summarizationModel"]>;
|
|
15
9
|
|
|
10
|
+
type ToolCallOrigin = { name: string; step: number };
|
|
11
|
+
|
|
16
12
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
13
|
+
* A tool message names only the call it answers, so both the tool's own name and the
|
|
14
|
+
* step it belongs to have to be recovered from the assistant message that asked for
|
|
15
|
+
* it. One tool message carries one result, so a step that issued three calls in
|
|
16
|
+
* parallel arrives as three messages; regrouping them into their step is what stops
|
|
17
|
+
* a step's own results from ageing each other out.
|
|
22
18
|
*/
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
) {
|
|
27
|
-
// Collect indices of all tool-role messages
|
|
28
|
-
const toolMessageIndices: number[] = [];
|
|
29
|
-
for (let i = 0; i < prompt.length; i++) {
|
|
30
|
-
if (prompt[i]!.role === "tool") {
|
|
31
|
-
toolMessageIndices.push(i);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Need at least 3 tool messages to have "old" ones to compress
|
|
36
|
-
// (keep last 1 fully intact, compress the rest)
|
|
37
|
-
if (toolMessageIndices.length < 3) return prompt;
|
|
38
|
-
|
|
39
|
-
// Clone the prompt so we don't mutate the original
|
|
40
|
-
const result = prompt.map((msg) => ({ ...msg }));
|
|
19
|
+
function toolStepsOf(messages: ModelMessage[]) {
|
|
20
|
+
const calls = new Map<string, ToolCallOrigin>();
|
|
21
|
+
const steps: number[][] = [];
|
|
41
22
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const compressedContent = msg.content.map((part) => {
|
|
48
|
-
if (part.type !== "tool-result") return part;
|
|
49
|
-
return compressToolResultPart(part, toolResultMaxTokens);
|
|
50
|
-
});
|
|
23
|
+
for (const [index, message] of messages.entries()) {
|
|
24
|
+
for (const call of message.toolCalls ?? []) {
|
|
25
|
+
calls.set(call.id, { name: call.function.name, step: steps.length });
|
|
26
|
+
}
|
|
27
|
+
if (message.role !== "tool") continue;
|
|
51
28
|
|
|
52
|
-
result
|
|
29
|
+
// A result whose call was never announced belongs to the step in progress;
|
|
30
|
+
// filing it anywhere else would invent a step that issued nothing.
|
|
31
|
+
const step = calls.get(message.toolCallId ?? "")?.step ?? steps.length;
|
|
32
|
+
(steps[step] ??= []).push(index);
|
|
53
33
|
}
|
|
54
34
|
|
|
55
|
-
return
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function compressToolResultPart(
|
|
59
|
-
part: LanguageModelV3ToolResultPart,
|
|
60
|
-
maxTokens: number,
|
|
61
|
-
): LanguageModelV3ToolResultPart {
|
|
62
|
-
const output = part.output;
|
|
63
|
-
|
|
64
|
-
// Already small enough
|
|
65
|
-
const outputStr = stringifyOutput(output);
|
|
66
|
-
if (estimateTokens(outputStr) <= maxTokens) return part;
|
|
67
|
-
|
|
68
|
-
const compressed = compressOutputToOneLiner(output, part.toolName);
|
|
69
|
-
|
|
70
|
-
return {
|
|
71
|
-
...part,
|
|
72
|
-
output: { type: "text", value: compressed },
|
|
73
|
-
};
|
|
35
|
+
return { calls, steps };
|
|
74
36
|
}
|
|
75
37
|
|
|
76
|
-
function
|
|
77
|
-
|
|
78
|
-
case "text":
|
|
79
|
-
case "error-text":
|
|
80
|
-
return output.value;
|
|
81
|
-
case "json":
|
|
82
|
-
case "error-json":
|
|
83
|
-
return JSON.stringify(output.value);
|
|
84
|
-
case "execution-denied":
|
|
85
|
-
return output.reason ?? "denied";
|
|
86
|
-
case "content":
|
|
87
|
-
return JSON.stringify(output.value);
|
|
88
|
-
default:
|
|
89
|
-
return "";
|
|
90
|
-
}
|
|
38
|
+
function toolNameOf(message: ModelMessage, calls: Map<string, ToolCallOrigin>) {
|
|
39
|
+
return calls.get(message.toolCallId ?? "")?.name ?? "tool";
|
|
91
40
|
}
|
|
92
41
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
42
|
+
/**
|
|
43
|
+
* A message's content is either a plain string or content parts, of which only the
|
|
44
|
+
* text ones can be digested — which is all a one-line stand-in was going to keep.
|
|
45
|
+
*/
|
|
46
|
+
function contentText(content: ModelMessage["content"]) {
|
|
47
|
+
if (typeof content === "string") return content;
|
|
48
|
+
if (content === null) return "";
|
|
98
49
|
|
|
99
|
-
|
|
100
|
-
case "text": {
|
|
101
|
-
const preview = extractPreview(output.value);
|
|
102
|
-
return `${tag} ${preview}`;
|
|
103
|
-
}
|
|
104
|
-
case "json":
|
|
105
|
-
return `${tag} ${summarizeValue(output.value)}`;
|
|
106
|
-
case "error-text": {
|
|
107
|
-
const firstLine = output.value.split("\n")[0] ?? "error";
|
|
108
|
-
return `${tag} ERROR - ${firstLine}`;
|
|
109
|
-
}
|
|
110
|
-
case "error-json": {
|
|
111
|
-
const errStr = JSON.stringify(output.value).slice(0, 200);
|
|
112
|
-
return `${tag} ERROR - ${errStr}`;
|
|
113
|
-
}
|
|
114
|
-
case "execution-denied":
|
|
115
|
-
return `${tag} execution denied${output.reason ? ` - ${output.reason}` : ""}`;
|
|
116
|
-
case "content": {
|
|
117
|
-
const textParts = output.value
|
|
118
|
-
.filter((p): p is Extract<typeof p, { type: "text" }> => p.type === "text")
|
|
119
|
-
.map((p) => p.text);
|
|
120
|
-
const joined = textParts.join(" ");
|
|
121
|
-
const preview = extractPreview(joined);
|
|
122
|
-
return `${tag} ${preview}`;
|
|
123
|
-
}
|
|
124
|
-
default:
|
|
125
|
-
return `${tag} completed`;
|
|
126
|
-
}
|
|
50
|
+
return content.flatMap((part) => (part.type === "text" ? [part.content] : [])).join(" ");
|
|
127
51
|
}
|
|
128
52
|
|
|
129
|
-
function extractPreview(text: string)
|
|
53
|
+
function extractPreview(text: string) {
|
|
130
54
|
// Try to parse as JSON for structured summary
|
|
131
55
|
try {
|
|
132
56
|
const parsed: unknown = JSON.parse(text);
|
|
@@ -141,124 +65,117 @@ function extractPreview(text: string): string {
|
|
|
141
65
|
return text.slice(0, 147) + "...";
|
|
142
66
|
}
|
|
143
67
|
|
|
68
|
+
/**
|
|
69
|
+
* Compresses tool results from older steps in the prompt.
|
|
70
|
+
*
|
|
71
|
+
* On step N, tool results from steps 1..N-2 are aggressively compressed
|
|
72
|
+
* to short one-liners. Only the most recent step's results stay in full.
|
|
73
|
+
* Does not mutate the input — returns a new array.
|
|
74
|
+
*/
|
|
75
|
+
export function compressIntraTurnToolResults(
|
|
76
|
+
messages: ModelMessage[],
|
|
77
|
+
toolResultMaxTokens: number,
|
|
78
|
+
) {
|
|
79
|
+
const { calls, steps } = toolStepsOf(messages);
|
|
80
|
+
|
|
81
|
+
// Below three there is nothing genuinely "old" to compress once the most
|
|
82
|
+
// recent step is kept intact.
|
|
83
|
+
if (steps.length < 3) return messages;
|
|
84
|
+
|
|
85
|
+
const result = [...messages];
|
|
86
|
+
|
|
87
|
+
for (const index of steps.slice(0, -1).flat()) {
|
|
88
|
+
const message = messages[index]!;
|
|
89
|
+
const text = contentText(message.content);
|
|
90
|
+
if (estimateTokens(text) <= toolResultMaxTokens) continue;
|
|
91
|
+
|
|
92
|
+
const tag = `[COMPRESSED prior ${toolNameOf(message, calls)} result]`;
|
|
93
|
+
result[index] = { ...message, content: `${tag} ${extractPreview(text)}` };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
|
|
144
99
|
/**
|
|
145
100
|
* Estimates the total token count of tool results in the prompt.
|
|
146
101
|
*/
|
|
147
|
-
export function estimateToolResultTokens(
|
|
102
|
+
export function estimateToolResultTokens(messages: ModelMessage[]) {
|
|
148
103
|
let total = 0;
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
if (msg.role !== "tool") continue;
|
|
152
|
-
for (const part of msg.content) {
|
|
153
|
-
if (part.type === "tool-result") {
|
|
154
|
-
total += estimateTokens(stringifyOutput(part.output));
|
|
155
|
-
}
|
|
156
|
-
}
|
|
104
|
+
for (const message of messages) {
|
|
105
|
+
if (message.role === "tool") total += estimateTokens(contentText(message.content));
|
|
157
106
|
}
|
|
158
107
|
|
|
159
108
|
return total;
|
|
160
109
|
}
|
|
161
110
|
|
|
111
|
+
const SUMMARIZER_SYSTEM_PROMPT = `You are a tool result summarizer. Given previous tool call results from an AI agent's workflow, produce a concise summary preserving:
|
|
112
|
+
- Key data values, IDs, and counts
|
|
113
|
+
- Success/failure status of each operation
|
|
114
|
+
- Any error messages
|
|
115
|
+
- Data that subsequent tool calls may need
|
|
116
|
+
|
|
117
|
+
Maximum 300 tokens. Use bullet points. No preamble.`;
|
|
118
|
+
|
|
119
|
+
function requestSummary(resultTexts: string[], modelConfig: SummarizationModelConfig) {
|
|
120
|
+
return chat({
|
|
121
|
+
adapter: createModel(modelConfig, { name: "summarization" }),
|
|
122
|
+
systemPrompts: [SUMMARIZER_SYSTEM_PROMPT],
|
|
123
|
+
messages: [
|
|
124
|
+
{
|
|
125
|
+
role: "user",
|
|
126
|
+
content: `Summarize these tool results:\n\n${resultTexts.join("\n\n")}`,
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
stream: false,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
162
133
|
/**
|
|
163
134
|
* When accumulated tool result tokens exceed the threshold, summarizes
|
|
164
135
|
* older step results using a lightweight LLM call.
|
|
165
136
|
*
|
|
166
|
-
* Replaces
|
|
167
|
-
* summary in the oldest tool message.
|
|
137
|
+
* Replaces every tool result before the last two steps with a single
|
|
138
|
+
* synthetic summary in the oldest tool message.
|
|
168
139
|
*/
|
|
169
140
|
export async function summarizeOldStepResults(
|
|
170
|
-
|
|
141
|
+
messages: ModelMessage[],
|
|
171
142
|
thresholdTokens: number,
|
|
172
143
|
modelConfig: SummarizationModelConfig,
|
|
173
144
|
) {
|
|
174
|
-
|
|
175
|
-
if (totalToolTokens <= thresholdTokens) return prompt;
|
|
145
|
+
if (estimateToolResultTokens(messages) <= thresholdTokens) return messages;
|
|
176
146
|
|
|
177
|
-
|
|
178
|
-
const toolMessageIndices: number[] = [];
|
|
179
|
-
for (let i = 0; i < prompt.length; i++) {
|
|
180
|
-
if (prompt[i]!.role === "tool") {
|
|
181
|
-
toolMessageIndices.push(i);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
147
|
+
const { calls, steps } = toolStepsOf(messages);
|
|
184
148
|
|
|
185
|
-
//
|
|
186
|
-
|
|
149
|
+
// Summarization keeps the last two steps intact — one more than compression
|
|
150
|
+
// does, because a summary loses more detail than a truncated one-liner.
|
|
151
|
+
if (steps.length < 3) return messages;
|
|
187
152
|
|
|
188
|
-
|
|
153
|
+
// An emptied tool message has nothing to contribute to the digest, and nothing
|
|
154
|
+
// to gain from being pointed at one.
|
|
155
|
+
const indices = steps
|
|
156
|
+
.slice(0, -2)
|
|
157
|
+
.flat()
|
|
158
|
+
.filter((index) => contentText(messages[index]!.content) !== "");
|
|
159
|
+
if (indices.length === 0) return messages;
|
|
189
160
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
const msg = prompt[idx] as ToolRoleMessage;
|
|
194
|
-
for (const part of msg.content) {
|
|
195
|
-
if (part.type === "tool-result") {
|
|
196
|
-
resultTexts.push(`[${part.toolName}]: ${stringifyOutput(part.output)}`);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
if (resultTexts.length === 0) return prompt;
|
|
202
|
-
|
|
203
|
-
// Summarize with LLM
|
|
204
|
-
const provider = createOpenAICompatible({
|
|
205
|
-
name: modelConfig.providerName ?? "summarization-provider",
|
|
206
|
-
baseURL: modelConfig.baseURL,
|
|
207
|
-
apiKey: modelConfig.apiKey,
|
|
161
|
+
const resultTexts = indices.map((index) => {
|
|
162
|
+
const message = messages[index]!;
|
|
163
|
+
return `[${toolNameOf(message, calls)}]: ${contentText(message.content)}`;
|
|
208
164
|
});
|
|
209
165
|
|
|
210
|
-
const
|
|
166
|
+
const summary = await requestSummary(resultTexts, modelConfig);
|
|
211
167
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
168
|
+
// The first old tool message carries the summary and the rest point at it, so
|
|
169
|
+
// the model reads the digest once rather than once per collapsed message.
|
|
170
|
+
const result = [...messages];
|
|
171
|
+
indices.forEach((index, position) => {
|
|
172
|
+
const content =
|
|
173
|
+
position === 0
|
|
174
|
+
? `[Summary of ${indices.length} earlier tool results]:\n${summary}`
|
|
175
|
+
: "[see summary above]";
|
|
219
176
|
|
|
220
|
-
|
|
221
|
-
prompt: `Summarize these tool results:\n\n${resultTexts.join("\n\n")}`,
|
|
177
|
+
result[index] = { ...messages[index]!, content };
|
|
222
178
|
});
|
|
223
179
|
|
|
224
|
-
// Replace old tool messages with collapsed versions containing just the summary
|
|
225
|
-
const result = [...prompt];
|
|
226
|
-
|
|
227
|
-
for (let i = 0; i < indicesToSummarize.length; i++) {
|
|
228
|
-
const idx = indicesToSummarize[i]!;
|
|
229
|
-
const originalMsg = prompt[idx] as ToolRoleMessage;
|
|
230
|
-
|
|
231
|
-
if (i === 0) {
|
|
232
|
-
// First old tool message gets the summary
|
|
233
|
-
const summarizedContent = originalMsg.content.map((part) => {
|
|
234
|
-
if (part.type !== "tool-result") return part;
|
|
235
|
-
return {
|
|
236
|
-
...part,
|
|
237
|
-
output: {
|
|
238
|
-
type: "text" as const,
|
|
239
|
-
value: `[Summary of ${resultTexts.length} earlier tool results]:\n${summary}`,
|
|
240
|
-
},
|
|
241
|
-
};
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
// Keep only the first tool-result part with the summary
|
|
245
|
-
const firstResultIdx = summarizedContent.findIndex((p) => p.type === "tool-result");
|
|
246
|
-
const collapsedContent =
|
|
247
|
-
firstResultIdx >= 0 ? [summarizedContent[firstResultIdx]!] : summarizedContent;
|
|
248
|
-
|
|
249
|
-
result[idx] = { ...originalMsg, content: collapsedContent } as LanguageModelV3Message;
|
|
250
|
-
} else {
|
|
251
|
-
// Subsequent old tool messages get one-liners
|
|
252
|
-
const collapsedContent = originalMsg.content.map((part) => {
|
|
253
|
-
if (part.type !== "tool-result") return part;
|
|
254
|
-
return {
|
|
255
|
-
...part,
|
|
256
|
-
output: { type: "text" as const, value: `[see summary above]` },
|
|
257
|
-
};
|
|
258
|
-
});
|
|
259
|
-
result[idx] = { ...originalMsg, content: collapsedContent } as LanguageModelV3Message;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
180
|
return result;
|
|
264
181
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { ResolvedCortexAgentConfig } from "@/config";
|
|
2
|
+
import type { ChatMessage, Thread } from "@/types";
|
|
3
|
+
import type { ThreadContextMeta } from "./types";
|
|
4
|
+
import { estimateMessagesTokens } from "./token-estimator";
|
|
5
|
+
import { summarizeMessages } from "./summarizer";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Post-response context optimization, called fire-and-forget from onFinish.
|
|
9
|
+
*
|
|
10
|
+
* Below the summarization threshold this only refreshes the token estimate —
|
|
11
|
+
* summarizing early would burn a model call to compress context that still fits.
|
|
12
|
+
*/
|
|
13
|
+
export async function optimizeThreadContext(
|
|
14
|
+
thread: Thread,
|
|
15
|
+
messages: ChatMessage[],
|
|
16
|
+
config: ResolvedCortexAgentConfig,
|
|
17
|
+
) {
|
|
18
|
+
const contextConfig = config.context;
|
|
19
|
+
const estimates = estimateMessagesTokens(messages);
|
|
20
|
+
const totalEstimatedTokens = estimates.reduce((sum, e) => sum + e.tokens, 0);
|
|
21
|
+
const threshold = contextConfig.maxContextTokens * contextConfig.summarizationThreshold;
|
|
22
|
+
|
|
23
|
+
if (totalEstimatedTokens <= threshold) {
|
|
24
|
+
await config.db.threads.updateContextMeta(thread.id, {
|
|
25
|
+
summary: thread.contextMeta?.summary ?? null,
|
|
26
|
+
summaryUpToMessageId: thread.contextMeta?.summaryUpToMessageId ?? null,
|
|
27
|
+
totalEstimatedTokens,
|
|
28
|
+
lastOptimizedAt: new Date().toISOString(),
|
|
29
|
+
} satisfies ThreadContextMeta);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// The most recent messages stay unsummarized — they're the hot context.
|
|
34
|
+
const recentCount = Math.min(contextConfig.recentMessagesToKeep, messages.length);
|
|
35
|
+
const messagesToSummarize = messages.slice(0, messages.length - recentCount);
|
|
36
|
+
if (messagesToSummarize.length === 0) return;
|
|
37
|
+
|
|
38
|
+
const summary = await summarizeMessages(
|
|
39
|
+
messagesToSummarize,
|
|
40
|
+
thread.contextMeta?.summary ?? null,
|
|
41
|
+
contextConfig.summarizationModel ?? config.model,
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
await config.db.threads.updateContextMeta(thread.id, {
|
|
45
|
+
summary,
|
|
46
|
+
summaryUpToMessageId: messagesToSummarize.at(-1)?.id ?? null,
|
|
47
|
+
totalEstimatedTokens,
|
|
48
|
+
lastOptimizedAt: new Date().toISOString(),
|
|
49
|
+
} satisfies ThreadContextMeta);
|
|
50
|
+
}
|
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import type { ContextConfig } from "./types
|
|
1
|
+
import { chat } from "@tanstack/ai";
|
|
2
|
+
import { createModel } from "@/ai/helpers";
|
|
3
|
+
import type { ChatMessage } from "@/types";
|
|
4
|
+
import type { ContextConfig } from "./types";
|
|
5
5
|
|
|
6
6
|
type SummarizationModelConfig = NonNullable<ContextConfig["summarizationModel"]>;
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
const SYSTEM_PROMPT = `You are a precise conversation summarizer. Produce a concise summary that preserves:
|
|
9
|
+
- Key decisions and conclusions
|
|
10
|
+
- Important entities (names, IDs, URLs, values)
|
|
11
|
+
- User intent and goals
|
|
12
|
+
- Any unresolved questions or next steps
|
|
13
|
+
|
|
14
|
+
Maximum 500 tokens. Use bullet points. Do not include preamble.`;
|
|
15
|
+
|
|
16
|
+
export function summarizeMessages(
|
|
17
|
+
messages: ChatMessage[],
|
|
10
18
|
existingSummary: string | null,
|
|
11
19
|
modelConfig: SummarizationModelConfig,
|
|
12
20
|
) {
|
|
13
|
-
const provider = createOpenAICompatible({
|
|
14
|
-
name: modelConfig.providerName ?? "summarization-provider",
|
|
15
|
-
baseURL: modelConfig.baseURL,
|
|
16
|
-
apiKey: modelConfig.apiKey,
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
const model = provider.chatModel(modelConfig.modelName);
|
|
20
|
-
|
|
21
21
|
const conversationText = messages
|
|
22
22
|
.map(function (msg) {
|
|
23
|
-
const
|
|
24
|
-
.
|
|
25
|
-
.
|
|
26
|
-
return `[${msg.role}]: ${
|
|
23
|
+
const text = msg.parts
|
|
24
|
+
.flatMap((part) => (part.type === "text" ? [part.content] : []))
|
|
25
|
+
.join(" ");
|
|
26
|
+
return `[${msg.role}]: ${text}`;
|
|
27
27
|
})
|
|
28
28
|
.join("\n");
|
|
29
29
|
|
|
@@ -31,20 +31,18 @@ export async function summarizeMessages(
|
|
|
31
31
|
? `\nPrior summary of earlier messages:\n${existingSummary}\n`
|
|
32
32
|
: "";
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
Maximum 500 tokens. Use bullet points. Do not include preamble.`,
|
|
43
|
-
prompt: `${summaryContext}
|
|
34
|
+
return chat({
|
|
35
|
+
adapter: createModel(modelConfig, { name: "summarization" }),
|
|
36
|
+
systemPrompts: [SYSTEM_PROMPT],
|
|
37
|
+
messages: [
|
|
38
|
+
{
|
|
39
|
+
role: "user",
|
|
40
|
+
content: `${summaryContext}
|
|
44
41
|
Summarize the following conversation:
|
|
45
42
|
|
|
46
43
|
${conversationText}`,
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
stream: false,
|
|
47
47
|
});
|
|
48
|
-
|
|
49
|
-
return text;
|
|
50
48
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { MessagePart } from "@tanstack/ai";
|
|
2
|
+
import type { ChatMessage } from "@/types";
|
|
2
3
|
|
|
3
4
|
/** Average characters per token for English text. Used by the heuristic estimator. */
|
|
4
5
|
export const CHARS_PER_TOKEN = 4;
|
|
@@ -12,45 +13,49 @@ export function estimateTokens(text: string) {
|
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
|
-
*
|
|
16
|
+
* Media and UI parts carry a source, not text. What the provider actually bills
|
|
17
|
+
* for them is set by its own tokenizer — tiles for an image, pages for a document —
|
|
18
|
+
* and the length of a base64 payload says nothing useful about it, so they are
|
|
19
|
+
* charged a flat rate instead.
|
|
16
20
|
*/
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
} else if (part.type === "source-url") {
|
|
32
|
-
tokens += estimateTokens(part.url);
|
|
33
|
-
} else if (part.type === "source-document") {
|
|
34
|
-
tokens += estimateTokens(part.title);
|
|
35
|
-
} else if (part.type === "file") {
|
|
36
|
-
tokens += estimateTokens(part.url);
|
|
37
|
-
} else {
|
|
38
|
-
// step-start, data parts, etc.
|
|
39
|
-
tokens += 5;
|
|
21
|
+
const OPAQUE_PART_TOKENS = 5;
|
|
22
|
+
|
|
23
|
+
function estimatePartTokens(part: MessagePart) {
|
|
24
|
+
switch (part.type) {
|
|
25
|
+
case "text":
|
|
26
|
+
case "thinking":
|
|
27
|
+
return estimateTokens(part.content);
|
|
28
|
+
case "tool-call": {
|
|
29
|
+
// `arguments` is already the JSON the model emitted. `output` is only
|
|
30
|
+
// set for client-executed tools and for calls resolved after approval.
|
|
31
|
+
const output: unknown = part.output;
|
|
32
|
+
const outputTokens = output === undefined ? 0 : estimateTokens(JSON.stringify(output));
|
|
33
|
+
|
|
34
|
+
return estimateTokens(part.arguments) + outputTokens;
|
|
40
35
|
}
|
|
36
|
+
case "tool-result":
|
|
37
|
+
return estimateTokens(
|
|
38
|
+
typeof part.content === "string" ? part.content : JSON.stringify(part.content),
|
|
39
|
+
);
|
|
40
|
+
case "structured-output":
|
|
41
|
+
return estimateTokens(part.raw);
|
|
42
|
+
default:
|
|
43
|
+
return OPAQUE_PART_TOKENS;
|
|
41
44
|
}
|
|
45
|
+
}
|
|
42
46
|
|
|
43
|
-
|
|
44
|
-
|
|
47
|
+
export function estimateMessageTokens(message: ChatMessage) {
|
|
48
|
+
const parts = message.parts.reduce((sum, part) => sum + estimatePartTokens(part), 0);
|
|
45
49
|
|
|
46
|
-
|
|
50
|
+
// Per-message overhead (role, metadata framing)
|
|
51
|
+
return parts + 4;
|
|
47
52
|
}
|
|
48
53
|
|
|
49
54
|
/**
|
|
50
|
-
* Estimates token counts for an array of
|
|
55
|
+
* Estimates token counts for an array of messages.
|
|
51
56
|
* Returns per-message estimates in the same order.
|
|
52
57
|
*/
|
|
53
|
-
export function estimateMessagesTokens(messages:
|
|
58
|
+
export function estimateMessagesTokens(messages: ChatMessage[]) {
|
|
54
59
|
return messages.map(function (message) {
|
|
55
60
|
return {
|
|
56
61
|
message,
|
package/src/lib/ai/fetch.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { ResolvedCortexAgentConfig } from "
|
|
1
|
+
import type { ResolvedCortexAgentConfig } from "@/config";
|
|
2
|
+
import { resolveBackendUrl } from "./backend-url";
|
|
2
3
|
|
|
3
4
|
export async function fetchBackend(
|
|
4
5
|
path: string,
|
|
@@ -14,18 +15,22 @@ export async function fetchBackend(
|
|
|
14
15
|
finalOptions?.body &&
|
|
15
16
|
typeof finalOptions.body === "string"
|
|
16
17
|
) {
|
|
18
|
+
let parsed: Record<string, unknown> | undefined;
|
|
17
19
|
try {
|
|
18
|
-
|
|
20
|
+
parsed = JSON.parse(finalOptions.body) as Record<string, unknown>;
|
|
21
|
+
} catch {
|
|
22
|
+
// Non-JSON bodies pass through unchanged.
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (parsed !== undefined) {
|
|
19
26
|
const transformed = await backendFetch.transformRequestBody(parsed, {
|
|
20
27
|
token,
|
|
21
28
|
});
|
|
22
29
|
finalOptions = { ...finalOptions, body: JSON.stringify(transformed) };
|
|
23
|
-
} catch {
|
|
24
|
-
// If body isn't valid JSON, pass through as-is
|
|
25
30
|
}
|
|
26
31
|
}
|
|
27
32
|
|
|
28
|
-
return fetch(
|
|
33
|
+
return fetch(resolveBackendUrl(backendFetch.baseUrl, path), {
|
|
29
34
|
...finalOptions,
|
|
30
35
|
headers: {
|
|
31
36
|
"Content-Type": "application/json",
|