circuschief 0.1.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/package.json +33 -0
- package/packages/server/bin/cli.js +4 -0
- package/packages/server/src/agents/AgentGateway.js +64 -0
- package/packages/server/src/agents/BaseAgent.js +41 -0
- package/packages/server/src/agents/LoggingAgentWrapper.js +73 -0
- package/packages/server/src/agents/adapters/ClaudeCodeAdapter.js +33 -0
- package/packages/server/src/agents/adapters/CodexAdapter.js +26 -0
- package/packages/server/src/agents/types.js +43 -0
- package/packages/server/src/agents/vcr/CassetteStore.js +111 -0
- package/packages/server/src/agents/vcr/VCRAgentAdapter.js +126 -0
- package/packages/server/src/agents/vcr/VCRSummaryWrapper.js +71 -0
- package/packages/server/src/api/canvas-helpers.js +249 -0
- package/packages/server/src/api/canvas-trash-routes.js +205 -0
- package/packages/server/src/api/canvas.js +331 -0
- package/packages/server/src/api/commandButtons.js +312 -0
- package/packages/server/src/api/commands.js +169 -0
- package/packages/server/src/api/filesystem.js +62 -0
- package/packages/server/src/api/git.js +85 -0
- package/packages/server/src/api/index.js +44 -0
- package/packages/server/src/api/kanban.js +342 -0
- package/packages/server/src/api/metrics.js +194 -0
- package/packages/server/src/api/projects-helpers.js +43 -0
- package/packages/server/src/api/projects-session-helpers.js +295 -0
- package/packages/server/src/api/projects.js +384 -0
- package/packages/server/src/api/providers.js +249 -0
- package/packages/server/src/api/quickResponses.js +129 -0
- package/packages/server/src/api/sessions-archive.js +69 -0
- package/packages/server/src/api/sessions-commands.js +220 -0
- package/packages/server/src/api/sessions-conversations.js +168 -0
- package/packages/server/src/api/sessions-draft.js +72 -0
- package/packages/server/src/api/sessions-lifecycle.js +190 -0
- package/packages/server/src/api/sessions-messages.js +141 -0
- package/packages/server/src/api/sessions-notes.js +51 -0
- package/packages/server/src/api/sessions-patch.js +252 -0
- package/packages/server/src/api/sessions-streaming.js +86 -0
- package/packages/server/src/api/sessions.js +269 -0
- package/packages/server/src/api/settings.js +194 -0
- package/packages/server/src/api/templates.js +63 -0
- package/packages/server/src/app.js +51 -0
- package/packages/server/src/database.js +58 -0
- package/packages/server/src/db/AgentCallLogRepository.js +322 -0
- package/packages/server/src/db/AttachmentRepository.js +191 -0
- package/packages/server/src/db/BaseRepository.js +39 -0
- package/packages/server/src/db/CanvasItemRepository.js +315 -0
- package/packages/server/src/db/CommandButtonRepository.js +75 -0
- package/packages/server/src/db/CommandRunRepository.js +219 -0
- package/packages/server/src/db/ConversationRepository.js +379 -0
- package/packages/server/src/db/DatabaseManager.js +91 -0
- package/packages/server/src/db/KanbanBoardRepository.js +92 -0
- package/packages/server/src/db/KanbanCardRepository.js +286 -0
- package/packages/server/src/db/KanbanLaneRepository.js +279 -0
- package/packages/server/src/db/MessageRepository.js +156 -0
- package/packages/server/src/db/ProjectDefaultsRepository.js +173 -0
- package/packages/server/src/db/ProjectRepository.js +110 -0
- package/packages/server/src/db/ProviderRepository.js +307 -0
- package/packages/server/src/db/QuickResponseRepository.js +186 -0
- package/packages/server/src/db/SessionNoteRepository.js +60 -0
- package/packages/server/src/db/SessionRepository.js +314 -0
- package/packages/server/src/db/SessionSummaryRepository.js +200 -0
- package/packages/server/src/db/SessionTemplateRepository.js +171 -0
- package/packages/server/src/db/SettingsRepository.js +211 -0
- package/packages/server/src/db/TodoRepository.js +132 -0
- package/packages/server/src/db/WorkLogRepository.js +122 -0
- package/packages/server/src/db/conversation-helpers.js +119 -0
- package/packages/server/src/db/index.js +100 -0
- package/packages/server/src/db/migrations/canvasItemsMigrations.js +109 -0
- package/packages/server/src/db/migrations/conversationsMigrations.js +183 -0
- package/packages/server/src/db/migrations/index.js +199 -0
- package/packages/server/src/db/migrations/kanbanMigrations.js +99 -0
- package/packages/server/src/db/migrations/migrationUtils.js +55 -0
- package/packages/server/src/db/migrations/miscMigrations.js +242 -0
- package/packages/server/src/db/migrations/projectsMigrations.js +95 -0
- package/packages/server/src/db/migrations/sessionsMigrations.js +282 -0
- package/packages/server/src/db/session-helpers.js +150 -0
- package/packages/server/src/index.js +106 -0
- package/packages/server/src/logger.js +22 -0
- package/packages/server/src/middleware/sessionLookup.js +57 -0
- package/packages/server/src/middleware/upload.js +94 -0
- package/packages/server/src/schema.sql +363 -0
- package/packages/server/src/services/agentCallLogger.js +116 -0
- package/packages/server/src/services/canvasStore.js +56 -0
- package/packages/server/src/services/childSessionContext.js +61 -0
- package/packages/server/src/services/commandRunner.js +422 -0
- package/packages/server/src/services/conversationContext.js +72 -0
- package/packages/server/src/services/diffService.js +172 -0
- package/packages/server/src/services/draftSessionService.js +181 -0
- package/packages/server/src/services/encryption.js +134 -0
- package/packages/server/src/services/ghService.js +169 -0
- package/packages/server/src/services/gitService.js +520 -0
- package/packages/server/src/services/gitSessionSetup.js +48 -0
- package/packages/server/src/services/hookService.js +60 -0
- package/packages/server/src/services/kanbanService.js +262 -0
- package/packages/server/src/services/kanbanTriggers.js +273 -0
- package/packages/server/src/services/nodeSpawnHelper.js +63 -0
- package/packages/server/src/services/prStatusService.js +204 -0
- package/packages/server/src/services/prUrlService.js +224 -0
- package/packages/server/src/services/providerTestService.js +81 -0
- package/packages/server/src/services/scheduleService.js +110 -0
- package/packages/server/src/services/schedulerService.js +281 -0
- package/packages/server/src/services/sessionDuplicator.js +63 -0
- package/packages/server/src/services/sessionErrors.js +173 -0
- package/packages/server/src/services/sessionExecution.js +378 -0
- package/packages/server/src/services/sessionManager.js +356 -0
- package/packages/server/src/services/sessionPrompts.js +427 -0
- package/packages/server/src/services/sessionProvider.js +107 -0
- package/packages/server/src/services/slashCommandDiscovery.js +258 -0
- package/packages/server/src/services/slashCommandPluginDiscovery.js +216 -0
- package/packages/server/src/services/slashCommandService.js +306 -0
- package/packages/server/src/services/streamEventCallbacks.js +170 -0
- package/packages/server/src/services/streamEventHandler.js +488 -0
- package/packages/server/src/services/streamUsageHandler.js +228 -0
- package/packages/server/src/services/summaryBroadcast.js +61 -0
- package/packages/server/src/services/summaryClaudeClient.js +180 -0
- package/packages/server/src/services/summaryPrompts.js +169 -0
- package/packages/server/src/services/summaryService.js +552 -0
- package/packages/server/src/services/summaryStaleCheck.js +35 -0
- package/packages/server/src/services/systemMonitor.js +281 -0
- package/packages/server/src/services/templateTriggerService.js +197 -0
- package/packages/server/src/services/terminalOutput.js +160 -0
- package/packages/server/src/services/todoStore.js +58 -0
- package/packages/server/src/services/usageTracker.js +69 -0
- package/packages/server/src/services/withConcurrencyGuard.js +110 -0
- package/packages/server/src/websocket.js +10 -0
- package/packages/server/src/ws/WebSocketManager.js +240 -0
- package/packages/server/src/ws/index.js +50 -0
- package/packages/shared/package.json +27 -0
- package/packages/shared/src/constants.js +44 -0
- package/packages/shared/src/contracts/canvas.js +25 -0
- package/packages/shared/src/contracts/commandButtons.js +36 -0
- package/packages/shared/src/contracts/kanban.js +142 -0
- package/packages/shared/src/contracts/projects.js +63 -0
- package/packages/shared/src/contracts/providers.js +81 -0
- package/packages/shared/src/contracts/quickResponses.js +44 -0
- package/packages/shared/src/contracts/sessions.js +112 -0
- package/packages/shared/src/contracts/templates.js +51 -0
- package/packages/shared/src/index.js +5 -0
- package/packages/shared/src/protocol.js +76 -0
- package/packages/shared/src/routeParams.js +36 -0
- package/packages/shared/src/types.js +167 -0
- package/packages/shared/src/utils.js +101 -0
- package/packages/web/dist/assets/ActiveSessionsView-BQc76Jc8.js +1 -0
- package/packages/web/dist/assets/ActiveSessionsView-ofSvx-K1.css +1 -0
- package/packages/web/dist/assets/AgentLogsView-CTCjHjsu.js +2 -0
- package/packages/web/dist/assets/AgentLogsView-D90PnQVk.css +1 -0
- package/packages/web/dist/assets/ApiClient-Dbs1H78V.js +1 -0
- package/packages/web/dist/assets/ArchiveConfirmModal-CCxSZ52u.js +1 -0
- package/packages/web/dist/assets/ArchiveConfirmModal-CQZeuYBz.css +1 -0
- package/packages/web/dist/assets/CommandButtonDetailView-CF_-LXpU.js +1 -0
- package/packages/web/dist/assets/CommandButtonDetailView-DBm3rzhw.css +1 -0
- package/packages/web/dist/assets/EffortLevelSelector-BQaQmU2d.css +1 -0
- package/packages/web/dist/assets/EffortLevelSelector-DPofLvm-.js +1 -0
- package/packages/web/dist/assets/GeneralSettingsView-BCf53fpC.css +1 -0
- package/packages/web/dist/assets/GeneralSettingsView-BY1G-Kv8.js +1 -0
- package/packages/web/dist/assets/InterpolationHelp-CgdbNcJB.js +1 -0
- package/packages/web/dist/assets/InterpolationHelp-iNxTxmhs.css +1 -0
- package/packages/web/dist/assets/MarkdownEditor-CqT1U8lo.js +2 -0
- package/packages/web/dist/assets/MarkdownEditor-enuH2yvP.css +1 -0
- package/packages/web/dist/assets/ModelSelector-BBn_Ve0D.js +1 -0
- package/packages/web/dist/assets/ModelSelector-DPPD-92R.css +1 -0
- package/packages/web/dist/assets/NewSessionView-Bo5l49nu.js +3 -0
- package/packages/web/dist/assets/NewSessionView-Byoi1XdQ.css +1 -0
- package/packages/web/dist/assets/PathChooser-BoMGzeg2.css +1 -0
- package/packages/web/dist/assets/PathChooser-Cx9gQ-Qt.js +1 -0
- package/packages/web/dist/assets/ProjectEditView-BFuscj-V.js +1 -0
- package/packages/web/dist/assets/ProjectEditView-DNwBUNRk.css +1 -0
- package/packages/web/dist/assets/ProjectListView-C55H1JHQ.css +1 -0
- package/packages/web/dist/assets/ProjectListView-Dj0jBZ46.js +1 -0
- package/packages/web/dist/assets/ProjectNewView-Brdp-xUu.js +1 -0
- package/packages/web/dist/assets/ProjectNewView-CpgE4R-l.css +1 -0
- package/packages/web/dist/assets/ProvidersView-B_QQF3RM.css +1 -0
- package/packages/web/dist/assets/ProvidersView-Cxc-1skq.js +1 -0
- package/packages/web/dist/assets/QuickResponseSettings-B2eVAtHW.js +1 -0
- package/packages/web/dist/assets/QuickResponseSettings-B8188A1D.css +1 -0
- package/packages/web/dist/assets/QuickResponsesPanel-DIBQFj0W.css +1 -0
- package/packages/web/dist/assets/QuickResponsesPanel-lU8pW2B0.js +1 -0
- package/packages/web/dist/assets/ResizableTextarea-B5nAA0RV.css +1 -0
- package/packages/web/dist/assets/ResizableTextarea-DSy1mWGY.js +1 -0
- package/packages/web/dist/assets/SessionCard-BvjLwVYg.js +1 -0
- package/packages/web/dist/assets/SessionCard-D20G3bX8.css +1 -0
- package/packages/web/dist/assets/SessionDetailView-BQbPg-RJ.js +36 -0
- package/packages/web/dist/assets/SessionDetailView-BrMG4p2-.css +1 -0
- package/packages/web/dist/assets/SessionFormOptions-BgqFR-5f.js +1 -0
- package/packages/web/dist/assets/SessionFormOptions-BuLlDF-7.css +1 -0
- package/packages/web/dist/assets/SessionListView-BAIBtJF7.css +1 -0
- package/packages/web/dist/assets/SessionListView-CYIHI8qF.js +1 -0
- package/packages/web/dist/assets/SessionLogStream-B-FwUMJQ.js +18 -0
- package/packages/web/dist/assets/SessionLogStream-zPUTiGbe.css +1 -0
- package/packages/web/dist/assets/SettingsView-DC8-hTQ-.css +1 -0
- package/packages/web/dist/assets/SettingsView-fZxpiGp7.js +1 -0
- package/packages/web/dist/assets/SlashCommandWizard-BB30cSvo.css +1 -0
- package/packages/web/dist/assets/SlashCommandWizard-BgaOw9W3.js +1 -0
- package/packages/web/dist/assets/SummarySettingsView-DcsmSVJI.css +1 -0
- package/packages/web/dist/assets/SummarySettingsView-eeu1Xq86.js +1 -0
- package/packages/web/dist/assets/TemplateDetailView-DEPKSwDo.js +1 -0
- package/packages/web/dist/assets/TemplateDetailView-DT2m06W7.css +1 -0
- package/packages/web/dist/assets/apl-B4CMkyY2.js +1 -0
- package/packages/web/dist/assets/asciiarmor-Df11BRmG.js +1 -0
- package/packages/web/dist/assets/asn1-EdZsLKOL.js +1 -0
- package/packages/web/dist/assets/asterisk-B-8jnY81.js +1 -0
- package/packages/web/dist/assets/brainfuck-C4LP7Hcl.js +1 -0
- package/packages/web/dist/assets/clike-B9uivgTg.js +1 -0
- package/packages/web/dist/assets/clojure-BMjYHr_A.js +1 -0
- package/packages/web/dist/assets/cmake-BQqOBYOt.js +1 -0
- package/packages/web/dist/assets/cobol-CWcv1MsR.js +1 -0
- package/packages/web/dist/assets/coffeescript-S37ZYGWr.js +1 -0
- package/packages/web/dist/assets/commandButtons-DNSHH8IA.js +4 -0
- package/packages/web/dist/assets/commonlisp-DBKNyK5s.js +1 -0
- package/packages/web/dist/assets/crystal-SjHAIU92.js +1 -0
- package/packages/web/dist/assets/css-BnMrqG3P.js +1 -0
- package/packages/web/dist/assets/cypher-C_CwsFkJ.js +1 -0
- package/packages/web/dist/assets/d-pRatUO7H.js +1 -0
- package/packages/web/dist/assets/diff-DbItnlRl.js +1 -0
- package/packages/web/dist/assets/dockerfile-BKs6k2Af.js +1 -0
- package/packages/web/dist/assets/dtd-DF_7sFjM.js +1 -0
- package/packages/web/dist/assets/dylan-DwRh75JA.js +1 -0
- package/packages/web/dist/assets/ebnf-CDyGwa7X.js +1 -0
- package/packages/web/dist/assets/ecl-Cabwm37j.js +1 -0
- package/packages/web/dist/assets/eiffel-CnydiIhH.js +1 -0
- package/packages/web/dist/assets/elm-vLlmbW-K.js +1 -0
- package/packages/web/dist/assets/erlang-BNw1qcRV.js +1 -0
- package/packages/web/dist/assets/factor-kuTfRLto.js +1 -0
- package/packages/web/dist/assets/fcl-Kvtd6kyn.js +1 -0
- package/packages/web/dist/assets/forth-Ffai-XNe.js +1 -0
- package/packages/web/dist/assets/fortran-DYz_wnZ1.js +1 -0
- package/packages/web/dist/assets/gas-Bneqetm1.js +1 -0
- package/packages/web/dist/assets/gherkin-heZmZLOM.js +1 -0
- package/packages/web/dist/assets/groovy-D9Dt4D0W.js +1 -0
- package/packages/web/dist/assets/haskell-BWDZoCOh.js +1 -0
- package/packages/web/dist/assets/haxe-H-WmDvRZ.js +1 -0
- package/packages/web/dist/assets/http-DBlCnlav.js +1 -0
- package/packages/web/dist/assets/idl-BEugSyMb.js +1 -0
- package/packages/web/dist/assets/index-BZlHgDSz.js +1 -0
- package/packages/web/dist/assets/index-BhWX8AfE.js +2 -0
- package/packages/web/dist/assets/index-Bi3XvF_f.js +1 -0
- package/packages/web/dist/assets/index-BqXoPf_D.js +1 -0
- package/packages/web/dist/assets/index-CAuTOZSD.js +1 -0
- package/packages/web/dist/assets/index-CKYk-fkb.js +1 -0
- package/packages/web/dist/assets/index-CTumW_tV.js +318 -0
- package/packages/web/dist/assets/index-CVOJVSsC.js +82 -0
- package/packages/web/dist/assets/index-CXK2Z3_z.js +1 -0
- package/packages/web/dist/assets/index-CYllQ3Vd.js +1 -0
- package/packages/web/dist/assets/index-CpsfI08O.js +1 -0
- package/packages/web/dist/assets/index-DQkhDeTA.js +3 -0
- package/packages/web/dist/assets/index-DWP8iCBp.js +1 -0
- package/packages/web/dist/assets/index-DkVb9W_J.js +1 -0
- package/packages/web/dist/assets/index-DmKHPbIa.js +1 -0
- package/packages/web/dist/assets/index-DrlQi03X.js +1 -0
- package/packages/web/dist/assets/index-gmCCsCQ1.css +1 -0
- package/packages/web/dist/assets/index-prTEzzgO.js +1 -0
- package/packages/web/dist/assets/index-wqgejMCM.js +1 -0
- package/packages/web/dist/assets/index-yh0ZHIWw.js +7 -0
- package/packages/web/dist/assets/javascript-qCveANmP.js +1 -0
- package/packages/web/dist/assets/julia-DuME0IfC.js +1 -0
- package/packages/web/dist/assets/livescript-BwQOo05w.js +1 -0
- package/packages/web/dist/assets/lua-BgMRiT3U.js +1 -0
- package/packages/web/dist/assets/mathematica-DTrFuWx2.js +1 -0
- package/packages/web/dist/assets/mbox-CNhZ1qSd.js +1 -0
- package/packages/web/dist/assets/mirc-CjQqDB4T.js +1 -0
- package/packages/web/dist/assets/mllike-CXdrOF99.js +1 -0
- package/packages/web/dist/assets/modelica-Dc1JOy9r.js +1 -0
- package/packages/web/dist/assets/mscgen-BA5vi2Kp.js +1 -0
- package/packages/web/dist/assets/mumps-BT43cFF4.js +1 -0
- package/packages/web/dist/assets/nginx-DdIZxoE0.js +1 -0
- package/packages/web/dist/assets/nsis-LdVXkNf5.js +1 -0
- package/packages/web/dist/assets/ntriples-BfvgReVJ.js +1 -0
- package/packages/web/dist/assets/octave-Ck1zUtKM.js +1 -0
- package/packages/web/dist/assets/oz-BzwKVEFT.js +1 -0
- package/packages/web/dist/assets/pascal--L3eBynH.js +1 -0
- package/packages/web/dist/assets/perl-CdXCOZ3F.js +1 -0
- package/packages/web/dist/assets/pig-CevX1Tat.js +1 -0
- package/packages/web/dist/assets/powershell-CFHJl5sT.js +1 -0
- package/packages/web/dist/assets/projects-DbBQQH-V.js +1 -0
- package/packages/web/dist/assets/properties-C78fOPTZ.js +1 -0
- package/packages/web/dist/assets/protobuf-ChK-085T.js +1 -0
- package/packages/web/dist/assets/providers-ceCc4xRU.js +1 -0
- package/packages/web/dist/assets/pug-DukmZTjD.js +1 -0
- package/packages/web/dist/assets/puppet-DMA9R1ak.js +1 -0
- package/packages/web/dist/assets/python-BuPzkPfP.js +1 -0
- package/packages/web/dist/assets/q-pXgVlZs6.js +1 -0
- package/packages/web/dist/assets/r-DUYO_cvP.js +1 -0
- package/packages/web/dist/assets/rpm-CTu-6PCP.js +1 -0
- package/packages/web/dist/assets/ruby-B2Rjki9n.js +1 -0
- package/packages/web/dist/assets/sas-B4kiWyti.js +1 -0
- package/packages/web/dist/assets/scheme-C41bIUwD.js +1 -0
- package/packages/web/dist/assets/sessions-D681M81k.js +1 -0
- package/packages/web/dist/assets/settings-D0evez2V.js +1 -0
- package/packages/web/dist/assets/shell-CjFT_Tl9.js +1 -0
- package/packages/web/dist/assets/sieve-C3Gn_uJK.js +1 -0
- package/packages/web/dist/assets/simple-mode-GW_nhZxv.js +1 -0
- package/packages/web/dist/assets/smalltalk-CnHTOXQT.js +1 -0
- package/packages/web/dist/assets/solr-DehyRSwq.js +1 -0
- package/packages/web/dist/assets/sparql-DkYu6x3z.js +1 -0
- package/packages/web/dist/assets/spreadsheet-BCZA_wO0.js +1 -0
- package/packages/web/dist/assets/sql-D0XecflT.js +1 -0
- package/packages/web/dist/assets/stex-C3f8Ysf7.js +1 -0
- package/packages/web/dist/assets/style-BTin-zR_.css +1 -0
- package/packages/web/dist/assets/stylus-B533Al4x.js +1 -0
- package/packages/web/dist/assets/swift-BzpIVaGY.js +1 -0
- package/packages/web/dist/assets/tcl-DVfN8rqt.js +1 -0
- package/packages/web/dist/assets/textile-CnDTJFAw.js +1 -0
- package/packages/web/dist/assets/tiddlywiki-DO-Gjzrf.js +1 -0
- package/packages/web/dist/assets/tiki-DGYXhP31.js +1 -0
- package/packages/web/dist/assets/toml-Bm5Em-hy.js +1 -0
- package/packages/web/dist/assets/troff-wAsdV37c.js +1 -0
- package/packages/web/dist/assets/ttcn-CfJYG6tj.js +1 -0
- package/packages/web/dist/assets/ttcn-cfg-B9xdYoR4.js +1 -0
- package/packages/web/dist/assets/turtle-B1tBg_DP.js +1 -0
- package/packages/web/dist/assets/vb-CmGdzxic.js +1 -0
- package/packages/web/dist/assets/vbscript-BuJXcnF6.js +1 -0
- package/packages/web/dist/assets/velocity-D8B20fx6.js +1 -0
- package/packages/web/dist/assets/verilog-C6RDOZhf.js +1 -0
- package/packages/web/dist/assets/vhdl-lSbBsy5d.js +1 -0
- package/packages/web/dist/assets/webidl-ZXfAyPTL.js +1 -0
- package/packages/web/dist/assets/xquery-CQfU5ijd.js +1 -0
- package/packages/web/dist/assets/yacas-BJ4BC0dw.js +1 -0
- package/packages/web/dist/assets/z80-Hz9HOZM7.js +1 -0
- package/packages/web/dist/favicon.png +0 -0
- package/packages/web/dist/index.html +17 -0
- package/packages/web/dist/logo.png +0 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { sessions, messages, conversations, projects, attachments } from '../database.js';
|
|
2
|
+
import { broadcastToSession } from '../websocket.js';
|
|
3
|
+
import { WS_MESSAGE_TYPES } from '../../../shared/src/index.js';
|
|
4
|
+
import * as slashCommandService from './slashCommandService.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Service for managing scheduled session execution
|
|
8
|
+
* Polls for due sessions every 30 seconds and handles rescheduling logic
|
|
9
|
+
*/
|
|
10
|
+
class SchedulerService {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.pollInterval = 30000; // 30 seconds
|
|
13
|
+
this.intervalId = null;
|
|
14
|
+
this.sessionManager = null; // Will be set during initialization
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Initialize the scheduler with dependencies
|
|
19
|
+
* @param {object} sessionManager - Session manager instance
|
|
20
|
+
*/
|
|
21
|
+
initialize(sessionManager) {
|
|
22
|
+
this.sessionManager = sessionManager;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Start the scheduler polling
|
|
27
|
+
*/
|
|
28
|
+
start() {
|
|
29
|
+
if (this.intervalId) {
|
|
30
|
+
console.log('[SchedulerService] Already running');
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
console.log('[SchedulerService] Starting scheduler with', this.pollInterval, 'ms interval');
|
|
35
|
+
this.intervalId = setInterval(() => this.checkScheduledSessions(), this.pollInterval);
|
|
36
|
+
|
|
37
|
+
// Also check immediately on startup
|
|
38
|
+
this.checkScheduledSessions();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Stop the scheduler polling
|
|
43
|
+
*/
|
|
44
|
+
stop() {
|
|
45
|
+
if (this.intervalId) {
|
|
46
|
+
console.log('[SchedulerService] Stopping scheduler');
|
|
47
|
+
clearInterval(this.intervalId);
|
|
48
|
+
this.intervalId = null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Check for scheduled sessions that are due to start
|
|
54
|
+
*/
|
|
55
|
+
async checkScheduledSessions() {
|
|
56
|
+
const now = Date.now();
|
|
57
|
+
const dueSessions = sessions.getScheduledSessionsDue(now);
|
|
58
|
+
|
|
59
|
+
if (dueSessions.length > 0) {
|
|
60
|
+
console.log(`[SchedulerService] Found ${dueSessions.length} session(s) due to start`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
for (const session of dueSessions) {
|
|
64
|
+
try {
|
|
65
|
+
await this.startScheduledSession(session);
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error(`[SchedulerService] Error starting scheduled session ${session.id}:`, error);
|
|
68
|
+
// Mark session as error
|
|
69
|
+
sessions.update(session.id, {
|
|
70
|
+
status: 'error',
|
|
71
|
+
error: `Failed to start scheduled session: ${error.message}`,
|
|
72
|
+
});
|
|
73
|
+
broadcastToSession(session.id, WS_MESSAGE_TYPES.SESSION_STATUS, { sessionId: session.id, status: 'error' });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Start a scheduled session
|
|
80
|
+
* @param {object} session - Session to start
|
|
81
|
+
*/
|
|
82
|
+
async startScheduledSession(session) {
|
|
83
|
+
if (!this.sessionManager) {
|
|
84
|
+
throw new Error('SchedulerService not initialized with sessionManager');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
console.log(`[SchedulerService] Starting scheduled session ${session.id}: ${session.name}`);
|
|
88
|
+
|
|
89
|
+
// Get the project for working directory and system prompt
|
|
90
|
+
const project = projects.getById(session.projectId);
|
|
91
|
+
if (!project) {
|
|
92
|
+
throw new Error(`Project not found for session ${session.id}`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Determine working directory
|
|
96
|
+
const workingDirectory = session.gitWorktree || project.workingDirectory;
|
|
97
|
+
|
|
98
|
+
// Use pendingPrompt as the message to send
|
|
99
|
+
if (!session.pendingPrompt || session.pendingPrompt.trim() === '') {
|
|
100
|
+
throw new Error(`No pendingPrompt found for session ${session.id}`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const prompt = session.pendingPrompt.trim();
|
|
104
|
+
|
|
105
|
+
// Get the session messages to determine if this is initial or continuation
|
|
106
|
+
const sessionMessages = messages.getBySessionId(session.id);
|
|
107
|
+
const hasAssistantResponses = sessionMessages.some((msg) => msg.role === 'assistant');
|
|
108
|
+
|
|
109
|
+
// Get attachments for context
|
|
110
|
+
const sessionAttachments = attachments.getBySessionId(session.id);
|
|
111
|
+
|
|
112
|
+
// Resolve skill/command invocations so skill body goes into system prompt
|
|
113
|
+
const resolved = await slashCommandService.resolvePromptSkillOrCommand(
|
|
114
|
+
workingDirectory, prompt, project.systemPrompt
|
|
115
|
+
);
|
|
116
|
+
const effectivePrompt = resolved ? resolved.userMessage : prompt;
|
|
117
|
+
const effectiveSystemPrompt = resolved ? resolved.systemPrompt : project.systemPrompt;
|
|
118
|
+
|
|
119
|
+
// Determine if this is an initial run or a continuation
|
|
120
|
+
if (hasAssistantResponses) {
|
|
121
|
+
// Session has conversation history - this is a scheduled continuation
|
|
122
|
+
|
|
123
|
+
// Update status from 'scheduled' to 'starting' and clear pendingPrompt
|
|
124
|
+
sessions.update(session.id, {
|
|
125
|
+
status: 'starting',
|
|
126
|
+
scheduledAt: null,
|
|
127
|
+
pendingPrompt: null,
|
|
128
|
+
});
|
|
129
|
+
broadcastToSession(session.id, WS_MESSAGE_TYPES.SESSION_STATUS, { sessionId: session.id, status: 'starting' });
|
|
130
|
+
|
|
131
|
+
await this.sessionManager.continueSession(
|
|
132
|
+
session.id,
|
|
133
|
+
effectivePrompt,
|
|
134
|
+
workingDirectory,
|
|
135
|
+
{ systemPrompt: effectiveSystemPrompt, fileAttachments: sessionAttachments, model: session.pendingModel }
|
|
136
|
+
);
|
|
137
|
+
} else {
|
|
138
|
+
// Fresh session - initial run
|
|
139
|
+
// First, create the user message so it appears in the conversation
|
|
140
|
+
|
|
141
|
+
// Get the active conversation
|
|
142
|
+
const activeConv = conversations.getActiveBySessionId(session.id);
|
|
143
|
+
if (!activeConv) {
|
|
144
|
+
throw new Error(`No active conversation found for session ${session.id}`);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Create the initial user message
|
|
148
|
+
const userMessage = messages.create(session.id, 'user', prompt, { toolUse: null, conversationId: activeConv.id });
|
|
149
|
+
|
|
150
|
+
// Broadcast the new message so UI updates
|
|
151
|
+
broadcastToSession(session.id, WS_MESSAGE_TYPES.MESSAGE_CREATED, {
|
|
152
|
+
sessionId: session.id,
|
|
153
|
+
message: userMessage,
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// Update status from 'scheduled' to 'starting' and clear pendingPrompt
|
|
157
|
+
sessions.update(session.id, {
|
|
158
|
+
status: 'starting',
|
|
159
|
+
scheduledAt: null,
|
|
160
|
+
pendingPrompt: null,
|
|
161
|
+
});
|
|
162
|
+
broadcastToSession(session.id, WS_MESSAGE_TYPES.SESSION_STATUS, { sessionId: session.id, status: 'starting' });
|
|
163
|
+
|
|
164
|
+
await this.sessionManager.runSession(
|
|
165
|
+
session.id,
|
|
166
|
+
effectivePrompt,
|
|
167
|
+
workingDirectory,
|
|
168
|
+
{ systemPrompt: effectiveSystemPrompt, fileAttachments: sessionAttachments, model: session.pendingModel }
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Reschedule a session with a delay
|
|
175
|
+
* @param {string} sessionId - Session ID to reschedule
|
|
176
|
+
* @param {string} reason - Reason for rescheduling
|
|
177
|
+
* @returns {boolean} True if rescheduled, false if limits reached
|
|
178
|
+
*/
|
|
179
|
+
async rescheduleSession(sessionId, reason) {
|
|
180
|
+
const session = sessions.getById(sessionId);
|
|
181
|
+
if (!session) {
|
|
182
|
+
console.error(`[SchedulerService] Session not found: ${sessionId}`);
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Check reschedule limits
|
|
187
|
+
if (this.hasReachedLimits(session)) {
|
|
188
|
+
console.log(`[SchedulerService] Session ${sessionId} has reached reschedule limits`);
|
|
189
|
+
sessions.update(sessionId, {
|
|
190
|
+
status: 'error',
|
|
191
|
+
error: `Reschedule limits reached. ${reason}`,
|
|
192
|
+
});
|
|
193
|
+
broadcastToSession(sessionId, WS_MESSAGE_TYPES.SESSION_STATUS, { sessionId, status: 'error' });
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Get the last user message to use as pendingPrompt for restart
|
|
198
|
+
const sessionMessages = messages.getBySessionId(sessionId);
|
|
199
|
+
const lastUserMessage = [...sessionMessages].reverse().find(msg => msg.role === 'user');
|
|
200
|
+
|
|
201
|
+
if (!lastUserMessage) {
|
|
202
|
+
console.error(`[SchedulerService] No user message found for session ${sessionId}`);
|
|
203
|
+
sessions.update(sessionId, {
|
|
204
|
+
status: 'error',
|
|
205
|
+
error: `Cannot reschedule: No user message found. ${reason}`,
|
|
206
|
+
});
|
|
207
|
+
broadcastToSession(sessionId, WS_MESSAGE_TYPES.SESSION_STATUS, { sessionId, status: 'error' });
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Calculate new scheduled time
|
|
212
|
+
const newScheduledAt = Date.now() + session.rescheduleDelayMinutes * 60 * 1000;
|
|
213
|
+
const delayMinutes = session.rescheduleDelayMinutes;
|
|
214
|
+
const newRescheduleCount = session.rescheduleCount + 1;
|
|
215
|
+
|
|
216
|
+
console.log(
|
|
217
|
+
`[SchedulerService] Rescheduling session ${sessionId} for ${delayMinutes} minutes from now (attempt ${newRescheduleCount})`
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
// Update session to scheduled status with new time and pendingPrompt
|
|
221
|
+
sessions.update(sessionId, {
|
|
222
|
+
status: 'scheduled',
|
|
223
|
+
scheduledAt: newScheduledAt, // Fixed: camelCase
|
|
224
|
+
rescheduleCount: newRescheduleCount, // Fixed: camelCase
|
|
225
|
+
pendingPrompt: lastUserMessage.content, // Set prompt for scheduler
|
|
226
|
+
error: `Rescheduled (${newRescheduleCount}x): ${reason}`,
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
broadcastToSession(sessionId, WS_MESSAGE_TYPES.SESSION_STATUS, { sessionId, status: 'scheduled' });
|
|
230
|
+
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Check if a session has reached its reschedule limits
|
|
236
|
+
* @param {object} session - Session to check
|
|
237
|
+
* @returns {boolean} True if limits reached
|
|
238
|
+
*/
|
|
239
|
+
hasReachedLimits(session) {
|
|
240
|
+
// Check max reschedule count
|
|
241
|
+
if (session.maxRescheduleCount !== null && session.rescheduleCount >= session.maxRescheduleCount) {
|
|
242
|
+
console.log(
|
|
243
|
+
`[SchedulerService] Max reschedule count reached: ${session.rescheduleCount}/${session.maxRescheduleCount}`
|
|
244
|
+
);
|
|
245
|
+
return true;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Check max total tokens
|
|
249
|
+
if (session.maxTotalTokens !== null) {
|
|
250
|
+
const totalTokens = session.inputTokens + session.outputTokens;
|
|
251
|
+
if (totalTokens >= session.maxTotalTokens) {
|
|
252
|
+
console.log(
|
|
253
|
+
`[SchedulerService] Max total tokens reached: ${totalTokens.toLocaleString()}/${session.maxTotalTokens.toLocaleString()}`
|
|
254
|
+
);
|
|
255
|
+
return true;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Check if a session should be proactively rescheduled based on token threshold
|
|
264
|
+
* @param {object} session - Session to check
|
|
265
|
+
* @returns {boolean} True if should reschedule
|
|
266
|
+
*/
|
|
267
|
+
shouldProactivelyReschedule(session) {
|
|
268
|
+
if (!session.rescheduleAtTokenCount) {
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const totalTokens = session.inputTokens + session.outputTokens;
|
|
273
|
+
return totalTokens >= session.rescheduleAtTokenCount;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Singleton instance
|
|
278
|
+
export const schedulerService = new SchedulerService();
|
|
279
|
+
|
|
280
|
+
// Export class for testing
|
|
281
|
+
export { SchedulerService };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import {
|
|
2
|
+
sessions,
|
|
3
|
+
conversations,
|
|
4
|
+
messages,
|
|
5
|
+
canvasItems,
|
|
6
|
+
sessionNotes,
|
|
7
|
+
sessionSummaries,
|
|
8
|
+
projects,
|
|
9
|
+
} from '../db/index.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Duplicates a session including all related data.
|
|
13
|
+
* Handles git setup based on the source session's configuration.
|
|
14
|
+
*
|
|
15
|
+
* @param {string} sourceSessionId - ID of session to duplicate
|
|
16
|
+
* @param {object} options - Duplication options
|
|
17
|
+
* @param {string} [options.name] - Custom name for new session
|
|
18
|
+
* @returns {Promise<object>} The new session with all data duplicated
|
|
19
|
+
*/
|
|
20
|
+
export async function duplicateSession(sourceSessionId, options = {}) {
|
|
21
|
+
// 1. Get source session and project
|
|
22
|
+
const sourceSession = sessions.getById(sourceSessionId);
|
|
23
|
+
if (!sourceSession) {
|
|
24
|
+
throw new Error(`Session not found: ${sourceSessionId}`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const project = projects.getById(sourceSession.projectId);
|
|
28
|
+
if (!project) {
|
|
29
|
+
throw new Error(`Project not found: ${sourceSession.projectId}`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// 2. Duplicate session record (without git worktree path)
|
|
33
|
+
const newSession = sessions.duplicate(sourceSessionId, {
|
|
34
|
+
name: options.name,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
// 3. Duplicate conversations and get ID mapping
|
|
39
|
+
const conversationMapping = conversations.duplicateForSession(
|
|
40
|
+
sourceSessionId,
|
|
41
|
+
newSession.id
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
// 4. Duplicate messages using conversation mapping
|
|
45
|
+
messages.duplicateForConversations(conversationMapping, newSession.id);
|
|
46
|
+
|
|
47
|
+
// 5. Duplicate canvas items
|
|
48
|
+
canvasItems.duplicateForSession(sourceSessionId, newSession.id);
|
|
49
|
+
|
|
50
|
+
// 6. Duplicate session notes
|
|
51
|
+
sessionNotes.duplicateForSession(sourceSessionId, newSession.id);
|
|
52
|
+
|
|
53
|
+
// 7. Duplicate session summary (if exists)
|
|
54
|
+
sessionSummaries.duplicateForSession(sourceSessionId, newSession.id);
|
|
55
|
+
|
|
56
|
+
// Return the updated session
|
|
57
|
+
return sessions.getById(newSession.id);
|
|
58
|
+
} catch (error) {
|
|
59
|
+
// Cleanup: delete the new session if duplication fails
|
|
60
|
+
sessions.delete(newSession.id);
|
|
61
|
+
throw error;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { sessions, messages } from '../database.js';
|
|
2
|
+
import { schedulerService } from './schedulerService.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Check if error message matches token limit patterns
|
|
6
|
+
* @param {string} message - Error message to check
|
|
7
|
+
* @returns {boolean} True if matches token limit error
|
|
8
|
+
*/
|
|
9
|
+
export function matchesTokenLimitError(message) {
|
|
10
|
+
const patterns = [
|
|
11
|
+
'token',
|
|
12
|
+
'context length',
|
|
13
|
+
'max_tokens',
|
|
14
|
+
'context window',
|
|
15
|
+
'limit', // catches "You've hit your limit"
|
|
16
|
+
'quota',
|
|
17
|
+
'rate limit',
|
|
18
|
+
'exceeded', // catches usage exceeded messages
|
|
19
|
+
'cap', // catches usage cap messages
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
return patterns.some(pattern => message.includes(pattern));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Check if error message matches service error patterns
|
|
27
|
+
* @param {string} message - Error message to check
|
|
28
|
+
* @returns {boolean} True if matches service error
|
|
29
|
+
*/
|
|
30
|
+
export function matchesServiceError(message) {
|
|
31
|
+
const patterns = [
|
|
32
|
+
'overloaded',
|
|
33
|
+
'rate limit',
|
|
34
|
+
'503',
|
|
35
|
+
'529',
|
|
36
|
+
'unavailable',
|
|
37
|
+
'service unavailable',
|
|
38
|
+
'too many requests',
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
return patterns.some(pattern => message.includes(pattern));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Get the last assistant message for a session
|
|
46
|
+
* @param {string} sessionId - Session ID
|
|
47
|
+
* @returns {object|null} Last assistant message or null
|
|
48
|
+
*/
|
|
49
|
+
function getLastAssistantMessage(sessionId) {
|
|
50
|
+
try {
|
|
51
|
+
const sessionMessages = messages.getBySessionId(sessionId);
|
|
52
|
+
const assistantMessages = sessionMessages.filter(msg => msg.role === 'assistant');
|
|
53
|
+
return assistantMessages.length > 0 ? assistantMessages[assistantMessages.length - 1] : null;
|
|
54
|
+
} catch (error) {
|
|
55
|
+
console.error('[SessionManager] Error getting last assistant message:', error);
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Check if error message matches a rescheduling trigger and log the result
|
|
62
|
+
* @param {object} session - Session object
|
|
63
|
+
* @param {string} message - Message to check (lowercase)
|
|
64
|
+
* @param {string} source - Source description for logging (e.g., "error", "assistant message")
|
|
65
|
+
* @returns {boolean} True if matches a rescheduling trigger
|
|
66
|
+
*/
|
|
67
|
+
function checkRescheduleTrigger(session, message, source) {
|
|
68
|
+
if (session.rescheduleOnTokenLimit && matchesTokenLimitError(message)) {
|
|
69
|
+
console.log(`[SessionManager] Token limit detected in ${source}, rescheduling`);
|
|
70
|
+
console.log(`[SessionManager] ${source}:`, message);
|
|
71
|
+
console.log('[SessionManager] Session config: rescheduleOnTokenLimit=true, rescheduleDelayMinutes=', session.rescheduleDelayMinutes);
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (session.rescheduleOnServiceError && matchesServiceError(message)) {
|
|
76
|
+
console.log(`[SessionManager] Service error detected in ${source}, rescheduling`);
|
|
77
|
+
console.log(`[SessionManager] ${source}:`, message);
|
|
78
|
+
console.log('[SessionManager] Session config: rescheduleOnServiceError=true, rescheduleDelayMinutes=', session.rescheduleDelayMinutes);
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Log when a rescheduling check is skipped
|
|
87
|
+
* @param {string} setting - The setting name that was disabled
|
|
88
|
+
*/
|
|
89
|
+
function logSkippedReschedule(setting) {
|
|
90
|
+
console.log(`[SessionManager] ${setting} is false, skipping ${setting.replace('reschedule', '').toLowerCase()} rescheduling`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Check if an error should trigger automatic rescheduling
|
|
95
|
+
* @param {object} session - Session object
|
|
96
|
+
* @param {Error} error - Error that occurred
|
|
97
|
+
* @param {string} sessionId - Session ID
|
|
98
|
+
* @returns {boolean} True if should reschedule
|
|
99
|
+
*/
|
|
100
|
+
export function shouldRescheduleOnError(session, error, sessionId = null) {
|
|
101
|
+
// Check if auto-reschedule is enabled first (master switch)
|
|
102
|
+
if (!session.autoRescheduleEnabled) {
|
|
103
|
+
console.log('[SessionManager] autoRescheduleEnabled is false, skipping all rescheduling');
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const errorMessage = error.message.toLowerCase();
|
|
108
|
+
|
|
109
|
+
// Log skipped checks for debugging
|
|
110
|
+
if (!session.rescheduleOnTokenLimit) logSkippedReschedule('rescheduleOnTokenLimit');
|
|
111
|
+
if (!session.rescheduleOnServiceError) logSkippedReschedule('rescheduleOnServiceError');
|
|
112
|
+
|
|
113
|
+
// Check error message for rescheduling triggers
|
|
114
|
+
if (checkRescheduleTrigger(session, errorMessage, 'error')) {
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Also check last assistant message if available
|
|
119
|
+
if (sessionId) {
|
|
120
|
+
const lastAssistantMessage = getLastAssistantMessage(sessionId);
|
|
121
|
+
if (lastAssistantMessage) {
|
|
122
|
+
const messageContent = lastAssistantMessage.content.toLowerCase();
|
|
123
|
+
if (checkRescheduleTrigger(session, messageContent, 'assistant message')) {
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
console.log('[SessionManager] Error does not match any rescheduling triggers');
|
|
130
|
+
console.log('[SessionManager] Session config: rescheduleOnTokenLimit=', session.rescheduleOnTokenLimit, ', rescheduleOnServiceError=', session.rescheduleOnServiceError);
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Check if session should be proactively rescheduled based on token count
|
|
136
|
+
* Called after processing each message to check token thresholds
|
|
137
|
+
* @param {string} sessionId - Session ID
|
|
138
|
+
* @returns {Promise<boolean>} True if rescheduled
|
|
139
|
+
*/
|
|
140
|
+
export async function _checkProactiveReschedule(sessionId) {
|
|
141
|
+
const session = sessions.getById(sessionId);
|
|
142
|
+
if (!session || !session.rescheduleAtTokenCount) {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Check if auto-reschedule is enabled first (master switch)
|
|
147
|
+
if (!session.autoRescheduleEnabled) {
|
|
148
|
+
console.log('[SessionManager] autoRescheduleEnabled is false, skipping proactive rescheduling');
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const totalTokens = session.inputTokens + session.outputTokens;
|
|
153
|
+
if (totalTokens >= session.rescheduleAtTokenCount) {
|
|
154
|
+
console.log(
|
|
155
|
+
`[SessionManager] Proactive token threshold reached: ${totalTokens.toLocaleString()}/${session.rescheduleAtTokenCount.toLocaleString()}`
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
// Check if we've reached limits
|
|
159
|
+
if (schedulerService.hasReachedLimits(session)) {
|
|
160
|
+
console.log('[SessionManager] Cannot reschedule - limits reached');
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Gracefully reschedule
|
|
165
|
+
await schedulerService.rescheduleSession(
|
|
166
|
+
sessionId,
|
|
167
|
+
`Token threshold reached (${totalTokens.toLocaleString()} tokens)`
|
|
168
|
+
);
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return false;
|
|
173
|
+
}
|