@clinebot/core 0.0.0 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -7
- package/dist/default-tools/definitions.d.ts +1 -1
- package/dist/default-tools/executors/index.d.ts +1 -1
- package/dist/default-tools/index.d.ts +2 -1
- package/dist/default-tools/model-tool-routing.d.ts +33 -0
- package/dist/default-tools/schemas.d.ts +13 -7
- package/dist/index.browser.d.ts +1 -0
- package/dist/index.browser.js +220 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +47 -47
- package/dist/index.node.d.ts +36 -0
- package/dist/index.node.js +622 -0
- package/dist/providers/local-provider-service.d.ts +37 -0
- package/dist/session/default-session-manager.d.ts +3 -1
- package/dist/session/session-host.d.ts +2 -2
- package/dist/session/session-manager.d.ts +8 -0
- package/dist/session/unified-session-persistence-service.d.ts +1 -1
- package/dist/session/utils/helpers.d.ts +11 -0
- package/dist/session/utils/types.d.ts +42 -0
- package/dist/session/utils/usage.d.ts +9 -0
- package/dist/storage/provider-settings-manager.d.ts +2 -0
- package/dist/types/config.d.ts +8 -1
- package/dist/types.d.ts +1 -1
- package/package.json +11 -32
- package/src/default-tools/definitions.test.ts +130 -1
- package/src/default-tools/definitions.ts +7 -3
- package/src/default-tools/executors/editor.ts +10 -9
- package/src/default-tools/executors/file-read.test.ts +1 -1
- package/src/default-tools/executors/file-read.ts +11 -6
- package/src/default-tools/executors/index.ts +1 -1
- package/src/default-tools/index.ts +6 -1
- package/src/default-tools/model-tool-routing.test.ts +86 -0
- package/src/default-tools/model-tool-routing.ts +132 -0
- package/src/default-tools/schemas.ts +49 -52
- package/src/index.browser.ts +1 -0
- package/src/{server/index.ts → index.node.ts} +51 -109
- package/src/index.ts +41 -2
- package/src/input/file-indexer.ts +28 -2
- package/src/providers/local-provider-service.ts +591 -0
- package/src/runtime/runtime-builder.test.ts +69 -0
- package/src/runtime/runtime-builder.ts +20 -0
- package/src/runtime/runtime-parity.test.ts +20 -9
- package/src/session/default-session-manager.e2e.test.ts +11 -1
- package/src/session/default-session-manager.test.ts +270 -0
- package/src/session/default-session-manager.ts +109 -191
- package/src/session/index.ts +7 -2
- package/src/session/session-host.ts +30 -18
- package/src/session/session-manager.ts +11 -0
- package/src/session/unified-session-persistence-service.ts +11 -5
- package/src/session/utils/helpers.ts +148 -0
- package/src/session/utils/types.ts +46 -0
- package/src/session/utils/usage.ts +32 -0
- package/src/storage/provider-settings-legacy-migration.test.ts +3 -3
- package/src/storage/provider-settings-manager.test.ts +34 -0
- package/src/storage/provider-settings-manager.ts +22 -1
- package/src/types/config.ts +13 -0
- package/src/types.ts +1 -0
- package/dist/server/index.d.ts +0 -47
- package/dist/server/index.js +0 -641
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
mergeAgentHooks,
|
|
31
31
|
} from "../runtime/hook-file-hooks";
|
|
32
32
|
import { DefaultRuntimeBuilder } from "../runtime/runtime-builder";
|
|
33
|
-
import type {
|
|
33
|
+
import type { RuntimeBuilder } from "../runtime/session-runtime";
|
|
34
34
|
import { ProviderSettingsManager } from "../storage/provider-settings-manager";
|
|
35
35
|
import {
|
|
36
36
|
buildTeamProgressSummary,
|
|
@@ -53,6 +53,7 @@ import {
|
|
|
53
53
|
import { nowIso } from "./session-artifacts";
|
|
54
54
|
import type {
|
|
55
55
|
SendSessionInput,
|
|
56
|
+
SessionAccumulatedUsage,
|
|
56
57
|
SessionManager,
|
|
57
58
|
StartSessionInput,
|
|
58
59
|
StartSessionResult,
|
|
@@ -63,47 +64,26 @@ import type {
|
|
|
63
64
|
RootSessionArtifacts,
|
|
64
65
|
SessionRowShape,
|
|
65
66
|
} from "./session-service";
|
|
67
|
+
import {
|
|
68
|
+
extractWorkspaceMetadataFromSystemPrompt,
|
|
69
|
+
hasRuntimeHooks,
|
|
70
|
+
mergeAgentExtensions,
|
|
71
|
+
serializeAgentEvent,
|
|
72
|
+
toSessionRecord,
|
|
73
|
+
withLatestAssistantTurnMetadata,
|
|
74
|
+
} from "./utils/helpers";
|
|
75
|
+
import type {
|
|
76
|
+
ActiveSession,
|
|
77
|
+
PreparedTurnInput,
|
|
78
|
+
TeamRunUpdate,
|
|
79
|
+
} from "./utils/types";
|
|
80
|
+
import {
|
|
81
|
+
accumulateUsageTotals,
|
|
82
|
+
createInitialAccumulatedUsage,
|
|
83
|
+
} from "./utils/usage";
|
|
66
84
|
|
|
67
85
|
type SessionBackend = CoreSessionService | RpcCoreSessionService;
|
|
68
86
|
|
|
69
|
-
type ActiveSession = {
|
|
70
|
-
sessionId: string;
|
|
71
|
-
config: CoreSessionConfig;
|
|
72
|
-
artifacts?: RootSessionArtifacts;
|
|
73
|
-
source: SessionSource;
|
|
74
|
-
startedAt: string;
|
|
75
|
-
pendingPrompt?: string;
|
|
76
|
-
runtime: BuiltRuntime;
|
|
77
|
-
agent: Agent;
|
|
78
|
-
started: boolean;
|
|
79
|
-
aborting: boolean;
|
|
80
|
-
interactive: boolean;
|
|
81
|
-
activeTeamRunIds: Set<string>;
|
|
82
|
-
pendingTeamRunUpdates: TeamRunUpdate[];
|
|
83
|
-
teamRunWaiters: Array<() => void>;
|
|
84
|
-
pluginSandboxShutdown?: () => Promise<void>;
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
type TeamRunUpdate = {
|
|
88
|
-
runId: string;
|
|
89
|
-
agentId: string;
|
|
90
|
-
taskId?: string;
|
|
91
|
-
status: "completed" | "failed" | "cancelled" | "interrupted";
|
|
92
|
-
error?: string;
|
|
93
|
-
iterations?: number;
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
type StoredMessageWithMetadata = LlmsProviders.MessageWithMetadata & {
|
|
97
|
-
providerId?: string;
|
|
98
|
-
modelId?: string;
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
type PreparedTurnInput = {
|
|
102
|
-
prompt: string;
|
|
103
|
-
userImages?: string[];
|
|
104
|
-
userFiles?: string[];
|
|
105
|
-
};
|
|
106
|
-
|
|
107
87
|
export interface DefaultSessionManagerOptions {
|
|
108
88
|
distinctId: string;
|
|
109
89
|
sessionService: SessionBackend;
|
|
@@ -136,134 +116,6 @@ async function loadUserFileContent(path: string): Promise<string> {
|
|
|
136
116
|
return content;
|
|
137
117
|
}
|
|
138
118
|
|
|
139
|
-
function hasRuntimeHooks(hooks: AgentConfig["hooks"]): boolean {
|
|
140
|
-
if (!hooks) {
|
|
141
|
-
return false;
|
|
142
|
-
}
|
|
143
|
-
return Object.values(hooks).some((value) => typeof value === "function");
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
function mergeAgentExtensions(
|
|
147
|
-
explicitExtensions: AgentConfig["extensions"] | undefined,
|
|
148
|
-
loadedExtensions: AgentConfig["extensions"] | undefined,
|
|
149
|
-
): AgentConfig["extensions"] {
|
|
150
|
-
const merged = [...(explicitExtensions ?? []), ...(loadedExtensions ?? [])];
|
|
151
|
-
if (merged.length === 0) {
|
|
152
|
-
return undefined;
|
|
153
|
-
}
|
|
154
|
-
const deduped: NonNullable<AgentConfig["extensions"]> = [];
|
|
155
|
-
const seenNames = new Set<string>();
|
|
156
|
-
for (const extension of merged) {
|
|
157
|
-
if (seenNames.has(extension.name)) {
|
|
158
|
-
continue;
|
|
159
|
-
}
|
|
160
|
-
seenNames.add(extension.name);
|
|
161
|
-
deduped.push(extension);
|
|
162
|
-
}
|
|
163
|
-
return deduped;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
function serializeAgentEvent(event: AgentEvent): string {
|
|
167
|
-
return JSON.stringify(event, (_key, value) => {
|
|
168
|
-
if (value instanceof Error) {
|
|
169
|
-
return {
|
|
170
|
-
name: value.name,
|
|
171
|
-
message: value.message,
|
|
172
|
-
stack: value.stack,
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
return value;
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
function withLatestAssistantTurnMetadata(
|
|
180
|
-
messages: LlmsProviders.Message[],
|
|
181
|
-
result: AgentResult,
|
|
182
|
-
): StoredMessageWithMetadata[] {
|
|
183
|
-
const next = messages.map((message) => ({
|
|
184
|
-
...message,
|
|
185
|
-
})) as StoredMessageWithMetadata[];
|
|
186
|
-
const assistantIndex = [...next]
|
|
187
|
-
.reverse()
|
|
188
|
-
.findIndex((message) => message.role === "assistant");
|
|
189
|
-
if (assistantIndex === -1) {
|
|
190
|
-
return next;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
const targetIndex = next.length - 1 - assistantIndex;
|
|
194
|
-
const target = next[targetIndex];
|
|
195
|
-
const usage = result.usage;
|
|
196
|
-
next[targetIndex] = {
|
|
197
|
-
...target,
|
|
198
|
-
providerId: target.providerId ?? result.model.provider,
|
|
199
|
-
modelId: target.modelId ?? result.model.id,
|
|
200
|
-
modelInfo: target.modelInfo ?? {
|
|
201
|
-
id: result.model.id,
|
|
202
|
-
provider: result.model.provider,
|
|
203
|
-
},
|
|
204
|
-
metrics: {
|
|
205
|
-
...(target.metrics ?? {}),
|
|
206
|
-
inputTokens: usage.inputTokens,
|
|
207
|
-
outputTokens: usage.outputTokens,
|
|
208
|
-
cacheReadTokens: usage.cacheReadTokens,
|
|
209
|
-
cacheWriteTokens: usage.cacheWriteTokens,
|
|
210
|
-
cost: usage.totalCost,
|
|
211
|
-
},
|
|
212
|
-
ts: target.ts ?? result.endedAt.getTime(),
|
|
213
|
-
};
|
|
214
|
-
return next;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
function toSessionRecord(row: SessionRowShape): SessionRecord {
|
|
218
|
-
const metadata =
|
|
219
|
-
typeof row.metadata_json === "string" && row.metadata_json.trim().length > 0
|
|
220
|
-
? (() => {
|
|
221
|
-
try {
|
|
222
|
-
const parsed = JSON.parse(row.metadata_json) as unknown;
|
|
223
|
-
if (
|
|
224
|
-
parsed &&
|
|
225
|
-
typeof parsed === "object" &&
|
|
226
|
-
!Array.isArray(parsed)
|
|
227
|
-
) {
|
|
228
|
-
return parsed as Record<string, unknown>;
|
|
229
|
-
}
|
|
230
|
-
} catch {
|
|
231
|
-
// Ignore malformed metadata payloads.
|
|
232
|
-
}
|
|
233
|
-
return undefined;
|
|
234
|
-
})()
|
|
235
|
-
: undefined;
|
|
236
|
-
return {
|
|
237
|
-
sessionId: row.session_id,
|
|
238
|
-
source: row.source as SessionSource,
|
|
239
|
-
pid: row.pid,
|
|
240
|
-
startedAt: row.started_at,
|
|
241
|
-
endedAt: row.ended_at ?? null,
|
|
242
|
-
exitCode: row.exit_code ?? null,
|
|
243
|
-
status: row.status,
|
|
244
|
-
interactive: row.interactive === 1,
|
|
245
|
-
provider: row.provider,
|
|
246
|
-
model: row.model,
|
|
247
|
-
cwd: row.cwd,
|
|
248
|
-
workspaceRoot: row.workspace_root,
|
|
249
|
-
teamName: row.team_name ?? undefined,
|
|
250
|
-
enableTools: row.enable_tools === 1,
|
|
251
|
-
enableSpawn: row.enable_spawn === 1,
|
|
252
|
-
enableTeams: row.enable_teams === 1,
|
|
253
|
-
parentSessionId: row.parent_session_id ?? undefined,
|
|
254
|
-
parentAgentId: row.parent_agent_id ?? undefined,
|
|
255
|
-
agentId: row.agent_id ?? undefined,
|
|
256
|
-
conversationId: row.conversation_id ?? undefined,
|
|
257
|
-
isSubagent: row.is_subagent === 1,
|
|
258
|
-
prompt: row.prompt ?? undefined,
|
|
259
|
-
metadata,
|
|
260
|
-
transcriptPath: row.transcript_path,
|
|
261
|
-
hookPath: row.hook_path,
|
|
262
|
-
messagesPath: row.messages_path ?? undefined,
|
|
263
|
-
updatedAt: row.updated_at ?? nowIso(),
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
|
|
267
119
|
export class DefaultSessionManager implements SessionManager {
|
|
268
120
|
private readonly sessionService: SessionBackend;
|
|
269
121
|
private readonly runtimeBuilder: RuntimeBuilder;
|
|
@@ -277,6 +129,7 @@ export class DefaultSessionManager implements SessionManager {
|
|
|
277
129
|
) => Promise<ToolApprovalResult>;
|
|
278
130
|
private readonly listeners = new Set<(event: CoreSessionEvent) => void>();
|
|
279
131
|
private readonly sessions = new Map<string, ActiveSession>();
|
|
132
|
+
private readonly usageBySession = new Map<string, SessionAccumulatedUsage>();
|
|
280
133
|
|
|
281
134
|
constructor(options: DefaultSessionManagerOptions) {
|
|
282
135
|
const homeDir = homedir();
|
|
@@ -319,10 +172,16 @@ export class DefaultSessionManager implements SessionManager {
|
|
|
319
172
|
baseUrl: config.baseUrl ?? settings.baseUrl,
|
|
320
173
|
headers: config.headers ?? settings.headers,
|
|
321
174
|
reasoning:
|
|
322
|
-
typeof config.thinking === "boolean"
|
|
175
|
+
typeof config.thinking === "boolean" ||
|
|
176
|
+
typeof config.reasoningEffort === "string"
|
|
323
177
|
? {
|
|
324
178
|
...(settings.reasoning ?? {}),
|
|
325
|
-
|
|
179
|
+
...(typeof config.thinking === "boolean"
|
|
180
|
+
? { enabled: config.thinking }
|
|
181
|
+
: {}),
|
|
182
|
+
...(typeof config.reasoningEffort === "string"
|
|
183
|
+
? { effort: config.reasoningEffort }
|
|
184
|
+
: {}),
|
|
326
185
|
}
|
|
327
186
|
: settings.reasoning,
|
|
328
187
|
};
|
|
@@ -341,6 +200,7 @@ export class DefaultSessionManager implements SessionManager {
|
|
|
341
200
|
requestedSessionId.length > 0
|
|
342
201
|
? requestedSessionId
|
|
343
202
|
: `${Date.now()}_${nanoid(5)}`;
|
|
203
|
+
this.usageBySession.set(sessionId, createInitialAccumulatedUsage());
|
|
344
204
|
const sessionsDir =
|
|
345
205
|
((await this.invokeOptionalValue("ensureSessionsDir")) as
|
|
346
206
|
| string
|
|
@@ -440,8 +300,11 @@ export class DefaultSessionManager implements SessionManager {
|
|
|
440
300
|
knownModels: providerConfig.knownModels,
|
|
441
301
|
providerConfig,
|
|
442
302
|
thinking: effectiveConfig.thinking,
|
|
303
|
+
reasoningEffort:
|
|
304
|
+
effectiveConfig.reasoningEffort ?? providerConfig.reasoningEffort,
|
|
443
305
|
systemPrompt: effectiveConfig.systemPrompt,
|
|
444
306
|
maxIterations: effectiveConfig.maxIterations,
|
|
307
|
+
maxConsecutiveMistakes: effectiveConfig.maxConsecutiveMistakes,
|
|
445
308
|
tools,
|
|
446
309
|
hooks: effectiveHooks,
|
|
447
310
|
extensions: effectiveExtensions,
|
|
@@ -451,9 +314,22 @@ export class DefaultSessionManager implements SessionManager {
|
|
|
451
314
|
toolPolicies: input.toolPolicies ?? this.defaultToolPolicies,
|
|
452
315
|
requestToolApproval:
|
|
453
316
|
input.requestToolApproval ?? this.defaultRequestToolApproval,
|
|
317
|
+
onConsecutiveMistakeLimitReached:
|
|
318
|
+
effectiveConfig.onConsecutiveMistakeLimitReached,
|
|
454
319
|
completionGuard: runtime.completionGuard,
|
|
455
320
|
logger: runtime.logger ?? effectiveConfig.logger,
|
|
456
321
|
onEvent: (event: AgentEvent) => {
|
|
322
|
+
const liveSession = this.sessions.get(sessionId);
|
|
323
|
+
if (event.type === "usage" && liveSession?.turnUsageBaseline) {
|
|
324
|
+
this.usageBySession.set(
|
|
325
|
+
sessionId,
|
|
326
|
+
accumulateUsageTotals(liveSession.turnUsageBaseline, {
|
|
327
|
+
inputTokens: event.totalInputTokens,
|
|
328
|
+
outputTokens: event.totalOutputTokens,
|
|
329
|
+
totalCost: event.totalCost,
|
|
330
|
+
}),
|
|
331
|
+
);
|
|
332
|
+
}
|
|
457
333
|
this.emit({
|
|
458
334
|
type: "agent_event",
|
|
459
335
|
payload: {
|
|
@@ -541,6 +417,16 @@ export class DefaultSessionManager implements SessionManager {
|
|
|
541
417
|
}
|
|
542
418
|
}
|
|
543
419
|
|
|
420
|
+
async getAccumulatedUsage(
|
|
421
|
+
sessionId: string,
|
|
422
|
+
): Promise<SessionAccumulatedUsage | undefined> {
|
|
423
|
+
const usage = this.usageBySession.get(sessionId);
|
|
424
|
+
if (!usage) {
|
|
425
|
+
return undefined;
|
|
426
|
+
}
|
|
427
|
+
return { ...usage };
|
|
428
|
+
}
|
|
429
|
+
|
|
544
430
|
async abort(sessionId: string): Promise<void> {
|
|
545
431
|
const session = this.sessions.get(sessionId);
|
|
546
432
|
if (!session) {
|
|
@@ -578,6 +464,7 @@ export class DefaultSessionManager implements SessionManager {
|
|
|
578
464
|
});
|
|
579
465
|
}),
|
|
580
466
|
);
|
|
467
|
+
this.usageBySession.clear();
|
|
581
468
|
}
|
|
582
469
|
|
|
583
470
|
async get(sessionId: string): Promise<SessionRecord | undefined> {
|
|
@@ -598,6 +485,9 @@ export class DefaultSessionManager implements SessionManager {
|
|
|
598
485
|
"deleteSession",
|
|
599
486
|
sessionId,
|
|
600
487
|
);
|
|
488
|
+
if (result.deleted) {
|
|
489
|
+
this.usageBySession.delete(sessionId);
|
|
490
|
+
}
|
|
601
491
|
return result.deleted;
|
|
602
492
|
}
|
|
603
493
|
|
|
@@ -709,28 +599,50 @@ export class DefaultSessionManager implements SessionManager {
|
|
|
709
599
|
const shouldContinue =
|
|
710
600
|
session.started || session.agent.getMessages().length > 0;
|
|
711
601
|
const baselineMessages = session.agent.getMessages();
|
|
712
|
-
const
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
602
|
+
const usageBaseline =
|
|
603
|
+
this.usageBySession.get(session.sessionId) ??
|
|
604
|
+
createInitialAccumulatedUsage();
|
|
605
|
+
session.turnUsageBaseline = usageBaseline;
|
|
606
|
+
try {
|
|
607
|
+
const result = shouldContinue
|
|
608
|
+
? await this.runWithAuthRetry(
|
|
609
|
+
session,
|
|
610
|
+
() => session.agent.continue(prompt, userImages, userFiles),
|
|
611
|
+
baselineMessages,
|
|
612
|
+
)
|
|
613
|
+
: await this.runWithAuthRetry(
|
|
614
|
+
session,
|
|
615
|
+
() => session.agent.run(prompt, userImages, userFiles),
|
|
616
|
+
baselineMessages,
|
|
617
|
+
);
|
|
618
|
+
session.started = true;
|
|
619
|
+
const persistedMessages = withLatestAssistantTurnMetadata(
|
|
620
|
+
result.messages,
|
|
621
|
+
result,
|
|
622
|
+
);
|
|
623
|
+
this.usageBySession.set(
|
|
624
|
+
session.sessionId,
|
|
625
|
+
accumulateUsageTotals(usageBaseline, result.usage),
|
|
626
|
+
);
|
|
627
|
+
await this.invoke<void>(
|
|
628
|
+
"persistSessionMessages",
|
|
629
|
+
session.sessionId,
|
|
630
|
+
persistedMessages,
|
|
631
|
+
session.config.systemPrompt,
|
|
632
|
+
);
|
|
633
|
+
return result;
|
|
634
|
+
} catch (error) {
|
|
635
|
+
// Persist whatever was rendered so far even when a turn fails.
|
|
636
|
+
await this.invoke<void>(
|
|
637
|
+
"persistSessionMessages",
|
|
638
|
+
session.sessionId,
|
|
639
|
+
session.agent.getMessages(),
|
|
640
|
+
session.config.systemPrompt,
|
|
641
|
+
);
|
|
642
|
+
throw error;
|
|
643
|
+
} finally {
|
|
644
|
+
session.turnUsageBaseline = undefined;
|
|
645
|
+
}
|
|
734
646
|
}
|
|
735
647
|
|
|
736
648
|
private async prepareTurnInput(
|
|
@@ -963,10 +875,15 @@ export class DefaultSessionManager implements SessionManager {
|
|
|
963
875
|
return createSpawnAgentTool({
|
|
964
876
|
providerId: config.providerId,
|
|
965
877
|
modelId: config.modelId,
|
|
878
|
+
cwd: config.cwd,
|
|
966
879
|
apiKey: config.apiKey,
|
|
967
880
|
baseUrl: config.baseUrl,
|
|
968
881
|
providerConfig: config.providerConfig,
|
|
969
882
|
knownModels: config.knownModels,
|
|
883
|
+
clineWorkspaceMetadata:
|
|
884
|
+
config.providerId === "cline"
|
|
885
|
+
? extractWorkspaceMetadataFromSystemPrompt(config.systemPrompt)
|
|
886
|
+
: undefined,
|
|
970
887
|
createSubAgentTools,
|
|
971
888
|
hooks: config.hooks,
|
|
972
889
|
extensions: config.extensions,
|
|
@@ -1039,6 +956,7 @@ export class DefaultSessionManager implements SessionManager {
|
|
|
1039
956
|
event.agentId,
|
|
1040
957
|
"failed",
|
|
1041
958
|
`[error] ${event.error.message}`,
|
|
959
|
+
event.messages,
|
|
1042
960
|
);
|
|
1043
961
|
break;
|
|
1044
962
|
}
|
package/src/session/index.ts
CHANGED
|
@@ -6,10 +6,15 @@ export {
|
|
|
6
6
|
makeTeamTaskSubSessionId,
|
|
7
7
|
sanitizeSessionToken,
|
|
8
8
|
} from "./session-graph";
|
|
9
|
-
export type {
|
|
10
|
-
|
|
9
|
+
export type {
|
|
10
|
+
CreateSessionHostOptions,
|
|
11
|
+
SessionBackend,
|
|
12
|
+
SessionHost,
|
|
13
|
+
} from "./session-host";
|
|
14
|
+
export { createSessionHost, resolveSessionBackend } from "./session-host";
|
|
11
15
|
export type {
|
|
12
16
|
SendSessionInput,
|
|
17
|
+
SessionAccumulatedUsage,
|
|
13
18
|
SessionManager,
|
|
14
19
|
StartSessionInput,
|
|
15
20
|
StartSessionResult,
|
|
@@ -6,7 +6,7 @@ import type {
|
|
|
6
6
|
ToolApprovalRequest,
|
|
7
7
|
ToolApprovalResult,
|
|
8
8
|
} from "@clinebot/agents";
|
|
9
|
-
import { getRpcServerHealth } from "@clinebot/rpc";
|
|
9
|
+
import { getRpcServerDefaultAddress, getRpcServerHealth } from "@clinebot/rpc";
|
|
10
10
|
import { resolveSessionDataDir } from "@clinebot/shared/storage";
|
|
11
11
|
import { nanoid } from "nanoid";
|
|
12
12
|
import type { ToolExecutors } from "../default-tools";
|
|
@@ -17,9 +17,9 @@ import type { SessionManager } from "./session-manager";
|
|
|
17
17
|
import { CoreSessionService } from "./session-service";
|
|
18
18
|
|
|
19
19
|
const DEFAULT_RPC_ADDRESS =
|
|
20
|
-
process.env.CLINE_RPC_ADDRESS?.trim() ||
|
|
20
|
+
process.env.CLINE_RPC_ADDRESS?.trim() || getRpcServerDefaultAddress();
|
|
21
21
|
|
|
22
|
-
type SessionBackend = RpcCoreSessionService | CoreSessionService;
|
|
22
|
+
export type SessionBackend = RpcCoreSessionService | CoreSessionService;
|
|
23
23
|
|
|
24
24
|
let cachedBackend: SessionBackend | undefined;
|
|
25
25
|
let backendInitPromise: Promise<SessionBackend> | undefined;
|
|
@@ -41,24 +41,35 @@ export interface CreateSessionHostOptions {
|
|
|
41
41
|
|
|
42
42
|
export type SessionHost = SessionManager;
|
|
43
43
|
|
|
44
|
-
function isLikelyScriptEntryPath(pathValue: string | undefined): boolean {
|
|
45
|
-
if (!pathValue) {
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
return /\.(?:[cm]?[jt]s|tsx?)$/i.test(pathValue);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
44
|
function startRpcServerInBackground(address: string): void {
|
|
52
|
-
const launcher = process.
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
45
|
+
const launcher = process.execPath;
|
|
46
|
+
const entryArg = process.argv[1]?.trim();
|
|
47
|
+
if (!entryArg) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const entry = resolve(process.cwd(), entryArg);
|
|
51
|
+
if (!existsSync(entry)) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const conditionsArg = process.execArgv.find((arg) =>
|
|
55
|
+
arg.startsWith("--conditions="),
|
|
56
|
+
);
|
|
57
|
+
const args = [
|
|
58
|
+
...(conditionsArg ? [conditionsArg] : []),
|
|
59
|
+
entry,
|
|
60
|
+
"rpc",
|
|
61
|
+
"start",
|
|
62
|
+
"--address",
|
|
63
|
+
address,
|
|
64
|
+
];
|
|
57
65
|
|
|
58
66
|
const child = spawn(launcher, args, {
|
|
59
67
|
detached: true,
|
|
60
68
|
stdio: "ignore",
|
|
61
|
-
env:
|
|
69
|
+
env: {
|
|
70
|
+
...process.env,
|
|
71
|
+
CLINE_NO_INTERACTIVE: "1",
|
|
72
|
+
},
|
|
62
73
|
cwd: process.cwd(),
|
|
63
74
|
});
|
|
64
75
|
child.unref();
|
|
@@ -116,7 +127,7 @@ function resolveHostDistinctId(explicitDistinctId: string | undefined): string {
|
|
|
116
127
|
return generatedDistinctId;
|
|
117
128
|
}
|
|
118
129
|
|
|
119
|
-
async function
|
|
130
|
+
export async function resolveSessionBackend(
|
|
120
131
|
options: CreateSessionHostOptions,
|
|
121
132
|
): Promise<SessionBackend> {
|
|
122
133
|
if (cachedBackend) {
|
|
@@ -179,7 +190,8 @@ async function resolveBackend(
|
|
|
179
190
|
export async function createSessionHost(
|
|
180
191
|
options: CreateSessionHostOptions,
|
|
181
192
|
): Promise<SessionHost> {
|
|
182
|
-
const backend =
|
|
193
|
+
const backend =
|
|
194
|
+
options.sessionService ?? (await resolveSessionBackend(options));
|
|
183
195
|
return new DefaultSessionManager({
|
|
184
196
|
sessionService: backend,
|
|
185
197
|
defaultToolExecutors: options.defaultToolExecutors,
|
|
@@ -40,9 +40,20 @@ export interface SendSessionInput {
|
|
|
40
40
|
userFiles?: string[];
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
export interface SessionAccumulatedUsage {
|
|
44
|
+
inputTokens: number;
|
|
45
|
+
outputTokens: number;
|
|
46
|
+
cacheReadTokens: number;
|
|
47
|
+
cacheWriteTokens: number;
|
|
48
|
+
totalCost: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
43
51
|
export interface SessionManager {
|
|
44
52
|
start(input: StartSessionInput): Promise<StartSessionResult>;
|
|
45
53
|
send(input: SendSessionInput): Promise<AgentResult | undefined>;
|
|
54
|
+
getAccumulatedUsage(
|
|
55
|
+
sessionId: string,
|
|
56
|
+
): Promise<SessionAccumulatedUsage | undefined>;
|
|
46
57
|
abort(sessionId: string): Promise<void>;
|
|
47
58
|
stop(sessionId: string): Promise<void>;
|
|
48
59
|
dispose(reason?: string): Promise<void>;
|
|
@@ -499,15 +499,21 @@ export class UnifiedSessionPersistenceService {
|
|
|
499
499
|
async persistSessionMessages(
|
|
500
500
|
sessionId: string,
|
|
501
501
|
messages: LlmsProviders.Message[],
|
|
502
|
+
systemPrompt?: string,
|
|
502
503
|
): Promise<void> {
|
|
503
504
|
const path =
|
|
504
505
|
(await this.sessionPathFromStore(sessionId, "messages_path")) ??
|
|
505
506
|
this.sessionMessagesPath(sessionId);
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
507
|
+
const payload: {
|
|
508
|
+
version: number;
|
|
509
|
+
updated_at: string;
|
|
510
|
+
systemPrompt?: string;
|
|
511
|
+
messages: LlmsProviders.Message[];
|
|
512
|
+
} = { version: 1, updated_at: nowIso(), messages };
|
|
513
|
+
if (systemPrompt !== undefined && systemPrompt !== "") {
|
|
514
|
+
payload.systemPrompt = systemPrompt;
|
|
515
|
+
}
|
|
516
|
+
writeFileSync(path, `${JSON.stringify(payload, null, 2)}\n`, "utf8");
|
|
511
517
|
}
|
|
512
518
|
|
|
513
519
|
async applySubagentStatus(
|