circuschief 0.6.0 → 0.8.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 +1 -1
- package/packages/server/src/agents/adapters/CodexAdapter.js +5 -4
- package/packages/server/src/api/canvas.js +22 -57
- package/packages/server/src/api/index.js +2 -0
- package/packages/server/src/api/kanban.js +4 -2
- package/packages/server/src/api/projects-helpers.js +20 -3
- package/packages/server/src/api/projects-session-helpers.js +35 -4
- package/packages/server/src/api/projects.js +11 -0
- package/packages/server/src/api/providers.js +11 -1
- package/packages/server/src/api/sessions-commands.js +35 -17
- package/packages/server/src/api/sessions-draft.js +1 -0
- package/packages/server/src/api/sessions-lifecycle.js +10 -10
- package/packages/server/src/api/sessions-patch.js +4 -0
- package/packages/server/src/api/sessions.js +6 -5
- package/packages/server/src/api/settings.js +52 -4
- package/packages/server/src/database.js +0 -2
- package/packages/server/src/db/ConversationRepository.js +16 -3
- package/packages/server/src/db/DatabaseManager.js +5 -1
- package/packages/server/src/db/ProjectDefaultsRepository.js +50 -40
- package/packages/server/src/db/ProviderRepository.js +87 -32
- package/packages/server/src/db/SessionRepository.js +13 -8
- package/packages/server/src/db/SettingsRepository.js +44 -16
- package/packages/server/src/db/conversation-helpers.js +1 -0
- package/packages/server/src/db/index.js +0 -3
- package/packages/server/src/db/migrations/index.js +36 -200
- package/packages/server/src/db/seedBaselineData.js +137 -0
- package/packages/server/src/db/session-helpers.js +9 -3
- package/packages/server/src/middleware/sessionLookup.js +81 -8
- package/packages/server/src/schema.sql +157 -132
- package/packages/server/src/scripts/backupDatabase.js +21 -0
- package/packages/server/src/scripts/dbUtils.js +81 -0
- package/packages/server/src/scripts/inspectDatabaseSchema.js +81 -0
- package/packages/server/src/scripts/validateDatabaseBaseline.js +212 -0
- package/packages/server/src/services/agentCallLogger.js +1 -1
- package/packages/server/src/services/codexSpawnHelper.js +9 -0
- package/packages/server/src/services/commandButtonPrompts.js +48 -0
- package/packages/server/src/services/commandRunner.js +7 -1
- package/packages/server/src/services/draftSessionService.js +2 -0
- package/packages/server/src/services/e2eSpawnCapture.js +147 -0
- package/packages/server/src/services/gitCommitAttribution.js +120 -0
- package/packages/server/src/services/gitService.js +11 -2
- package/packages/server/src/services/gitSessionSetup.js +11 -1
- package/packages/server/src/services/kanbanTriggers.js +6 -3
- package/packages/server/src/services/nodeSpawnHelper.js +9 -0
- package/packages/server/src/services/prUrlService.js +3 -3
- package/packages/server/src/services/queryParamBuilder.js +90 -0
- package/packages/server/src/services/sessionDuplicator.js +1 -5
- package/packages/server/src/services/sessionExecution.js +56 -106
- package/packages/server/src/services/sessionPrompts.js +16 -47
- package/packages/server/src/services/sessionProvider.js +16 -8
- package/packages/server/src/services/streamEventCallbacks.js +72 -40
- package/packages/server/src/services/streamEventHandler.js +13 -2
- package/packages/server/src/services/streamUsageHandler.js +6 -0
- package/packages/server/src/services/summaryClaudeClient.js +37 -12
- package/packages/server/src/services/summaryModelClient.js +154 -0
- package/packages/server/src/services/summaryModelResolver.js +148 -0
- package/packages/server/src/services/summaryService.js +11 -7
- package/packages/server/src/services/summaryStaleCheck.js +23 -4
- package/packages/server/src/services/templateTriggerService.js +3 -1
- package/packages/server/src/services/usageTracker.js +5 -1
- package/packages/server/src/services/visibleFinalErrorMessage.js +123 -0
- package/packages/shared/src/constants.js +4 -2
- package/packages/shared/src/contracts/commandButtons.js +16 -2
- package/packages/shared/src/contracts/projects.js +4 -2
- package/packages/shared/src/contracts/providers.js +60 -0
- package/packages/shared/src/contracts/sessions.js +2 -1
- package/packages/shared/src/contracts/templates.js +2 -2
- package/packages/shared/src/types.js +1 -9
- package/packages/shared/src/utils.js +11 -19
- package/packages/web/dist/assets/ActiveSessionsView-B0XHqLmv.js +1 -0
- package/packages/web/dist/assets/{AgentLogsView-Cdw4nmvd.js → AgentLogsView-DmsjUMlB.js} +2 -2
- package/packages/web/dist/assets/ApiClient-C3ztI9s9.js +1 -0
- package/packages/web/dist/assets/ArchiveConfirmModal-BlCyn5Vt.js +1 -0
- package/packages/web/dist/assets/ArchiveConfirmModal-DeoCVGXt.css +1 -0
- package/packages/web/dist/assets/{CommandButtonDetailView-DnFhJY5A.js → CommandButtonDetailView-CdSCPp78.js} +1 -1
- package/packages/web/dist/assets/EffortLevelSelector-hc2MNKg6.js +1 -0
- package/packages/web/dist/assets/{GeneralSettingsView-CQkmdczf.js → GeneralSettingsView-D1nI8_zk.js} +1 -1
- package/packages/web/dist/assets/InputWithButton-CAkttyqx.js +1 -0
- package/packages/web/dist/assets/{InputWithButton-cYdrEmTs.css → InputWithButton-D9HMvfR5.css} +1 -1
- package/packages/web/dist/assets/{InterpolationHelp-PfYR3KJo.js → InterpolationHelp-BO1j9Z3_.js} +1 -1
- package/packages/web/dist/assets/MarkdownEditor-ucRAP_UM.js +2 -0
- package/packages/web/dist/assets/{ModelSelector-BZOT1Jc6.css → ModelSelector-BSxKUSus.css} +1 -1
- package/packages/web/dist/assets/ModelSelector-CwTz8ZWO.js +1 -0
- package/packages/web/dist/assets/NewSessionView-BDPb-1qr.css +1 -0
- package/packages/web/dist/assets/NewSessionView-BsDrp8mj.js +3 -0
- package/packages/web/dist/assets/ProjectEditView-CwTOeSun.js +1 -0
- package/packages/web/dist/assets/ProjectEditView-J15mcsWz.css +1 -0
- package/packages/web/dist/assets/{ProjectListView-CuYMmd3O.js → ProjectListView-DcNyuINs.js} +1 -1
- package/packages/web/dist/assets/{ProjectNewView-CNaA4Maf.js → ProjectNewView-B5YV62hv.js} +1 -1
- package/packages/web/dist/assets/ProvidersView-bZemq_Rv.css +1 -0
- package/packages/web/dist/assets/ProvidersView-nY9GnDdO.js +1 -0
- package/packages/web/dist/assets/QuickResponseSettings-B352c75l.css +1 -0
- package/packages/web/dist/assets/QuickResponseSettings-BQwQXuL7.js +1 -0
- package/packages/web/dist/assets/{QuickResponsesPanel-DIBQFj0W.css → QuickResponsesPanel-BlFDvnZ2.css} +1 -1
- package/packages/web/dist/assets/{QuickResponsesPanel-BqMYSHb0.js → QuickResponsesPanel-BzSYcCSP.js} +1 -1
- package/packages/web/dist/assets/{ResizableTextarea-wYF3K2RO.js → ResizableTextarea-B3YIdIXv.js} +1 -1
- package/packages/web/dist/assets/{SessionCard-bLaQEWWX.js → SessionCard-CjE1tXiT.js} +1 -1
- package/packages/web/dist/assets/SessionDetailView-3cPZrbS3.js +36 -0
- package/packages/web/dist/assets/SessionDetailView-CZRZMrfM.css +1 -0
- package/packages/web/dist/assets/SessionFormOptions-B6AxyREh.js +1 -0
- package/packages/web/dist/assets/SessionFormOptions-BpUALRKn.css +1 -0
- package/packages/web/dist/assets/SessionListView-B5_6gW49.css +1 -0
- package/packages/web/dist/assets/SessionListView-CLXBfLcq.js +1 -0
- package/packages/web/dist/assets/{SessionLogStream-DTnDAF95.js → SessionLogStream-LlZ3z_Xj.js} +1 -1
- package/packages/web/dist/assets/{SettingsView-DNLUSsHV.js → SettingsView-CTGiGvR2.js} +1 -1
- package/packages/web/dist/assets/{SlashCommandWizard-CRGFaO8t.js → SlashCommandWizard-Cy04d7-o.js} +1 -1
- package/packages/web/dist/assets/{SlashCommandWizard-Dn7sNaBd.css → SlashCommandWizard-DJzw3LP5.css} +1 -1
- package/packages/web/dist/assets/SummarySettingsView-BR2ZjEa3.js +1 -0
- package/packages/web/dist/assets/SummarySettingsView-l2bxHmZZ.css +1 -0
- package/packages/web/dist/assets/TemplateDetailView-DH6Oswsp.js +1 -0
- package/packages/web/dist/assets/{commandButtons-Bbjf3fCt.js → commandButtons-BfqR-fqq.js} +1 -1
- package/packages/web/dist/assets/index-1zziPL6l.js +1 -0
- package/packages/web/dist/assets/index-7kzHPxSF.js +1 -0
- package/packages/web/dist/assets/index-B0N_obMc.js +1 -0
- package/packages/web/dist/assets/index-BNk_gdfI.js +1 -0
- package/packages/web/dist/assets/{index-gmCCsCQ1.css → index-BY174HVJ.css} +1 -1
- package/packages/web/dist/assets/index-CSqaAH-0.js +1 -0
- package/packages/web/dist/assets/index-C_q4WlK8.js +1 -0
- package/packages/web/dist/assets/index-D1wpU4y0.js +7 -0
- package/packages/web/dist/assets/index-D5zCA8sD.js +1 -0
- package/packages/web/dist/assets/index-DGR8ELWY.js +1 -0
- package/packages/web/dist/assets/index-DHga8pXo.js +1 -0
- package/packages/web/dist/assets/index-DSby02Wl.js +1 -0
- package/packages/web/dist/assets/{index-Cf6vdW-B.js → index-DgkC10TW.js} +3 -3
- package/packages/web/dist/assets/index-DqjXJTVI.js +1 -0
- package/packages/web/dist/assets/{index-Bs7Qf5D6.js → index-DtfUt785.js} +2 -2
- package/packages/web/dist/assets/index-_4S2uLDI.js +1 -0
- package/packages/web/dist/assets/{index-BQL_L4gL.js → index-fK8FIZgP.js} +15 -14
- package/packages/web/dist/assets/index-gmiZeFXN.js +1 -0
- package/packages/web/dist/assets/index-irD539ZM.js +3 -0
- package/packages/web/dist/assets/index-yq-E1Y00.js +1 -0
- package/packages/web/dist/assets/{projects-CPt3AB7U.js → projects-DXYQNJIi.js} +1 -1
- package/packages/web/dist/assets/{providers-ChfeMvUq.js → providers-1bnH-exJ.js} +1 -1
- package/packages/web/dist/assets/sessions-6zGUlFrt.js +1 -0
- package/packages/web/dist/assets/settings-MbfRir0d.js +1 -0
- package/packages/web/dist/index.html +2 -2
- package/packages/server/src/api/sessions-notes.js +0 -51
- package/packages/server/src/db/SessionNoteRepository.js +0 -60
- package/packages/server/src/db/migrations/canvasItemsMigrations.js +0 -109
- package/packages/server/src/db/migrations/conversationsMigrations.js +0 -183
- package/packages/server/src/db/migrations/kanbanMigrations.js +0 -99
- package/packages/server/src/db/migrations/miscMigrations.js +0 -369
- package/packages/server/src/db/migrations/projectsMigrations.js +0 -99
- package/packages/server/src/db/migrations/sessionsMigrations.js +0 -282
- package/packages/web/dist/assets/ActiveSessionsView-UCbQrF1b.js +0 -1
- package/packages/web/dist/assets/ApiClient-CWbXWDUY.js +0 -1
- package/packages/web/dist/assets/ArchiveConfirmModal-BQ-4gI0R.css +0 -1
- package/packages/web/dist/assets/ArchiveConfirmModal-J48eh3zw.js +0 -1
- package/packages/web/dist/assets/EffortLevelSelector-bXbPo4Zw.js +0 -1
- package/packages/web/dist/assets/InputWithButton-XyM3k6lN.js +0 -1
- package/packages/web/dist/assets/MarkdownEditor-P8F5kO-o.js +0 -2
- package/packages/web/dist/assets/ModelSelector-CowKfGMP.js +0 -1
- package/packages/web/dist/assets/NewSessionView-D_Hi7M9g.css +0 -1
- package/packages/web/dist/assets/NewSessionView-DkjFLvHU.js +0 -3
- package/packages/web/dist/assets/ProjectEditView-CpeKj-_w.css +0 -1
- package/packages/web/dist/assets/ProjectEditView-embVT7NC.js +0 -1
- package/packages/web/dist/assets/ProvidersView-C7rydtOd.js +0 -1
- package/packages/web/dist/assets/ProvidersView-DE82G_5W.css +0 -1
- package/packages/web/dist/assets/QuickResponseSettings-B8188A1D.css +0 -1
- package/packages/web/dist/assets/QuickResponseSettings-BTQEKhwJ.js +0 -1
- package/packages/web/dist/assets/SessionDetailView-Cv-xMzXp.css +0 -1
- package/packages/web/dist/assets/SessionDetailView-CvQOUsW2.js +0 -36
- package/packages/web/dist/assets/SessionFormOptions-3pzbgI2Q.js +0 -1
- package/packages/web/dist/assets/SessionFormOptions-DhhIkjIS.css +0 -1
- package/packages/web/dist/assets/SessionListView-Dranfb72.js +0 -1
- package/packages/web/dist/assets/SessionListView-fHlQyecX.css +0 -1
- package/packages/web/dist/assets/SummarySettingsView-C7G_suHp.js +0 -1
- package/packages/web/dist/assets/SummarySettingsView-DcsmSVJI.css +0 -1
- package/packages/web/dist/assets/TemplateDetailView-B78_DLMR.js +0 -1
- package/packages/web/dist/assets/index--V7c-VZf.js +0 -1
- package/packages/web/dist/assets/index-8Q04yd7H.js +0 -1
- package/packages/web/dist/assets/index-B47XRBDH.js +0 -1
- package/packages/web/dist/assets/index-BXbgZrhS.js +0 -1
- package/packages/web/dist/assets/index-CGhDVPen.js +0 -1
- package/packages/web/dist/assets/index-CKcRO1A6.js +0 -1
- package/packages/web/dist/assets/index-CTq-SLIW.js +0 -1
- package/packages/web/dist/assets/index-CYyos3iC.js +0 -1
- package/packages/web/dist/assets/index-CsCREAxF.js +0 -1
- package/packages/web/dist/assets/index-DJTTk_8T.js +0 -3
- package/packages/web/dist/assets/index-DPqUJ5JK.js +0 -1
- package/packages/web/dist/assets/index-EwAe1dKg.js +0 -1
- package/packages/web/dist/assets/index-JBA8axyA.js +0 -1
- package/packages/web/dist/assets/index-JkVHFtK5.js +0 -7
- package/packages/web/dist/assets/index-gMPUwT55.js +0 -1
- package/packages/web/dist/assets/index-wadc_0zT.js +0 -1
- package/packages/web/dist/assets/sessions-CwPsJOb1.js +0 -1
- package/packages/web/dist/assets/settings-BOj6wq6t.js +0 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { sessions, attachments, projects, kanbanBoards, kanbanLanes } from '../database.js';
|
|
2
2
|
import { DEFAULT_SERVER_PORT, DEFAULT_SYSTEM_PROMPT } from '../../../shared/src/index.js';
|
|
3
|
+
import { buildCommandButtonApiInstructions } from './commandButtonPrompts.js';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Get the base API URL for canvas and session operations.
|
|
@@ -161,10 +162,7 @@ CRITICAL: Do NOT start coding until you have presented a plan and received appro
|
|
|
161
162
|
*/
|
|
162
163
|
function buildCanvasWriteSystemPrompt(session) {
|
|
163
164
|
const apiUrl = getApiBaseUrl();
|
|
164
|
-
|
|
165
|
-
const sessionId = session
|
|
166
|
-
? (sessions.getRootSessionId(session.id) || session.id)
|
|
167
|
-
: 'unknown-session';
|
|
165
|
+
const sessionId = session?.id || 'unknown-session';
|
|
168
166
|
return `When you generate artifacts that should be displayed on the canvas (images, markdown documents, code snippets, data visualizations, PDFs), POST them to:
|
|
169
167
|
|
|
170
168
|
POST ${apiUrl}/api/sessions/${sessionId}/canvas
|
|
@@ -186,10 +184,7 @@ The file type is automatically detected from the file extension. Supported forma
|
|
|
186
184
|
*/
|
|
187
185
|
function buildCanvasReadSystemPrompt(session) {
|
|
188
186
|
const apiUrl = getApiBaseUrl();
|
|
189
|
-
|
|
190
|
-
const sessionId = session
|
|
191
|
-
? (sessions.getRootSessionId(session.id) || session.id)
|
|
192
|
-
: 'unknown-session';
|
|
187
|
+
const sessionId = session?.id || 'unknown-session';
|
|
193
188
|
return `## Reading from Canvas
|
|
194
189
|
|
|
195
190
|
To list all files on the canvas:
|
|
@@ -224,9 +219,10 @@ function buildSessionCrudOps(apiUrl, projectId) {
|
|
|
224
219
|
\`\`\`bash
|
|
225
220
|
curl -X POST ${apiUrl}/api/projects/${projectId}/sessions \\
|
|
226
221
|
-H "Content-Type: application/json" \\
|
|
227
|
-
-d '{"prompt": "Your task description here"
|
|
222
|
+
-d '{"prompt": "Your task description here"}'
|
|
228
223
|
\`\`\`
|
|
229
|
-
|
|
224
|
+
Only \`prompt\` is required. Omitted settings are automatically derived from the project's session defaults, then system defaults, matching UI behavior.
|
|
225
|
+
Optional override fields: \`name\`, \`mode\`, \`thinkingEnabled\` (boolean), \`effortLevel\` (low/medium/high/max/auto), \`model\`, \`providerId\`, \`gitBranch\`, \`gitMode\`, \`templateId\`, \`nextTemplateId\`, \`parentSessionId\` (to create a related follow-up session from the current session), \`startImmediately\`, \`scheduledAt\`, \`autoRescheduleEnabled\`, \`rescheduleDelayMinutes\`, \`rescheduleOnTokenLimit\`, \`rescheduleOnServiceError\`, \`maxRescheduleCount\`, \`maxTotalTokens\`, and \`rescheduleAtTokenCount\`.
|
|
230
226
|
|
|
231
227
|
### Send a Follow-up Message
|
|
232
228
|
\`\`\`bash
|
|
@@ -257,8 +253,8 @@ curl -X PATCH ${apiUrl}/api/sessions/<session_id> \\
|
|
|
257
253
|
\`\`\``;
|
|
258
254
|
}
|
|
259
255
|
|
|
260
|
-
/** Build project
|
|
261
|
-
function
|
|
256
|
+
/** Build project and summary operations section */
|
|
257
|
+
function buildProjectOps(apiUrl, sessionId) {
|
|
262
258
|
return `### Project Operations
|
|
263
259
|
\`\`\`bash
|
|
264
260
|
curl ${apiUrl}/api/projects # List all projects
|
|
@@ -270,18 +266,10 @@ curl -X POST ${apiUrl}/api/projects \\
|
|
|
270
266
|
\`\`\`
|
|
271
267
|
Optional field: \`systemPrompt\`
|
|
272
268
|
|
|
273
|
-
###
|
|
269
|
+
### Workflow Summary
|
|
274
270
|
\`\`\`bash
|
|
275
|
-
curl ${apiUrl}/api/sessions
|
|
276
|
-
curl -X POST ${apiUrl}/api/sessions
|
|
277
|
-
-H "Content-Type: application/json" \\
|
|
278
|
-
-d '{"content": "Note content"}'
|
|
279
|
-
\`\`\`
|
|
280
|
-
|
|
281
|
-
### Session Summary
|
|
282
|
-
\`\`\`bash
|
|
283
|
-
curl "${apiUrl}/api/sessions/<session_id>/summary?generate=true"
|
|
284
|
-
curl -X POST ${apiUrl}/api/sessions/<session_id>/summary # Regenerate
|
|
271
|
+
curl "${apiUrl}/api/sessions/${sessionId}/summary?generate=true"
|
|
272
|
+
curl -X POST ${apiUrl}/api/sessions/${sessionId}/summary # Regenerate
|
|
285
273
|
\`\`\``;
|
|
286
274
|
}
|
|
287
275
|
|
|
@@ -298,7 +286,7 @@ You can create and modify sessions in this system using curl or similar HTTP too
|
|
|
298
286
|
|
|
299
287
|
${buildSessionCrudOps(apiUrl, projectId)}
|
|
300
288
|
|
|
301
|
-
${
|
|
289
|
+
${buildProjectOps(apiUrl, sessionId)}`;
|
|
302
290
|
}
|
|
303
291
|
|
|
304
292
|
/**
|
|
@@ -335,7 +323,7 @@ ${laneContext}
|
|
|
335
323
|
curl ${apiUrl}/api/projects/${projectId}/kanban
|
|
336
324
|
\`\`\`
|
|
337
325
|
|
|
338
|
-
### Add
|
|
326
|
+
### Add Current Workflow to the Board
|
|
339
327
|
\`\`\`bash
|
|
340
328
|
curl -X POST ${apiUrl}/api/projects/${projectId}/kanban/cards \\
|
|
341
329
|
-H "Content-Type: application/json" \\
|
|
@@ -393,26 +381,6 @@ This session is running in an isolated git worktree:
|
|
|
393
381
|
CRITICAL: Do NOT use \`cd\` to navigate to the main repository. Your working directory is already set to the worktree. Running \`cd /home/ubuntu/workspace/circus-chief && ...\` will escape the worktree isolation and affect the main repository instead.`;
|
|
394
382
|
}
|
|
395
383
|
|
|
396
|
-
/**
|
|
397
|
-
* Build child session context for system prompt
|
|
398
|
-
* @param {Object} session - Session object
|
|
399
|
-
* @returns {string} Child session context or empty string
|
|
400
|
-
*/
|
|
401
|
-
function buildChildSessionContext(session) {
|
|
402
|
-
if (!session || !session.parentSessionId) {
|
|
403
|
-
return '';
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
// Get root session ID using existing method
|
|
407
|
-
const rootSessionId = sessions.getRootSessionId(session.id);
|
|
408
|
-
|
|
409
|
-
return `## Child Session
|
|
410
|
-
|
|
411
|
-
This session is part of a multi-session workflow:
|
|
412
|
-
- Parent Session ID: ${session.parentSessionId}
|
|
413
|
-
- Root Session ID: ${rootSessionId}`;
|
|
414
|
-
}
|
|
415
|
-
|
|
416
384
|
/**
|
|
417
385
|
* Build the full system prompt configuration
|
|
418
386
|
* @param {string} sessionId
|
|
@@ -422,14 +390,15 @@ This session is part of a multi-session workflow:
|
|
|
422
390
|
* @returns {string} System prompt string
|
|
423
391
|
*/
|
|
424
392
|
export function buildSystemPromptConfig(sessionId, projectId, customSystemPrompt, mode) {
|
|
393
|
+
const apiUrl = getApiBaseUrl();
|
|
425
394
|
const session = sessions.getById(sessionId);
|
|
426
395
|
const canvasWriteInstructions = buildCanvasWriteSystemPrompt(session); // Pass session object
|
|
427
396
|
const canvasReadInstructions = buildCanvasReadSystemPrompt(session); // Pass session object
|
|
428
397
|
const sessionApiInstructions = buildSessionApiInstructions(sessionId, projectId);
|
|
398
|
+
const commandButtonApiInstructions = buildCommandButtonApiInstructions(apiUrl, sessionId, projectId);
|
|
429
399
|
const kanbanApiInstructions = buildKanbanApiInstructions(sessionId, projectId);
|
|
430
400
|
const attachmentsContext = getSessionAttachmentsContext(sessionId);
|
|
431
401
|
const worktreeContext = buildWorktreeContext(session);
|
|
432
|
-
const childSessionContext = buildChildSessionContext(session);
|
|
433
402
|
const basePrompt = customSystemPrompt || DEFAULT_SYSTEM_PROMPT;
|
|
434
403
|
|
|
435
404
|
// Prepend plan mode instructions if in plan mode
|
|
@@ -439,12 +408,12 @@ export function buildSystemPromptConfig(sessionId, projectId, customSystemPrompt
|
|
|
439
408
|
const parts = [
|
|
440
409
|
modePrompt,
|
|
441
410
|
basePrompt,
|
|
442
|
-
childSessionContext,
|
|
443
411
|
worktreeContext,
|
|
444
412
|
attachmentsContext,
|
|
445
413
|
canvasWriteInstructions,
|
|
446
414
|
canvasReadInstructions,
|
|
447
415
|
sessionApiInstructions,
|
|
416
|
+
commandButtonApiInstructions,
|
|
448
417
|
kanbanApiInstructions
|
|
449
418
|
].filter(Boolean);
|
|
450
419
|
|
|
@@ -11,6 +11,16 @@ export function resolveProviderFromModel(modelId) {
|
|
|
11
11
|
return modelProviders.getProviderByModelId(modelId);
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
export function resolveProviderMetadataFromModel(modelId) {
|
|
15
|
+
if (!modelId) {
|
|
16
|
+
return modelProviders.getById?.('anthropic-default') || null;
|
|
17
|
+
}
|
|
18
|
+
if (typeof modelProviders.getProviderMetadataByModelId === 'function') {
|
|
19
|
+
return modelProviders.getProviderMetadataByModelId(modelId);
|
|
20
|
+
}
|
|
21
|
+
return modelProviders.getProviderByModelId(modelId);
|
|
22
|
+
}
|
|
23
|
+
|
|
14
24
|
/**
|
|
15
25
|
* Resolve the agent type (claude-code vs codex) for a given model ID.
|
|
16
26
|
* Uses the owning provider's kind:
|
|
@@ -204,14 +214,12 @@ function stripAnthropicHostEnv(env) {
|
|
|
204
214
|
|
|
205
215
|
function replaceWithCodexCliEnv(sessionEnv, providerEnv) {
|
|
206
216
|
const target = sessionEnv;
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
Object.assign(
|
|
213
|
-
for (const key of Object.keys(target)) delete target[key];
|
|
214
|
-
Object.assign(target, cleaned);
|
|
217
|
+
delete target.OPENAI_API_KEY;
|
|
218
|
+
delete target.OPENAI_BASE_URL;
|
|
219
|
+
delete target.OPENAI_API_BASE;
|
|
220
|
+
delete target.OPENAI_ORG_ID;
|
|
221
|
+
delete target.OPENAI_PROJECT;
|
|
222
|
+
Object.assign(target, providerEnv);
|
|
215
223
|
}
|
|
216
224
|
|
|
217
225
|
function stripOpenAIBaseUrlUnlessProvided(sessionEnv, providerEnv) {
|
|
@@ -3,71 +3,102 @@ import { broadcastToSession } from '../websocket.js';
|
|
|
3
3
|
import { WS_MESSAGE_TYPES } from '../../../shared/src/index.js';
|
|
4
4
|
import * as summaryService from './summaryService.js';
|
|
5
5
|
import * as kanbanService from './kanbanService.js';
|
|
6
|
+
import { createVisibleFinalErrorMessage } from './visibleFinalErrorMessage.js';
|
|
6
7
|
import {
|
|
7
8
|
lastMessageIds,
|
|
8
9
|
activeSessions,
|
|
9
10
|
activeConversationIds,
|
|
11
|
+
finalErrorSessionIds,
|
|
10
12
|
associateAndBroadcastWorkLogs,
|
|
11
13
|
broadcastSessionStatus,
|
|
12
14
|
broadcastChangesUpdate,
|
|
13
15
|
} from './streamEventHandler.js';
|
|
14
16
|
|
|
15
17
|
/**
|
|
16
|
-
*
|
|
17
|
-
* Encapsulates the duplicated completion block from runSession/continueSession/continueSessionWithExistingMessage
|
|
18
|
+
* Associate work logs with the last message and clean up tracking state.
|
|
18
19
|
* @param {string} sessionId
|
|
19
|
-
* @param {string} workingDirectory
|
|
20
|
-
* @param {{ handleTemplateTriggerIfNeeded?: Function, checkProactiveReschedule?: Function, handleAutoSendIfNeeded?: Function }} callbacks
|
|
21
20
|
*/
|
|
22
|
-
|
|
23
|
-
const { handleTemplateTriggerIfNeeded, checkProactiveReschedule: _checkProactiveReschedule, handleAutoSendIfNeeded } = callbacks;
|
|
24
|
-
// Associate work logs with the last message now that the turn is complete
|
|
21
|
+
function associateAndCleanupWorkLogs(sessionId) {
|
|
25
22
|
const lastMessageId = lastMessageIds.get(sessionId);
|
|
26
23
|
if (lastMessageId) {
|
|
27
24
|
associateAndBroadcastWorkLogs(sessionId, lastMessageId);
|
|
28
25
|
lastMessageIds.delete(sessionId);
|
|
29
26
|
}
|
|
27
|
+
}
|
|
30
28
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Handle post-turn activities for a session that's ready for follow-up.
|
|
31
|
+
* @param {string} sessionId
|
|
32
|
+
* @param {string} workingDirectory
|
|
33
|
+
* @param {{ checkProactiveReschedule?: Function, handleAutoSendIfNeeded?: Function, handleTemplateTriggerIfNeeded?: Function }} callbacks
|
|
34
|
+
* @returns {Promise<boolean>} True if rescheduled, false otherwise
|
|
35
|
+
*/
|
|
36
|
+
async function handleActiveSessionCompletion(sessionId, workingDirectory, callbacks) {
|
|
37
|
+
sessions.update(sessionId, { status: 'waiting', error: null });
|
|
38
|
+
broadcastSessionStatus(sessionId, 'waiting');
|
|
39
|
+
|
|
40
|
+
// Check if session should be proactively rescheduled based on token threshold
|
|
41
|
+
const { checkProactiveReschedule } = callbacks;
|
|
42
|
+
if (checkProactiveReschedule) {
|
|
43
|
+
const wasRescheduled = await checkProactiveReschedule(sessionId);
|
|
44
|
+
if (wasRescheduled) {
|
|
45
|
+
return true; // Session was rescheduled, don't continue with normal completion
|
|
43
46
|
}
|
|
47
|
+
}
|
|
44
48
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
// Extract PR URL immediately (lightweight, no API call)
|
|
50
|
+
summaryService.extractPrUrlIfNeeded(sessionId);
|
|
51
|
+
// Trigger debounced summary generation on turn completion (not complete yet)
|
|
52
|
+
summaryService.onSessionActivity(sessionId);
|
|
49
53
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
// Broadcast changes update when turn completes (real-time indicator)
|
|
55
|
+
const currentSession = sessions.getById(sessionId);
|
|
56
|
+
if (currentSession) {
|
|
57
|
+
await broadcastChangesUpdate(sessionId, currentSession.projectId, workingDirectory);
|
|
58
|
+
}
|
|
55
59
|
|
|
56
|
-
|
|
57
|
-
|
|
60
|
+
// Handle kanban lane movements based on targetLaneId
|
|
61
|
+
await kanbanService.handleTurnCompletion(sessionId);
|
|
58
62
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
// Auto-send queued prompt if enabled (runs BEFORE template trigger)
|
|
64
|
+
const { handleAutoSendIfNeeded, handleTemplateTriggerIfNeeded } = callbacks;
|
|
65
|
+
let autoSendFired = false;
|
|
66
|
+
if (handleAutoSendIfNeeded) {
|
|
67
|
+
autoSendFired = await handleAutoSendIfNeeded(sessionId);
|
|
68
|
+
}
|
|
64
69
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
+
// Only trigger next template if auto-send did NOT fire
|
|
71
|
+
// (if auto-send fired, template will trigger after that turn completes)
|
|
72
|
+
if (!autoSendFired && handleTemplateTriggerIfNeeded) {
|
|
73
|
+
await handleTemplateTriggerIfNeeded(sessionId);
|
|
70
74
|
}
|
|
75
|
+
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Handle post-turn completion logic (after stream loop ends successfully)
|
|
81
|
+
* Encapsulates the duplicated completion block from runSession/continueSession/continueSessionWithExistingMessage
|
|
82
|
+
* @param {string} sessionId
|
|
83
|
+
* @param {string} workingDirectory
|
|
84
|
+
* @param {{ handleTemplateTriggerIfNeeded?: Function, checkProactiveReschedule?: Function, handleAutoSendIfNeeded?: Function }} callbacks
|
|
85
|
+
*/
|
|
86
|
+
export async function handleTurnCompletion(sessionId, workingDirectory, callbacks = {}) {
|
|
87
|
+
// Associate work logs with the last message now that the turn is complete
|
|
88
|
+
associateAndCleanupWorkLogs(sessionId);
|
|
89
|
+
|
|
90
|
+
// Sessions with final errors should not transition to waiting
|
|
91
|
+
if (finalErrorSessionIds.has(sessionId)) {
|
|
92
|
+
finalErrorSessionIds.delete(sessionId);
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Session ready for follow-up - set to waiting instead of completed
|
|
97
|
+
const activeSession = activeSessions.get(sessionId);
|
|
98
|
+
if (activeSession && !activeSession.controller?.signal?.aborted) {
|
|
99
|
+
return handleActiveSessionCompletion(sessionId, workingDirectory, callbacks);
|
|
100
|
+
}
|
|
101
|
+
|
|
71
102
|
return false;
|
|
72
103
|
}
|
|
73
104
|
|
|
@@ -149,6 +180,7 @@ export async function handleSessionError(sessionId, error, options = {}) {
|
|
|
149
180
|
|
|
150
181
|
// Normal error handling (no reschedule or reschedule limits reached)
|
|
151
182
|
sessions.update(sessionId, { status: 'error', error: error.message });
|
|
183
|
+
createVisibleFinalErrorMessage(sessionId, error, activeConversationIds);
|
|
152
184
|
broadcastToSession(sessionId, WS_MESSAGE_TYPES.SESSION_ERROR, { sessionId, error: error.message });
|
|
153
185
|
|
|
154
186
|
// Optionally broadcast final conversation state (continueSession does this)
|
|
@@ -10,6 +10,10 @@ import {
|
|
|
10
10
|
handleTextDelta as _handleTextDelta,
|
|
11
11
|
handleResultUsage,
|
|
12
12
|
} from './streamUsageHandler.js';
|
|
13
|
+
import {
|
|
14
|
+
createVisibleFinalErrorMessage,
|
|
15
|
+
normalizeFinalErrorMessage,
|
|
16
|
+
} from './visibleFinalErrorMessage.js';
|
|
13
17
|
|
|
14
18
|
// ── Shared module-level state ──────────────────────────────────────────────
|
|
15
19
|
|
|
@@ -34,6 +38,9 @@ export const currentModels = new Map();
|
|
|
34
38
|
/** @type {Map<string, Set<string>>} Track tool_use IDs that have already been logged per session */
|
|
35
39
|
export const loggedToolUseIds = new Map();
|
|
36
40
|
|
|
41
|
+
/** @type {Set<string>} Track sessions that received a final result.error event */
|
|
42
|
+
export const finalErrorSessionIds = new Set();
|
|
43
|
+
|
|
37
44
|
// ── Helper functions ───────────────────────────────────────────────────────
|
|
38
45
|
|
|
39
46
|
/**
|
|
@@ -404,8 +411,11 @@ function handleResultEvent(sessionId, event) {
|
|
|
404
411
|
* @param {Object} event
|
|
405
412
|
*/
|
|
406
413
|
function handleResultError(sessionId, event) {
|
|
407
|
-
|
|
408
|
-
|
|
414
|
+
const errorMessage = normalizeFinalErrorMessage(event.error);
|
|
415
|
+
finalErrorSessionIds.add(sessionId);
|
|
416
|
+
sessions.update(sessionId, { status: 'error', error: errorMessage });
|
|
417
|
+
createVisibleFinalErrorMessage(sessionId, errorMessage, activeConversationIds);
|
|
418
|
+
broadcastToSession(sessionId, WS_MESSAGE_TYPES.SESSION_ERROR, { sessionId, error: errorMessage });
|
|
409
419
|
// Broadcast error status to project subscribers for session list updates
|
|
410
420
|
broadcastSessionStatus(sessionId, 'error');
|
|
411
421
|
// Extract PR URL before generating summary (PR may have been created before error)
|
|
@@ -481,6 +491,7 @@ export function cleanupSessionState(sessionId, includeConversationId = false) {
|
|
|
481
491
|
thinkingAccumulators.delete(sessionId);
|
|
482
492
|
currentModels.delete(sessionId);
|
|
483
493
|
loggedToolUseIds.delete(sessionId);
|
|
494
|
+
finalErrorSessionIds.delete(sessionId);
|
|
484
495
|
activeSessions.delete(sessionId);
|
|
485
496
|
if (includeConversationId) {
|
|
486
497
|
activeConversationIds.delete(sessionId);
|
|
@@ -74,6 +74,7 @@ export function handleTextDelta(sessionId, delta, textAccumulators) {
|
|
|
74
74
|
const turnData = currentTurnUsage.get(conversationId) || {
|
|
75
75
|
inputTokens: 0,
|
|
76
76
|
outputTokens: 0,
|
|
77
|
+
thinkingTokens: 0,
|
|
77
78
|
lastMessageOutput: 0,
|
|
78
79
|
cacheReadInputTokens: 0,
|
|
79
80
|
cacheCreationInputTokens: 0,
|
|
@@ -83,6 +84,7 @@ export function handleTextDelta(sessionId, delta, textAccumulators) {
|
|
|
83
84
|
const broadcastUsage = {
|
|
84
85
|
inputTokens: turnData.inputTokens,
|
|
85
86
|
outputTokens: turnData.outputTokens + Math.max(turnData.lastMessageOutput, newEstimate),
|
|
87
|
+
thinkingTokens: turnData.thinkingTokens,
|
|
86
88
|
cacheReadInputTokens: turnData.cacheReadInputTokens,
|
|
87
89
|
cacheCreationInputTokens: turnData.cacheCreationInputTokens,
|
|
88
90
|
};
|
|
@@ -123,6 +125,7 @@ export function extractTurnUsage(sessionId, event) {
|
|
|
123
125
|
return {
|
|
124
126
|
inputTokens: resolveTokenField(modelUsageEntry, event.usage, { camel: 'inputTokens', snake: 'input_tokens' }),
|
|
125
127
|
outputTokens: resolveTokenField(modelUsageEntry, event.usage, { camel: 'outputTokens', snake: 'output_tokens' }),
|
|
128
|
+
thinkingTokens: resolveTokenField(modelUsageEntry, event.usage, { camel: 'thinkingTokens', snake: 'thinking_tokens' }),
|
|
126
129
|
cacheReadInputTokens: resolveTokenField(modelUsageEntry, event.usage, { camel: 'cacheReadInputTokens', snake: 'cache_read_input_tokens' }),
|
|
127
130
|
cacheCreationInputTokens: resolveTokenField(modelUsageEntry, event.usage, { camel: 'cacheCreationInputTokens', snake: 'cache_creation_input_tokens' }),
|
|
128
131
|
webSearchRequests: modelUsageEntry?.webSearchRequests || 0,
|
|
@@ -142,6 +145,7 @@ export function buildCumulativeSessionUsage(sessionId, turnUsage) {
|
|
|
142
145
|
return {
|
|
143
146
|
inputTokens: (currentSession.inputTokens || 0) + turnUsage.inputTokens,
|
|
144
147
|
outputTokens: (currentSession.outputTokens || 0) + turnUsage.outputTokens,
|
|
148
|
+
thinkingTokens: (currentSession.thinkingTokens || 0) + turnUsage.thinkingTokens,
|
|
145
149
|
cacheReadInputTokens: (currentSession.cacheReadInputTokens || 0) + turnUsage.cacheReadInputTokens,
|
|
146
150
|
cacheCreationInputTokens: (currentSession.cacheCreationInputTokens || 0) + turnUsage.cacheCreationInputTokens,
|
|
147
151
|
webSearchRequests: (currentSession.webSearchRequests || 0) + turnUsage.webSearchRequests,
|
|
@@ -162,6 +166,7 @@ export function updateConversationUsage(conversationId, currentConversation, tur
|
|
|
162
166
|
const cumulativeConversationUsage = {
|
|
163
167
|
inputTokens: (currentConversation.inputTokens || 0) + turnUsage.inputTokens,
|
|
164
168
|
outputTokens: (currentConversation.outputTokens || 0) + turnUsage.outputTokens,
|
|
169
|
+
thinkingTokens: (currentConversation.thinkingTokens || 0) + turnUsage.thinkingTokens,
|
|
165
170
|
cacheReadInputTokens: (currentConversation.cacheReadInputTokens || 0) + turnUsage.cacheReadInputTokens,
|
|
166
171
|
cacheCreationInputTokens: (currentConversation.cacheCreationInputTokens || 0) + turnUsage.cacheCreationInputTokens,
|
|
167
172
|
webSearchRequests: (currentConversation.webSearchRequests || 0) + turnUsage.webSearchRequests,
|
|
@@ -197,6 +202,7 @@ export function handleResultUsage(sessionId, event) {
|
|
|
197
202
|
usage: updatedConversation ? {
|
|
198
203
|
inputTokens: updatedConversation.inputTokens,
|
|
199
204
|
outputTokens: updatedConversation.outputTokens,
|
|
205
|
+
thinkingTokens: updatedConversation.thinkingTokens,
|
|
200
206
|
cacheReadInputTokens: updatedConversation.cacheReadInputTokens,
|
|
201
207
|
cacheCreationInputTokens: updatedConversation.cacheCreationInputTokens,
|
|
202
208
|
webSearchRequests: updatedConversation.webSearchRequests,
|
|
@@ -49,11 +49,16 @@ function logResultUsage(callId, event) {
|
|
|
49
49
|
/**
|
|
50
50
|
* Build the query parameters for the Claude SDK call.
|
|
51
51
|
* @param {string} prompt - The prompt to send
|
|
52
|
-
* @param {{ systemPrompt?: string, jsonSchema?: Object }} options
|
|
52
|
+
* @param {{ systemPrompt?: string, jsonSchema?: Object, model?: string, env?: Object }} options
|
|
53
53
|
* @returns {Object} queryParams ready for the SDK query function
|
|
54
54
|
*/
|
|
55
55
|
function buildClaudeRequest(prompt, options) {
|
|
56
|
-
const {
|
|
56
|
+
const {
|
|
57
|
+
systemPrompt = null,
|
|
58
|
+
jsonSchema = null,
|
|
59
|
+
model = 'claude-haiku-4-5-20251001',
|
|
60
|
+
env = null,
|
|
61
|
+
} = options || {};
|
|
57
62
|
const schema = jsonSchema || SESSION_SUMMARY_SCHEMA;
|
|
58
63
|
|
|
59
64
|
return {
|
|
@@ -62,7 +67,8 @@ function buildClaudeRequest(prompt, options) {
|
|
|
62
67
|
cwd: process.cwd(),
|
|
63
68
|
permissionMode: 'bypassPermissions',
|
|
64
69
|
maxTurns: 1,
|
|
65
|
-
model
|
|
70
|
+
model,
|
|
71
|
+
...(env && { env }),
|
|
66
72
|
...(systemPrompt && { systemPrompt }),
|
|
67
73
|
outputFormat: {
|
|
68
74
|
type: 'json_schema',
|
|
@@ -108,6 +114,21 @@ async function handleClaudeResponse(eventStream, callId) {
|
|
|
108
114
|
return state.responseText;
|
|
109
115
|
}
|
|
110
116
|
|
|
117
|
+
function buildSummaryCallMetadata({ logMeta, model, providerId, selectionReason, promptLength }) {
|
|
118
|
+
return {
|
|
119
|
+
sessionId: logMeta.sessionId,
|
|
120
|
+
conversationId: logMeta.conversationId || null,
|
|
121
|
+
agentType: 'summary',
|
|
122
|
+
model,
|
|
123
|
+
callType: logMeta.callType,
|
|
124
|
+
promptLength,
|
|
125
|
+
metadata: {
|
|
126
|
+
...(providerId ? { providerId } : {}),
|
|
127
|
+
...(selectionReason ? { selectionReason } : {}),
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
111
132
|
export const SESSION_SUMMARY_SCHEMA = {
|
|
112
133
|
type: 'object',
|
|
113
134
|
properties: {
|
|
@@ -130,11 +151,16 @@ export const SESSION_SUMMARY_SCHEMA = {
|
|
|
130
151
|
* @param {string} prompt - The prompt to send
|
|
131
152
|
* @param {Array} recentMessages - Messages (for mock mode context)
|
|
132
153
|
* @param {string} sessionStatus - Session status (for mock mode context)
|
|
133
|
-
* @param {{ logMeta?: Object, systemPrompt?: string, jsonSchema?: Object }} options - Optional parameters
|
|
154
|
+
* @param {{ logMeta?: Object, systemPrompt?: string, jsonSchema?: Object, model?: string, env?: Object, providerId?: string|null, selectionReason?: string }} options - Optional parameters
|
|
134
155
|
* @returns {Promise<string>} The text response (JSON string)
|
|
135
156
|
*/
|
|
136
157
|
export async function callClaude(prompt, recentMessages, sessionStatus, options = {}) {
|
|
137
|
-
const {
|
|
158
|
+
const {
|
|
159
|
+
logMeta = null,
|
|
160
|
+
model = 'claude-haiku-4-5-20251001',
|
|
161
|
+
providerId = null,
|
|
162
|
+
selectionReason = null,
|
|
163
|
+
} = options || {};
|
|
138
164
|
// Build stable key for VCR cassette (session prompts are hardcoded strings in E2E tests)
|
|
139
165
|
let keyHint = null;
|
|
140
166
|
if (process.env.VCR_MODE && logMeta?.sessionId) {
|
|
@@ -151,14 +177,13 @@ export async function callClaude(prompt, recentMessages, sessionStatus, options
|
|
|
151
177
|
// Start logging if metadata provided
|
|
152
178
|
let callId = null;
|
|
153
179
|
if (logMeta) {
|
|
154
|
-
callId = agentCallLogger.startCall({
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
callType: logMeta.callType,
|
|
180
|
+
callId = agentCallLogger.startCall(buildSummaryCallMetadata({
|
|
181
|
+
logMeta,
|
|
182
|
+
model,
|
|
183
|
+
providerId,
|
|
184
|
+
selectionReason,
|
|
160
185
|
promptLength: prompt.length,
|
|
161
|
-
});
|
|
186
|
+
}));
|
|
162
187
|
}
|
|
163
188
|
|
|
164
189
|
try {
|