@agentconnect/host 0.2.4 → 0.2.6
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/dist/host.js +125 -68
- package/dist/providers/claude.d.ts +1 -1
- package/dist/providers/claude.js +237 -10
- package/dist/providers/codex.d.ts +1 -1
- package/dist/providers/codex.js +87 -17
- package/dist/providers/cursor.d.ts +1 -1
- package/dist/providers/cursor.js +81 -7
- package/dist/providers/local.d.ts +1 -1
- package/dist/providers/local.js +8 -2
- package/dist/providers/utils.d.ts +1 -0
- package/dist/providers/utils.js +7 -3
- package/dist/summary.d.ts +2 -7
- package/dist/summary.js +26 -74
- package/dist/types.d.ts +26 -6
- package/package.json +1 -1
package/dist/host.js
CHANGED
|
@@ -5,11 +5,11 @@ import fs from 'fs';
|
|
|
5
5
|
import { promises as fsp } from 'fs';
|
|
6
6
|
import net from 'net';
|
|
7
7
|
import path from 'path';
|
|
8
|
-
import { listModels, listRecentModels, providers, resolveProviderForModel } from './providers/index.js';
|
|
8
|
+
import { listModels, listRecentModels, providers, resolveProviderForModel, } from './providers/index.js';
|
|
9
9
|
import { debugLog, setSpawnLogging } from './providers/utils.js';
|
|
10
10
|
import { createObservedTracker } from './observed.js';
|
|
11
11
|
import { createStorage } from './storage.js';
|
|
12
|
-
import { buildSummaryPrompt,
|
|
12
|
+
import { buildSummaryPrompt, buildSummaryPromptWithOverride, getSummaryModel, runSummaryPrompt, } from './summary.js';
|
|
13
13
|
function send(socket, payload) {
|
|
14
14
|
socket.send(JSON.stringify(payload));
|
|
15
15
|
}
|
|
@@ -33,8 +33,7 @@ function buildProviderList(statuses) {
|
|
|
33
33
|
});
|
|
34
34
|
}
|
|
35
35
|
function resolveLoginExperience(mode) {
|
|
36
|
-
const raw = process.env.AGENTCONNECT_LOGIN_EXPERIENCE ||
|
|
37
|
-
process.env.AGENTCONNECT_CLAUDE_LOGIN_EXPERIENCE;
|
|
36
|
+
const raw = process.env.AGENTCONNECT_LOGIN_EXPERIENCE || process.env.AGENTCONNECT_CLAUDE_LOGIN_EXPERIENCE;
|
|
38
37
|
if (raw) {
|
|
39
38
|
const normalized = raw.trim().toLowerCase();
|
|
40
39
|
if (normalized === 'terminal' || normalized === 'manual')
|
|
@@ -127,6 +126,29 @@ function createHostRuntime(options) {
|
|
|
127
126
|
return null;
|
|
128
127
|
}
|
|
129
128
|
}
|
|
129
|
+
function normalizeSummaryMode(value) {
|
|
130
|
+
const raw = typeof value === 'string' ? value.trim().toLowerCase() : '';
|
|
131
|
+
if (raw === 'auto' || raw === 'off' || raw === 'force')
|
|
132
|
+
return raw;
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
function normalizeSummaryPrompt(value) {
|
|
136
|
+
if (typeof value !== 'string')
|
|
137
|
+
return undefined;
|
|
138
|
+
const trimmed = value.trim();
|
|
139
|
+
return trimmed ? trimmed : undefined;
|
|
140
|
+
}
|
|
141
|
+
function resolveSummaryMode(session, requested) {
|
|
142
|
+
if (requested)
|
|
143
|
+
return requested;
|
|
144
|
+
return session.summaryMode ?? 'auto';
|
|
145
|
+
}
|
|
146
|
+
function resolveEffectiveSummaryMode(session, requested) {
|
|
147
|
+
const mode = resolveSummaryMode(session, requested);
|
|
148
|
+
if (mode === 'auto' && session.summaryAutoUsed)
|
|
149
|
+
return 'off';
|
|
150
|
+
return mode;
|
|
151
|
+
}
|
|
130
152
|
function recordCapability(capability) {
|
|
131
153
|
observedTracker.record(capability);
|
|
132
154
|
}
|
|
@@ -139,6 +161,17 @@ function createHostRuntime(options) {
|
|
|
139
161
|
function recordProviderCapability(providerId) {
|
|
140
162
|
recordCapability(`model.${providerId}`);
|
|
141
163
|
}
|
|
164
|
+
function resolveSystemPrompt(providerId, input) {
|
|
165
|
+
if (typeof input === 'string') {
|
|
166
|
+
const trimmed = input.trim();
|
|
167
|
+
return trimmed ? trimmed : undefined;
|
|
168
|
+
}
|
|
169
|
+
const envKey = `AGENTCONNECT_SYSTEM_PROMPT_${providerId.toUpperCase()}`;
|
|
170
|
+
const envValue = process.env[envKey];
|
|
171
|
+
if (envValue && envValue.trim())
|
|
172
|
+
return envValue.trim();
|
|
173
|
+
return undefined;
|
|
174
|
+
}
|
|
142
175
|
const SUMMARY_REASONING_MAX_LINES = 3;
|
|
143
176
|
const SUMMARY_REASONING_MAX_CHARS = 280;
|
|
144
177
|
function appendSummaryReasoning(session, text) {
|
|
@@ -173,62 +206,57 @@ function createHostRuntime(options) {
|
|
|
173
206
|
function clearSummarySeed(session) {
|
|
174
207
|
session.summarySeed = undefined;
|
|
175
208
|
session.summaryReasoning = undefined;
|
|
209
|
+
session.summaryNextMode = undefined;
|
|
210
|
+
session.summaryNextPrompt = undefined;
|
|
176
211
|
}
|
|
177
212
|
async function startPromptSummary(options) {
|
|
178
|
-
const { sessionId, session, message, reasoning, emit } = options;
|
|
179
|
-
if (session.providerId === 'claude')
|
|
180
|
-
return;
|
|
213
|
+
const { sessionId, session, message, reasoning, summaryPrompt, mode, emit } = options;
|
|
181
214
|
if (session.summaryRequested)
|
|
182
215
|
return;
|
|
183
216
|
session.summaryRequested = true;
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
source: 'claude-log',
|
|
228
|
-
provider: 'claude',
|
|
229
|
-
model: session.model ?? null,
|
|
230
|
-
createdAt: new Date().toISOString(),
|
|
231
|
-
}, session);
|
|
217
|
+
let completed = false;
|
|
218
|
+
try {
|
|
219
|
+
const provider = providers[session.providerId];
|
|
220
|
+
if (!provider)
|
|
221
|
+
return;
|
|
222
|
+
const prompt = summaryPrompt
|
|
223
|
+
? buildSummaryPromptWithOverride(summaryPrompt, message, reasoning)
|
|
224
|
+
: buildSummaryPrompt(message, reasoning);
|
|
225
|
+
const summaryModel = getSummaryModel(session.providerId);
|
|
226
|
+
const cwd = session.cwd || basePath;
|
|
227
|
+
const repoRoot = session.repoRoot || basePath;
|
|
228
|
+
const result = await runSummaryPrompt({
|
|
229
|
+
provider,
|
|
230
|
+
prompt,
|
|
231
|
+
model: summaryModel,
|
|
232
|
+
cwd,
|
|
233
|
+
repoRoot,
|
|
234
|
+
});
|
|
235
|
+
if (!result)
|
|
236
|
+
return;
|
|
237
|
+
persistSummary(emit, sessionId, {
|
|
238
|
+
summary: result.summary,
|
|
239
|
+
source: 'prompt',
|
|
240
|
+
provider: session.providerId,
|
|
241
|
+
model: result.model ?? null,
|
|
242
|
+
createdAt: new Date().toISOString(),
|
|
243
|
+
}, session);
|
|
244
|
+
completed = true;
|
|
245
|
+
}
|
|
246
|
+
finally {
|
|
247
|
+
session.summaryRequested = false;
|
|
248
|
+
if (!completed && mode === 'auto') {
|
|
249
|
+
session.summaryAutoUsed = true;
|
|
250
|
+
}
|
|
251
|
+
if (session.summarySeed) {
|
|
252
|
+
maybeStartPromptSummary({
|
|
253
|
+
sessionId,
|
|
254
|
+
session,
|
|
255
|
+
emit,
|
|
256
|
+
trigger: 'output',
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
232
260
|
}
|
|
233
261
|
async function getCachedStatus(provider, options = {}) {
|
|
234
262
|
if (options.force) {
|
|
@@ -346,7 +374,8 @@ function createHostRuntime(options) {
|
|
|
346
374
|
}
|
|
347
375
|
function maybeStartPromptSummary(options) {
|
|
348
376
|
const { sessionId, session, emit, trigger } = options;
|
|
349
|
-
|
|
377
|
+
const mode = resolveEffectiveSummaryMode(session, session.summaryNextMode);
|
|
378
|
+
if (mode === 'off')
|
|
350
379
|
return;
|
|
351
380
|
if (session.summaryRequested)
|
|
352
381
|
return;
|
|
@@ -356,8 +385,17 @@ function createHostRuntime(options) {
|
|
|
356
385
|
return;
|
|
357
386
|
const message = session.summarySeed;
|
|
358
387
|
const reasoning = session.summaryReasoning;
|
|
388
|
+
const summaryPrompt = session.summaryNextPrompt ?? session.summaryPrompt;
|
|
359
389
|
clearSummarySeed(session);
|
|
360
|
-
void startPromptSummary({
|
|
390
|
+
void startPromptSummary({
|
|
391
|
+
sessionId,
|
|
392
|
+
session,
|
|
393
|
+
message,
|
|
394
|
+
reasoning,
|
|
395
|
+
summaryPrompt,
|
|
396
|
+
mode,
|
|
397
|
+
emit,
|
|
398
|
+
});
|
|
361
399
|
}
|
|
362
400
|
function sessionSummaryKey(sessionId) {
|
|
363
401
|
return `session:${sessionId}:summary`;
|
|
@@ -366,9 +404,6 @@ function createHostRuntime(options) {
|
|
|
366
404
|
if (!payload.summary)
|
|
367
405
|
return;
|
|
368
406
|
if (session) {
|
|
369
|
-
if (session.summarySource === 'claude-log' && payload.source === 'prompt') {
|
|
370
|
-
return;
|
|
371
|
-
}
|
|
372
407
|
if (session.summary === payload.summary && session.summarySource === payload.source) {
|
|
373
408
|
return;
|
|
374
409
|
}
|
|
@@ -376,6 +411,7 @@ function createHostRuntime(options) {
|
|
|
376
411
|
session.summarySource = payload.source;
|
|
377
412
|
session.summaryModel = payload.model ?? null;
|
|
378
413
|
session.summaryCreatedAt = payload.createdAt;
|
|
414
|
+
session.summaryAutoUsed = true;
|
|
379
415
|
}
|
|
380
416
|
emitSessionEvent(emit, sessionId, 'summary', payload);
|
|
381
417
|
storage.set(sessionSummaryKey(sessionId), payload);
|
|
@@ -598,6 +634,7 @@ function createHostRuntime(options) {
|
|
|
598
634
|
model = await pickDefaultModel(rawProvider);
|
|
599
635
|
}
|
|
600
636
|
const reasoningEffort = params.reasoningEffort || null;
|
|
637
|
+
const systemPrompt = resolveSystemPrompt(providerId, params.system);
|
|
601
638
|
const cwd = params.cwd ? resolveAppPathInternal(params.cwd) : undefined;
|
|
602
639
|
const repoRoot = params.repoRoot ? resolveAppPathInternal(params.repoRoot) : undefined;
|
|
603
640
|
const providerDetailLevel = params.providerDetailLevel || undefined;
|
|
@@ -607,6 +644,8 @@ function createHostRuntime(options) {
|
|
|
607
644
|
else {
|
|
608
645
|
recordProviderCapability(providerId);
|
|
609
646
|
}
|
|
647
|
+
const summaryMode = normalizeSummaryMode(params.summary?.mode);
|
|
648
|
+
const summaryPrompt = normalizeSummaryPrompt(params.summary?.prompt);
|
|
610
649
|
sessions.set(sessionId, {
|
|
611
650
|
id: sessionId,
|
|
612
651
|
providerId,
|
|
@@ -615,9 +654,13 @@ function createHostRuntime(options) {
|
|
|
615
654
|
reasoningEffort,
|
|
616
655
|
cwd,
|
|
617
656
|
repoRoot,
|
|
657
|
+
systemPrompt,
|
|
618
658
|
providerDetailLevel: providerDetailLevel === 'raw' || providerDetailLevel === 'minimal'
|
|
619
659
|
? providerDetailLevel
|
|
620
660
|
: undefined,
|
|
661
|
+
summaryMode: summaryMode === 'force' ? 'auto' : summaryMode ?? 'auto',
|
|
662
|
+
summaryPrompt,
|
|
663
|
+
summaryAutoUsed: false,
|
|
621
664
|
});
|
|
622
665
|
responder.reply(id, { sessionId });
|
|
623
666
|
return;
|
|
@@ -638,12 +681,25 @@ function createHostRuntime(options) {
|
|
|
638
681
|
if (params.repoRoot) {
|
|
639
682
|
existing.repoRoot = resolveAppPathInternal(params.repoRoot);
|
|
640
683
|
}
|
|
684
|
+
if ('system' in params) {
|
|
685
|
+
existing.systemPrompt = resolveSystemPrompt(existing.providerId, params.system);
|
|
686
|
+
}
|
|
641
687
|
if (params.providerDetailLevel) {
|
|
642
688
|
const level = String(params.providerDetailLevel);
|
|
643
689
|
if (level === 'raw' || level === 'minimal') {
|
|
644
690
|
existing.providerDetailLevel = level;
|
|
645
691
|
}
|
|
646
692
|
}
|
|
693
|
+
if ('summary' in params) {
|
|
694
|
+
const summaryMode = normalizeSummaryMode(params.summary?.mode);
|
|
695
|
+
const summaryPrompt = normalizeSummaryPrompt(params.summary?.prompt);
|
|
696
|
+
if (summaryMode) {
|
|
697
|
+
existing.summaryMode = summaryMode === 'force' ? 'auto' : summaryMode;
|
|
698
|
+
}
|
|
699
|
+
if (summaryPrompt !== undefined) {
|
|
700
|
+
existing.summaryPrompt = summaryPrompt;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
647
703
|
if (!existing.model && typeof params.model === 'string' && params.model.trim()) {
|
|
648
704
|
const candidate = params.model.trim();
|
|
649
705
|
const matches = await isModelForProvider(candidate, existing.providerId);
|
|
@@ -699,10 +755,13 @@ function createHostRuntime(options) {
|
|
|
699
755
|
return;
|
|
700
756
|
}
|
|
701
757
|
}
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
758
|
+
const summaryMode = resolveEffectiveSummaryMode(session, normalizeSummaryMode(params.summary?.mode));
|
|
759
|
+
const summaryPrompt = normalizeSummaryPrompt(params.summary?.prompt);
|
|
760
|
+
session.summaryNextMode = summaryMode;
|
|
761
|
+
if (summaryPrompt !== undefined) {
|
|
762
|
+
session.summaryNextPrompt = summaryPrompt;
|
|
763
|
+
}
|
|
764
|
+
if (summaryMode !== 'off' && message.trim()) {
|
|
706
765
|
session.summarySeed = message;
|
|
707
766
|
session.summaryReasoning = '';
|
|
708
767
|
}
|
|
@@ -726,6 +785,7 @@ function createHostRuntime(options) {
|
|
|
726
785
|
repoRoot,
|
|
727
786
|
cwd,
|
|
728
787
|
providerDetailLevel,
|
|
788
|
+
system: session.systemPrompt,
|
|
729
789
|
signal: controller.signal,
|
|
730
790
|
onEvent: (event) => {
|
|
731
791
|
const current = activeRuns.get(sessionId);
|
|
@@ -746,9 +806,7 @@ function createHostRuntime(options) {
|
|
|
746
806
|
trigger: 'reasoning',
|
|
747
807
|
});
|
|
748
808
|
}
|
|
749
|
-
if (event.type === 'delta' ||
|
|
750
|
-
event.type === 'message' ||
|
|
751
|
-
event.type === 'final') {
|
|
809
|
+
if (event.type === 'delta' || event.type === 'message' || event.type === 'final') {
|
|
752
810
|
maybeStartPromptSummary({
|
|
753
811
|
sessionId,
|
|
754
812
|
session,
|
|
@@ -765,7 +823,6 @@ function createHostRuntime(options) {
|
|
|
765
823
|
return;
|
|
766
824
|
if (result?.sessionId) {
|
|
767
825
|
session.providerSessionId = result.sessionId;
|
|
768
|
-
void startClaudeLogSummary({ sessionId, session, emit: responder.emit });
|
|
769
826
|
}
|
|
770
827
|
})
|
|
771
828
|
.catch((err) => {
|
|
@@ -9,4 +9,4 @@ export declare function updateClaude(): Promise<ProviderStatus>;
|
|
|
9
9
|
export declare function loginClaude(options?: ProviderLoginOptions): Promise<{
|
|
10
10
|
loggedIn: boolean;
|
|
11
11
|
}>;
|
|
12
|
-
export declare function runClaudePrompt({ prompt, resumeSessionId, model, cwd, providerDetailLevel, onEvent, signal, }: RunPromptOptions): Promise<RunPromptResult>;
|
|
12
|
+
export declare function runClaudePrompt({ prompt, system, resumeSessionId, model, cwd, providerDetailLevel, onEvent, signal, }: RunPromptOptions): Promise<RunPromptResult>;
|
package/dist/providers/claude.js
CHANGED
|
@@ -184,7 +184,10 @@ function formatClaudeDisplayName(modelId) {
|
|
|
184
184
|
const value = modelId.trim();
|
|
185
185
|
if (!value.startsWith('claude-'))
|
|
186
186
|
return value;
|
|
187
|
-
const parts = value
|
|
187
|
+
const parts = value
|
|
188
|
+
.replace(/^claude-/, '')
|
|
189
|
+
.split('-')
|
|
190
|
+
.filter(Boolean);
|
|
188
191
|
if (!parts.length)
|
|
189
192
|
return value;
|
|
190
193
|
const family = parts[0];
|
|
@@ -560,8 +563,7 @@ async function checkClaudeCliStatus() {
|
|
|
560
563
|
: typeof message?.error === 'string'
|
|
561
564
|
? message.error
|
|
562
565
|
: '';
|
|
563
|
-
if (isClaudeAuthErrorText(text) ||
|
|
564
|
-
(errorText && isClaudeAuthErrorText(errorText))) {
|
|
566
|
+
if (isClaudeAuthErrorText(text) || (errorText && isClaudeAuthErrorText(errorText))) {
|
|
565
567
|
authError = authError ?? (text || errorText);
|
|
566
568
|
}
|
|
567
569
|
else if (text.trim()) {
|
|
@@ -901,6 +903,180 @@ function mapClaudeModel(model) {
|
|
|
901
903
|
return value.replace('claude-', '');
|
|
902
904
|
return model;
|
|
903
905
|
}
|
|
906
|
+
function extractUsageFromValue(value) {
|
|
907
|
+
if (!value || typeof value !== 'object')
|
|
908
|
+
return null;
|
|
909
|
+
const usage = value;
|
|
910
|
+
const toNumber = (v) => {
|
|
911
|
+
if (typeof v === 'number' && Number.isFinite(v))
|
|
912
|
+
return v;
|
|
913
|
+
if (typeof v === 'string' && v.trim()) {
|
|
914
|
+
const parsed = Number(v);
|
|
915
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
916
|
+
}
|
|
917
|
+
return undefined;
|
|
918
|
+
};
|
|
919
|
+
const input = toNumber(usage.input_tokens ?? usage.prompt_tokens ?? usage.inputTokens ?? usage.promptTokens);
|
|
920
|
+
const output = toNumber(usage.output_tokens ?? usage.completion_tokens ?? usage.outputTokens ?? usage.completionTokens);
|
|
921
|
+
const total = toNumber(usage.total_tokens ?? usage.totalTokens);
|
|
922
|
+
let cached = toNumber(usage.cached_input_tokens ?? usage.cachedInputTokens);
|
|
923
|
+
const cacheCreation = toNumber(usage.cache_creation_input_tokens ?? usage.cacheCreationInputTokens);
|
|
924
|
+
const cacheRead = toNumber(usage.cache_read_input_tokens ?? usage.cacheReadInputTokens);
|
|
925
|
+
if (cached === undefined) {
|
|
926
|
+
const sum = (cacheCreation ?? 0) + (cacheRead ?? 0);
|
|
927
|
+
if (sum > 0)
|
|
928
|
+
cached = sum;
|
|
929
|
+
}
|
|
930
|
+
const reasoning = toNumber(usage.reasoning_tokens ?? usage.reasoningTokens);
|
|
931
|
+
const out = {};
|
|
932
|
+
if (input !== undefined)
|
|
933
|
+
out.input_tokens = input;
|
|
934
|
+
if (output !== undefined)
|
|
935
|
+
out.output_tokens = output;
|
|
936
|
+
if (total !== undefined)
|
|
937
|
+
out.total_tokens = total;
|
|
938
|
+
if (cached !== undefined)
|
|
939
|
+
out.cached_input_tokens = cached;
|
|
940
|
+
if (reasoning !== undefined)
|
|
941
|
+
out.reasoning_tokens = reasoning;
|
|
942
|
+
return Object.keys(out).length ? out : null;
|
|
943
|
+
}
|
|
944
|
+
function pickModelUsage(value) {
|
|
945
|
+
if (!value || typeof value !== 'object')
|
|
946
|
+
return null;
|
|
947
|
+
const entries = Object.values(value);
|
|
948
|
+
for (const entry of entries) {
|
|
949
|
+
if (entry && typeof entry === 'object')
|
|
950
|
+
return entry;
|
|
951
|
+
}
|
|
952
|
+
return null;
|
|
953
|
+
}
|
|
954
|
+
function extractClaudeUsage(msg) {
|
|
955
|
+
const usage = msg.usage ??
|
|
956
|
+
msg.message?.usage ??
|
|
957
|
+
msg.event?.usage ??
|
|
958
|
+
msg.delta?.usage ??
|
|
959
|
+
msg.token_usage ??
|
|
960
|
+
msg.tokenUsage;
|
|
961
|
+
if (usage)
|
|
962
|
+
return extractUsageFromValue(usage);
|
|
963
|
+
const resultRecord = msg.result && typeof msg.result === 'object' ? msg.result : null;
|
|
964
|
+
const nestedUsage = resultRecord?.usage ??
|
|
965
|
+
resultRecord?.token_usage ??
|
|
966
|
+
resultRecord?.tokenUsage ??
|
|
967
|
+
resultRecord?.token_usage;
|
|
968
|
+
if (nestedUsage)
|
|
969
|
+
return extractUsageFromValue(nestedUsage);
|
|
970
|
+
const modelUsage = pickModelUsage(msg.modelUsage ?? msg.message?.modelUsage ?? resultRecord?.modelUsage);
|
|
971
|
+
return extractUsageFromValue(modelUsage);
|
|
972
|
+
}
|
|
973
|
+
function extractClaudeContextUsage(msg, usage) {
|
|
974
|
+
const context = msg.context_usage ??
|
|
975
|
+
msg.contextUsage ??
|
|
976
|
+
msg.message?.context_usage ??
|
|
977
|
+
msg.message?.contextUsage ??
|
|
978
|
+
msg.event?.context_usage ??
|
|
979
|
+
msg.event?.contextUsage;
|
|
980
|
+
const resultRecord = msg.result && typeof msg.result === 'object' ? msg.result : null;
|
|
981
|
+
const modelUsage = pickModelUsage(msg.modelUsage ?? msg.message?.modelUsage ?? resultRecord?.modelUsage);
|
|
982
|
+
const toNumber = (v) => {
|
|
983
|
+
if (typeof v === 'number' && Number.isFinite(v))
|
|
984
|
+
return v;
|
|
985
|
+
if (typeof v === 'string' && v.trim()) {
|
|
986
|
+
const parsed = Number(v);
|
|
987
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
988
|
+
}
|
|
989
|
+
return undefined;
|
|
990
|
+
};
|
|
991
|
+
const toBoolean = (v) => typeof v === 'boolean' ? v : undefined;
|
|
992
|
+
const contextWindow = toNumber(context?.context_window ??
|
|
993
|
+
context?.contextWindow ??
|
|
994
|
+
modelUsage?.contextWindow ??
|
|
995
|
+
modelUsage?.context_window ??
|
|
996
|
+
msg.context_window ??
|
|
997
|
+
msg.contextWindow);
|
|
998
|
+
let contextTokens = toNumber(context?.context_tokens ??
|
|
999
|
+
context?.contextTokens ??
|
|
1000
|
+
msg.context_tokens ??
|
|
1001
|
+
msg.contextTokens);
|
|
1002
|
+
let contextCachedTokens = toNumber(context?.context_cached_tokens ??
|
|
1003
|
+
context?.contextCachedTokens ??
|
|
1004
|
+
msg.context_cached_tokens ??
|
|
1005
|
+
msg.contextCachedTokens);
|
|
1006
|
+
let contextRemainingTokens = toNumber(context?.context_remaining_tokens ??
|
|
1007
|
+
context?.contextRemainingTokens ??
|
|
1008
|
+
msg.context_remaining_tokens ??
|
|
1009
|
+
msg.contextRemainingTokens);
|
|
1010
|
+
const contextTruncated = toBoolean(context?.context_truncated ??
|
|
1011
|
+
context?.contextTruncated ??
|
|
1012
|
+
msg.context_truncated ??
|
|
1013
|
+
msg.contextTruncated);
|
|
1014
|
+
if (contextCachedTokens === undefined) {
|
|
1015
|
+
const cached = toNumber(context?.cache_creation_input_tokens) ??
|
|
1016
|
+
toNumber(context?.cacheCreationInputTokens) ??
|
|
1017
|
+
toNumber(context?.cache_read_input_tokens) ??
|
|
1018
|
+
toNumber(context?.cacheReadInputTokens);
|
|
1019
|
+
if (cached !== undefined)
|
|
1020
|
+
contextCachedTokens = cached;
|
|
1021
|
+
}
|
|
1022
|
+
if (contextTokens === undefined) {
|
|
1023
|
+
if (usage?.input_tokens !== undefined &&
|
|
1024
|
+
usage?.cached_input_tokens !== undefined) {
|
|
1025
|
+
contextTokens = usage.input_tokens + usage.cached_input_tokens;
|
|
1026
|
+
}
|
|
1027
|
+
else if (usage?.input_tokens !== undefined) {
|
|
1028
|
+
contextTokens = usage.input_tokens;
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
if (contextCachedTokens === undefined && usage?.cached_input_tokens !== undefined) {
|
|
1032
|
+
contextCachedTokens = usage.cached_input_tokens;
|
|
1033
|
+
}
|
|
1034
|
+
if (contextRemainingTokens === undefined &&
|
|
1035
|
+
contextWindow !== undefined &&
|
|
1036
|
+
contextTokens !== undefined) {
|
|
1037
|
+
contextRemainingTokens = Math.max(0, contextWindow - contextTokens);
|
|
1038
|
+
}
|
|
1039
|
+
const out = {};
|
|
1040
|
+
if (contextWindow !== undefined)
|
|
1041
|
+
out.context_window = contextWindow;
|
|
1042
|
+
if (contextTokens !== undefined)
|
|
1043
|
+
out.context_tokens = contextTokens;
|
|
1044
|
+
if (contextCachedTokens !== undefined)
|
|
1045
|
+
out.context_cached_tokens = contextCachedTokens;
|
|
1046
|
+
if (contextRemainingTokens !== undefined)
|
|
1047
|
+
out.context_remaining_tokens = contextRemainingTokens;
|
|
1048
|
+
if (contextTruncated !== undefined)
|
|
1049
|
+
out.context_truncated = contextTruncated;
|
|
1050
|
+
return Object.keys(out).length ? out : null;
|
|
1051
|
+
}
|
|
1052
|
+
function mergeUsage(current, next) {
|
|
1053
|
+
const out = { ...(current ?? {}) };
|
|
1054
|
+
if (next.input_tokens !== undefined)
|
|
1055
|
+
out.input_tokens = next.input_tokens;
|
|
1056
|
+
if (next.output_tokens !== undefined)
|
|
1057
|
+
out.output_tokens = next.output_tokens;
|
|
1058
|
+
if (next.total_tokens !== undefined)
|
|
1059
|
+
out.total_tokens = next.total_tokens;
|
|
1060
|
+
if (next.cached_input_tokens !== undefined)
|
|
1061
|
+
out.cached_input_tokens = next.cached_input_tokens;
|
|
1062
|
+
if (next.reasoning_tokens !== undefined)
|
|
1063
|
+
out.reasoning_tokens = next.reasoning_tokens;
|
|
1064
|
+
return out;
|
|
1065
|
+
}
|
|
1066
|
+
function mergeContextUsage(current, next) {
|
|
1067
|
+
const out = { ...(current ?? {}) };
|
|
1068
|
+
if (next.context_window !== undefined)
|
|
1069
|
+
out.context_window = next.context_window;
|
|
1070
|
+
if (next.context_tokens !== undefined)
|
|
1071
|
+
out.context_tokens = next.context_tokens;
|
|
1072
|
+
if (next.context_cached_tokens !== undefined)
|
|
1073
|
+
out.context_cached_tokens = next.context_cached_tokens;
|
|
1074
|
+
if (next.context_remaining_tokens !== undefined)
|
|
1075
|
+
out.context_remaining_tokens = next.context_remaining_tokens;
|
|
1076
|
+
if (next.context_truncated !== undefined)
|
|
1077
|
+
out.context_truncated = next.context_truncated;
|
|
1078
|
+
return out;
|
|
1079
|
+
}
|
|
904
1080
|
function extractSessionId(msg) {
|
|
905
1081
|
const direct = msg.session_id ?? msg.sessionId;
|
|
906
1082
|
if (typeof direct === 'string' && direct)
|
|
@@ -960,7 +1136,7 @@ function extractResultText(msg) {
|
|
|
960
1136
|
const text = msg.result;
|
|
961
1137
|
return typeof text === 'string' && text ? text : null;
|
|
962
1138
|
}
|
|
963
|
-
export function runClaudePrompt({ prompt, resumeSessionId, model, cwd, providerDetailLevel, onEvent, signal, }) {
|
|
1139
|
+
export function runClaudePrompt({ prompt, system, resumeSessionId, model, cwd, providerDetailLevel, onEvent, signal, }) {
|
|
964
1140
|
return new Promise((resolve) => {
|
|
965
1141
|
const command = getClaudeCommand();
|
|
966
1142
|
const args = [
|
|
@@ -970,6 +1146,10 @@ export function runClaudePrompt({ prompt, resumeSessionId, model, cwd, providerD
|
|
|
970
1146
|
'--permission-mode',
|
|
971
1147
|
'bypassPermissions',
|
|
972
1148
|
];
|
|
1149
|
+
const systemPrompt = typeof system === 'string' ? system.trim() : '';
|
|
1150
|
+
if (systemPrompt) {
|
|
1151
|
+
args.push('--append-system-prompt', systemPrompt);
|
|
1152
|
+
}
|
|
973
1153
|
const modelValue = mapClaudeModel(model);
|
|
974
1154
|
if (modelValue) {
|
|
975
1155
|
args.push('--model', modelValue);
|
|
@@ -998,6 +1178,11 @@ export function runClaudePrompt({ prompt, resumeSessionId, model, cwd, providerD
|
|
|
998
1178
|
let finalSessionId = null;
|
|
999
1179
|
let didFinalize = false;
|
|
1000
1180
|
let sawError = false;
|
|
1181
|
+
let usageEmitted = false;
|
|
1182
|
+
let latestUsage = null;
|
|
1183
|
+
let latestContextUsage = null;
|
|
1184
|
+
let latestUsageDetail;
|
|
1185
|
+
let latestContextUsageDetail;
|
|
1001
1186
|
const toolBlocks = new Map();
|
|
1002
1187
|
const thinkingBlocks = new Set();
|
|
1003
1188
|
const includeRaw = providerDetailLevel === 'raw';
|
|
@@ -1021,11 +1206,46 @@ export function runClaudePrompt({ prompt, resumeSessionId, model, cwd, providerD
|
|
|
1021
1206
|
if (sawError)
|
|
1022
1207
|
return;
|
|
1023
1208
|
sawError = true;
|
|
1209
|
+
emitUsageIfAvailable();
|
|
1024
1210
|
emit({ type: 'error', message });
|
|
1025
1211
|
};
|
|
1026
1212
|
const emitFinal = (text, providerDetail) => {
|
|
1213
|
+
emitUsageIfAvailable();
|
|
1027
1214
|
emit({ type: 'final', text, providerDetail });
|
|
1028
1215
|
};
|
|
1216
|
+
const captureUsage = (msg, providerDetail) => {
|
|
1217
|
+
const usage = extractClaudeUsage(msg);
|
|
1218
|
+
if (usage) {
|
|
1219
|
+
latestUsage = mergeUsage(latestUsage, usage);
|
|
1220
|
+
latestUsageDetail = providerDetail;
|
|
1221
|
+
}
|
|
1222
|
+
const contextUsage = extractClaudeContextUsage(msg, latestUsage);
|
|
1223
|
+
if (contextUsage) {
|
|
1224
|
+
latestContextUsage = mergeContextUsage(latestContextUsage, contextUsage);
|
|
1225
|
+
latestContextUsageDetail = providerDetail;
|
|
1226
|
+
}
|
|
1227
|
+
};
|
|
1228
|
+
const emitUsageIfAvailable = () => {
|
|
1229
|
+
if (usageEmitted)
|
|
1230
|
+
return;
|
|
1231
|
+
if (!latestUsage && !latestContextUsage)
|
|
1232
|
+
return;
|
|
1233
|
+
if (latestUsage) {
|
|
1234
|
+
emit({
|
|
1235
|
+
type: 'usage',
|
|
1236
|
+
usage: latestUsage,
|
|
1237
|
+
providerDetail: latestUsageDetail,
|
|
1238
|
+
});
|
|
1239
|
+
}
|
|
1240
|
+
if (latestContextUsage) {
|
|
1241
|
+
emit({
|
|
1242
|
+
type: 'context_usage',
|
|
1243
|
+
contextUsage: latestContextUsage,
|
|
1244
|
+
providerDetail: latestContextUsageDetail ?? latestUsageDetail,
|
|
1245
|
+
});
|
|
1246
|
+
}
|
|
1247
|
+
usageEmitted = true;
|
|
1248
|
+
};
|
|
1029
1249
|
const handleLine = (line) => {
|
|
1030
1250
|
const parsed = safeJsonParse(line);
|
|
1031
1251
|
if (!parsed || typeof parsed !== 'object') {
|
|
@@ -1040,6 +1260,8 @@ export function runClaudePrompt({ prompt, resumeSessionId, model, cwd, providerD
|
|
|
1040
1260
|
finalSessionId = sid;
|
|
1041
1261
|
const msgType = String(msg.type ?? '');
|
|
1042
1262
|
let handled = false;
|
|
1263
|
+
const detail = buildProviderDetail(msgType || 'unknown', {}, msg);
|
|
1264
|
+
captureUsage(msg, detail);
|
|
1043
1265
|
if (msgType === 'assistant' || msgType === 'user' || msgType === 'system') {
|
|
1044
1266
|
const role = msg.message?.role === 'assistant' ||
|
|
1045
1267
|
msg.message?.role === 'user' ||
|
|
@@ -1054,7 +1276,7 @@ export function runClaudePrompt({ prompt, resumeSessionId, model, cwd, providerD
|
|
|
1054
1276
|
role,
|
|
1055
1277
|
content,
|
|
1056
1278
|
contentParts: rawContent ?? null,
|
|
1057
|
-
providerDetail:
|
|
1279
|
+
providerDetail: detail,
|
|
1058
1280
|
});
|
|
1059
1281
|
handled = true;
|
|
1060
1282
|
}
|
|
@@ -1063,7 +1285,9 @@ export function runClaudePrompt({ prompt, resumeSessionId, model, cwd, providerD
|
|
|
1063
1285
|
const index = typeof msg.event.index === 'number' ? msg.event.index : undefined;
|
|
1064
1286
|
const block = msg.event.content_block;
|
|
1065
1287
|
if (evType === 'content_block_start' && block && typeof index === 'number') {
|
|
1066
|
-
if (block.type === 'tool_use' ||
|
|
1288
|
+
if (block.type === 'tool_use' ||
|
|
1289
|
+
block.type === 'server_tool_use' ||
|
|
1290
|
+
block.type === 'mcp_tool_use') {
|
|
1067
1291
|
toolBlocks.set(index, { id: block.id, name: block.name });
|
|
1068
1292
|
emit({
|
|
1069
1293
|
type: 'tool_call',
|
|
@@ -1144,7 +1368,7 @@ export function runClaudePrompt({ prompt, resumeSessionId, model, cwd, providerD
|
|
|
1144
1368
|
emit({
|
|
1145
1369
|
type: 'delta',
|
|
1146
1370
|
text: delta,
|
|
1147
|
-
providerDetail:
|
|
1371
|
+
providerDetail: detail,
|
|
1148
1372
|
});
|
|
1149
1373
|
return;
|
|
1150
1374
|
}
|
|
@@ -1154,21 +1378,21 @@ export function runClaudePrompt({ prompt, resumeSessionId, model, cwd, providerD
|
|
|
1154
1378
|
emit({
|
|
1155
1379
|
type: 'delta',
|
|
1156
1380
|
text: assistant,
|
|
1157
|
-
providerDetail:
|
|
1381
|
+
providerDetail: detail,
|
|
1158
1382
|
});
|
|
1159
1383
|
return;
|
|
1160
1384
|
}
|
|
1161
1385
|
const result = extractResultText(msg);
|
|
1162
1386
|
if (result && !didFinalize && !sawError) {
|
|
1163
1387
|
didFinalize = true;
|
|
1164
|
-
emitFinal(aggregated || result,
|
|
1388
|
+
emitFinal(aggregated || result, detail);
|
|
1165
1389
|
handled = true;
|
|
1166
1390
|
}
|
|
1167
1391
|
if (!handled) {
|
|
1168
1392
|
emit({
|
|
1169
1393
|
type: 'detail',
|
|
1170
1394
|
provider: 'claude',
|
|
1171
|
-
providerDetail:
|
|
1395
|
+
providerDetail: detail,
|
|
1172
1396
|
});
|
|
1173
1397
|
}
|
|
1174
1398
|
};
|
|
@@ -1185,6 +1409,9 @@ export function runClaudePrompt({ prompt, resumeSessionId, model, cwd, providerD
|
|
|
1185
1409
|
emitFinal(aggregated);
|
|
1186
1410
|
}
|
|
1187
1411
|
}
|
|
1412
|
+
if (!usageEmitted) {
|
|
1413
|
+
emitUsageIfAvailable();
|
|
1414
|
+
}
|
|
1188
1415
|
resolve({ sessionId: finalSessionId });
|
|
1189
1416
|
});
|
|
1190
1417
|
child.on('error', (err) => {
|
|
@@ -8,4 +8,4 @@ export declare function loginCodex(): Promise<{
|
|
|
8
8
|
loggedIn: boolean;
|
|
9
9
|
}>;
|
|
10
10
|
export declare function listCodexModels(): Promise<ModelInfo[]>;
|
|
11
|
-
export declare function runCodexPrompt({ prompt, resumeSessionId, model, reasoningEffort, repoRoot, cwd, providerDetailLevel, onEvent, signal, }: RunPromptOptions): Promise<RunPromptResult>;
|
|
11
|
+
export declare function runCodexPrompt({ prompt, system, resumeSessionId, model, reasoningEffort, repoRoot, cwd, providerDetailLevel, onEvent, signal, }: RunPromptOptions): Promise<RunPromptResult>;
|
package/dist/providers/codex.js
CHANGED
|
@@ -3,7 +3,7 @@ import { readFile } from 'fs/promises';
|
|
|
3
3
|
import https from 'https';
|
|
4
4
|
import os from 'os';
|
|
5
5
|
import path from 'path';
|
|
6
|
-
import { buildInstallCommandAuto, buildLoginCommand, buildStatusCommand, checkCommandVersion, commandExists, createLineParser, debugLog, logProviderSpawn, resolveWindowsCommand, resolveCommandPath, resolveCommandRealPath, runCommand, } from './utils.js';
|
|
6
|
+
import { buildInstallCommandAuto, buildLoginCommand, buildStatusCommand, checkCommandVersion, commandExists, createLineParser, applySystemPrompt, debugLog, logProviderSpawn, resolveWindowsCommand, resolveCommandPath, resolveCommandRealPath, runCommand, } from './utils.js';
|
|
7
7
|
const CODEX_PACKAGE = '@openai/codex';
|
|
8
8
|
const DEFAULT_LOGIN = 'codex login';
|
|
9
9
|
const DEFAULT_STATUS = 'codex login status';
|
|
@@ -237,9 +237,7 @@ function buildCodexExecArgs(options) {
|
|
|
237
237
|
}
|
|
238
238
|
args.push('--yolo');
|
|
239
239
|
const summarySetting = process.env.AGENTCONNECT_CODEX_REASONING_SUMMARY;
|
|
240
|
-
const summary = summarySetting && summarySetting.trim()
|
|
241
|
-
? summarySetting.trim()
|
|
242
|
-
: 'detailed';
|
|
240
|
+
const summary = summarySetting && summarySetting.trim() ? summarySetting.trim() : 'detailed';
|
|
243
241
|
const summaryDisabled = ['0', 'false', 'off', 'none'].includes(summary.toLowerCase());
|
|
244
242
|
if (!summaryDisabled) {
|
|
245
243
|
args.push('--config', `model_reasoning_summary=${summary}`);
|
|
@@ -329,7 +327,9 @@ export async function getCodexStatus() {
|
|
|
329
327
|
const status = buildStatusCommand('AGENTCONNECT_CODEX_STATUS', DEFAULT_STATUS);
|
|
330
328
|
if (status.command) {
|
|
331
329
|
const statusCommand = resolveWindowsCommand(status.command);
|
|
332
|
-
const result = await runCommand(statusCommand, status.args, {
|
|
330
|
+
const result = await runCommand(statusCommand, status.args, {
|
|
331
|
+
env: { ...process.env, CI: '1' },
|
|
332
|
+
});
|
|
333
333
|
const output = `${result.stdout}\n${result.stderr}`.toLowerCase();
|
|
334
334
|
if (output.includes('not logged in') ||
|
|
335
335
|
output.includes('not logged') ||
|
|
@@ -430,11 +430,20 @@ function extractUsage(ev) {
|
|
|
430
430
|
const usage = ev.usage ?? ev.token_usage ?? ev.tokens ?? ev.tokenUsage;
|
|
431
431
|
if (!usage || typeof usage !== 'object')
|
|
432
432
|
return null;
|
|
433
|
-
const toNumber = (v) =>
|
|
433
|
+
const toNumber = (v) => {
|
|
434
|
+
if (typeof v === 'number' && Number.isFinite(v))
|
|
435
|
+
return v;
|
|
436
|
+
if (typeof v === 'string' && v.trim()) {
|
|
437
|
+
const parsed = Number(v);
|
|
438
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
439
|
+
}
|
|
440
|
+
return undefined;
|
|
441
|
+
};
|
|
434
442
|
const input = toNumber(usage.input_tokens ?? usage.prompt_tokens ?? usage.inputTokens ?? usage.promptTokens);
|
|
435
443
|
const output = toNumber(usage.output_tokens ?? usage.completion_tokens ?? usage.outputTokens ?? usage.completionTokens);
|
|
436
444
|
const total = toNumber(usage.total_tokens ?? usage.totalTokens);
|
|
437
445
|
const cached = toNumber(usage.cached_input_tokens ?? usage.cachedInputTokens);
|
|
446
|
+
const reasoning = toNumber(usage.reasoning_tokens ?? usage.reasoningTokens);
|
|
438
447
|
const out = {};
|
|
439
448
|
if (input !== undefined)
|
|
440
449
|
out.input_tokens = input;
|
|
@@ -444,6 +453,61 @@ function extractUsage(ev) {
|
|
|
444
453
|
out.total_tokens = total;
|
|
445
454
|
if (cached !== undefined)
|
|
446
455
|
out.cached_input_tokens = cached;
|
|
456
|
+
if (reasoning !== undefined)
|
|
457
|
+
out.reasoning_tokens = reasoning;
|
|
458
|
+
return Object.keys(out).length ? out : null;
|
|
459
|
+
}
|
|
460
|
+
function extractContextUsage(ev, usage) {
|
|
461
|
+
const context = ev.context_usage ?? ev.contextUsage;
|
|
462
|
+
const toNumber = (v) => {
|
|
463
|
+
if (typeof v === 'number' && Number.isFinite(v))
|
|
464
|
+
return v;
|
|
465
|
+
if (typeof v === 'string' && v.trim()) {
|
|
466
|
+
const parsed = Number(v);
|
|
467
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
468
|
+
}
|
|
469
|
+
return undefined;
|
|
470
|
+
};
|
|
471
|
+
const toBoolean = (v) => typeof v === 'boolean' ? v : undefined;
|
|
472
|
+
const contextWindow = toNumber(context?.context_window ?? context?.contextWindow ?? ev.context_window ?? ev.contextWindow);
|
|
473
|
+
let contextTokens = toNumber(context?.context_tokens ?? context?.contextTokens ?? ev.context_tokens ?? ev.contextTokens);
|
|
474
|
+
let contextCachedTokens = toNumber(context?.context_cached_tokens ??
|
|
475
|
+
context?.contextCachedTokens ??
|
|
476
|
+
ev.context_cached_tokens ??
|
|
477
|
+
ev.contextCachedTokens);
|
|
478
|
+
let contextRemainingTokens = toNumber(context?.context_remaining_tokens ??
|
|
479
|
+
context?.contextRemainingTokens ??
|
|
480
|
+
ev.context_remaining_tokens ??
|
|
481
|
+
ev.contextRemainingTokens);
|
|
482
|
+
const contextTruncated = toBoolean(context?.context_truncated ?? context?.contextTruncated ?? ev.context_truncated ?? ev.contextTruncated);
|
|
483
|
+
if (contextTokens === undefined) {
|
|
484
|
+
if (usage?.input_tokens !== undefined &&
|
|
485
|
+
usage?.cached_input_tokens !== undefined) {
|
|
486
|
+
contextTokens = usage.input_tokens + usage.cached_input_tokens;
|
|
487
|
+
}
|
|
488
|
+
else if (usage?.input_tokens !== undefined) {
|
|
489
|
+
contextTokens = usage.input_tokens;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
if (contextCachedTokens === undefined && usage?.cached_input_tokens !== undefined) {
|
|
493
|
+
contextCachedTokens = usage.cached_input_tokens;
|
|
494
|
+
}
|
|
495
|
+
if (contextRemainingTokens === undefined &&
|
|
496
|
+
contextWindow !== undefined &&
|
|
497
|
+
contextTokens !== undefined) {
|
|
498
|
+
contextRemainingTokens = Math.max(0, contextWindow - contextTokens);
|
|
499
|
+
}
|
|
500
|
+
const out = {};
|
|
501
|
+
if (contextWindow !== undefined)
|
|
502
|
+
out.context_window = contextWindow;
|
|
503
|
+
if (contextTokens !== undefined)
|
|
504
|
+
out.context_tokens = contextTokens;
|
|
505
|
+
if (contextCachedTokens !== undefined)
|
|
506
|
+
out.context_cached_tokens = contextCachedTokens;
|
|
507
|
+
if (contextRemainingTokens !== undefined)
|
|
508
|
+
out.context_remaining_tokens = contextRemainingTokens;
|
|
509
|
+
if (contextTruncated !== undefined)
|
|
510
|
+
out.context_truncated = contextTruncated;
|
|
447
511
|
return Object.keys(out).length ? out : null;
|
|
448
512
|
}
|
|
449
513
|
function normalizeItem(raw) {
|
|
@@ -644,16 +708,17 @@ export async function listCodexModels() {
|
|
|
644
708
|
// Fetch failed - return empty, don't cache so it retries next time
|
|
645
709
|
return [];
|
|
646
710
|
}
|
|
647
|
-
export function runCodexPrompt({ prompt, resumeSessionId, model, reasoningEffort, repoRoot, cwd, providerDetailLevel, onEvent, signal, }) {
|
|
711
|
+
export function runCodexPrompt({ prompt, system, resumeSessionId, model, reasoningEffort, repoRoot, cwd, providerDetailLevel, onEvent, signal, }) {
|
|
648
712
|
return new Promise((resolve) => {
|
|
649
713
|
const command = getCodexCommand();
|
|
650
714
|
const resolvedRepoRoot = repoRoot ? path.resolve(repoRoot) : null;
|
|
651
715
|
const resolvedCwd = cwd ? path.resolve(cwd) : null;
|
|
652
716
|
const runDir = resolvedCwd || resolvedRepoRoot || process.cwd();
|
|
653
717
|
const cdTarget = resolvedRepoRoot || resolvedCwd || '.';
|
|
718
|
+
const composedPrompt = applySystemPrompt(system, prompt);
|
|
654
719
|
const runAttempt = (mode) => new Promise((attemptResolve) => {
|
|
655
720
|
const args = buildCodexExecArgs({
|
|
656
|
-
prompt,
|
|
721
|
+
prompt: composedPrompt,
|
|
657
722
|
cdTarget,
|
|
658
723
|
resumeSessionId,
|
|
659
724
|
model,
|
|
@@ -839,8 +904,16 @@ export function runCodexPrompt({ prompt, resumeSessionId, model, reasoningEffort
|
|
|
839
904
|
if (usage) {
|
|
840
905
|
emit({
|
|
841
906
|
type: 'usage',
|
|
842
|
-
|
|
843
|
-
|
|
907
|
+
usage,
|
|
908
|
+
providerDetail,
|
|
909
|
+
});
|
|
910
|
+
handled = true;
|
|
911
|
+
}
|
|
912
|
+
const contextUsage = extractContextUsage(ev, usage);
|
|
913
|
+
if (contextUsage) {
|
|
914
|
+
emit({
|
|
915
|
+
type: 'context_usage',
|
|
916
|
+
contextUsage,
|
|
844
917
|
providerDetail,
|
|
845
918
|
});
|
|
846
919
|
handled = true;
|
|
@@ -893,9 +966,7 @@ export function runCodexPrompt({ prompt, resumeSessionId, model, reasoningEffort
|
|
|
893
966
|
}
|
|
894
967
|
if (isTerminalEvent(ev) && !didFinalize) {
|
|
895
968
|
if (ev.type === 'turn.failed') {
|
|
896
|
-
const message = typeof ev.error?.message === 'string'
|
|
897
|
-
? ev.error.message
|
|
898
|
-
: pendingError?.message;
|
|
969
|
+
const message = typeof ev.error?.message === 'string' ? ev.error.message : pendingError?.message;
|
|
899
970
|
emitError(message ?? 'Codex run failed', providerDetail);
|
|
900
971
|
didFinalize = true;
|
|
901
972
|
handled = true;
|
|
@@ -921,10 +992,9 @@ export function runCodexPrompt({ prompt, resumeSessionId, model, reasoningEffort
|
|
|
921
992
|
const hint = stderrLines.at(-1) || stdoutLines.at(-1) || '';
|
|
922
993
|
const context = pendingError?.message || hint;
|
|
923
994
|
const suffix = context ? `: ${context}` : '';
|
|
924
|
-
const fallback = mode === 'modern' &&
|
|
925
|
-
|
|
926
|
-
...stdoutLines
|
|
927
|
-
]);
|
|
995
|
+
const fallback = mode === 'modern' &&
|
|
996
|
+
!sawJson &&
|
|
997
|
+
shouldFallbackToLegacy([...stderrLines, ...stdoutLines]);
|
|
928
998
|
debugLog('Codex', 'exit', {
|
|
929
999
|
code,
|
|
930
1000
|
stderr: stderrLines,
|
|
@@ -8,4 +8,4 @@ export declare function updateCursor(): Promise<ProviderStatus>;
|
|
|
8
8
|
export declare function loginCursor(options?: ProviderLoginOptions): Promise<{
|
|
9
9
|
loggedIn: boolean;
|
|
10
10
|
}>;
|
|
11
|
-
export declare function runCursorPrompt({ prompt, resumeSessionId, model, repoRoot, cwd, providerDetailLevel, onEvent, signal, }: RunPromptOptions): Promise<RunPromptResult>;
|
|
11
|
+
export declare function runCursorPrompt({ prompt, system, resumeSessionId, model, repoRoot, cwd, providerDetailLevel, onEvent, signal, }: RunPromptOptions): Promise<RunPromptResult>;
|
package/dist/providers/cursor.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { spawn } from 'child_process';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
import { buildInstallCommand, buildLoginCommand, buildStatusCommand, checkCommandVersion, commandExists, createLineParser, debugLog, logProviderSpawn, resolveWindowsCommand, resolveCommandPath, resolveCommandRealPath, runCommand, } from './utils.js';
|
|
3
|
+
import { buildInstallCommand, buildLoginCommand, buildStatusCommand, checkCommandVersion, commandExists, createLineParser, applySystemPrompt, debugLog, logProviderSpawn, resolveWindowsCommand, resolveCommandPath, resolveCommandRealPath, runCommand, } from './utils.js';
|
|
4
4
|
const INSTALL_UNIX = 'curl https://cursor.com/install -fsS | bash';
|
|
5
5
|
const DEFAULT_LOGIN = 'cursor-agent login';
|
|
6
6
|
const DEFAULT_STATUS = 'cursor-agent status';
|
|
@@ -468,10 +468,20 @@ function extractUsage(ev) {
|
|
|
468
468
|
const usage = ev.usage ?? ev.token_usage ?? ev.tokenUsage ?? ev.tokens;
|
|
469
469
|
if (!usage || typeof usage !== 'object')
|
|
470
470
|
return null;
|
|
471
|
-
const toNumber = (v) =>
|
|
471
|
+
const toNumber = (v) => {
|
|
472
|
+
if (typeof v === 'number' && Number.isFinite(v))
|
|
473
|
+
return v;
|
|
474
|
+
if (typeof v === 'string' && v.trim()) {
|
|
475
|
+
const parsed = Number(v);
|
|
476
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
477
|
+
}
|
|
478
|
+
return undefined;
|
|
479
|
+
};
|
|
472
480
|
const input = toNumber(usage.input_tokens ?? usage.prompt_tokens ?? usage.inputTokens ?? usage.promptTokens);
|
|
473
481
|
const output = toNumber(usage.output_tokens ?? usage.completion_tokens ?? usage.outputTokens ?? usage.completionTokens);
|
|
474
482
|
const total = toNumber(usage.total_tokens ?? usage.totalTokens);
|
|
483
|
+
const cached = toNumber(usage.cached_input_tokens ?? usage.cachedInputTokens);
|
|
484
|
+
const reasoning = toNumber(usage.reasoning_tokens ?? usage.reasoningTokens);
|
|
475
485
|
const out = {};
|
|
476
486
|
if (input !== undefined)
|
|
477
487
|
out.input_tokens = input;
|
|
@@ -479,6 +489,63 @@ function extractUsage(ev) {
|
|
|
479
489
|
out.output_tokens = output;
|
|
480
490
|
if (total !== undefined)
|
|
481
491
|
out.total_tokens = total;
|
|
492
|
+
if (cached !== undefined)
|
|
493
|
+
out.cached_input_tokens = cached;
|
|
494
|
+
if (reasoning !== undefined)
|
|
495
|
+
out.reasoning_tokens = reasoning;
|
|
496
|
+
return Object.keys(out).length ? out : null;
|
|
497
|
+
}
|
|
498
|
+
function extractContextUsage(ev, usage) {
|
|
499
|
+
const context = ev.context_usage ?? ev.contextUsage;
|
|
500
|
+
const toNumber = (v) => {
|
|
501
|
+
if (typeof v === 'number' && Number.isFinite(v))
|
|
502
|
+
return v;
|
|
503
|
+
if (typeof v === 'string' && v.trim()) {
|
|
504
|
+
const parsed = Number(v);
|
|
505
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
506
|
+
}
|
|
507
|
+
return undefined;
|
|
508
|
+
};
|
|
509
|
+
const toBoolean = (v) => typeof v === 'boolean' ? v : undefined;
|
|
510
|
+
const contextWindow = toNumber(context?.context_window ?? context?.contextWindow ?? ev.context_window ?? ev.contextWindow);
|
|
511
|
+
let contextTokens = toNumber(context?.context_tokens ?? context?.contextTokens ?? ev.context_tokens ?? ev.contextTokens);
|
|
512
|
+
let contextCachedTokens = toNumber(context?.context_cached_tokens ??
|
|
513
|
+
context?.contextCachedTokens ??
|
|
514
|
+
ev.context_cached_tokens ??
|
|
515
|
+
ev.contextCachedTokens);
|
|
516
|
+
let contextRemainingTokens = toNumber(context?.context_remaining_tokens ??
|
|
517
|
+
context?.contextRemainingTokens ??
|
|
518
|
+
ev.context_remaining_tokens ??
|
|
519
|
+
ev.contextRemainingTokens);
|
|
520
|
+
const contextTruncated = toBoolean(context?.context_truncated ?? context?.contextTruncated ?? ev.context_truncated ?? ev.contextTruncated);
|
|
521
|
+
if (contextTokens === undefined) {
|
|
522
|
+
if (usage?.input_tokens !== undefined &&
|
|
523
|
+
usage?.cached_input_tokens !== undefined) {
|
|
524
|
+
contextTokens = usage.input_tokens + usage.cached_input_tokens;
|
|
525
|
+
}
|
|
526
|
+
else if (usage?.input_tokens !== undefined) {
|
|
527
|
+
contextTokens = usage.input_tokens;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
if (contextCachedTokens === undefined && usage?.cached_input_tokens !== undefined) {
|
|
531
|
+
contextCachedTokens = usage.cached_input_tokens;
|
|
532
|
+
}
|
|
533
|
+
if (contextRemainingTokens === undefined &&
|
|
534
|
+
contextWindow !== undefined &&
|
|
535
|
+
contextTokens !== undefined) {
|
|
536
|
+
contextRemainingTokens = Math.max(0, contextWindow - contextTokens);
|
|
537
|
+
}
|
|
538
|
+
const out = {};
|
|
539
|
+
if (contextWindow !== undefined)
|
|
540
|
+
out.context_window = contextWindow;
|
|
541
|
+
if (contextTokens !== undefined)
|
|
542
|
+
out.context_tokens = contextTokens;
|
|
543
|
+
if (contextCachedTokens !== undefined)
|
|
544
|
+
out.context_cached_tokens = contextCachedTokens;
|
|
545
|
+
if (contextRemainingTokens !== undefined)
|
|
546
|
+
out.context_remaining_tokens = contextRemainingTokens;
|
|
547
|
+
if (contextTruncated !== undefined)
|
|
548
|
+
out.context_truncated = contextTruncated;
|
|
482
549
|
return Object.keys(out).length ? out : null;
|
|
483
550
|
}
|
|
484
551
|
function extractTextFromContent(content) {
|
|
@@ -611,7 +678,7 @@ function extractErrorMessage(ev) {
|
|
|
611
678
|
return ev.result;
|
|
612
679
|
return null;
|
|
613
680
|
}
|
|
614
|
-
export function runCursorPrompt({ prompt, resumeSessionId, model, repoRoot, cwd, providerDetailLevel, onEvent, signal, }) {
|
|
681
|
+
export function runCursorPrompt({ prompt, system, resumeSessionId, model, repoRoot, cwd, providerDetailLevel, onEvent, signal, }) {
|
|
615
682
|
return new Promise((resolve) => {
|
|
616
683
|
const command = getCursorCommand();
|
|
617
684
|
const resolvedRepoRoot = repoRoot ? path.resolve(repoRoot) : null;
|
|
@@ -630,7 +697,8 @@ export function runCursorPrompt({ prompt, resumeSessionId, model, repoRoot, cwd,
|
|
|
630
697
|
if (endpoint) {
|
|
631
698
|
args.push('--endpoint', endpoint);
|
|
632
699
|
}
|
|
633
|
-
|
|
700
|
+
const composedPrompt = applySystemPrompt(system, prompt);
|
|
701
|
+
args.push(composedPrompt);
|
|
634
702
|
logProviderSpawn({
|
|
635
703
|
provider: 'cursor',
|
|
636
704
|
command,
|
|
@@ -650,7 +718,7 @@ export function runCursorPrompt({ prompt, resumeSessionId, model, repoRoot, cwd,
|
|
|
650
718
|
endpoint: endpoint || null,
|
|
651
719
|
resume: resumeSessionId || null,
|
|
652
720
|
apiKeyConfigured: Boolean(getCursorApiKey().trim()),
|
|
653
|
-
promptChars:
|
|
721
|
+
promptChars: composedPrompt.length,
|
|
654
722
|
});
|
|
655
723
|
const child = spawn(command, args, {
|
|
656
724
|
cwd: runDir,
|
|
@@ -786,8 +854,14 @@ export function runCursorPrompt({ prompt, resumeSessionId, model, repoRoot, cwd,
|
|
|
786
854
|
if (usage) {
|
|
787
855
|
emit({
|
|
788
856
|
type: 'usage',
|
|
789
|
-
|
|
790
|
-
|
|
857
|
+
usage,
|
|
858
|
+
});
|
|
859
|
+
}
|
|
860
|
+
const contextUsage = extractContextUsage(ev, usage);
|
|
861
|
+
if (contextUsage) {
|
|
862
|
+
emit({
|
|
863
|
+
type: 'context_usage',
|
|
864
|
+
contextUsage,
|
|
791
865
|
});
|
|
792
866
|
}
|
|
793
867
|
if (isErrorEvent(ev)) {
|
|
@@ -6,4 +6,4 @@ export declare function loginLocal(options?: ProviderLoginOptions): Promise<{
|
|
|
6
6
|
loggedIn: boolean;
|
|
7
7
|
}>;
|
|
8
8
|
export declare function listLocalModels(): Promise<ModelInfo[]>;
|
|
9
|
-
export declare function runLocalPrompt({ prompt, model, onEvent, }: RunPromptOptions): Promise<RunPromptResult>;
|
|
9
|
+
export declare function runLocalPrompt({ prompt, system, model, onEvent, }: RunPromptOptions): Promise<RunPromptResult>;
|
package/dist/providers/local.js
CHANGED
|
@@ -76,7 +76,7 @@ export async function listLocalModels() {
|
|
|
76
76
|
.map((entry) => ({ id: entry.id, provider: 'local', displayName: entry.id }))
|
|
77
77
|
.filter((entry) => entry.id);
|
|
78
78
|
}
|
|
79
|
-
export async function runLocalPrompt({ prompt, model, onEvent, }) {
|
|
79
|
+
export async function runLocalPrompt({ prompt, system, model, onEvent, }) {
|
|
80
80
|
const base = getLocalBaseUrl();
|
|
81
81
|
const fallback = process.env.AGENTCONNECT_LOCAL_MODEL || '';
|
|
82
82
|
const resolvedModel = resolveLocalModel(model, fallback);
|
|
@@ -90,9 +90,15 @@ export async function runLocalPrompt({ prompt, model, onEvent, }) {
|
|
|
90
90
|
args: ['--base-url', base, '--model', resolvedModel, prompt],
|
|
91
91
|
cwd: process.cwd(),
|
|
92
92
|
});
|
|
93
|
+
const messages = [];
|
|
94
|
+
const systemPrompt = typeof system === 'string' ? system.trim() : '';
|
|
95
|
+
if (systemPrompt) {
|
|
96
|
+
messages.push({ role: 'system', content: systemPrompt });
|
|
97
|
+
}
|
|
98
|
+
messages.push({ role: 'user', content: prompt });
|
|
93
99
|
const payload = {
|
|
94
100
|
model: resolvedModel,
|
|
95
|
-
messages
|
|
101
|
+
messages,
|
|
96
102
|
stream: false,
|
|
97
103
|
};
|
|
98
104
|
const headers = { 'Content-Type': 'application/json' };
|
|
@@ -10,6 +10,7 @@ export declare function logProviderSpawn(options: {
|
|
|
10
10
|
redactIndex?: number;
|
|
11
11
|
}): void;
|
|
12
12
|
export declare function debugLog(scope: string, message: string, details?: Record<string, unknown>): void;
|
|
13
|
+
export declare function applySystemPrompt(system: string | undefined, prompt: string): string;
|
|
13
14
|
export interface SplitCommandResult {
|
|
14
15
|
command: string;
|
|
15
16
|
args: string[];
|
package/dist/providers/utils.js
CHANGED
|
@@ -17,9 +17,7 @@ export function logProviderSpawn(options) {
|
|
|
17
17
|
}
|
|
18
18
|
const cwd = options.cwd || process.cwd();
|
|
19
19
|
const formatted = formatShellCommand(options.command, redacted);
|
|
20
|
-
const fullCommand = cwd
|
|
21
|
-
? `${formatShellCommand('cd', [cwd])} && ${formatted}`
|
|
22
|
-
: formatted;
|
|
20
|
+
const fullCommand = cwd ? `${formatShellCommand('cd', [cwd])} && ${formatted}` : formatted;
|
|
23
21
|
console.log(`AgentConnect: ${fullCommand}`);
|
|
24
22
|
}
|
|
25
23
|
function formatShellCommand(command, args) {
|
|
@@ -46,6 +44,12 @@ export function debugLog(scope, message, details) {
|
|
|
46
44
|
}
|
|
47
45
|
console.log(`[AgentConnect][${scope}] ${message}${suffix}`);
|
|
48
46
|
}
|
|
47
|
+
export function applySystemPrompt(system, prompt) {
|
|
48
|
+
const trimmed = typeof system === 'string' ? system.trim() : '';
|
|
49
|
+
if (!trimmed)
|
|
50
|
+
return prompt;
|
|
51
|
+
return `<<SYSTEM>>\n${trimmed}\n<</SYSTEM>>\n\n<<USER>>\n${prompt}`;
|
|
52
|
+
}
|
|
49
53
|
export function splitCommand(value) {
|
|
50
54
|
if (!value)
|
|
51
55
|
return { command: '', args: [] };
|
package/dist/summary.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Provider, ProviderId } from './types.js';
|
|
2
|
-
export type SummarySource = 'prompt'
|
|
2
|
+
export type SummarySource = 'prompt';
|
|
3
3
|
export type SummaryPayload = {
|
|
4
4
|
summary: string;
|
|
5
5
|
source: SummarySource;
|
|
@@ -9,6 +9,7 @@ export type SummaryPayload = {
|
|
|
9
9
|
};
|
|
10
10
|
export declare function getSummaryModel(providerId: ProviderId): string | null;
|
|
11
11
|
export declare function buildSummaryPrompt(userPrompt: string, reasoning?: string): string;
|
|
12
|
+
export declare function buildSummaryPromptWithOverride(template: string, userPrompt: string, reasoning?: string): string;
|
|
12
13
|
export declare function sanitizeSummary(raw: string): string;
|
|
13
14
|
export declare function runSummaryPrompt(options: {
|
|
14
15
|
provider: Provider;
|
|
@@ -21,9 +22,3 @@ export declare function runSummaryPrompt(options: {
|
|
|
21
22
|
summary: string;
|
|
22
23
|
model?: string | null;
|
|
23
24
|
} | null>;
|
|
24
|
-
export declare function pollClaudeSummary(options: {
|
|
25
|
-
basePath: string;
|
|
26
|
-
sessionId: string;
|
|
27
|
-
timeoutMs?: number;
|
|
28
|
-
intervalMs?: number;
|
|
29
|
-
}): Promise<string | null>;
|
package/dist/summary.js
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import { promises as fsp } from 'fs';
|
|
3
|
-
import os from 'os';
|
|
4
|
-
import path from 'path';
|
|
5
1
|
const SUMMARY_MODEL_OVERRIDES = {
|
|
6
2
|
claude: 'haiku',
|
|
7
3
|
codex: 'gpt-5.1-codex-mini',
|
|
@@ -30,6 +26,7 @@ export function buildSummaryPrompt(userPrompt, reasoning) {
|
|
|
30
26
|
const clippedReasoning = reasoning?.trim() ? clipText(reasoning, REASONING_MAX_CHARS) : '';
|
|
31
27
|
const lines = [
|
|
32
28
|
'You write ultra-short task summaries for a chat list.',
|
|
29
|
+
'Do not run commands or edit files; only write the summary.',
|
|
33
30
|
`Summarize the task in ${Math.max(6, SUMMARY_MAX_WORDS - 4)}-${SUMMARY_MAX_WORDS} words.`,
|
|
34
31
|
'Capture the task and outcome; include key file/component/tech if present.',
|
|
35
32
|
'Use a specific action verb; avoid vague verbs like "help" or "work on".',
|
|
@@ -46,8 +43,32 @@ export function buildSummaryPrompt(userPrompt, reasoning) {
|
|
|
46
43
|
}
|
|
47
44
|
return lines.join('\n');
|
|
48
45
|
}
|
|
46
|
+
export function buildSummaryPromptWithOverride(template, userPrompt, reasoning) {
|
|
47
|
+
const trimmedTemplate = template.trim();
|
|
48
|
+
if (!trimmedTemplate)
|
|
49
|
+
return buildSummaryPrompt(userPrompt, reasoning);
|
|
50
|
+
const clipped = clipText(userPrompt.trim(), 1200);
|
|
51
|
+
const clippedReasoning = reasoning?.trim() ? clipText(reasoning, REASONING_MAX_CHARS) : '';
|
|
52
|
+
const hasMessage = trimmedTemplate.includes('{{message}}');
|
|
53
|
+
const hasReasoning = trimmedTemplate.includes('{{reasoning}}');
|
|
54
|
+
let prompt = trimmedTemplate;
|
|
55
|
+
if (hasMessage)
|
|
56
|
+
prompt = prompt.replaceAll('{{message}}', clipped);
|
|
57
|
+
if (hasReasoning)
|
|
58
|
+
prompt = prompt.replaceAll('{{reasoning}}', clippedReasoning);
|
|
59
|
+
if (!hasMessage) {
|
|
60
|
+
prompt = `${prompt}\n\nUser request:\n${clipped}`;
|
|
61
|
+
}
|
|
62
|
+
if (clippedReasoning && !hasReasoning) {
|
|
63
|
+
prompt = `${prompt}\n\nInitial reasoning (first lines):\n${clippedReasoning}`;
|
|
64
|
+
}
|
|
65
|
+
return prompt;
|
|
66
|
+
}
|
|
49
67
|
export function sanitizeSummary(raw) {
|
|
50
|
-
const normalized = raw
|
|
68
|
+
const normalized = raw
|
|
69
|
+
.replace(/[\r\n]+/g, ' ')
|
|
70
|
+
.replace(/\s+/g, ' ')
|
|
71
|
+
.trim();
|
|
51
72
|
const stripped = normalized.replace(/^["']+|["']+$/g, '').trim();
|
|
52
73
|
const cleaned = stripped.replace(/[.!?]+$/g, '').trim();
|
|
53
74
|
if (!cleaned)
|
|
@@ -107,72 +128,3 @@ export async function runSummaryPrompt(options) {
|
|
|
107
128
|
}
|
|
108
129
|
return attempt(null);
|
|
109
130
|
}
|
|
110
|
-
function buildClaudeProjectKey(basePath) {
|
|
111
|
-
const resolved = path.resolve(basePath);
|
|
112
|
-
const normalized = resolved.split(path.sep).filter(Boolean).join('-');
|
|
113
|
-
return `-${normalized}`;
|
|
114
|
-
}
|
|
115
|
-
function resolveClaudeSummaryPath(basePath, sessionId) {
|
|
116
|
-
if (!sessionId)
|
|
117
|
-
return null;
|
|
118
|
-
const root = process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), '.claude');
|
|
119
|
-
const projectKey = buildClaudeProjectKey(basePath);
|
|
120
|
-
return path.join(root, 'projects', projectKey, `${sessionId}.jsonl`);
|
|
121
|
-
}
|
|
122
|
-
async function readClaudeSummaryFile(filePath) {
|
|
123
|
-
if (!fs.existsSync(filePath))
|
|
124
|
-
return null;
|
|
125
|
-
try {
|
|
126
|
-
const raw = await fsp.readFile(filePath, 'utf8');
|
|
127
|
-
let latest = null;
|
|
128
|
-
for (const line of raw.split(/\r?\n/)) {
|
|
129
|
-
if (!line.trim())
|
|
130
|
-
continue;
|
|
131
|
-
let parsed;
|
|
132
|
-
try {
|
|
133
|
-
parsed = JSON.parse(line);
|
|
134
|
-
}
|
|
135
|
-
catch {
|
|
136
|
-
continue;
|
|
137
|
-
}
|
|
138
|
-
if (!parsed || typeof parsed !== 'object')
|
|
139
|
-
continue;
|
|
140
|
-
const record = parsed;
|
|
141
|
-
if (record.type !== 'summary')
|
|
142
|
-
continue;
|
|
143
|
-
const summary = record.summary;
|
|
144
|
-
if (typeof summary === 'string' && summary.trim()) {
|
|
145
|
-
latest = summary.trim();
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
return latest ? sanitizeSummary(latest) : null;
|
|
149
|
-
}
|
|
150
|
-
catch {
|
|
151
|
-
return null;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
export async function pollClaudeSummary(options) {
|
|
155
|
-
const { basePath, sessionId, timeoutMs = 30000, intervalMs = 1500 } = options;
|
|
156
|
-
const filePath = resolveClaudeSummaryPath(basePath, sessionId);
|
|
157
|
-
if (!filePath)
|
|
158
|
-
return null;
|
|
159
|
-
const start = Date.now();
|
|
160
|
-
let lastMtime = 0;
|
|
161
|
-
while (Date.now() - start < timeoutMs) {
|
|
162
|
-
try {
|
|
163
|
-
const stat = await fsp.stat(filePath);
|
|
164
|
-
const mtime = stat.mtimeMs;
|
|
165
|
-
if (mtime !== lastMtime) {
|
|
166
|
-
lastMtime = mtime;
|
|
167
|
-
const summary = await readClaudeSummaryFile(filePath);
|
|
168
|
-
if (summary)
|
|
169
|
-
return summary;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
catch {
|
|
173
|
-
// ignore
|
|
174
|
-
}
|
|
175
|
-
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
176
|
-
}
|
|
177
|
-
return null;
|
|
178
|
-
}
|
package/dist/types.d.ts
CHANGED
|
@@ -116,6 +116,20 @@ export interface ModelInfo {
|
|
|
116
116
|
reasoningEfforts?: ReasoningEffort[];
|
|
117
117
|
defaultReasoningEffort?: string;
|
|
118
118
|
}
|
|
119
|
+
export type TokenUsage = {
|
|
120
|
+
input_tokens?: number;
|
|
121
|
+
output_tokens?: number;
|
|
122
|
+
total_tokens?: number;
|
|
123
|
+
cached_input_tokens?: number;
|
|
124
|
+
reasoning_tokens?: number;
|
|
125
|
+
};
|
|
126
|
+
export type ContextUsage = {
|
|
127
|
+
context_window?: number;
|
|
128
|
+
context_tokens?: number;
|
|
129
|
+
context_cached_tokens?: number;
|
|
130
|
+
context_remaining_tokens?: number;
|
|
131
|
+
context_truncated?: boolean;
|
|
132
|
+
};
|
|
119
133
|
export interface ProviderLoginOptions {
|
|
120
134
|
baseUrl?: string;
|
|
121
135
|
apiKey?: string;
|
|
@@ -125,15 +139,15 @@ export interface ProviderLoginOptions {
|
|
|
125
139
|
loginExperience?: 'embedded' | 'terminal';
|
|
126
140
|
}
|
|
127
141
|
export interface SessionEvent {
|
|
128
|
-
type: 'delta' | 'final' | 'usage' | 'status' | 'error' | 'raw_line' | 'message' | 'thinking' | 'tool_call' | 'detail' | 'summary';
|
|
142
|
+
type: 'delta' | 'final' | 'usage' | 'context_usage' | 'status' | 'error' | 'raw_line' | 'message' | 'thinking' | 'tool_call' | 'detail' | 'summary';
|
|
129
143
|
text?: string;
|
|
130
144
|
message?: string;
|
|
131
145
|
line?: string;
|
|
132
146
|
provider?: ProviderId;
|
|
133
147
|
providerDetail?: ProviderDetail;
|
|
134
148
|
providerSessionId?: string | null;
|
|
135
|
-
|
|
136
|
-
|
|
149
|
+
usage?: TokenUsage;
|
|
150
|
+
contextUsage?: ContextUsage;
|
|
137
151
|
role?: 'system' | 'user' | 'assistant';
|
|
138
152
|
content?: string;
|
|
139
153
|
contentParts?: unknown;
|
|
@@ -146,12 +160,13 @@ export interface SessionEvent {
|
|
|
146
160
|
timestampMs?: number;
|
|
147
161
|
cancelled?: boolean;
|
|
148
162
|
summary?: string;
|
|
149
|
-
source?: 'prompt'
|
|
163
|
+
source?: 'prompt';
|
|
150
164
|
model?: string | null;
|
|
151
165
|
createdAt?: string;
|
|
152
166
|
}
|
|
153
167
|
export interface RunPromptOptions {
|
|
154
168
|
prompt: string;
|
|
169
|
+
system?: string;
|
|
155
170
|
resumeSessionId?: string | null;
|
|
156
171
|
model?: string;
|
|
157
172
|
reasoningEffort?: string | null;
|
|
@@ -193,12 +208,17 @@ export interface SessionState {
|
|
|
193
208
|
cwd?: string;
|
|
194
209
|
repoRoot?: string;
|
|
195
210
|
providerDetailLevel?: ProviderDetailLevel;
|
|
211
|
+
systemPrompt?: string;
|
|
212
|
+
summaryMode?: 'auto' | 'off';
|
|
213
|
+
summaryPrompt?: string;
|
|
214
|
+
summaryNextMode?: 'auto' | 'off' | 'force';
|
|
215
|
+
summaryNextPrompt?: string;
|
|
216
|
+
summaryAutoUsed?: boolean;
|
|
196
217
|
summaryRequested?: boolean;
|
|
197
|
-
claudeSummaryWatch?: boolean;
|
|
198
218
|
summarySeed?: string;
|
|
199
219
|
summaryReasoning?: string;
|
|
200
220
|
summary?: string | null;
|
|
201
|
-
summarySource?: 'prompt'
|
|
221
|
+
summarySource?: 'prompt';
|
|
202
222
|
summaryModel?: string | null;
|
|
203
223
|
summaryCreatedAt?: string;
|
|
204
224
|
}
|