@clinebot/core 0.0.32 → 0.0.33

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.
@@ -1 +1 @@
1
- {"version":3,"file":"session-agent-events.d.ts","sourceRoot":"","sources":["../../src/session/session-agent-events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAON,KAAK,gCAAgC,EACrC,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAEjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGnD,wBAAgB,6BAA6B,CAC5C,KAAK,EAAE,OAAO,GACZ,MAAM,GAAG,SAAS,CAOpB;AAED,MAAM,WAAW,iBAAiB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,WAAW,EAAE,aAAa,GAAG,SAAS,CAAC;IACvC,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC;IACrD,eAAe,EAAE,CAChB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,OAAO,EAAE,EACnB,YAAY,CAAC,EAAE,MAAM,KACjB,IAAI,CAAC;IACV,IAAI,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;CACxC;AAED,MAAM,WAAW,8BAA8B;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,UAAU,GAAG;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB,CAgBA;AAED,wBAAgB,2BAA2B,CAC1C,OAAO,EAAE,8BAA8B,GACrC,gCAAgC,GAAG,SAAS,CA4B9C;AAED,wBAAgB,gBAAgB,CAC/B,GAAG,EAAE,iBAAiB,EACtB,KAAK,EAAE,UAAU,EACjB,SAAS,CAAC,EAAE,8BAA8B,GACxC,IAAI,CAwIN"}
1
+ {"version":3,"file":"session-agent-events.d.ts","sourceRoot":"","sources":["../../src/session/session-agent-events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAON,KAAK,gCAAgC,EACrC,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAEjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGnD,wBAAgB,6BAA6B,CAC5C,KAAK,EAAE,OAAO,GACZ,MAAM,GAAG,SAAS,CAOpB;AAED,MAAM,WAAW,iBAAiB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,WAAW,EAAE,aAAa,GAAG,SAAS,CAAC;IACvC,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC;IACrD,eAAe,EAAE,CAChB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,OAAO,EAAE,EACnB,YAAY,CAAC,EAAE,MAAM,KACjB,IAAI,CAAC;IACV,IAAI,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;CACxC;AAED,MAAM,WAAW,8BAA8B;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,UAAU,GAAG;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB,CAgBA;AAED,wBAAgB,2BAA2B,CAC1C,OAAO,EAAE,8BAA8B,GACrC,gCAAgC,GAAG,SAAS,CA4B9C;AAED,wBAAgB,gBAAgB,CAC/B,GAAG,EAAE,iBAAiB,EACtB,KAAK,EAAE,UAAU,EACjB,SAAS,CAAC,EAAE,8BAA8B,GACxC,IAAI,CAgJN"}
@@ -51,6 +51,10 @@ export type CoreSessionEvent = {
51
51
  payload: {
52
52
  sessionId: string;
53
53
  event: import("@clinebot/shared").AgentEvent;
54
+ /** Identifies the named agent within the team (e.g. "educator", "assessor", "coordinator") for both lead and teammate agents */
55
+ teamAgentId?: string;
56
+ /** Whether this is the lead agent or a teammate */
57
+ teamRole?: "lead" | "teammate";
54
58
  };
55
59
  } | {
56
60
  type: "team_progress";
@@ -1 +1 @@
1
- {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/types/events.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,iBAAiB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,gBAAgB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EACV,WAAW,GACX,aAAa,GACb,WAAW,GACX,aAAa,GACb,kBAAkB,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,EAAE,CAAC,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,wBAAwB;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,kBAAkB,EAAE,0BAA0B,CAAC;IACjE,OAAO,EAAE,OAAO,kBAAkB,EAAE,mBAAmB,CAAC;CACxD;AAED,MAAM,WAAW,0BAA0B;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,KAAK,CAAC;QACd,EAAE,EAAE,MAAM,CAAC;QACX,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC;QAC5B,eAAe,EAAE,MAAM,CAAC;KACxB,CAAC,CAAC;CACH;AAED,MAAM,WAAW,kCAAkC;IAClD,SAAS,EAAE,MAAM,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,gBAAgB,GACzB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,iBAAiB,CAAA;CAAE,GAC7C;IACA,IAAI,EAAE,aAAa,CAAC;IACpB,OAAO,EAAE;QACR,SAAS,EAAE,MAAM,CAAC;QAClB,KAAK,EAAE,OAAO,kBAAkB,EAAE,UAAU,CAAC;KAC7C,CAAC;CACD,GACD;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,OAAO,EAAE,wBAAwB,CAAA;CAAE,GAC5D;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,OAAO,EAAE,0BAA0B,CAAA;CAAE,GAChE;IACA,IAAI,EAAE,0BAA0B,CAAC;IACjC,OAAO,EAAE,kCAAkC,CAAC;CAC3C,GACD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,iBAAiB,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,gBAAgB,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC"}
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/types/events.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,iBAAiB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,gBAAgB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EACV,WAAW,GACX,aAAa,GACb,WAAW,GACX,aAAa,GACb,kBAAkB,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,EAAE,CAAC,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,wBAAwB;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,kBAAkB,EAAE,0BAA0B,CAAC;IACjE,OAAO,EAAE,OAAO,kBAAkB,EAAE,mBAAmB,CAAC;CACxD;AAED,MAAM,WAAW,0BAA0B;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,KAAK,CAAC;QACd,EAAE,EAAE,MAAM,CAAC;QACX,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC;QAC5B,eAAe,EAAE,MAAM,CAAC;KACxB,CAAC,CAAC;CACH;AAED,MAAM,WAAW,kCAAkC;IAClD,SAAS,EAAE,MAAM,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,gBAAgB,GACzB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,iBAAiB,CAAA;CAAE,GAC7C;IACA,IAAI,EAAE,aAAa,CAAC;IACpB,OAAO,EAAE;QACR,SAAS,EAAE,MAAM,CAAC;QAClB,KAAK,EAAE,OAAO,kBAAkB,EAAE,UAAU,CAAC;QAC7C,gIAAgI;QAChI,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,mDAAmD;QACnD,QAAQ,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;KAC/B,CAAC;CACD,GACD;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,OAAO,EAAE,wBAAwB,CAAA;CAAE,GAC5D;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,OAAO,EAAE,0BAA0B,CAAA;CAAE,GAChE;IACA,IAAI,EAAE,0BAA0B,CAAC;IACjC,OAAO,EAAE,kCAAkC,CAAC;CAC3C,GACD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,iBAAiB,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,gBAAgB,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@clinebot/core",
3
3
  "description": "Cline Core SDK for Node Runtime",
4
- "version": "0.0.32",
4
+ "version": "0.0.33",
5
5
  "type": "module",
6
6
  "types": "./dist/index.d.ts",
7
7
  "main": "./dist/index.js",
@@ -36,8 +36,8 @@
36
36
  "test:watch": "vitest --config vitest.config.ts"
37
37
  },
38
38
  "dependencies": {
39
- "@clinebot/agents": "0.0.32",
40
- "@clinebot/llms": "0.0.32",
39
+ "@clinebot/agents": "0.0.33",
40
+ "@clinebot/llms": "0.0.33",
41
41
  "@opentelemetry/api": "^1.9.0",
42
42
  "@opentelemetry/api-logs": "^0.214.0",
43
43
  "@opentelemetry/exporter-logs-otlp-http": "^0.214.0",
@@ -58,7 +58,7 @@
58
58
  },
59
59
  "devDependencies": {
60
60
  "@clinebot/rpc": "0.0.28",
61
- "@clinebot/shared": "0.0.32"
61
+ "@clinebot/shared": "0.0.33"
62
62
  },
63
63
  "engines": {
64
64
  "node": ">=22"
@@ -106,14 +106,26 @@ export async function runAgenticCompaction(options: {
106
106
  (total, message) => total + options.estimateMessageTokens(message),
107
107
  0,
108
108
  );
109
- return {
110
- messages: [
111
- buildSummaryMessage({
112
- summary,
113
- fileOps,
114
- tokensBefore,
115
- }),
116
- ...messages.slice(cutIndex),
117
- ],
118
- };
109
+ const resultMessages = [
110
+ buildSummaryMessage({
111
+ summary,
112
+ fileOps,
113
+ tokensBefore,
114
+ }),
115
+ ...messages.slice(cutIndex),
116
+ ];
117
+ const tokensAfter = resultMessages.reduce(
118
+ (total, message) => total + options.estimateMessageTokens(message),
119
+ 0,
120
+ );
121
+ options.logger?.debug("Performed agentic compaction", {
122
+ messagesBefore: messages.length,
123
+ messagesAfter: resultMessages.length,
124
+ messagesSummarized: cutIndex,
125
+ messagesPreserved: messages.length - cutIndex,
126
+ tokensBefore,
127
+ tokensAfter,
128
+ contextWindowTokens: options.context.contextWindowTokens,
129
+ });
130
+ return { messages: resultMessages };
119
131
  }
@@ -33,17 +33,19 @@ function sanitizeMessageForBasic(
33
33
  return text ? { ...message, content: text } : undefined;
34
34
  }
35
35
 
36
- const textParts: string[] = [];
37
- for (const block of message.content) {
38
- if (block.type === "text") {
39
- const text = block.text.trim();
40
- if (text) {
41
- textParts.push(text);
42
- }
43
- }
36
+ // Preserve array structure: keep only text blocks with non-empty content.
37
+ const kept = message.content.filter(
38
+ (block) => block.type === "text" && block.text.trim(),
39
+ );
40
+ if (kept.length === 0) {
41
+ return undefined;
44
42
  }
45
- const text = textParts.join("\n\n").trim();
46
- return text ? { ...message, content: text } : undefined;
43
+ return {
44
+ ...message,
45
+ content: kept.map((block) =>
46
+ block.type === "text" ? { ...block, text: block.text.trim() } : block,
47
+ ),
48
+ };
47
49
  }
48
50
 
49
51
  function getTotalTokens(
@@ -60,14 +62,25 @@ function truncateMessageToTokens(
60
62
  message: MessageWithMetadata,
61
63
  maxTokens: number,
62
64
  ): MessageWithMetadata {
63
- const content = typeof message.content === "string" ? message.content : "";
64
65
  const safeMaxTokens = Math.max(1, maxTokens);
65
66
  const targetChars = Math.max(16, safeMaxTokens * 4);
66
- const truncated = truncateText(content, targetChars).trim();
67
- return {
68
- ...message,
69
- content: truncated || "...",
70
- };
67
+
68
+ if (typeof message.content === "string") {
69
+ const truncated = truncateText(message.content, targetChars).trim();
70
+ return { ...message, content: truncated || "..." };
71
+ }
72
+
73
+ // Preserve content block array structure while truncating text blocks.
74
+ let remaining = targetChars;
75
+ const truncatedBlocks = message.content.map((block) => {
76
+ if (block.type !== "text" || remaining <= 0) {
77
+ return block;
78
+ }
79
+ const truncated = truncateText(block.text, remaining).trim();
80
+ remaining -= truncated.length;
81
+ return { ...block, text: truncated || "..." };
82
+ });
83
+ return { ...message, content: truncatedBlocks };
71
84
  }
72
85
 
73
86
  function buildBasicCandidates(
@@ -265,10 +278,22 @@ export function runBasicCompaction(options: {
265
278
  return undefined;
266
279
  }
267
280
 
281
+ const beforeTokens = getTotalTokens(
282
+ options.context.messages.map((m) => sanitizeMessageForBasic(m) ?? m),
283
+ options.estimateMessageTokens,
284
+ );
285
+ const afterTokens = getTotalTokens(
286
+ nextMessages,
287
+ options.estimateMessageTokens,
288
+ );
268
289
  options.logger?.debug("Performed basic compaction", {
269
- beforeCount: options.context.messages.length,
270
- afterCount: nextMessages.length,
290
+ messagesBefore: options.context.messages.length,
291
+ messagesAfter: nextMessages.length,
292
+ messagesRemoved: options.context.messages.length - nextMessages.length,
293
+ tokensBefore: beforeTokens,
294
+ tokensAfter: afterTokens,
271
295
  targetTokens,
296
+ contextWindowTokens: options.context.contextWindowTokens,
272
297
  });
273
298
 
274
299
  return { messages: nextMessages };
@@ -6,7 +6,7 @@ import type {
6
6
  } from "../../types/config";
7
7
 
8
8
  export const DEFAULT_CONTEXT_WINDOW_TOKENS = 200_000;
9
- export const DEFAULT_THRESHOLD_RATIO = 0.8;
9
+ export const DEFAULT_THRESHOLD_RATIO = 0.95;
10
10
  export const DEFAULT_RESERVE_TOKENS = 16_384;
11
11
  export const DEFAULT_PRESERVE_RECENT_TOKENS = 20_000;
12
12
  export const DEFAULT_SUMMARY_MAX_OUTPUT_TOKENS = 1_024;
@@ -363,16 +363,22 @@ describe("createContextCompactionPrepareTurn", () => {
363
363
  );
364
364
  expect(result?.messages).toBeDefined();
365
365
  expect(result?.messages.length).toBeGreaterThan(0);
366
- expect(
367
- result?.messages.every((message) => typeof message.content === "string"),
368
- ).toBe(true);
369
- expect(
370
- result?.messages.some((message) =>
371
- typeof message.content === "string"
372
- ? message.content.includes("tool output that should be removed")
373
- : false,
374
- ),
375
- ).toBe(false);
366
+ // Compacted messages should not contain tool_result content that was pruned.
367
+ for (const message of result?.messages ?? []) {
368
+ if (typeof message.content === "string") {
369
+ expect(message.content).not.toContain(
370
+ "tool output that should be removed",
371
+ );
372
+ } else {
373
+ for (const block of message.content) {
374
+ if (block.type === "text") {
375
+ expect(block.text).not.toContain(
376
+ "tool output that should be removed",
377
+ );
378
+ }
379
+ }
380
+ }
381
+ }
376
382
  });
377
383
 
378
384
  it("defaults to threshold ratio when reserveTokens is not configured", async () => {
@@ -185,19 +185,42 @@ export function createContextCompactionPrepareTurn(
185
185
  contextWindowTokens,
186
186
  });
187
187
 
188
- if (userCompaction?.compact) {
189
- return await userCompaction.compact(compactionContext);
188
+ const beforeMessageCount = context.messages.length;
189
+
190
+ const result = userCompaction?.compact
191
+ ? await userCompaction.compact(compactionContext)
192
+ : await runBuiltinStrategy({
193
+ context: compactionContext,
194
+ providerConfig: {
195
+ ...providerConfig,
196
+ abortSignal: context.abortSignal,
197
+ },
198
+ compaction: userCompaction,
199
+ estimateMessageTokens,
200
+ logger: config.logger,
201
+ });
202
+
203
+ if (result?.messages) {
204
+ const afterTokens = result.messages.reduce(
205
+ (total: number, message) => total + estimateMessageTokens(message),
206
+ 0,
207
+ );
208
+ config.logger?.log("Context compaction completed", {
209
+ severity: "info",
210
+ strategy: strategy,
211
+ contextWindowTokens,
212
+ inputTokens,
213
+ afterTokens,
214
+ tokensSaved: inputTokens - afterTokens,
215
+ utilizationBefore: `${((inputTokens / contextWindowTokens) * 100).toFixed(1)}%`,
216
+ utilizationAfter: `${((afterTokens / contextWindowTokens) * 100).toFixed(1)}%`,
217
+ thresholdTrigger: `${(triggerState.thresholdRatio * 100).toFixed(1)}%`,
218
+ messagesBefore: beforeMessageCount,
219
+ messagesAfter: result.messages.length,
220
+ messagesRemoved: beforeMessageCount - result.messages.length,
221
+ } as Record<string, unknown>);
190
222
  }
191
223
 
192
- return await runBuiltinStrategy({
193
- context: compactionContext,
194
- providerConfig: {
195
- ...providerConfig,
196
- abortSignal: context.abortSignal,
197
- },
198
- compaction: userCompaction,
199
- estimateMessageTokens,
200
- logger: config.logger,
201
- });
224
+ return result;
202
225
  };
203
226
  }
@@ -922,7 +922,7 @@ describe("listLocalProviders", () => {
922
922
  ).toBe(true);
923
923
  });
924
924
 
925
- it("uses the same built-in model list for cline as vercel-ai-gateway", async () => {
925
+ it("uses the same built-in model list for cline as openrouter", async () => {
926
926
  manager.saveProviderSettings(
927
927
  {
928
928
  provider: "cline",
@@ -935,12 +935,12 @@ describe("listLocalProviders", () => {
935
935
 
936
936
  const { providers } = await listLocalProviders(manager);
937
937
  const cline = providers.find((provider) => provider.id === "cline");
938
- const gateway = providers.find(
939
- (provider) => provider.id === "vercel-ai-gateway",
938
+ const openrouter = providers.find(
939
+ (provider) => provider.id === "openrouter",
940
940
  );
941
941
 
942
942
  expect(cline?.modelList?.length).toBeGreaterThan(0);
943
- expect(cline?.modelList).toEqual(gateway?.modelList);
943
+ expect(cline?.modelList).toEqual(openrouter?.modelList);
944
944
  });
945
945
 
946
946
  it("does not eagerly fetch LiteLLM private models while listing providers", async () => {
@@ -234,7 +234,15 @@ export function handleAgentEvent(
234
234
 
235
235
  emit({
236
236
  type: "agent_event",
237
- payload: { sessionId, event },
237
+ payload: {
238
+ sessionId,
239
+ event,
240
+ teamAgentId: overrides?.teamAgentId,
241
+ teamRole:
242
+ overrides !== undefined
243
+ ? (overrides.teamRole ?? (isPrimaryAgentEvent ? "lead" : undefined))
244
+ : undefined,
245
+ },
238
246
  });
239
247
  emit({
240
248
  type: "chunk",
@@ -61,6 +61,10 @@ export type CoreSessionEvent =
61
61
  payload: {
62
62
  sessionId: string;
63
63
  event: import("@clinebot/shared").AgentEvent;
64
+ /** Identifies the named agent within the team (e.g. "educator", "assessor", "coordinator") for both lead and teammate agents */
65
+ teamAgentId?: string;
66
+ /** Whether this is the lead agent or a teammate */
67
+ teamRole?: "lead" | "teammate";
64
68
  };
65
69
  }
66
70
  | { type: "team_progress"; payload: SessionTeamProgressEvent }