beth-copilot 1.0.15 → 1.0.16

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.
Files changed (136) hide show
  1. package/README.md +197 -77
  2. package/bin/cli.js +47 -0
  3. package/dist/core/context.d.ts +171 -0
  4. package/dist/core/context.d.ts.map +1 -0
  5. package/dist/core/context.js +353 -0
  6. package/dist/core/context.js.map +1 -0
  7. package/dist/core/context.test.d.ts +8 -0
  8. package/dist/core/context.test.d.ts.map +1 -0
  9. package/dist/core/context.test.js +253 -0
  10. package/dist/core/context.test.js.map +1 -0
  11. package/dist/core/handoffs.d.ts +151 -0
  12. package/dist/core/handoffs.d.ts.map +1 -0
  13. package/dist/core/handoffs.js +220 -0
  14. package/dist/core/handoffs.js.map +1 -0
  15. package/dist/core/handoffs.test.d.ts +8 -0
  16. package/dist/core/handoffs.test.d.ts.map +1 -0
  17. package/dist/core/handoffs.test.js +231 -0
  18. package/dist/core/handoffs.test.js.map +1 -0
  19. package/dist/core/orchestrator.d.ts +246 -0
  20. package/dist/core/orchestrator.d.ts.map +1 -0
  21. package/dist/core/orchestrator.js +514 -0
  22. package/dist/core/orchestrator.js.map +1 -0
  23. package/dist/core/orchestrator.test.d.ts +8 -0
  24. package/dist/core/orchestrator.test.d.ts.map +1 -0
  25. package/dist/core/orchestrator.test.js +517 -0
  26. package/dist/core/orchestrator.test.js.map +1 -0
  27. package/dist/core/router.d.ts +102 -0
  28. package/dist/core/router.d.ts.map +1 -0
  29. package/dist/core/router.js +178 -0
  30. package/dist/core/router.js.map +1 -0
  31. package/dist/core/router.test.d.ts +8 -0
  32. package/dist/core/router.test.d.ts.map +1 -0
  33. package/dist/core/router.test.js +215 -0
  34. package/dist/core/router.test.js.map +1 -0
  35. package/dist/index.d.ts +9 -0
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +7 -0
  38. package/dist/index.js.map +1 -1
  39. package/dist/tools/cli/beads.d.ts +27 -0
  40. package/dist/tools/cli/beads.d.ts.map +1 -0
  41. package/dist/tools/cli/beads.js +172 -0
  42. package/dist/tools/cli/beads.js.map +1 -0
  43. package/dist/tools/cli/beads.test.d.ts +8 -0
  44. package/dist/tools/cli/beads.test.d.ts.map +1 -0
  45. package/dist/tools/cli/beads.test.js +264 -0
  46. package/dist/tools/cli/beads.test.js.map +1 -0
  47. package/dist/tools/cli/editFile.d.ts +17 -0
  48. package/dist/tools/cli/editFile.d.ts.map +1 -0
  49. package/dist/tools/cli/editFile.js +125 -0
  50. package/dist/tools/cli/editFile.js.map +1 -0
  51. package/dist/tools/cli/editFile.test.d.ts +8 -0
  52. package/dist/tools/cli/editFile.test.d.ts.map +1 -0
  53. package/dist/tools/cli/editFile.test.js +177 -0
  54. package/dist/tools/cli/editFile.test.js.map +1 -0
  55. package/dist/tools/cli/readFile.d.ts +25 -0
  56. package/dist/tools/cli/readFile.d.ts.map +1 -0
  57. package/dist/tools/cli/readFile.js +118 -0
  58. package/dist/tools/cli/readFile.js.map +1 -0
  59. package/dist/tools/cli/readFile.test.d.ts +8 -0
  60. package/dist/tools/cli/readFile.test.d.ts.map +1 -0
  61. package/dist/tools/cli/readFile.test.js +194 -0
  62. package/dist/tools/cli/readFile.test.js.map +1 -0
  63. package/dist/tools/cli/search.d.ts +16 -0
  64. package/dist/tools/cli/search.d.ts.map +1 -0
  65. package/dist/tools/cli/search.js +261 -0
  66. package/dist/tools/cli/search.js.map +1 -0
  67. package/dist/tools/cli/search.test.d.ts +8 -0
  68. package/dist/tools/cli/search.test.d.ts.map +1 -0
  69. package/dist/tools/cli/search.test.js +172 -0
  70. package/dist/tools/cli/search.test.js.map +1 -0
  71. package/dist/tools/cli/subagent.d.ts +43 -0
  72. package/dist/tools/cli/subagent.d.ts.map +1 -0
  73. package/dist/tools/cli/subagent.js +99 -0
  74. package/dist/tools/cli/subagent.js.map +1 -0
  75. package/dist/tools/cli/subagent.test.d.ts +8 -0
  76. package/dist/tools/cli/subagent.test.d.ts.map +1 -0
  77. package/dist/tools/cli/subagent.test.js +190 -0
  78. package/dist/tools/cli/subagent.test.js.map +1 -0
  79. package/dist/tools/cli/terminal.d.ts +19 -0
  80. package/dist/tools/cli/terminal.d.ts.map +1 -0
  81. package/dist/tools/cli/terminal.js +164 -0
  82. package/dist/tools/cli/terminal.js.map +1 -0
  83. package/dist/tools/cli/terminal.test.d.ts +8 -0
  84. package/dist/tools/cli/terminal.test.d.ts.map +1 -0
  85. package/dist/tools/cli/terminal.test.js +161 -0
  86. package/dist/tools/cli/terminal.test.js.map +1 -0
  87. package/dist/tools/index.d.ts +25 -0
  88. package/dist/tools/index.d.ts.map +1 -0
  89. package/dist/tools/index.js +41 -0
  90. package/dist/tools/index.js.map +1 -0
  91. package/dist/tools/interface.d.ts +64 -0
  92. package/dist/tools/interface.d.ts.map +1 -0
  93. package/dist/tools/interface.js +37 -0
  94. package/dist/tools/interface.js.map +1 -0
  95. package/dist/tools/interface.test.d.ts +7 -0
  96. package/dist/tools/interface.test.d.ts.map +1 -0
  97. package/dist/tools/interface.test.js +179 -0
  98. package/dist/tools/interface.test.js.map +1 -0
  99. package/dist/tools/mcp/bridge.d.ts +48 -0
  100. package/dist/tools/mcp/bridge.d.ts.map +1 -0
  101. package/dist/tools/mcp/bridge.js +128 -0
  102. package/dist/tools/mcp/bridge.js.map +1 -0
  103. package/dist/tools/mcp/bridge.test.d.ts +8 -0
  104. package/dist/tools/mcp/bridge.test.d.ts.map +1 -0
  105. package/dist/tools/mcp/bridge.test.js +300 -0
  106. package/dist/tools/mcp/bridge.test.js.map +1 -0
  107. package/dist/tools/mcp/client.d.ts +135 -0
  108. package/dist/tools/mcp/client.d.ts.map +1 -0
  109. package/dist/tools/mcp/client.js +263 -0
  110. package/dist/tools/mcp/client.js.map +1 -0
  111. package/dist/tools/mcp/client.test.d.ts +8 -0
  112. package/dist/tools/mcp/client.test.d.ts.map +1 -0
  113. package/dist/tools/mcp/client.test.js +390 -0
  114. package/dist/tools/mcp/client.test.js.map +1 -0
  115. package/dist/tools/registry.d.ts +82 -0
  116. package/dist/tools/registry.d.ts.map +1 -0
  117. package/dist/tools/registry.js +99 -0
  118. package/dist/tools/registry.js.map +1 -0
  119. package/dist/tools/registry.test.d.ts +7 -0
  120. package/dist/tools/registry.test.d.ts.map +1 -0
  121. package/dist/tools/registry.test.js +199 -0
  122. package/dist/tools/registry.test.js.map +1 -0
  123. package/dist/tools/suite.test.d.ts +11 -0
  124. package/dist/tools/suite.test.d.ts.map +1 -0
  125. package/dist/tools/suite.test.js +119 -0
  126. package/dist/tools/suite.test.js.map +1 -0
  127. package/dist/tools/types.d.ts +75 -0
  128. package/dist/tools/types.d.ts.map +1 -0
  129. package/dist/tools/types.js +30 -0
  130. package/dist/tools/types.js.map +1 -0
  131. package/dist/tools/types.test.d.ts +7 -0
  132. package/dist/tools/types.test.d.ts.map +1 -0
  133. package/dist/tools/types.test.js +178 -0
  134. package/dist/tools/types.test.js.map +1 -0
  135. package/package.json +2 -2
  136. package/sbom.json +209 -209
@@ -0,0 +1,353 @@
1
+ /**
2
+ * Conversation Context Manager
3
+ *
4
+ * Manages conversation state for agent interactions:
5
+ * - Message history with role tracking
6
+ * - Context window management (token estimation + truncation)
7
+ * - System prompt construction from agent definitions + skills
8
+ * - Skill injection when trigger phrases match user input
9
+ *
10
+ * Each agent session gets its own ConversationContext. When handoffs occur,
11
+ * a summary can be extracted and injected into the new agent's context.
12
+ */
13
+ // =============================================================================
14
+ // Configuration
15
+ // =============================================================================
16
+ /** Default context window size in estimated tokens */
17
+ const DEFAULT_MAX_TOKENS = 128_000;
18
+ /** Reserve tokens for the model's response */
19
+ const DEFAULT_RESPONSE_RESERVE = 4_096;
20
+ /** Approximate characters per token (GPT-family heuristic) */
21
+ const CHARS_PER_TOKEN = 4;
22
+ // =============================================================================
23
+ // ConversationContext
24
+ // =============================================================================
25
+ /**
26
+ * Manages conversation state for a single agent session.
27
+ *
28
+ * Handles message accumulation, context window enforcement,
29
+ * and system prompt construction from agent definitions and skills.
30
+ *
31
+ * @example
32
+ * ```typescript
33
+ * const ctx = new ConversationContext(developerAgent);
34
+ * ctx.addUserMessage('Implement the login page');
35
+ *
36
+ * const messages = ctx.getMessages(); // system + user message
37
+ * // Send to LLM...
38
+ *
39
+ * ctx.addAssistantMessage('I\'ll create the login component...');
40
+ * ctx.addAssistantToolCalls([{ id: '1', type: 'function', function: { name: 'editFile', arguments: '...' } }]);
41
+ * ctx.addToolResult('1', 'File updated successfully');
42
+ * ```
43
+ */
44
+ export class ConversationContext {
45
+ /** The agent this context belongs to */
46
+ agent;
47
+ /** Conversation messages (excluding system prompt; it's built dynamically) */
48
+ messages = [];
49
+ /** Skills injected into this context */
50
+ injectedSkills = new Set();
51
+ /** Skill content appended to system prompt */
52
+ skillContent = [];
53
+ /** Context window configuration */
54
+ maxTokens;
55
+ responseReserve;
56
+ /** Custom context additions (handoff summaries, etc.) */
57
+ additionalContext = [];
58
+ constructor(agent, options) {
59
+ this.agent = agent;
60
+ this.maxTokens = options?.maxTokens ?? DEFAULT_MAX_TOKENS;
61
+ this.responseReserve = options?.responseReserve ?? DEFAULT_RESPONSE_RESERVE;
62
+ if (options?.initialMessages) {
63
+ this.messages = [...options.initialMessages];
64
+ }
65
+ }
66
+ // ===========================================================================
67
+ // Message Management
68
+ // ===========================================================================
69
+ /**
70
+ * Add a user message to the conversation.
71
+ */
72
+ addUserMessage(content) {
73
+ this.messages.push({ role: 'user', content });
74
+ }
75
+ /**
76
+ * Add an assistant text response to the conversation.
77
+ */
78
+ addAssistantMessage(content) {
79
+ this.messages.push({ role: 'assistant', content });
80
+ }
81
+ /**
82
+ * Add an assistant message with tool calls.
83
+ */
84
+ addAssistantToolCalls(toolCalls, content) {
85
+ this.messages.push({
86
+ role: 'assistant',
87
+ content: content ?? '',
88
+ tool_calls: toolCalls,
89
+ });
90
+ }
91
+ /**
92
+ * Add a tool result message.
93
+ */
94
+ addToolResult(toolCallId, result) {
95
+ this.messages.push({
96
+ role: 'tool',
97
+ content: result,
98
+ tool_call_id: toolCallId,
99
+ });
100
+ }
101
+ /**
102
+ * Get the full message array for sending to the LLM.
103
+ * Includes the constructed system prompt as the first message.
104
+ * Applies truncation if context window is exceeded.
105
+ */
106
+ getMessages() {
107
+ const systemPrompt = this.buildSystemPrompt();
108
+ const systemMessage = { role: 'system', content: systemPrompt };
109
+ const systemTokens = this.estimateTokens(systemPrompt);
110
+ const availableTokens = this.maxTokens - this.responseReserve - systemTokens;
111
+ const truncated = this.truncateMessages(this.messages, availableTokens);
112
+ return [systemMessage, ...truncated];
113
+ }
114
+ /**
115
+ * Get just the conversation messages (without system prompt).
116
+ */
117
+ getRawMessages() {
118
+ return [...this.messages];
119
+ }
120
+ /**
121
+ * Get the number of conversation turns (user messages).
122
+ */
123
+ getTurnCount() {
124
+ return this.messages.filter((m) => m.role === 'user').length;
125
+ }
126
+ /**
127
+ * Get estimated token count for the current context.
128
+ */
129
+ getEstimatedTokens() {
130
+ const systemPrompt = this.buildSystemPrompt();
131
+ const systemTokens = this.estimateTokens(systemPrompt);
132
+ const messageTokens = this.messages.reduce((sum, m) => sum + this.estimateMessageTokens(m), 0);
133
+ return systemTokens + messageTokens;
134
+ }
135
+ /**
136
+ * Clear the conversation history, keeping injected skills.
137
+ */
138
+ clearHistory() {
139
+ this.messages = [];
140
+ }
141
+ // ===========================================================================
142
+ // Skill Injection
143
+ // ===========================================================================
144
+ /**
145
+ * Inject a skill's content into the system prompt.
146
+ * Each skill is only injected once per context.
147
+ *
148
+ * @param skill - The skill to inject
149
+ * @returns true if the skill was injected, false if already present
150
+ */
151
+ injectSkill(skill) {
152
+ if (this.injectedSkills.has(skill.id)) {
153
+ return false;
154
+ }
155
+ this.injectedSkills.add(skill.id);
156
+ this.skillContent.push(`\n\n---\n## Skill: ${skill.frontmatter.name}\n\n${skill.body}`);
157
+ return true;
158
+ }
159
+ /**
160
+ * Check if a skill has been injected.
161
+ */
162
+ hasSkill(skillId) {
163
+ return this.injectedSkills.has(skillId);
164
+ }
165
+ /**
166
+ * Get the IDs of all injected skills.
167
+ */
168
+ getInjectedSkillIds() {
169
+ return [...this.injectedSkills];
170
+ }
171
+ // ===========================================================================
172
+ // Context Additions
173
+ // ===========================================================================
174
+ /**
175
+ * Add additional context (e.g., handoff summary from previous agent).
176
+ */
177
+ addContext(context) {
178
+ this.additionalContext.push(context);
179
+ }
180
+ // ===========================================================================
181
+ // Summary / Handoff
182
+ // ===========================================================================
183
+ /**
184
+ * Generate a summary of this conversation for handoff purposes.
185
+ */
186
+ getSummary() {
187
+ const toolCallSummary = [];
188
+ for (const msg of this.messages) {
189
+ if (msg.tool_calls) {
190
+ for (const tc of msg.tool_calls) {
191
+ toolCallSummary.push(`${tc.function.name}(${tc.function.arguments.slice(0, 100)})`);
192
+ }
193
+ }
194
+ }
195
+ // Build summary from the last few assistant messages
196
+ const assistantMessages = this.messages
197
+ .filter((m) => m.role === 'assistant' && m.content.length > 0)
198
+ .slice(-3);
199
+ const summaryText = assistantMessages.length > 0
200
+ ? assistantMessages.map((m) => m.content.slice(0, 200)).join('\n')
201
+ : 'No assistant responses yet.';
202
+ return {
203
+ agentId: this.agent.id,
204
+ summary: summaryText,
205
+ turnCount: this.getTurnCount(),
206
+ toolCallSummary,
207
+ };
208
+ }
209
+ /**
210
+ * Get the agent definition this context belongs to.
211
+ */
212
+ getAgent() {
213
+ return this.agent;
214
+ }
215
+ // ===========================================================================
216
+ // System Prompt Construction
217
+ // ===========================================================================
218
+ /**
219
+ * Build the full system prompt from the agent definition + injected content.
220
+ */
221
+ buildSystemPrompt() {
222
+ const parts = [];
223
+ // 1. Agent's body (main system prompt from .agent.md)
224
+ if (this.agent.body) {
225
+ parts.push(this.agent.body);
226
+ }
227
+ // 2. Additional context (handoff summaries, etc.)
228
+ if (this.additionalContext.length > 0) {
229
+ parts.push('\n\n---\n## Additional Context\n');
230
+ parts.push(this.additionalContext.join('\n\n'));
231
+ }
232
+ // 3. Injected skills
233
+ if (this.skillContent.length > 0) {
234
+ parts.push(this.skillContent.join(''));
235
+ }
236
+ return parts.join('\n');
237
+ }
238
+ // ===========================================================================
239
+ // Token Estimation & Truncation
240
+ // ===========================================================================
241
+ /**
242
+ * Estimate token count for a string.
243
+ */
244
+ estimateTokens(text) {
245
+ return Math.ceil(text.length / CHARS_PER_TOKEN);
246
+ }
247
+ /**
248
+ * Estimate token count for a single message including structure overhead.
249
+ */
250
+ estimateMessageTokens(message) {
251
+ let chars = message.content.length;
252
+ // Role + formatting overhead
253
+ chars += message.role.length + 4;
254
+ if (message.name) {
255
+ chars += message.name.length + 2;
256
+ }
257
+ if (message.tool_call_id) {
258
+ chars += message.tool_call_id.length + 4;
259
+ }
260
+ if (message.tool_calls) {
261
+ for (const tc of message.tool_calls) {
262
+ chars += tc.function.name.length;
263
+ chars += tc.function.arguments.length;
264
+ chars += 20; // Structure overhead
265
+ }
266
+ }
267
+ return Math.ceil(chars / CHARS_PER_TOKEN);
268
+ }
269
+ /**
270
+ * Truncate messages to fit within the token budget.
271
+ *
272
+ * Strategy: Keep the most recent messages. Drop oldest messages first,
273
+ * but never drop tool results that are paired with a tool call in the
274
+ * retained messages (to avoid orphaned tool call references).
275
+ *
276
+ * @param messages - Messages to truncate
277
+ * @param maxTokens - Maximum tokens available
278
+ * @returns Truncated message array
279
+ */
280
+ truncateMessages(messages, maxTokens) {
281
+ if (maxTokens <= 0) {
282
+ return [];
283
+ }
284
+ // Calculate total tokens
285
+ let totalTokens = 0;
286
+ const tokenCounts = messages.map((m) => {
287
+ const count = this.estimateMessageTokens(m);
288
+ totalTokens += count;
289
+ return count;
290
+ });
291
+ // If within budget, return all messages
292
+ if (totalTokens <= maxTokens) {
293
+ return [...messages];
294
+ }
295
+ // Drop oldest messages until we fit
296
+ // Work from the beginning, marking messages for removal
297
+ let tokensToRemove = totalTokens - maxTokens;
298
+ const keep = new Array(messages.length).fill(true);
299
+ for (let i = 0; i < messages.length && tokensToRemove > 0; i++) {
300
+ // Never drop the very last user message (the current request)
301
+ if (i === messages.length - 1 && messages[i].role === 'user') {
302
+ break;
303
+ }
304
+ keep[i] = false;
305
+ tokensToRemove -= tokenCounts[i];
306
+ }
307
+ // Collect kept messages
308
+ const result = [];
309
+ for (let i = 0; i < messages.length; i++) {
310
+ if (keep[i]) {
311
+ result.push(messages[i]);
312
+ }
313
+ }
314
+ // Validate tool call consistency: ensure no orphaned tool results
315
+ return this.repairToolCallConsistency(result);
316
+ }
317
+ /**
318
+ * Remove orphaned tool results (where the corresponding assistant
319
+ * tool_calls message was truncated) and orphaned tool calls
320
+ * (where the results were truncated).
321
+ */
322
+ repairToolCallConsistency(messages) {
323
+ // Collect all tool call IDs from assistant messages
324
+ const toolCallIds = new Set();
325
+ for (const msg of messages) {
326
+ if (msg.role === 'assistant' && msg.tool_calls) {
327
+ for (const tc of msg.tool_calls) {
328
+ toolCallIds.add(tc.id);
329
+ }
330
+ }
331
+ }
332
+ // Collect all tool result IDs
333
+ const toolResultIds = new Set();
334
+ for (const msg of messages) {
335
+ if (msg.role === 'tool' && msg.tool_call_id) {
336
+ toolResultIds.add(msg.tool_call_id);
337
+ }
338
+ }
339
+ // Remove tool results without matching tool calls
340
+ // Remove tool call messages where NONE of their calls have results
341
+ return messages.filter((msg) => {
342
+ if (msg.role === 'tool' && msg.tool_call_id) {
343
+ return toolCallIds.has(msg.tool_call_id);
344
+ }
345
+ if (msg.role === 'assistant' && msg.tool_calls && msg.tool_calls.length > 0) {
346
+ // Keep if at least one tool call has a matching result
347
+ return msg.tool_calls.some((tc) => toolResultIds.has(tc.id));
348
+ }
349
+ return true;
350
+ });
351
+ }
352
+ }
353
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/core/context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * ConversationContext Tests
3
+ *
4
+ * Tests for conversation state management, message handling,
5
+ * context window enforcement, skill injection, and handoff summaries.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=context.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.test.d.ts","sourceRoot":"","sources":["../../src/core/context.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,253 @@
1
+ /**
2
+ * ConversationContext Tests
3
+ *
4
+ * Tests for conversation state management, message handling,
5
+ * context window enforcement, skill injection, and handoff summaries.
6
+ */
7
+ import { describe, it } from 'node:test';
8
+ import assert from 'node:assert';
9
+ import { ConversationContext } from './context.js';
10
+ // =============================================================================
11
+ // Test Fixtures
12
+ // =============================================================================
13
+ function createTestAgent(overrides) {
14
+ return {
15
+ id: 'test-agent',
16
+ frontmatter: {
17
+ name: 'Test Agent',
18
+ description: 'A test agent',
19
+ tools: ['readFile', 'editFiles'],
20
+ },
21
+ body: '# Test Agent\n\nYou are a helpful test agent.',
22
+ sourcePath: '/test/test-agent.agent.md',
23
+ ...overrides,
24
+ };
25
+ }
26
+ function createTestSkill(id, name, body) {
27
+ return {
28
+ id,
29
+ frontmatter: { name },
30
+ body,
31
+ sourcePath: `/test/skills/${id}/SKILL.md`,
32
+ triggers: [`${id} trigger`],
33
+ };
34
+ }
35
+ // =============================================================================
36
+ // Tests
37
+ // =============================================================================
38
+ describe('ConversationContext', () => {
39
+ describe('Construction', () => {
40
+ it('should create with default options', () => {
41
+ const agent = createTestAgent();
42
+ const ctx = new ConversationContext(agent);
43
+ assert.strictEqual(ctx.getTurnCount(), 0);
44
+ assert.strictEqual(ctx.getRawMessages().length, 0);
45
+ assert.deepStrictEqual(ctx.getInjectedSkillIds(), []);
46
+ });
47
+ it('should create with initial messages', () => {
48
+ const agent = createTestAgent();
49
+ const initial = [
50
+ { role: 'user', content: 'Hello' },
51
+ { role: 'assistant', content: 'Hi there' },
52
+ ];
53
+ const ctx = new ConversationContext(agent, { initialMessages: initial });
54
+ assert.strictEqual(ctx.getRawMessages().length, 2);
55
+ assert.strictEqual(ctx.getTurnCount(), 1);
56
+ });
57
+ it('should store the agent definition', () => {
58
+ const agent = createTestAgent({ id: 'my-agent' });
59
+ const ctx = new ConversationContext(agent);
60
+ assert.strictEqual(ctx.getAgent().id, 'my-agent');
61
+ });
62
+ });
63
+ describe('Message Management', () => {
64
+ it('should add user messages', () => {
65
+ const ctx = new ConversationContext(createTestAgent());
66
+ ctx.addUserMessage('Hello');
67
+ ctx.addUserMessage('How are you?');
68
+ assert.strictEqual(ctx.getTurnCount(), 2);
69
+ assert.strictEqual(ctx.getRawMessages().length, 2);
70
+ assert.strictEqual(ctx.getRawMessages()[0].role, 'user');
71
+ assert.strictEqual(ctx.getRawMessages()[0].content, 'Hello');
72
+ });
73
+ it('should add assistant messages', () => {
74
+ const ctx = new ConversationContext(createTestAgent());
75
+ ctx.addUserMessage('Hello');
76
+ ctx.addAssistantMessage('Hi there');
77
+ const msgs = ctx.getRawMessages();
78
+ assert.strictEqual(msgs.length, 2);
79
+ assert.strictEqual(msgs[1].role, 'assistant');
80
+ assert.strictEqual(msgs[1].content, 'Hi there');
81
+ });
82
+ it('should add assistant tool calls', () => {
83
+ const ctx = new ConversationContext(createTestAgent());
84
+ ctx.addUserMessage('Read my file');
85
+ ctx.addAssistantToolCalls([{ id: 'tc1', type: 'function', function: { name: 'readFile', arguments: '{"path":"test.ts"}' } }], 'Let me read that file.');
86
+ const msgs = ctx.getRawMessages();
87
+ assert.strictEqual(msgs.length, 2);
88
+ assert.strictEqual(msgs[1].role, 'assistant');
89
+ assert.strictEqual(msgs[1].tool_calls?.length, 1);
90
+ assert.strictEqual(msgs[1].tool_calls[0].function.name, 'readFile');
91
+ assert.strictEqual(msgs[1].content, 'Let me read that file.');
92
+ });
93
+ it('should add tool results', () => {
94
+ const ctx = new ConversationContext(createTestAgent());
95
+ ctx.addUserMessage('Read my file');
96
+ ctx.addAssistantToolCalls([{ id: 'tc1', type: 'function', function: { name: 'readFile', arguments: '{}' } }]);
97
+ ctx.addToolResult('tc1', 'File contents here');
98
+ const msgs = ctx.getRawMessages();
99
+ assert.strictEqual(msgs.length, 3);
100
+ assert.strictEqual(msgs[2].role, 'tool');
101
+ assert.strictEqual(msgs[2].tool_call_id, 'tc1');
102
+ assert.strictEqual(msgs[2].content, 'File contents here');
103
+ });
104
+ it('should clear history', () => {
105
+ const ctx = new ConversationContext(createTestAgent());
106
+ ctx.addUserMessage('Hello');
107
+ ctx.addAssistantMessage('Hi');
108
+ ctx.clearHistory();
109
+ assert.strictEqual(ctx.getTurnCount(), 0);
110
+ assert.strictEqual(ctx.getRawMessages().length, 0);
111
+ });
112
+ });
113
+ describe('System Prompt Construction', () => {
114
+ it('should include agent body in system prompt', () => {
115
+ const agent = createTestAgent({ body: '# My Agent\n\nSpecial instructions.' });
116
+ const ctx = new ConversationContext(agent);
117
+ const prompt = ctx.buildSystemPrompt();
118
+ assert.ok(prompt.includes('# My Agent'));
119
+ assert.ok(prompt.includes('Special instructions.'));
120
+ });
121
+ it('should include additional context in system prompt', () => {
122
+ const ctx = new ConversationContext(createTestAgent());
123
+ ctx.addContext('Previous agent completed the design phase.');
124
+ const prompt = ctx.buildSystemPrompt();
125
+ assert.ok(prompt.includes('Additional Context'));
126
+ assert.ok(prompt.includes('Previous agent completed the design phase.'));
127
+ });
128
+ it('should include injected skills in system prompt', () => {
129
+ const ctx = new ConversationContext(createTestAgent());
130
+ const skill = createTestSkill('prd', 'PRD Generation', 'Generate product requirements.');
131
+ ctx.injectSkill(skill);
132
+ const prompt = ctx.buildSystemPrompt();
133
+ assert.ok(prompt.includes('Skill: PRD Generation'));
134
+ assert.ok(prompt.includes('Generate product requirements.'));
135
+ });
136
+ it('getMessages should prepend system prompt', () => {
137
+ const ctx = new ConversationContext(createTestAgent());
138
+ ctx.addUserMessage('Hello');
139
+ const msgs = ctx.getMessages();
140
+ assert.strictEqual(msgs.length, 2);
141
+ assert.strictEqual(msgs[0].role, 'system');
142
+ assert.ok(msgs[0].content.includes('Test Agent'));
143
+ assert.strictEqual(msgs[1].role, 'user');
144
+ });
145
+ });
146
+ describe('Skill Injection', () => {
147
+ it('should inject a skill once', () => {
148
+ const ctx = new ConversationContext(createTestAgent());
149
+ const skill = createTestSkill('prd', 'PRD', 'PRD content');
150
+ const first = ctx.injectSkill(skill);
151
+ const second = ctx.injectSkill(skill);
152
+ assert.strictEqual(first, true);
153
+ assert.strictEqual(second, false);
154
+ });
155
+ it('should track injected skill IDs', () => {
156
+ const ctx = new ConversationContext(createTestAgent());
157
+ ctx.injectSkill(createTestSkill('prd', 'PRD', 'content'));
158
+ ctx.injectSkill(createTestSkill('shadcn', 'shadcn', 'content'));
159
+ const ids = ctx.getInjectedSkillIds();
160
+ assert.deepStrictEqual(ids.sort(), ['prd', 'shadcn']);
161
+ });
162
+ it('should check if a skill is injected', () => {
163
+ const ctx = new ConversationContext(createTestAgent());
164
+ ctx.injectSkill(createTestSkill('prd', 'PRD', 'content'));
165
+ assert.strictEqual(ctx.hasSkill('prd'), true);
166
+ assert.strictEqual(ctx.hasSkill('other'), false);
167
+ });
168
+ });
169
+ describe('Token Estimation', () => {
170
+ it('should estimate tokens for context', () => {
171
+ const ctx = new ConversationContext(createTestAgent());
172
+ ctx.addUserMessage('Hello world');
173
+ const tokens = ctx.getEstimatedTokens();
174
+ assert.ok(tokens > 0);
175
+ });
176
+ it('should increase count with more messages', () => {
177
+ const ctx = new ConversationContext(createTestAgent());
178
+ ctx.addUserMessage('Hello');
179
+ const tokensSmall = ctx.getEstimatedTokens();
180
+ ctx.addAssistantMessage('I am a very helpful assistant with a lot to say about this topic.');
181
+ ctx.addUserMessage('Tell me more about something else.');
182
+ const tokensLarge = ctx.getEstimatedTokens();
183
+ assert.ok(tokensLarge > tokensSmall);
184
+ });
185
+ });
186
+ describe('Context Window Truncation', () => {
187
+ it('should truncate old messages when exceeding context window', () => {
188
+ const agent = createTestAgent({ body: 'Short prompt.' });
189
+ const ctx = new ConversationContext(agent, {
190
+ maxTokens: 200, // Very small context window
191
+ responseReserve: 50,
192
+ });
193
+ // Add many messages
194
+ for (let i = 0; i < 20; i++) {
195
+ ctx.addUserMessage(`Message number ${i} with some extra content to fill tokens.`);
196
+ ctx.addAssistantMessage(`Response number ${i} with some extra content as well.`);
197
+ }
198
+ const msgs = ctx.getMessages();
199
+ // Should be truncated — fewer messages than what we added
200
+ assert.ok(msgs.length < 41); // 40 user+assistant + 1 system
201
+ assert.strictEqual(msgs[0].role, 'system');
202
+ });
203
+ it('should return all messages when within context window', () => {
204
+ const ctx = new ConversationContext(createTestAgent());
205
+ ctx.addUserMessage('Hello');
206
+ ctx.addAssistantMessage('Hi');
207
+ const msgs = ctx.getMessages();
208
+ assert.strictEqual(msgs.length, 3); // system + user + assistant
209
+ });
210
+ });
211
+ describe('Tool Call Consistency Repair', () => {
212
+ it('should handle normal tool call flow without issues', () => {
213
+ const ctx = new ConversationContext(createTestAgent());
214
+ ctx.addUserMessage('Read file');
215
+ ctx.addAssistantToolCalls([{ id: 'tc1', type: 'function', function: { name: 'readFile', arguments: '{}' } }]);
216
+ ctx.addToolResult('tc1', 'file contents');
217
+ ctx.addAssistantMessage('Here are the contents.');
218
+ const msgs = ctx.getMessages();
219
+ // system + user + assistant(tool_calls) + tool + assistant
220
+ assert.strictEqual(msgs.length, 5);
221
+ });
222
+ });
223
+ describe('Conversation Summary', () => {
224
+ it('should generate a summary', () => {
225
+ const ctx = new ConversationContext(createTestAgent({ id: 'developer' }));
226
+ ctx.addUserMessage('Implement login');
227
+ ctx.addAssistantMessage('I will create the login component.');
228
+ ctx.addUserMessage('Include remember me');
229
+ ctx.addAssistantMessage('Added remember me checkbox.');
230
+ const summary = ctx.getSummary();
231
+ assert.strictEqual(summary.agentId, 'developer');
232
+ assert.strictEqual(summary.turnCount, 2);
233
+ assert.ok(summary.summary.includes('login component'));
234
+ });
235
+ it('should include tool call summary', () => {
236
+ const ctx = new ConversationContext(createTestAgent());
237
+ ctx.addUserMessage('Edit file');
238
+ ctx.addAssistantToolCalls([{ id: 'tc1', type: 'function', function: { name: 'editFile', arguments: '{"path":"a.ts"}' } }]);
239
+ ctx.addToolResult('tc1', 'OK');
240
+ ctx.addAssistantMessage('Done.');
241
+ const summary = ctx.getSummary();
242
+ assert.ok(summary.toolCallSummary.length > 0);
243
+ assert.ok(summary.toolCallSummary[0].includes('editFile'));
244
+ });
245
+ it('should handle empty conversation', () => {
246
+ const ctx = new ConversationContext(createTestAgent());
247
+ const summary = ctx.getSummary();
248
+ assert.strictEqual(summary.turnCount, 0);
249
+ assert.ok(summary.summary.includes('No assistant responses'));
250
+ });
251
+ });
252
+ });
253
+ //# sourceMappingURL=context.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.test.js","sourceRoot":"","sources":["../../src/core/context.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAKnD,gFAAgF;AAChF,gBAAgB;AAChB,gFAAgF;AAEhF,SAAS,eAAe,CAAC,SAAoC;IAC3D,OAAO;QACL,EAAE,EAAE,YAAY;QAChB,WAAW,EAAE;YACX,IAAI,EAAE,YAAY;YAClB,WAAW,EAAE,cAAc;YAC3B,KAAK,EAAE,CAAC,UAAU,EAAE,WAAW,CAAC;SACjC;QACD,IAAI,EAAE,+CAA+C;QACrD,UAAU,EAAE,2BAA2B;QACvC,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,EAAU,EAAE,IAAY,EAAE,IAAY;IAC7D,OAAO;QACL,EAAE;QACF,WAAW,EAAE,EAAE,IAAI,EAAE;QACrB,IAAI;QACJ,UAAU,EAAE,gBAAgB,EAAE,WAAW;QACzC,QAAQ,EAAE,CAAC,GAAG,EAAE,UAAU,CAAC;KAC5B,CAAC;AACJ,CAAC;AAED,gFAAgF;AAChF,QAAQ;AACR,gFAAgF;AAEhF,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;QAC5B,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;YAC5C,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC;YAChC,MAAM,GAAG,GAAG,IAAI,mBAAmB,CAAC,KAAK,CAAC,CAAC;YAE3C,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,CAAC;YAC1C,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YACnD,MAAM,CAAC,eAAe,CAAC,GAAG,CAAC,mBAAmB,EAAE,EAAE,EAAE,CAAC,CAAC;QACxD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;YAC7C,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC;YAChC,MAAM,OAAO,GAAkB;gBAC7B,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE;gBAClC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,UAAU,EAAE;aAC3C,CAAC;YAEF,MAAM,GAAG,GAAG,IAAI,mBAAmB,CAAC,KAAK,EAAE,EAAE,eAAe,EAAE,OAAO,EAAE,CAAC,CAAC;YAEzE,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YACnD,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;YAC3C,MAAM,KAAK,GAAG,eAAe,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;YAClD,MAAM,GAAG,GAAG,IAAI,mBAAmB,CAAC,KAAK,CAAC,CAAC;YAE3C,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;QACpD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;QAClC,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;YAClC,MAAM,GAAG,GAAG,IAAI,mBAAmB,CAAC,eAAe,EAAE,CAAC,CAAC;YAEvD,GAAG,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;YAC5B,GAAG,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC;YAEnC,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,CAAC;YAC1C,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YACnD,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YACzD,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC/D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;YACvC,MAAM,GAAG,GAAG,IAAI,mBAAmB,CAAC,eAAe,EAAE,CAAC,CAAC;YAEvD,GAAG,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;YAC5B,GAAG,CAAC,mBAAmB,CAAC,UAAU,CAAC,CAAC;YAEpC,MAAM,IAAI,GAAG,GAAG,CAAC,cAAc,EAAE,CAAC;YAClC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YACnC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;YAC9C,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;QAClD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;YACzC,MAAM,GAAG,GAAG,IAAI,mBAAmB,CAAC,eAAe,EAAE,CAAC,CAAC;YAEvD,GAAG,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC;YACnC,GAAG,CAAC,qBAAqB,CACvB,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,oBAAoB,EAAE,EAAE,CAAC,EAClG,wBAAwB,CACzB,CAAC;YAEF,MAAM,IAAI,GAAG,GAAG,CAAC,cAAc,EAAE,CAAC;YAClC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YACnC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;YAC9C,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;YAClD,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,UAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;YACrE,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,wBAAwB,CAAC,CAAC;QAChE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yBAAyB,EAAE,GAAG,EAAE;YACjC,MAAM,GAAG,GAAG,IAAI,mBAAmB,CAAC,eAAe,EAAE,CAAC,CAAC;YAEvD,GAAG,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC;YACnC,GAAG,CAAC,qBAAqB,CACvB,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC,CACnF,CAAC;YACF,GAAG,CAAC,aAAa,CAAC,KAAK,EAAE,oBAAoB,CAAC,CAAC;YAE/C,MAAM,IAAI,GAAG,GAAG,CAAC,cAAc,EAAE,CAAC;YAClC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YACnC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YACzC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;YAChD,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,oBAAoB,CAAC,CAAC;QAC5D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sBAAsB,EAAE,GAAG,EAAE;YAC9B,MAAM,GAAG,GAAG,IAAI,mBAAmB,CAAC,eAAe,EAAE,CAAC,CAAC;YAEvD,GAAG,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;YAC5B,GAAG,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC;YAC9B,GAAG,CAAC,YAAY,EAAE,CAAC;YAEnB,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,CAAC;YAC1C,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACrD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,4BAA4B,EAAE,GAAG,EAAE;QAC1C,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;YACpD,MAAM,KAAK,GAAG,eAAe,CAAC,EAAE,IAAI,EAAE,qCAAqC,EAAE,CAAC,CAAC;YAC/E,MAAM,GAAG,GAAG,IAAI,mBAAmB,CAAC,KAAK,CAAC,CAAC;YAE3C,MAAM,MAAM,GAAG,GAAG,CAAC,iBAAiB,EAAE,CAAC;YACvC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC;YACzC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,uBAAuB,CAAC,CAAC,CAAC;QACtD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;YAC5D,MAAM,GAAG,GAAG,IAAI,mBAAmB,CAAC,eAAe,EAAE,CAAC,CAAC;YACvD,GAAG,CAAC,UAAU,CAAC,4CAA4C,CAAC,CAAC;YAE7D,MAAM,MAAM,GAAG,GAAG,CAAC,iBAAiB,EAAE,CAAC;YACvC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC,CAAC;YACjD,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,4CAA4C,CAAC,CAAC,CAAC;QAC3E,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;YACzD,MAAM,GAAG,GAAG,IAAI,mBAAmB,CAAC,eAAe,EAAE,CAAC,CAAC;YACvD,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,EAAE,gBAAgB,EAAE,gCAAgC,CAAC,CAAC;YAEzF,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YAEvB,MAAM,MAAM,GAAG,GAAG,CAAC,iBAAiB,EAAE,CAAC;YACvC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,uBAAuB,CAAC,CAAC,CAAC;YACpD,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,gCAAgC,CAAC,CAAC,CAAC;QAC/D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;YAClD,MAAM,GAAG,GAAG,IAAI,mBAAmB,CAAC,eAAe,EAAE,CAAC,CAAC;YACvD,GAAG,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;YAE5B,MAAM,IAAI,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;YAC/B,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YACnC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YAC3C,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC;YAClD,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;QAC/B,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;YACpC,MAAM,GAAG,GAAG,IAAI,mBAAmB,CAAC,eAAe,EAAE,CAAC,CAAC;YACvD,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC;YAE3D,MAAM,KAAK,GAAG,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YACrC,MAAM,MAAM,GAAG,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YAEtC,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YAChC,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;YACzC,MAAM,GAAG,GAAG,IAAI,mBAAmB,CAAC,eAAe,EAAE,CAAC,CAAC;YAEvD,GAAG,CAAC,WAAW,CAAC,eAAe,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC;YAC1D,GAAG,CAAC,WAAW,CAAC,eAAe,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC;YAEhE,MAAM,GAAG,GAAG,GAAG,CAAC,mBAAmB,EAAE,CAAC;YACtC,MAAM,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC;QACxD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;YAC7C,MAAM,GAAG,GAAG,IAAI,mBAAmB,CAAC,eAAe,EAAE,CAAC,CAAC;YAEvD,GAAG,CAAC,WAAW,CAAC,eAAe,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC;YAE1D,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC;YAC9C,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,CAAC;QACnD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAChC,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;YAC5C,MAAM,GAAG,GAAG,IAAI,mBAAmB,CAAC,eAAe,EAAE,CAAC,CAAC;YACvD,GAAG,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;YAElC,MAAM,MAAM,GAAG,GAAG,CAAC,kBAAkB,EAAE,CAAC;YACxC,MAAM,CAAC,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACxB,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;YAClD,MAAM,GAAG,GAAG,IAAI,mBAAmB,CAAC,eAAe,EAAE,CAAC,CAAC;YACvD,GAAG,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;YAE5B,MAAM,WAAW,GAAG,GAAG,CAAC,kBAAkB,EAAE,CAAC;YAE7C,GAAG,CAAC,mBAAmB,CAAC,mEAAmE,CAAC,CAAC;YAC7F,GAAG,CAAC,cAAc,CAAC,oCAAoC,CAAC,CAAC;YAEzD,MAAM,WAAW,GAAG,GAAG,CAAC,kBAAkB,EAAE,CAAC;YAC7C,MAAM,CAAC,EAAE,CAAC,WAAW,GAAG,WAAW,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACzC,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;YACpE,MAAM,KAAK,GAAG,eAAe,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC,CAAC;YACzD,MAAM,GAAG,GAAG,IAAI,mBAAmB,CAAC,KAAK,EAAE;gBACzC,SAAS,EAAE,GAAG,EAAE,4BAA4B;gBAC5C,eAAe,EAAE,EAAE;aACpB,CAAC,CAAC;YAEH,oBAAoB;YACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC5B,GAAG,CAAC,cAAc,CAAC,kBAAkB,CAAC,0CAA0C,CAAC,CAAC;gBAClF,GAAG,CAAC,mBAAmB,CAAC,mBAAmB,CAAC,mCAAmC,CAAC,CAAC;YACnF,CAAC;YAED,MAAM,IAAI,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;YAC/B,0DAA0D;YAC1D,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,+BAA+B;YAC5D,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;YAC/D,MAAM,GAAG,GAAG,IAAI,mBAAmB,CAAC,eAAe,EAAE,CAAC,CAAC;YAEvD,GAAG,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;YAC5B,GAAG,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC;YAE9B,MAAM,IAAI,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;YAC/B,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,4BAA4B;QAClE,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,8BAA8B,EAAE,GAAG,EAAE;QAC5C,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;YAC5D,MAAM,GAAG,GAAG,IAAI,mBAAmB,CAAC,eAAe,EAAE,CAAC,CAAC;YAEvD,GAAG,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;YAChC,GAAG,CAAC,qBAAqB,CACvB,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC,CACnF,CAAC;YACF,GAAG,CAAC,aAAa,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC;YAC1C,GAAG,CAAC,mBAAmB,CAAC,wBAAwB,CAAC,CAAC;YAElD,MAAM,IAAI,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;YAC/B,2DAA2D;YAC3D,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;QACpC,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;YACnC,MAAM,GAAG,GAAG,IAAI,mBAAmB,CAAC,eAAe,CAAC,EAAE,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC;YAE1E,GAAG,CAAC,cAAc,CAAC,iBAAiB,CAAC,CAAC;YACtC,GAAG,CAAC,mBAAmB,CAAC,oCAAoC,CAAC,CAAC;YAC9D,GAAG,CAAC,cAAc,CAAC,qBAAqB,CAAC,CAAC;YAC1C,GAAG,CAAC,mBAAmB,CAAC,6BAA6B,CAAC,CAAC;YAEvD,MAAM,OAAO,GAAG,GAAG,CAAC,UAAU,EAAE,CAAC;YACjC,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;YACjD,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;YACzC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC,CAAC;QACzD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;YAC1C,MAAM,GAAG,GAAG,IAAI,mBAAmB,CAAC,eAAe,EAAE,CAAC,CAAC;YAEvD,GAAG,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;YAChC,GAAG,CAAC,qBAAqB,CACvB,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,iBAAiB,EAAE,EAAE,CAAC,CAChG,CAAC;YACF,GAAG,CAAC,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YAC/B,GAAG,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC;YAEjC,MAAM,OAAO,GAAG,GAAG,CAAC,UAAU,EAAE,CAAC;YACjC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YAC9C,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;QAC7D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;YAC1C,MAAM,GAAG,GAAG,IAAI,mBAAmB,CAAC,eAAe,EAAE,CAAC,CAAC;YAEvD,MAAM,OAAO,GAAG,GAAG,CAAC,UAAU,EAAE,CAAC;YACjC,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;YACzC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAC,CAAC,CAAC;QAChE,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}