circuschief 0.6.0 → 0.7.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/api/projects-session-helpers.js +25 -0
- package/packages/server/src/api/projects.js +1 -0
- package/packages/server/src/api/sessions-draft.js +1 -0
- package/packages/server/src/api/settings.js +52 -4
- package/packages/server/src/db/ConversationRepository.js +16 -3
- package/packages/server/src/db/ProjectDefaultsRepository.js +47 -37
- package/packages/server/src/db/SessionRepository.js +12 -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/migrations/conversationsMigrations.js +4 -0
- package/packages/server/src/db/migrations/index.js +2 -0
- package/packages/server/src/db/migrations/sessionsMigrations.js +6 -1
- package/packages/server/src/db/session-helpers.js +3 -0
- package/packages/server/src/schema.sql +8 -0
- package/packages/server/src/services/agentCallLogger.js +1 -1
- package/packages/server/src/services/commandButtonPrompts.js +48 -0
- package/packages/server/src/services/draftSessionService.js +2 -0
- package/packages/server/src/services/sessionExecution.js +3 -1
- package/packages/server/src/services/sessionPrompts.js +4 -0
- package/packages/server/src/services/sessionProvider.js +6 -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 +6 -4
- package/packages/server/src/services/usageTracker.js +5 -1
- package/packages/server/src/services/visibleFinalErrorMessage.js +123 -0
- package/packages/shared/src/constants.js +1 -2
- package/packages/shared/src/contracts/projects.js +2 -0
- package/packages/shared/src/utils.js +9 -17
- package/packages/web/dist/assets/ActiveSessionsView-UJsCILDL.js +1 -0
- package/packages/web/dist/assets/{AgentLogsView-Cdw4nmvd.js → AgentLogsView-BGFPLjLa.js} +1 -1
- package/packages/web/dist/assets/ApiClient-B4YTtyY4.js +1 -0
- package/packages/web/dist/assets/{ArchiveConfirmModal-J48eh3zw.js → ArchiveConfirmModal-OFaj_uX5.js} +1 -1
- package/packages/web/dist/assets/{CommandButtonDetailView-DnFhJY5A.js → CommandButtonDetailView-D8S258uP.js} +1 -1
- package/packages/web/dist/assets/EffortLevelSelector-C2378L8e.js +1 -0
- package/packages/web/dist/assets/{GeneralSettingsView-CQkmdczf.js → GeneralSettingsView-DsHChEhv.js} +1 -1
- package/packages/web/dist/assets/{InputWithButton-XyM3k6lN.js → InputWithButton-Ci15ox0a.js} +1 -1
- package/packages/web/dist/assets/{InterpolationHelp-PfYR3KJo.js → InterpolationHelp-CIkOSkWX.js} +1 -1
- package/packages/web/dist/assets/MarkdownEditor-5-bexzUT.js +2 -0
- package/packages/web/dist/assets/ModelSelector-BMpR0DPr.js +1 -0
- package/packages/web/dist/assets/{ModelSelector-BZOT1Jc6.css → ModelSelector-D8hbTRIt.css} +1 -1
- package/packages/web/dist/assets/{NewSessionView-DkjFLvHU.js → NewSessionView-BCqtIgWH.js} +2 -2
- package/packages/web/dist/assets/{NewSessionView-D_Hi7M9g.css → NewSessionView-CUUdHkfv.css} +1 -1
- package/packages/web/dist/assets/ProjectEditView-D9sK0fdH.css +1 -0
- package/packages/web/dist/assets/ProjectEditView-RFaxHhAX.js +1 -0
- package/packages/web/dist/assets/{ProjectListView-CuYMmd3O.js → ProjectListView-B9FuWESY.js} +1 -1
- package/packages/web/dist/assets/{ProjectNewView-CNaA4Maf.js → ProjectNewView-D62jYlBL.js} +1 -1
- package/packages/web/dist/assets/ProvidersView-DDKMIQWZ.js +1 -0
- package/packages/web/dist/assets/QuickResponseSettings-CDm5vwP7.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-DZ_Lre_l.js} +1 -1
- package/packages/web/dist/assets/{ResizableTextarea-wYF3K2RO.js → ResizableTextarea-DiIOEGjN.js} +1 -1
- package/packages/web/dist/assets/{SessionCard-bLaQEWWX.js → SessionCard-DmjnVYWn.js} +1 -1
- package/packages/web/dist/assets/SessionDetailView-CL7nmfiB.js +36 -0
- package/packages/web/dist/assets/SessionDetailView-CupIkI7u.css +1 -0
- package/packages/web/dist/assets/SessionFormOptions-BpUALRKn.css +1 -0
- package/packages/web/dist/assets/SessionFormOptions-DYUISplS.js +1 -0
- package/packages/web/dist/assets/SessionListView-BcxGz4aC.js +1 -0
- package/packages/web/dist/assets/{SessionLogStream-DTnDAF95.js → SessionLogStream-DpUE6Xsh.js} +1 -1
- package/packages/web/dist/assets/{SettingsView-DNLUSsHV.js → SettingsView-BC055tIA.js} +1 -1
- package/packages/web/dist/assets/{SlashCommandWizard-CRGFaO8t.js → SlashCommandWizard-DmTyNG9O.js} +1 -1
- package/packages/web/dist/assets/SummarySettingsView-BgnRCwlq.js +1 -0
- package/packages/web/dist/assets/SummarySettingsView-l2bxHmZZ.css +1 -0
- package/packages/web/dist/assets/TemplateDetailView-BlhOmLUX.js +1 -0
- package/packages/web/dist/assets/{commandButtons-Bbjf3fCt.js → commandButtons-D4RPpLiu.js} +1 -1
- package/packages/web/dist/assets/index-4rhEeO0B.js +1 -0
- package/packages/web/dist/assets/index-9vb2KaAd.js +1 -0
- package/packages/web/dist/assets/index-B0CvZXuN.js +7 -0
- package/packages/web/dist/assets/{index-BQL_L4gL.js → index-B6G18FqB.js} +14 -14
- package/packages/web/dist/assets/{index-Cf6vdW-B.js → index-BGwH4Cfn.js} +3 -3
- package/packages/web/dist/assets/index-BUhvkAdF.js +1 -0
- package/packages/web/dist/assets/index-BcnkUk2o.js +1 -0
- package/packages/web/dist/assets/{index-Bs7Qf5D6.js → index-Bn5xdGFM.js} +2 -2
- package/packages/web/dist/assets/index-CNwkdB0T.js +1 -0
- package/packages/web/dist/assets/index-CfL84oGW.js +1 -0
- package/packages/web/dist/assets/index-CkmxO8Mm.js +1 -0
- package/packages/web/dist/assets/index-Cpy4-yv3.js +1 -0
- package/packages/web/dist/assets/index-CrAQJmoZ.js +1 -0
- package/packages/web/dist/assets/{index-gmCCsCQ1.css → index-Cs2nxhrT.css} +1 -1
- package/packages/web/dist/assets/index-D6Ky9vJe.js +3 -0
- package/packages/web/dist/assets/index-DfrE0gAC.js +1 -0
- package/packages/web/dist/assets/index-KwEyz0F3.js +1 -0
- package/packages/web/dist/assets/index-OfCywayk.js +1 -0
- package/packages/web/dist/assets/index-PDesaJc6.js +1 -0
- package/packages/web/dist/assets/index-uB6nhSvz.js +1 -0
- package/packages/web/dist/assets/{projects-CPt3AB7U.js → projects-BUiOGmmb.js} +1 -1
- package/packages/web/dist/assets/{providers-ChfeMvUq.js → providers-Bh1ZiiJi.js} +1 -1
- package/packages/web/dist/assets/sessions-DH1R-NhV.js +1 -0
- package/packages/web/dist/assets/settings-Z4AVVmkJ.js +1 -0
- package/packages/web/dist/index.html +2 -2
- 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/EffortLevelSelector-bXbPo4Zw.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/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/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/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
package/package.json
CHANGED
|
@@ -44,6 +44,26 @@ export function resolveDefault(explicit, projectDefault, systemDefault) {
|
|
|
44
44
|
return systemDefault;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Normalize provider IDs from JSON or multipart request fields.
|
|
49
|
+
* @param {*} value - Raw providerId value
|
|
50
|
+
* @returns {string|null|undefined}
|
|
51
|
+
*/
|
|
52
|
+
export function normalizeProviderId(value) {
|
|
53
|
+
if (value === undefined) return undefined;
|
|
54
|
+
if (value === null || value === '') return null;
|
|
55
|
+
if (typeof value !== 'string') {
|
|
56
|
+
throw new TypeError('providerId must be a string or null');
|
|
57
|
+
}
|
|
58
|
+
return value;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function resolveProviderDefault(explicit, projectDefault, systemDefault) {
|
|
62
|
+
if (explicit !== undefined) return explicit;
|
|
63
|
+
if (projectDefault !== undefined && projectDefault !== null) return projectDefault;
|
|
64
|
+
return systemDefault ?? null;
|
|
65
|
+
}
|
|
66
|
+
|
|
47
67
|
/**
|
|
48
68
|
* Resolve thinkingEnabled with special boolean handling.
|
|
49
69
|
* @param {object} body - Request body
|
|
@@ -114,11 +134,16 @@ export function prepareSessionConfig(body, projectDefs, systemDefaults) {
|
|
|
114
134
|
effortLevel = null;
|
|
115
135
|
}
|
|
116
136
|
|
|
137
|
+
const explicitProviderId = normalizeProviderId(body.providerId);
|
|
138
|
+
const projectProviderId = normalizeProviderId(projectDefs?.providerId);
|
|
139
|
+
const systemProviderId = normalizeProviderId(systemDefaults.providerId);
|
|
140
|
+
|
|
117
141
|
return {
|
|
118
142
|
prompt: body.prompt,
|
|
119
143
|
name: body.name,
|
|
120
144
|
mode: resolveDefault(body.mode, projectDefs?.mode, systemDefaults.mode),
|
|
121
145
|
model: resolveDefault(body.model, projectDefs?.model, systemDefaults.model || null),
|
|
146
|
+
providerId: resolveProviderDefault(explicitProviderId, projectProviderId, systemProviderId),
|
|
122
147
|
effortLevel,
|
|
123
148
|
gitBranch: resolveDefault(body.gitBranch, projectDefs?.gitBranch, null),
|
|
124
149
|
gitMode: resolveDefault(body.gitMode, projectDefs?.gitMode, null),
|
|
@@ -243,6 +243,7 @@ function createSessionRow(projectId, config, nextTemplateId, initialStatus) {
|
|
|
243
243
|
parentSessionId: config.parentSessionId,
|
|
244
244
|
status: initialStatus,
|
|
245
245
|
model: config.model,
|
|
246
|
+
providerId: config.providerId,
|
|
246
247
|
effortLevel: config.effortLevel,
|
|
247
248
|
agentType: config.agentType,
|
|
248
249
|
});
|
|
@@ -57,6 +57,7 @@ router.post('/:id/start', requireSession, async (req, res) => {
|
|
|
57
57
|
const updatedSession = await startDraft(req.session_, {
|
|
58
58
|
prompt: req.body.prompt,
|
|
59
59
|
model: req.body.model,
|
|
60
|
+
providerId: req.body.providerId,
|
|
60
61
|
});
|
|
61
62
|
|
|
62
63
|
res.json({ success: true, session: updatedSession });
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Router } from 'express';
|
|
2
|
-
import { settings } from '../db/index.js';
|
|
2
|
+
import { modelProviders, settings } from '../db/index.js';
|
|
3
3
|
import { DEFAULT_SESSION_TITLE_PROMPT } from '../services/summaryService.js';
|
|
4
4
|
|
|
5
5
|
const router = Router();
|
|
6
|
+
const SUPPORTED_SUMMARY_PROVIDER_KINDS = new Set(['anthropic', 'openai']);
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* GET /api/settings/token-weights
|
|
@@ -93,19 +94,42 @@ router.get('/summary', (req, res) => {
|
|
|
93
94
|
*/
|
|
94
95
|
router.put('/summary', (req, res) => {
|
|
95
96
|
try {
|
|
96
|
-
const
|
|
97
|
+
const body = req.body || {};
|
|
98
|
+
const {
|
|
99
|
+
disableSessionSummaries,
|
|
100
|
+
sessionTitlePrompt,
|
|
101
|
+
summaryModel,
|
|
102
|
+
summaryProviderId,
|
|
103
|
+
} = body;
|
|
97
104
|
|
|
98
105
|
// Validate that all required fields are present
|
|
99
106
|
if (typeof disableSessionSummaries !== 'boolean' ||
|
|
100
|
-
typeof sessionTitlePrompt !== 'string'
|
|
107
|
+
typeof sessionTitlePrompt !== 'string' ||
|
|
108
|
+
!Object.prototype.hasOwnProperty.call(body, 'summaryModel') ||
|
|
109
|
+
!Object.prototype.hasOwnProperty.call(body, 'summaryProviderId')) {
|
|
101
110
|
return res.status(400).json({
|
|
102
|
-
error: 'Invalid summary settings. disableSessionSummaries must be a boolean, sessionTitlePrompt must be a string'
|
|
111
|
+
error: 'Invalid summary settings. disableSessionSummaries must be a boolean, sessionTitlePrompt must be a string, summaryModel must be present, and summaryProviderId must be present'
|
|
103
112
|
});
|
|
104
113
|
}
|
|
105
114
|
|
|
115
|
+
if (typeof summaryModel !== 'string') {
|
|
116
|
+
return res.status(400).json({ error: 'summaryModel must be a string' });
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (summaryProviderId !== null && typeof summaryProviderId !== 'string') {
|
|
120
|
+
return res.status(400).json({ error: 'summaryProviderId must be a string or null' });
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const validationError = validateSummaryModelSelection(summaryModel, summaryProviderId);
|
|
124
|
+
if (validationError) {
|
|
125
|
+
return res.status(400).json({ error: validationError });
|
|
126
|
+
}
|
|
127
|
+
|
|
106
128
|
const updatedSettings = settings.setSummarySettings({
|
|
107
129
|
disableSessionSummaries,
|
|
108
130
|
sessionTitlePrompt,
|
|
131
|
+
summaryModel,
|
|
132
|
+
summaryProviderId,
|
|
109
133
|
});
|
|
110
134
|
|
|
111
135
|
// Include the default prompt for UI display/editing
|
|
@@ -119,6 +143,30 @@ router.put('/summary', (req, res) => {
|
|
|
119
143
|
}
|
|
120
144
|
});
|
|
121
145
|
|
|
146
|
+
function validateSummaryModelSelection(summaryModel, summaryProviderId) {
|
|
147
|
+
if (!summaryModel) {
|
|
148
|
+
if (summaryProviderId !== null) {
|
|
149
|
+
return 'summaryProviderId must be null when summaryModel is empty';
|
|
150
|
+
}
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (!summaryProviderId) {
|
|
155
|
+
return 'summaryProviderId is required when summaryModel is set';
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const provider = modelProviders.getById(summaryProviderId);
|
|
159
|
+
if (!provider) return `Unknown summary provider: ${summaryProviderId}`;
|
|
160
|
+
if (!SUPPORTED_SUMMARY_PROVIDER_KINDS.has(provider.kind || 'anthropic')) {
|
|
161
|
+
return `Unsupported summary provider kind: ${provider.kind}`;
|
|
162
|
+
}
|
|
163
|
+
const ownsModel = provider.models?.some((model) => model.modelId === summaryModel);
|
|
164
|
+
if (!ownsModel) {
|
|
165
|
+
return `Provider ${summaryProviderId} does not own summary model ${summaryModel}`;
|
|
166
|
+
}
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
|
|
122
170
|
/**
|
|
123
171
|
* DELETE /api/settings/summary
|
|
124
172
|
* Reset summary settings to defaults
|
|
@@ -237,6 +237,7 @@ export class ConversationRepository extends BaseRepository {
|
|
|
237
237
|
* @param {Object} usage - Usage data
|
|
238
238
|
* @param {number} usage.inputTokens
|
|
239
239
|
* @param {number} usage.outputTokens
|
|
240
|
+
* @param {number} usage.thinkingTokens
|
|
240
241
|
* @param {number} usage.cacheReadInputTokens
|
|
241
242
|
* @param {number} usage.cacheCreationInputTokens
|
|
242
243
|
* @param {number} usage.webSearchRequests
|
|
@@ -255,6 +256,7 @@ export class ConversationRepository extends BaseRepository {
|
|
|
255
256
|
`UPDATE conversations SET
|
|
256
257
|
input_tokens = ?,
|
|
257
258
|
output_tokens = ?,
|
|
259
|
+
thinking_tokens = ?,
|
|
258
260
|
cache_read_input_tokens = ?,
|
|
259
261
|
cache_creation_input_tokens = ?,
|
|
260
262
|
web_search_requests = ?,
|
|
@@ -265,6 +267,7 @@ export class ConversationRepository extends BaseRepository {
|
|
|
265
267
|
.run(
|
|
266
268
|
usage.inputTokens,
|
|
267
269
|
usage.outputTokens,
|
|
270
|
+
usage.thinkingTokens || 0,
|
|
268
271
|
usage.cacheReadInputTokens,
|
|
269
272
|
usage.cacheCreationInputTokens,
|
|
270
273
|
usage.webSearchRequests,
|
|
@@ -290,9 +293,12 @@ export class ConversationRepository extends BaseRepository {
|
|
|
290
293
|
const now = Date.now();
|
|
291
294
|
|
|
292
295
|
this.db
|
|
293
|
-
|
|
294
|
-
`INSERT INTO conversations (id, session_id, name, summary, is_active,
|
|
295
|
-
|
|
296
|
+
.prepare(
|
|
297
|
+
`INSERT INTO conversations (id, session_id, name, summary, is_active,
|
|
298
|
+
input_tokens, output_tokens, thinking_tokens,
|
|
299
|
+
cache_read_input_tokens, cache_creation_input_tokens,
|
|
300
|
+
web_search_requests, context_window, created_at, updated_at)
|
|
301
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
296
302
|
)
|
|
297
303
|
.run(
|
|
298
304
|
id,
|
|
@@ -300,6 +306,13 @@ export class ConversationRepository extends BaseRepository {
|
|
|
300
306
|
conv.name,
|
|
301
307
|
conv.summary,
|
|
302
308
|
conv.isActive ? 1 : 0,
|
|
309
|
+
conv.inputTokens,
|
|
310
|
+
conv.outputTokens,
|
|
311
|
+
conv.thinkingTokens,
|
|
312
|
+
conv.cacheReadInputTokens,
|
|
313
|
+
conv.cacheCreationInputTokens,
|
|
314
|
+
conv.webSearchRequests,
|
|
315
|
+
conv.contextWindow,
|
|
303
316
|
now,
|
|
304
317
|
now
|
|
305
318
|
);
|
|
@@ -12,6 +12,7 @@ const UPSERT_FIELD_MAP = [
|
|
|
12
12
|
{ key: 'gitMode', column: 'git_mode' },
|
|
13
13
|
{ key: 'gitBranch', column: 'git_branch' },
|
|
14
14
|
{ key: 'model', column: 'model' },
|
|
15
|
+
{ key: 'providerId', column: 'provider_id' },
|
|
15
16
|
{ key: 'effortLevel', column: 'effort_level' },
|
|
16
17
|
];
|
|
17
18
|
|
|
@@ -47,6 +48,7 @@ export class ProjectDefaultsRepository extends BaseRepository {
|
|
|
47
48
|
gitMode: row.git_mode || null,
|
|
48
49
|
gitBranch: row.git_branch || null,
|
|
49
50
|
model: row.model || null,
|
|
51
|
+
providerId: row.provider_id || null,
|
|
50
52
|
effortLevel: row.effort_level || null,
|
|
51
53
|
createdAt: row.created_at,
|
|
52
54
|
updatedAt: row.updated_at,
|
|
@@ -72,47 +74,53 @@ export class ProjectDefaultsRepository extends BaseRepository {
|
|
|
72
74
|
* @param {Object} data - Defaults data (all fields optional)
|
|
73
75
|
* @returns {Object} Updated defaults object
|
|
74
76
|
*/
|
|
77
|
+
#insertDefaults(projectId, data) {
|
|
78
|
+
const id = databaseManager.generateId();
|
|
79
|
+
const now = Date.now();
|
|
80
|
+
|
|
81
|
+
this.db
|
|
82
|
+
.prepare(
|
|
83
|
+
`INSERT INTO project_session_defaults
|
|
84
|
+
(id, project_id, mode, thinking_enabled, start_immediately, git_mode, git_branch, model, provider_id, effort_level, created_at, updated_at)
|
|
85
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
86
|
+
)
|
|
87
|
+
.run(
|
|
88
|
+
id,
|
|
89
|
+
projectId,
|
|
90
|
+
data.mode || null,
|
|
91
|
+
data.thinkingEnabled !== undefined ? (data.thinkingEnabled ? 1 : 0) : null,
|
|
92
|
+
data.startImmediately !== undefined ? (data.startImmediately ? 1 : 0) : null,
|
|
93
|
+
data.gitMode || null,
|
|
94
|
+
data.gitBranch || null,
|
|
95
|
+
data.model || null,
|
|
96
|
+
data.providerId || null,
|
|
97
|
+
data.effortLevel || null,
|
|
98
|
+
now,
|
|
99
|
+
now
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
#updateDefaults(projectId, data) {
|
|
104
|
+
const { updates, values } = buildUpdateFields(data);
|
|
105
|
+
|
|
106
|
+
if (updates.length > 0) {
|
|
107
|
+
updates.push('updated_at = ?');
|
|
108
|
+
values.push(Date.now());
|
|
109
|
+
values.push(projectId);
|
|
110
|
+
|
|
111
|
+
this.db
|
|
112
|
+
.prepare(`UPDATE project_session_defaults SET ${updates.join(', ')} WHERE project_id = ?`)
|
|
113
|
+
.run(...values);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
75
117
|
upsert(projectId, data) {
|
|
76
|
-
// Get existing defaults if any
|
|
77
118
|
const existing = this.getByProjectId(projectId);
|
|
78
119
|
|
|
79
120
|
if (!existing) {
|
|
80
|
-
|
|
81
|
-
const id = databaseManager.generateId();
|
|
82
|
-
const now = Date.now();
|
|
83
|
-
|
|
84
|
-
this.db
|
|
85
|
-
.prepare(
|
|
86
|
-
`INSERT INTO project_session_defaults
|
|
87
|
-
(id, project_id, mode, thinking_enabled, start_immediately, git_mode, git_branch, model, effort_level, created_at, updated_at)
|
|
88
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
89
|
-
)
|
|
90
|
-
.run(
|
|
91
|
-
id,
|
|
92
|
-
projectId,
|
|
93
|
-
data.mode || null,
|
|
94
|
-
data.thinkingEnabled !== undefined ? (data.thinkingEnabled ? 1 : 0) : null,
|
|
95
|
-
data.startImmediately !== undefined ? (data.startImmediately ? 1 : 0) : null,
|
|
96
|
-
data.gitMode || null,
|
|
97
|
-
data.gitBranch || null,
|
|
98
|
-
data.model || null,
|
|
99
|
-
data.effortLevel || null,
|
|
100
|
-
now,
|
|
101
|
-
now
|
|
102
|
-
);
|
|
121
|
+
this.#insertDefaults(projectId, data);
|
|
103
122
|
} else {
|
|
104
|
-
|
|
105
|
-
const { updates, values } = buildUpdateFields(data);
|
|
106
|
-
|
|
107
|
-
if (updates.length > 0) {
|
|
108
|
-
updates.push('updated_at = ?');
|
|
109
|
-
values.push(Date.now());
|
|
110
|
-
values.push(projectId);
|
|
111
|
-
|
|
112
|
-
this.db
|
|
113
|
-
.prepare(`UPDATE project_session_defaults SET ${updates.join(', ')} WHERE project_id = ?`)
|
|
114
|
-
.run(...values);
|
|
115
|
-
}
|
|
123
|
+
this.#updateDefaults(projectId, data);
|
|
116
124
|
}
|
|
117
125
|
|
|
118
126
|
return this.getByProjectId(projectId);
|
|
@@ -137,7 +145,8 @@ export class ProjectDefaultsRepository extends BaseRepository {
|
|
|
137
145
|
.prepare(
|
|
138
146
|
`UPDATE project_session_defaults
|
|
139
147
|
SET mode = NULL, thinking_enabled = NULL, start_immediately = NULL,
|
|
140
|
-
git_mode = NULL, git_branch = NULL, model = NULL,
|
|
148
|
+
git_mode = NULL, git_branch = NULL, model = NULL, provider_id = NULL,
|
|
149
|
+
effort_level = NULL, updated_at = ?
|
|
141
150
|
WHERE project_id = ?`
|
|
142
151
|
)
|
|
143
152
|
.run(Date.now(), projectId);
|
|
@@ -167,6 +176,7 @@ export class ProjectDefaultsRepository extends BaseRepository {
|
|
|
167
176
|
gitMode: null,
|
|
168
177
|
gitBranch: null,
|
|
169
178
|
model: null,
|
|
179
|
+
providerId: null,
|
|
170
180
|
effortLevel: null,
|
|
171
181
|
};
|
|
172
182
|
}
|
|
@@ -45,6 +45,7 @@ export class SessionRepository extends BaseRepository {
|
|
|
45
45
|
status: row.status,
|
|
46
46
|
mode: row.mode,
|
|
47
47
|
model: row.model,
|
|
48
|
+
providerId: row.provider_id || null,
|
|
48
49
|
thinkingEnabled: Boolean(row.thinking_enabled),
|
|
49
50
|
archived: Boolean(row.archived),
|
|
50
51
|
starred: Boolean(row.starred),
|
|
@@ -84,7 +85,7 @@ export class SessionRepository extends BaseRepository {
|
|
|
84
85
|
return this.map(row);
|
|
85
86
|
}
|
|
86
87
|
|
|
87
|
-
/** Create a new session with optional config (mode, thinkingEnabled, gitBranch, parentSessionId, status, model, effortLevel, agentType) */
|
|
88
|
+
/** Create a new session with optional config (mode, thinkingEnabled, gitBranch, parentSessionId, status, model, providerId, effortLevel, agentType) */
|
|
88
89
|
create(projectId, name, prompt, options = {}) {
|
|
89
90
|
const config = parseCreateConfig(options, Array.prototype.slice.call(arguments, 4));
|
|
90
91
|
|
|
@@ -98,8 +99,8 @@ export class SessionRepository extends BaseRepository {
|
|
|
98
99
|
const now = Date.now();
|
|
99
100
|
this.db
|
|
100
101
|
.prepare(
|
|
101
|
-
`INSERT INTO sessions (id, project_id, name, status, mode, thinking_enabled, git_branch, parent_session_id, model, effort_level, agent_type, created_at, updated_at)
|
|
102
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
102
|
+
`INSERT INTO sessions (id, project_id, name, status, mode, thinking_enabled, git_branch, parent_session_id, model, provider_id, effort_level, agent_type, created_at, updated_at)
|
|
103
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
103
104
|
)
|
|
104
105
|
.run(
|
|
105
106
|
id,
|
|
@@ -111,6 +112,7 @@ export class SessionRepository extends BaseRepository {
|
|
|
111
112
|
config.gitBranch,
|
|
112
113
|
config.parentSessionId,
|
|
113
114
|
config.model,
|
|
115
|
+
config.providerId,
|
|
114
116
|
config.effortLevel,
|
|
115
117
|
agentType,
|
|
116
118
|
now,
|
|
@@ -282,10 +284,10 @@ export class SessionRepository extends BaseRepository {
|
|
|
282
284
|
// Insert new session with same settings but new ID and status
|
|
283
285
|
this.db
|
|
284
286
|
.prepare(
|
|
285
|
-
`INSERT INTO sessions (id, project_id, name, status, mode, thinking_enabled, git_branch, model, effort_level, agent_type, context_window,
|
|
286
|
-
input_tokens, output_tokens, cache_read_input_tokens, cache_creation_input_tokens,
|
|
287
|
+
`INSERT INTO sessions (id, project_id, name, status, mode, thinking_enabled, git_branch, model, provider_id, effort_level, agent_type, context_window,
|
|
288
|
+
input_tokens, output_tokens, thinking_tokens, cache_read_input_tokens, cache_creation_input_tokens,
|
|
287
289
|
web_search_requests, cost_usd, created_at, updated_at)
|
|
288
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
290
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
289
291
|
)
|
|
290
292
|
.run(
|
|
291
293
|
id,
|
|
@@ -296,11 +298,13 @@ export class SessionRepository extends BaseRepository {
|
|
|
296
298
|
source.thinkingEnabled ? 1 : 0,
|
|
297
299
|
source.gitBranch, // Copy branch name (NOT worktree path)
|
|
298
300
|
source.model,
|
|
301
|
+
source.providerId,
|
|
299
302
|
source.effortLevel,
|
|
300
303
|
source.agentType || DEFAULT_AGENT_TYPE,
|
|
301
304
|
source.contextWindow,
|
|
302
305
|
source.inputTokens,
|
|
303
306
|
source.outputTokens,
|
|
307
|
+
source.thinkingTokens,
|
|
304
308
|
source.cacheReadInputTokens,
|
|
305
309
|
source.cacheCreationInputTokens,
|
|
306
310
|
source.webSearchRequests,
|
|
@@ -326,11 +330,11 @@ export class SessionRepository extends BaseRepository {
|
|
|
326
330
|
updateUsage(id, usage) {
|
|
327
331
|
this.db
|
|
328
332
|
.prepare(
|
|
329
|
-
`UPDATE sessions SET input_tokens = ?, output_tokens = ?, cache_read_input_tokens = ?,
|
|
333
|
+
`UPDATE sessions SET input_tokens = ?, output_tokens = ?, thinking_tokens = ?, cache_read_input_tokens = ?,
|
|
330
334
|
cache_creation_input_tokens = ?, web_search_requests = ?, context_window = ?, updated_at = ?
|
|
331
335
|
WHERE id = ?`
|
|
332
336
|
)
|
|
333
|
-
.run(usage.inputTokens, usage.outputTokens, usage.cacheReadInputTokens,
|
|
337
|
+
.run(usage.inputTokens, usage.outputTokens, usage.thinkingTokens || 0, usage.cacheReadInputTokens,
|
|
334
338
|
usage.cacheCreationInputTokens, usage.webSearchRequests, usage.contextWindow, Date.now(), id);
|
|
335
339
|
return this.getById(id);
|
|
336
340
|
}
|
|
@@ -5,6 +5,13 @@ const TOKEN_WEIGHTS_KEY = 'token_cost_weights';
|
|
|
5
5
|
const SUMMARY_SETTINGS_KEY = 'summary_settings';
|
|
6
6
|
const GENERAL_SETTINGS_KEY = 'general_settings';
|
|
7
7
|
|
|
8
|
+
const DEFAULT_SUMMARY_SETTINGS = Object.freeze({
|
|
9
|
+
disableSessionSummaries: false,
|
|
10
|
+
sessionTitlePrompt: '',
|
|
11
|
+
summaryModel: '',
|
|
12
|
+
summaryProviderId: null,
|
|
13
|
+
});
|
|
14
|
+
|
|
8
15
|
/**
|
|
9
16
|
* Settings repository for managing application-wide settings
|
|
10
17
|
*/
|
|
@@ -114,22 +121,13 @@ export class SettingsRepository {
|
|
|
114
121
|
getSummarySettings() {
|
|
115
122
|
const value = this.get(SUMMARY_SETTINGS_KEY);
|
|
116
123
|
if (!value) {
|
|
117
|
-
return {
|
|
118
|
-
disableSessionSummaries: false,
|
|
119
|
-
sessionTitlePrompt: '',
|
|
120
|
-
};
|
|
124
|
+
return { ...DEFAULT_SUMMARY_SETTINGS };
|
|
121
125
|
}
|
|
122
126
|
try {
|
|
123
127
|
const parsed = JSON.parse(value);
|
|
124
|
-
return
|
|
125
|
-
disableSessionSummaries: parsed.disableSessionSummaries || false,
|
|
126
|
-
sessionTitlePrompt: parsed.sessionTitlePrompt || '',
|
|
127
|
-
};
|
|
128
|
+
return normalizeStoredSummarySettings(parsed);
|
|
128
129
|
} catch {
|
|
129
|
-
return {
|
|
130
|
-
disableSessionSummaries: false,
|
|
131
|
-
sessionTitlePrompt: '',
|
|
132
|
-
};
|
|
130
|
+
return { ...DEFAULT_SUMMARY_SETTINGS };
|
|
133
131
|
}
|
|
134
132
|
}
|
|
135
133
|
|
|
@@ -138,11 +136,22 @@ export class SettingsRepository {
|
|
|
138
136
|
* @param {Object} settings - Summary settings
|
|
139
137
|
* @param {boolean} settings.disableSessionSummaries - Disable session summaries
|
|
140
138
|
* @param {string} settings.sessionTitlePrompt - Custom session title prompt
|
|
139
|
+
* @param {string} [settings.summaryModel] - Summary model id; empty string means auto
|
|
140
|
+
* @param {string|null} [settings.summaryProviderId] - Provider id owning summaryModel
|
|
141
141
|
*/
|
|
142
142
|
setSummarySettings(settings) {
|
|
143
|
+
const summaryModel = String(settings.summaryModel || '');
|
|
144
|
+
const summaryProviderId = typeof settings.summaryProviderId === 'string'
|
|
145
|
+
? settings.summaryProviderId
|
|
146
|
+
: null;
|
|
147
|
+
if (summaryModel && !summaryProviderId) {
|
|
148
|
+
throw new Error('summaryProviderId is required when summaryModel is set');
|
|
149
|
+
}
|
|
143
150
|
const validated = {
|
|
144
151
|
disableSessionSummaries: Boolean(settings.disableSessionSummaries),
|
|
145
152
|
sessionTitlePrompt: String(settings.sessionTitlePrompt || ''),
|
|
153
|
+
summaryModel,
|
|
154
|
+
summaryProviderId: summaryModel ? summaryProviderId : null,
|
|
146
155
|
};
|
|
147
156
|
this.set(SUMMARY_SETTINGS_KEY, JSON.stringify(validated));
|
|
148
157
|
return validated;
|
|
@@ -154,10 +163,7 @@ export class SettingsRepository {
|
|
|
154
163
|
*/
|
|
155
164
|
resetSummarySettings() {
|
|
156
165
|
this.delete(SUMMARY_SETTINGS_KEY);
|
|
157
|
-
return {
|
|
158
|
-
disableSessionSummaries: false,
|
|
159
|
-
sessionTitlePrompt: '',
|
|
160
|
-
};
|
|
166
|
+
return { ...DEFAULT_SUMMARY_SETTINGS };
|
|
161
167
|
}
|
|
162
168
|
|
|
163
169
|
// General Settings
|
|
@@ -209,3 +215,25 @@ export class SettingsRepository {
|
|
|
209
215
|
};
|
|
210
216
|
}
|
|
211
217
|
}
|
|
218
|
+
|
|
219
|
+
function normalizeStoredSummarySettings(parsed) {
|
|
220
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
221
|
+
return { ...DEFAULT_SUMMARY_SETTINGS };
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const summaryModel = typeof parsed.summaryModel === 'string' ? parsed.summaryModel : '';
|
|
225
|
+
const summaryProviderId = typeof parsed.summaryProviderId === 'string' && parsed.summaryProviderId
|
|
226
|
+
? parsed.summaryProviderId
|
|
227
|
+
: null;
|
|
228
|
+
|
|
229
|
+
if (summaryModel && !summaryProviderId) {
|
|
230
|
+
return { ...DEFAULT_SUMMARY_SETTINGS };
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return {
|
|
234
|
+
disableSessionSummaries: Boolean(parsed.disableSessionSummaries),
|
|
235
|
+
sessionTitlePrompt: typeof parsed.sessionTitlePrompt === 'string' ? parsed.sessionTitlePrompt : '',
|
|
236
|
+
summaryModel,
|
|
237
|
+
summaryProviderId: summaryModel ? summaryProviderId : null,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
@@ -22,6 +22,7 @@ export function mapConversationRow(row) {
|
|
|
22
22
|
// Token usage fields
|
|
23
23
|
inputTokens: row.input_tokens || 0,
|
|
24
24
|
outputTokens: row.output_tokens || 0,
|
|
25
|
+
thinkingTokens: row.thinking_tokens || 0,
|
|
25
26
|
cacheReadInputTokens: row.cache_read_input_tokens || 0,
|
|
26
27
|
cacheCreationInputTokens: row.cache_creation_input_tokens || 0,
|
|
27
28
|
webSearchRequests: row.web_search_requests || 0,
|
|
@@ -113,6 +113,10 @@ export const conversationsMigrations = [
|
|
|
113
113
|
name: 'conversations-add-output_tokens',
|
|
114
114
|
up(db) { addColumnIfMissing(db, TABLE_CONVERSATIONS, 'output_tokens', COL_INTEGER_DEFAULT_0); },
|
|
115
115
|
},
|
|
116
|
+
{
|
|
117
|
+
name: 'conversations-add-thinking_tokens',
|
|
118
|
+
up(db) { addColumnIfMissing(db, TABLE_CONVERSATIONS, 'thinking_tokens', COL_INTEGER_DEFAULT_0); },
|
|
119
|
+
},
|
|
116
120
|
{
|
|
117
121
|
name: 'conversations-add-cache_read_input_tokens',
|
|
118
122
|
up(db) { addColumnIfMissing(db, TABLE_CONVERSATIONS, 'cache_read_input_tokens', COL_INTEGER_DEFAULT_0); },
|
|
@@ -114,6 +114,7 @@ export const allMigrations = validateMigrations([
|
|
|
114
114
|
c.get('conversations-add-claude_session_id'),
|
|
115
115
|
c.get('conversations-add-input_tokens'),
|
|
116
116
|
c.get('conversations-add-output_tokens'),
|
|
117
|
+
c.get('conversations-add-thinking_tokens'),
|
|
117
118
|
c.get('conversations-add-cache_read_input_tokens'),
|
|
118
119
|
c.get('conversations-add-cache_creation_input_tokens'),
|
|
119
120
|
c.get('conversations-add-web_search_requests'),
|
|
@@ -123,6 +124,7 @@ export const allMigrations = validateMigrations([
|
|
|
123
124
|
// --- Sessions token usage ---
|
|
124
125
|
s.get('sessions-add-input_tokens'),
|
|
125
126
|
s.get('sessions-add-output_tokens'),
|
|
127
|
+
s.get('sessions-add-thinking_tokens'),
|
|
126
128
|
s.get('sessions-add-cache_read_input_tokens'),
|
|
127
129
|
s.get('sessions-add-cache_creation_input_tokens'),
|
|
128
130
|
s.get('sessions-add-web_search_requests'),
|
|
@@ -32,6 +32,7 @@ const SESSIONS_BASE_COLUMNS = `
|
|
|
32
32
|
parent_session_id TEXT REFERENCES sessions(id) ON DELETE SET NULL,
|
|
33
33
|
input_tokens INTEGER DEFAULT 0,
|
|
34
34
|
output_tokens INTEGER DEFAULT 0,
|
|
35
|
+
thinking_tokens INTEGER DEFAULT 0,
|
|
35
36
|
cache_read_input_tokens INTEGER DEFAULT 0,
|
|
36
37
|
cache_creation_input_tokens INTEGER DEFAULT 0,
|
|
37
38
|
web_search_requests INTEGER DEFAULT 0,
|
|
@@ -59,7 +60,7 @@ const SESSIONS_ALL_COLUMNS = [
|
|
|
59
60
|
'id', 'project_id', 'name', 'status', 'mode', 'thinking_enabled',
|
|
60
61
|
'git_branch', 'git_worktree', 'pr_url', 'error', 'effort_level',
|
|
61
62
|
'cost_usd', 'claude_session_id', 'model', 'next_template_id',
|
|
62
|
-
'parent_session_id', 'input_tokens', 'output_tokens',
|
|
63
|
+
'parent_session_id', 'input_tokens', 'output_tokens', 'thinking_tokens',
|
|
63
64
|
'cache_read_input_tokens', 'cache_creation_input_tokens',
|
|
64
65
|
'web_search_requests', 'context_window', 'archived', 'starred',
|
|
65
66
|
'manually_named', 'scheduled_at', 'reschedule_delay_minutes',
|
|
@@ -211,6 +212,10 @@ export const sessionsMigrations = [
|
|
|
211
212
|
name: 'sessions-add-output_tokens',
|
|
212
213
|
up(db) { addColumnIfMissing(db, TABLE_SESSIONS, 'output_tokens', COL_INTEGER_DEFAULT_0); },
|
|
213
214
|
},
|
|
215
|
+
{
|
|
216
|
+
name: 'sessions-add-thinking_tokens',
|
|
217
|
+
up(db) { addColumnIfMissing(db, TABLE_SESSIONS, 'thinking_tokens', COL_INTEGER_DEFAULT_0); },
|
|
218
|
+
},
|
|
214
219
|
{
|
|
215
220
|
name: 'sessions-add-cache_read_input_tokens',
|
|
216
221
|
up(db) { addColumnIfMissing(db, TABLE_SESSIONS, 'cache_read_input_tokens', COL_INTEGER_DEFAULT_0); },
|
|
@@ -24,6 +24,7 @@ export function mapTokenUsage(row) {
|
|
|
24
24
|
return {
|
|
25
25
|
inputTokens: row.input_tokens || 0,
|
|
26
26
|
outputTokens: row.output_tokens || 0,
|
|
27
|
+
thinkingTokens: row.thinking_tokens || 0,
|
|
27
28
|
cacheReadInputTokens: row.cache_read_input_tokens || 0,
|
|
28
29
|
cacheCreationInputTokens: row.cache_creation_input_tokens || 0,
|
|
29
30
|
webSearchRequests: row.web_search_requests || 0,
|
|
@@ -58,6 +59,7 @@ const CONFIG_DEFAULTS = {
|
|
|
58
59
|
parentSessionId: null,
|
|
59
60
|
status: 'starting',
|
|
60
61
|
model: null,
|
|
62
|
+
providerId: null,
|
|
61
63
|
effortLevel: null,
|
|
62
64
|
// Agent runtime for the session: 'claude-code' (default) or 'codex'.
|
|
63
65
|
// Defaults to null so SessionRepository.create() can resolve it from the model.
|
|
@@ -100,6 +102,7 @@ export const DIRECT_FIELD_MAP = {
|
|
|
100
102
|
costUsd: 'cost_usd',
|
|
101
103
|
claudeSessionId: 'claude_session_id',
|
|
102
104
|
model: 'model',
|
|
105
|
+
providerId: 'provider_id',
|
|
103
106
|
nextTemplateId: 'next_template_id',
|
|
104
107
|
parentSessionId: 'parent_session_id',
|
|
105
108
|
scheduledAt: 'scheduled_at',
|
|
@@ -48,6 +48,13 @@ CREATE TABLE IF NOT EXISTS sessions (
|
|
|
48
48
|
claude_session_id TEXT,
|
|
49
49
|
next_template_id TEXT REFERENCES session_templates(id) ON DELETE SET NULL,
|
|
50
50
|
parent_session_id TEXT REFERENCES sessions(id) ON DELETE SET NULL,
|
|
51
|
+
input_tokens INTEGER DEFAULT 0,
|
|
52
|
+
output_tokens INTEGER DEFAULT 0,
|
|
53
|
+
thinking_tokens INTEGER DEFAULT 0,
|
|
54
|
+
cache_read_input_tokens INTEGER DEFAULT 0,
|
|
55
|
+
cache_creation_input_tokens INTEGER DEFAULT 0,
|
|
56
|
+
web_search_requests INTEGER DEFAULT 0,
|
|
57
|
+
context_window INTEGER DEFAULT 200000,
|
|
51
58
|
created_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000),
|
|
52
59
|
updated_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000)
|
|
53
60
|
);
|
|
@@ -64,6 +71,7 @@ CREATE TABLE IF NOT EXISTS conversations (
|
|
|
64
71
|
-- Token usage fields (per-conversation tracking)
|
|
65
72
|
input_tokens INTEGER DEFAULT 0,
|
|
66
73
|
output_tokens INTEGER DEFAULT 0,
|
|
74
|
+
thinking_tokens INTEGER DEFAULT 0,
|
|
67
75
|
cache_read_input_tokens INTEGER DEFAULT 0,
|
|
68
76
|
cache_creation_input_tokens INTEGER DEFAULT 0,
|
|
69
77
|
web_search_requests INTEGER DEFAULT 0,
|
|
@@ -20,7 +20,7 @@ export class AgentCallLogger {
|
|
|
20
20
|
const callId = nanoid();
|
|
21
21
|
|
|
22
22
|
// Build metadata object - only include keys with defined values
|
|
23
|
-
const metadata = {};
|
|
23
|
+
const metadata = { ...(meta.metadata || {}) };
|
|
24
24
|
if (meta.effortLevel !== undefined && meta.effortLevel !== null) {
|
|
25
25
|
metadata.effortLevel = meta.effortLevel;
|
|
26
26
|
}
|