byterover-cli 3.0.1 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/agent/core/domain/tools/constants.d.ts +1 -0
  2. package/dist/agent/core/domain/tools/constants.js +1 -0
  3. package/dist/agent/core/interfaces/cipher-services.d.ts +8 -0
  4. package/dist/agent/core/interfaces/i-cipher-agent.d.ts +1 -0
  5. package/dist/agent/infra/agent/agent-error-codes.d.ts +0 -1
  6. package/dist/agent/infra/agent/agent-error-codes.js +0 -1
  7. package/dist/agent/infra/agent/agent-error.d.ts +0 -1
  8. package/dist/agent/infra/agent/agent-error.js +0 -1
  9. package/dist/agent/infra/agent/agent-state-manager.d.ts +1 -3
  10. package/dist/agent/infra/agent/agent-state-manager.js +1 -3
  11. package/dist/agent/infra/agent/base-agent.d.ts +1 -1
  12. package/dist/agent/infra/agent/base-agent.js +1 -1
  13. package/dist/agent/infra/agent/cipher-agent.d.ts +15 -1
  14. package/dist/agent/infra/agent/cipher-agent.js +188 -3
  15. package/dist/agent/infra/agent/index.d.ts +1 -1
  16. package/dist/agent/infra/agent/index.js +1 -1
  17. package/dist/agent/infra/agent/service-initializer.d.ts +3 -3
  18. package/dist/agent/infra/agent/service-initializer.js +14 -8
  19. package/dist/agent/infra/agent/types.d.ts +0 -1
  20. package/dist/agent/infra/file-system/file-system-service.js +6 -5
  21. package/dist/agent/infra/folder-pack/folder-pack-service.d.ts +1 -0
  22. package/dist/agent/infra/folder-pack/folder-pack-service.js +29 -15
  23. package/dist/agent/infra/llm/providers/openai.js +12 -0
  24. package/dist/agent/infra/llm/stream-to-text.d.ts +7 -0
  25. package/dist/agent/infra/llm/stream-to-text.js +14 -0
  26. package/dist/agent/infra/map/abstract-generator.d.ts +22 -0
  27. package/dist/agent/infra/map/abstract-generator.js +67 -0
  28. package/dist/agent/infra/map/abstract-queue.d.ts +67 -0
  29. package/dist/agent/infra/map/abstract-queue.js +218 -0
  30. package/dist/agent/infra/memory/memory-deduplicator.d.ts +44 -0
  31. package/dist/agent/infra/memory/memory-deduplicator.js +88 -0
  32. package/dist/agent/infra/memory/memory-manager.d.ts +1 -0
  33. package/dist/agent/infra/memory/memory-manager.js +6 -5
  34. package/dist/agent/infra/sandbox/curate-service.d.ts +4 -2
  35. package/dist/agent/infra/sandbox/curate-service.js +6 -7
  36. package/dist/agent/infra/sandbox/local-sandbox.d.ts +5 -0
  37. package/dist/agent/infra/sandbox/local-sandbox.js +57 -1
  38. package/dist/agent/infra/sandbox/tools-sdk.d.ts +3 -1
  39. package/dist/agent/infra/session/session-compressor.d.ts +43 -0
  40. package/dist/agent/infra/session/session-compressor.js +296 -0
  41. package/dist/agent/infra/session/session-manager.d.ts +7 -0
  42. package/dist/agent/infra/session/session-manager.js +9 -0
  43. package/dist/agent/infra/tools/implementations/curate-tool.d.ts +3 -2
  44. package/dist/agent/infra/tools/implementations/curate-tool.js +54 -27
  45. package/dist/agent/infra/tools/implementations/expand-knowledge-tool.d.ts +3 -3
  46. package/dist/agent/infra/tools/implementations/expand-knowledge-tool.js +34 -7
  47. package/dist/agent/infra/tools/implementations/ingest-resource-tool.d.ts +17 -0
  48. package/dist/agent/infra/tools/implementations/ingest-resource-tool.js +224 -0
  49. package/dist/agent/infra/tools/implementations/memory-symbol-tree.d.ts +8 -0
  50. package/dist/agent/infra/tools/implementations/search-knowledge-service.d.ts +1 -1
  51. package/dist/agent/infra/tools/implementations/search-knowledge-service.js +207 -34
  52. package/dist/agent/infra/tools/implementations/search-knowledge-tool.js +2 -2
  53. package/dist/agent/infra/tools/tool-provider.js +1 -0
  54. package/dist/agent/infra/tools/tool-registry.d.ts +3 -0
  55. package/dist/agent/infra/tools/tool-registry.js +15 -4
  56. package/dist/server/constants.d.ts +2 -0
  57. package/dist/server/constants.js +2 -0
  58. package/dist/server/core/domain/knowledge/memory-scoring.d.ts +3 -3
  59. package/dist/server/core/domain/knowledge/memory-scoring.js +5 -5
  60. package/dist/server/core/domain/knowledge/summary-types.d.ts +4 -0
  61. package/dist/server/core/domain/transport/schemas.d.ts +10 -10
  62. package/dist/server/infra/context-tree/derived-artifact.js +5 -1
  63. package/dist/server/infra/context-tree/file-context-tree-manifest-service.d.ts +2 -1
  64. package/dist/server/infra/context-tree/file-context-tree-manifest-service.js +43 -7
  65. package/dist/server/infra/context-tree/file-context-tree-summary-service.js +20 -2
  66. package/dist/server/infra/executor/curate-executor.js +2 -1
  67. package/dist/server/infra/executor/folder-pack-executor.js +72 -2
  68. package/dist/server/infra/executor/query-executor.js +11 -3
  69. package/dist/server/infra/transport/handlers/status-handler.js +10 -0
  70. package/dist/server/utils/curate-result-parser.d.ts +4 -4
  71. package/dist/shared/transport/types/dto.d.ts +7 -0
  72. package/oclif.manifest.json +160 -160
  73. package/package.json +10 -4
@@ -9,6 +9,7 @@ export declare const ToolName: {
9
9
  readonly EXPAND_KNOWLEDGE: 'expand_knowledge';
10
10
  readonly GLOB_FILES: 'glob_files';
11
11
  readonly GREP_CONTENT: 'grep_content';
12
+ readonly INGEST_RESOURCE: 'ingest_resource';
12
13
  readonly LIST_DIRECTORY: 'list_directory';
13
14
  readonly LLM_MAP: 'llm_map';
14
15
  readonly READ_FILE: 'read_file';
@@ -9,6 +9,7 @@ export const ToolName = {
9
9
  EXPAND_KNOWLEDGE: 'expand_knowledge',
10
10
  GLOB_FILES: 'glob_files',
11
11
  GREP_CONTENT: 'grep_content',
12
+ INGEST_RESOURCE: 'ingest_resource',
12
13
  LIST_DIRECTORY: 'list_directory',
13
14
  LLM_MAP: 'llm_map',
14
15
  READ_FILE: 'read_file',
@@ -1,6 +1,7 @@
1
1
  import type { AgentEventBus, SessionEventBus } from '../../infra/events/event-emitter.js';
2
2
  import type { FileSystemService } from '../../infra/file-system/file-system-service.js';
3
3
  import type { CompactionService } from '../../infra/llm/context/compaction/compaction-service.js';
4
+ import type { AbstractGenerationQueue } from '../../infra/map/abstract-queue.js';
4
5
  import type { MemoryManager } from '../../infra/memory/memory-manager.js';
5
6
  import type { ProcessService } from '../../infra/process/process-service.js';
6
7
  import type { MessageStorageService } from '../../infra/storage/message-storage-service.js';
@@ -30,6 +31,11 @@ import type { IToolScheduler } from './i-tool-scheduler.js';
30
31
  * - ToolProvider: Provides available tools
31
32
  */
32
33
  export interface CipherAgentServices {
34
+ /**
35
+ * Background queue for generating L0/L1 abstract files (.abstract.md, .overview.md).
36
+ * Generator is injected lazily via setGenerator() from rebindCurateTools().
37
+ */
38
+ abstractQueue: AbstractGenerationQueue;
33
39
  agentEventBus: AgentEventBus;
34
40
  blobStorage: IBlobStorage;
35
41
  /**
@@ -50,6 +56,8 @@ export interface CipherAgentServices {
50
56
  toolManager: ToolManager;
51
57
  toolProvider: ToolProvider;
52
58
  toolScheduler: IToolScheduler;
59
+ /** Absolute path to the project working directory. */
60
+ workingDirectory: string;
53
61
  }
54
62
  /**
55
63
  * Session-specific services created per conversation session.
@@ -78,6 +78,7 @@ export interface ICipherAgent {
78
78
  */
79
79
  createTaskSession(taskId: string, commandType: string, options?: {
80
80
  mapRootEligible?: boolean;
81
+ userFacing?: boolean;
81
82
  }): Promise<string>;
82
83
  /**
83
84
  * Delete a sandbox variable from the agent's default session.
@@ -1,6 +1,5 @@
1
1
  /**
2
2
  * Agent-specific error codes.
3
- * Follows DextoAgent pattern for typed error identification.
4
3
  */
5
4
  export declare enum AgentErrorCode {
6
5
  ALREADY_STARTED = "agent_already_started",
@@ -1,6 +1,5 @@
1
1
  /**
2
2
  * Agent-specific error codes.
3
- * Follows DextoAgent pattern for typed error identification.
4
3
  */
5
4
  export var AgentErrorCode;
6
5
  (function (AgentErrorCode) {
@@ -4,7 +4,6 @@ import { AgentErrorCode } from './agent-error-codes.js';
4
4
  * Agent-specific error with typed error codes.
5
5
  * Extends ExitError for oclif CLI integration.
6
6
  *
7
- * Follows DextoAgent pattern with static factory methods
8
7
  * for creating well-typed errors.
9
8
  */
10
9
  export declare class AgentError extends ExitError {
@@ -4,7 +4,6 @@ import { AgentErrorCode } from './agent-error-codes.js';
4
4
  * Agent-specific error with typed error codes.
5
5
  * Extends ExitError for oclif CLI integration.
6
6
  *
7
- * Follows DextoAgent pattern with static factory methods
8
7
  * for creating well-typed errors.
9
8
  */
10
9
  export class AgentError extends ExitError {
@@ -9,11 +9,9 @@ export interface SessionOverride {
9
9
  llm?: Partial<ValidatedLLMConfig>;
10
10
  }
11
11
  /**
12
- * Unified agent state manager combining DextoAgent config patterns with execution state tracking.
13
- *
14
12
  * Manages two concerns:
15
13
  *
16
- * 1. Configuration State (DextoAgent pattern):
14
+ * 1. Configuration State:
17
15
  * - baselineConfig: Original validated config, never mutated
18
16
  * - runtimeConfig: Current active config, can be mutated
19
17
  * - sessionOverrides: Per-session config overrides
@@ -1,9 +1,7 @@
1
1
  /**
2
- * Unified agent state manager combining DextoAgent config patterns with execution state tracking.
3
- *
4
2
  * Manages two concerns:
5
3
  *
6
- * 1. Configuration State (DextoAgent pattern):
4
+ * 1. Configuration State:
7
5
  * - baselineConfig: Original validated config, never mutated
8
6
  * - runtimeConfig: Current active config, can be mutated
9
7
  * - sessionOverrides: Per-session config overrides
@@ -3,7 +3,7 @@ import type { AgentEventBus } from '../events/event-emitter.js';
3
3
  import { type LLMUpdates, type ValidatedAgentConfig, type ValidatedLLMConfig } from './agent-schemas.js';
4
4
  import { AgentStateManager } from './agent-state-manager.js';
5
5
  /**
6
- * Abstract base agent class encapsulating DextoAgent patterns.
6
+ * Abstract base agent class encapsulating.
7
7
  *
8
8
  * Provides:
9
9
  * - Two-phase initialization (constructor + start)
@@ -2,7 +2,7 @@ import { AgentError } from './agent-error.js';
2
2
  import { AgentConfigSchema, LLMUpdatesSchema } from './agent-schemas.js';
3
3
  import { AgentStateManager } from './agent-state-manager.js';
4
4
  /**
5
- * Abstract base agent class encapsulating DextoAgent patterns.
5
+ * Abstract base agent class encapsulating.
6
6
  *
7
7
  * Provides:
8
8
  * - Two-phase initialization (constructor + start)
@@ -25,7 +25,7 @@ import { BaseAgent } from './base-agent.js';
25
25
  * - Typed error handling
26
26
  * - Configuration validation (Zod)
27
27
  *
28
- * Architecture (DextoAgent pattern):
28
+ * Architecture:
29
29
  * - Agent creates AgentEventBus in constructor (available before start)
30
30
  * - Agent creates and owns shared services (ToolManager, SystemPromptManager, etc.)
31
31
  * - SessionManager creates session-specific services (LLM, SessionEventBus)
@@ -57,7 +57,11 @@ export declare class CipherAgent extends BaseAgent implements ICipherAgent {
57
57
  * Used for bulk deregistration on agent teardown (cleanupServices).
58
58
  */
59
59
  private readonly rootEligibleSessions;
60
+ /** Lazily-created session compressor, rebuilt on each rebindCurateTools() call. */
61
+ private sessionCompressor?;
60
62
  private sessionManager?;
63
+ /** Tracks user-facing task sessions for post-session memory extraction. */
64
+ private readonly userFacingTaskSessions;
61
65
  /**
62
66
  * Creates a new CipherAgent instance.
63
67
  * Does NOT initialize services - call start() for async initialization.
@@ -114,6 +118,7 @@ export declare class CipherAgent extends BaseAgent implements ICipherAgent {
114
118
  */
115
119
  createTaskSession(taskId: string, commandType: string, options?: {
116
120
  mapRootEligible?: boolean;
121
+ userFacing?: boolean;
117
122
  }): Promise<string>;
118
123
  /**
119
124
  * Delete a sandbox variable from the agent's default session.
@@ -131,6 +136,11 @@ export declare class CipherAgent extends BaseAgent implements ICipherAgent {
131
136
  * Delete a task session and all its resources (sandbox + history).
132
137
  */
133
138
  deleteTaskSession(sessionId: string): Promise<void>;
139
+ /**
140
+ * Wait for shared background work (such as abstract generation) to finish.
141
+ * Used by task executors before reporting task completion.
142
+ */
143
+ drainBackgroundWork(): Promise<void>;
134
144
  /**
135
145
  * Execute the agent with user input.
136
146
  * Uses the agent's default session (created during start()).
@@ -260,6 +270,8 @@ export declare class CipherAgent extends BaseAgent implements ICipherAgent {
260
270
  * Uses lazy providers when injected (child process mode), otherwise static config.
261
271
  */
262
272
  private buildHttpConfig;
273
+ private createFreshRetryableGenerator;
274
+ private drainAbstractQueue;
263
275
  private getHistoryStorageInternal;
264
276
  private getSessionIdInternal;
265
277
  private getSessionManagerInternal;
@@ -273,7 +285,9 @@ export declare class CipherAgent extends BaseAgent implements ICipherAgent {
273
285
  * Rebuild map tool dependencies and update ToolProvider + SandboxService.
274
286
  * Called from both start() (initial setup) and refreshProviderConfig() (hot-swap).
275
287
  */
288
+ private rebindCurateTools;
276
289
  private rebindMapTools;
290
+ private refreshSessionCompressorFromTransport;
277
291
  /**
278
292
  * Register a session as root-eligible and track it for lifecycle cleanup.
279
293
  * Routes all root-eligible registrations through a single point.
@@ -1,17 +1,25 @@
1
1
  import { randomUUID } from 'node:crypto';
2
2
  import { setMaxListeners } from 'node:events';
3
+ import { TransportStateEventNames } from '../../../server/core/domain/transport/schemas.js';
4
+ import { agentLog } from '../../../server/utils/process-logger.js';
3
5
  import { getEffectiveMaxInputTokens, resolveRegistryProvider } from '../../core/domain/llm/index.js';
4
6
  import { STREAMING_EVENT_NAMES } from '../../core/domain/streaming/types.js';
5
7
  import { ToolName } from '../../core/domain/tools/constants.js';
6
8
  import { AgentEventBus } from '../events/event-emitter.js';
9
+ import { RetryableContentGenerator } from '../llm/generators/index.js';
7
10
  import { createGeneratorForProvider } from '../llm/providers/index.js';
11
+ import { DEFAULT_RETRY_POLICY } from '../llm/retry/retry-policy.js';
8
12
  import { EventBasedLogger } from '../logger/event-based-logger.js';
9
13
  import { deregisterRootEligibleSession, registerRootEligibleSession } from '../map/agentic-map-service.js';
14
+ import { MemoryDeduplicator } from '../memory/memory-deduplicator.js';
15
+ import { createCurateService } from '../sandbox/curate-service.js';
16
+ import { SessionCompressor } from '../session/session-compressor.js';
10
17
  import { SessionManager } from '../session/session-manager.js';
11
18
  import { TransportEventBridge } from '../transport/transport-event-bridge.js';
12
19
  import { AgentError } from './agent-error.js';
13
20
  import { BaseAgent } from './base-agent.js';
14
21
  import { createCipherAgentServices } from './service-initializer.js';
22
+ const QUEUE_TRACE_ENABLED = process.env.BRV_QUEUE_TRACE === '1';
15
23
  /**
16
24
  * CipherAgent - Main agent implementation extending BaseAgent.
17
25
  *
@@ -22,7 +30,7 @@ import { createCipherAgentServices } from './service-initializer.js';
22
30
  * - Typed error handling
23
31
  * - Configuration validation (Zod)
24
32
  *
25
- * Architecture (DextoAgent pattern):
33
+ * Architecture:
26
34
  * - Agent creates AgentEventBus in constructor (available before start)
27
35
  * - Agent creates and owns shared services (ToolManager, SystemPromptManager, etc.)
28
36
  * - SessionManager creates session-specific services (LLM, SessionEventBus)
@@ -55,7 +63,11 @@ export class CipherAgent extends BaseAgent {
55
63
  * Used for bulk deregistration on agent teardown (cleanupServices).
56
64
  */
57
65
  rootEligibleSessions = new Set();
66
+ /** Lazily-created session compressor, rebuilt on each rebindCurateTools() call. */
67
+ sessionCompressor;
58
68
  sessionManager;
69
+ /** Tracks user-facing task sessions for post-session memory extraction. */
70
+ userFacingTaskSessions = new Set();
59
71
  /**
60
72
  * Creates a new CipherAgent instance.
61
73
  * Does NOT initialize services - call start() for async initialization.
@@ -72,7 +84,7 @@ export class CipherAgent extends BaseAgent {
72
84
  constructor(config, brvConfig, options) {
73
85
  // Call parent constructor (validates with Zod)
74
86
  super(config);
75
- // Create event bus early (DextoAgent pattern - available before start)
87
+ // Create event bus early (available before start)
76
88
  this._agentEventBus = new AgentEventBus();
77
89
  this._brvConfig = brvConfig;
78
90
  this._projectIdProvider = options?.projectIdProvider;
@@ -146,6 +158,8 @@ export class CipherAgent extends BaseAgent {
146
158
  }
147
159
  // === Public Methods (alphabetical order) ===
148
160
  async cleanupServices() {
161
+ // Drain abstract generation queue before session disposal
162
+ await this.drainAbstractQueue();
149
163
  // Abort all active streams and clear controllers
150
164
  for (const controller of this.activeStreamControllers.values()) {
151
165
  controller.abort();
@@ -207,6 +221,10 @@ export class CipherAgent extends BaseAgent {
207
221
  if (options?.mapRootEligible) {
208
222
  this.registerSessionInternal(childSession.id);
209
223
  }
224
+ // Track user-facing sessions for post-session memory extraction.
225
+ if (options?.userFacing) {
226
+ this.userFacingTaskSessions.add(childSession.id);
227
+ }
210
228
  return childSession.id;
211
229
  }
212
230
  /**
@@ -248,6 +266,38 @@ export class CipherAgent extends BaseAgent {
248
266
  */
249
267
  async deleteTaskSession(sessionId) {
250
268
  this.ensureStarted();
269
+ // Compress memories for user-facing sessions before disposal (fail-open).
270
+ if (this.userFacingTaskSessions.has(sessionId) && this.sessionCompressor) {
271
+ try {
272
+ // Refresh OAuth token and rebuild compressor before compression
273
+ if (this._transportClient && this.services) {
274
+ try {
275
+ await this.refreshSessionCompressorFromTransport();
276
+ }
277
+ catch {
278
+ // Fail-open: use existing compressor with potentially stale token
279
+ }
280
+ }
281
+ const session = this.getSessionManagerInternal().getSession(sessionId);
282
+ if (session) {
283
+ const messages = session.getLLMService().getContextManager().getComprehensiveMessages();
284
+ const commandType = this.getSessionManagerInternal().getSessionCommandType(sessionId) ?? 'curate';
285
+ // Task sessions often contain a compact prompt/response trace, so use a
286
+ // lower threshold than the interactive default to preserve useful memories.
287
+ await this.sessionCompressor.compress(messages, commandType, { minMessages: 2 }).catch((error) => {
288
+ const msg = error instanceof Error ? error.message : String(error);
289
+ console.debug(`[CipherAgent] Session compression failed for ${sessionId}: ${msg}`);
290
+ });
291
+ }
292
+ }
293
+ catch (error) {
294
+ // Fail-open: synchronous errors in the session accessor chain (e.g. corrupted
295
+ // session state) must not prevent clearSession + deleteSession from running.
296
+ const msg = error instanceof Error ? error.message : String(error);
297
+ console.debug(`[CipherAgent] Session compression setup failed for ${sessionId}: ${msg}`);
298
+ }
299
+ this.userFacingTaskSessions.delete(sessionId);
300
+ }
251
301
  await this.services.sandboxService.clearSession(sessionId);
252
302
  await this.getSessionManagerInternal().deleteSession(sessionId);
253
303
  // Deregister root-eligible record if this agent owns it.
@@ -258,6 +308,14 @@ export class CipherAgent extends BaseAgent {
258
308
  this.rootEligibleSessions.delete(sessionId);
259
309
  }
260
310
  }
311
+ /**
312
+ * Wait for shared background work (such as abstract generation) to finish.
313
+ * Used by task executors before reporting task completion.
314
+ */
315
+ async drainBackgroundWork() {
316
+ this.ensureStarted();
317
+ await this.drainAbstractQueue();
318
+ }
261
319
  /**
262
320
  * Execute the agent with user input.
263
321
  * Uses the agent's default session (created during start()).
@@ -388,7 +446,7 @@ export class CipherAgent extends BaseAgent {
388
446
  return this.getSystemPromptManagerInternal().build({});
389
447
  }
390
448
  async initializeServices() {
391
- // Pass pre-created event bus to service initializer (DextoAgent pattern)
449
+ // Pass pre-created event bus to service initializer
392
450
  return createCipherAgentServices(this.config, this._agentEventBus);
393
451
  }
394
452
  /**
@@ -461,6 +519,8 @@ export class CipherAgent extends BaseAgent {
461
519
  this.services.sandboxService.setSessionManager?.(this.sessionManager);
462
520
  // Rebind map tools with fresh generator/tokenizer/maxContextTokens
463
521
  this.rebindMapTools(services, httpConfig, sessionLLMConfig);
522
+ // Rebind curate tools with fresh generator + abstract queue
523
+ this.rebindCurateTools(services, httpConfig, sessionLLMConfig);
464
524
  }
465
525
  /**
466
526
  * Reset the agent to initial state.
@@ -562,6 +622,8 @@ export class CipherAgent extends BaseAgent {
562
622
  // Uses rebindMapTools() which atomically replaces map tools with fresh deps
563
623
  // (generator, tokenizer, maxContextTokens, logger).
564
624
  this.rebindMapTools(services, httpConfig, sessionLLMConfig);
625
+ // Wire abstract generation queue with curate generator + rebuild curate service.
626
+ this.rebindCurateTools(services, httpConfig, sessionLLMConfig);
565
627
  // Create event bridge if transport client is injected (child process mode).
566
628
  // The bridge forwards AgentEventBus llmservice:* events to the transport server.
567
629
  if (this._transportClient) {
@@ -778,6 +840,64 @@ export class CipherAgent extends BaseAgent {
778
840
  };
779
841
  }
780
842
  // === Private Helpers (alphabetical order) ===
843
+ createFreshRetryableGenerator(fresh, options) {
844
+ if (fresh.providerKeyMissing || !fresh.activeProvider) {
845
+ return;
846
+ }
847
+ const provider = fresh.provider ?? (fresh.openRouterApiKey ? 'openrouter' : 'byterover');
848
+ const freshGenerator = createGeneratorForProvider(provider, {
849
+ apiKey: provider === 'openrouter'
850
+ ? (fresh.openRouterApiKey ?? fresh.providerApiKey)
851
+ : fresh.providerApiKey,
852
+ baseUrl: fresh.providerBaseUrl,
853
+ headers: fresh.providerHeaders,
854
+ httpConfig: options.httpConfig,
855
+ httpReferer: options.httpReferer,
856
+ maxTokens: 4096,
857
+ model: fresh.activeModel ?? options.modelFallback,
858
+ siteName: options.siteName,
859
+ temperature: 0,
860
+ });
861
+ return new RetryableContentGenerator(freshGenerator, { policy: DEFAULT_RETRY_POLICY });
862
+ }
863
+ async drainAbstractQueue() {
864
+ const abstractQueue = this.services?.abstractQueue;
865
+ if (!abstractQueue) {
866
+ return;
867
+ }
868
+ const settleDeadline = Date.now() + 5000;
869
+ let idleSince;
870
+ let pass = 0;
871
+ /* eslint-disable no-await-in-loop */
872
+ while (Date.now() <= settleDeadline) {
873
+ pass++;
874
+ if (QUEUE_TRACE_ENABLED) {
875
+ agentLog(`drainAbstractQueue:pass:${pass}:start`);
876
+ }
877
+ await abstractQueue.drain();
878
+ const status = abstractQueue.getStatus();
879
+ if (QUEUE_TRACE_ENABLED) {
880
+ agentLog(`drainAbstractQueue:pass:${pass}:status pending=${status.pending} processing=${status.processing} processed=${status.processed} failed=${status.failed}`);
881
+ }
882
+ if (!status.processing && status.pending === 0) {
883
+ idleSince ??= Date.now();
884
+ if (Date.now() - idleSince >= 250) {
885
+ if (QUEUE_TRACE_ENABLED) {
886
+ agentLog(`drainAbstractQueue:settled pass=${pass}`);
887
+ }
888
+ return;
889
+ }
890
+ }
891
+ else {
892
+ idleSince = undefined;
893
+ }
894
+ await new Promise((resolve) => { setTimeout(resolve, 100); });
895
+ }
896
+ /* eslint-enable no-await-in-loop */
897
+ if (QUEUE_TRACE_ENABLED) {
898
+ agentLog('drainAbstractQueue:deadline-reached');
899
+ }
900
+ }
781
901
  getHistoryStorageInternal() {
782
902
  const storage = this.services?.historyStorage;
783
903
  if (!storage) {
@@ -818,6 +938,54 @@ export class CipherAgent extends BaseAgent {
818
938
  * Rebuild map tool dependencies and update ToolProvider + SandboxService.
819
939
  * Called from both start() (initial setup) and refreshProviderConfig() (hot-swap).
820
940
  */
941
+ rebindCurateTools(services, httpConfig, sessionLLMConfig) {
942
+ const curateProvider = sessionLLMConfig.provider
943
+ ?? (sessionLLMConfig.openRouterApiKey ? 'openrouter' : 'byterover');
944
+ const curateGenerator = createGeneratorForProvider(curateProvider, {
945
+ apiKey: curateProvider === 'openrouter'
946
+ ? (sessionLLMConfig.openRouterApiKey ?? sessionLLMConfig.providerApiKey)
947
+ : sessionLLMConfig.providerApiKey,
948
+ baseUrl: sessionLLMConfig.providerBaseUrl,
949
+ headers: sessionLLMConfig.providerHeaders,
950
+ httpConfig: httpConfig,
951
+ httpReferer: sessionLLMConfig.httpReferer,
952
+ maxTokens: 4096,
953
+ model: sessionLLMConfig.model,
954
+ siteName: sessionLLMConfig.siteName,
955
+ temperature: 0,
956
+ });
957
+ // Wrap with retry for background resilience (no event bus — background tasks have no UI)
958
+ const retryableCurateGenerator = new RetryableContentGenerator(curateGenerator, {
959
+ policy: DEFAULT_RETRY_POLICY,
960
+ });
961
+ // Wire generator into the abstract queue so background generation can proceed
962
+ services.abstractQueue.setGenerator(retryableCurateGenerator);
963
+ // Refresh OAuth token before each background generation (tokens expire between tasks)
964
+ if (this._transportClient) {
965
+ const transportClient = this._transportClient;
966
+ services.abstractQueue.setBeforeProcess(async () => {
967
+ const fresh = await transportClient.requestWithAck(TransportStateEventNames.GET_PROVIDER_CONFIG);
968
+ const retryableFreshGenerator = this.createFreshRetryableGenerator(fresh, {
969
+ httpConfig,
970
+ httpReferer: sessionLLMConfig.httpReferer,
971
+ modelFallback: sessionLLMConfig.model,
972
+ siteName: sessionLLMConfig.siteName,
973
+ });
974
+ if (!retryableFreshGenerator) {
975
+ return;
976
+ }
977
+ services.abstractQueue.setGenerator(retryableFreshGenerator);
978
+ });
979
+ }
980
+ // Rebuild sandbox CurateService with the queue — reuses existing hot-swap path
981
+ const newCurateService = createCurateService(services.workingDirectory, services.abstractQueue);
982
+ services.sandboxService.setCurateService?.(newCurateService);
983
+ // Atomically rebuild CURATE + INGEST_RESOURCE tools so both enqueue abstracts
984
+ services.toolProvider.replaceTools([ToolName.CURATE, ToolName.INGEST_RESOURCE], { abstractQueue: services.abstractQueue, contentGenerator: retryableCurateGenerator });
985
+ // Rebuild session compressor with the new generator (used in deleteTaskSession)
986
+ const deduplicator = new MemoryDeduplicator(retryableCurateGenerator);
987
+ this.sessionCompressor = new SessionCompressor(deduplicator, retryableCurateGenerator, services.memoryManager);
988
+ }
821
989
  rebindMapTools(services, httpConfig, sessionLLMConfig) {
822
990
  const mapProvider = sessionLLMConfig.provider
823
991
  ?? (sessionLLMConfig.openRouterApiKey ? 'openrouter' : 'byterover');
@@ -855,6 +1023,23 @@ export class CipherAgent extends BaseAgent {
855
1023
  // Update sandbox for tools.curation.mapExtract()
856
1024
  services.sandboxService.setContentGenerator?.(mapGenerator);
857
1025
  }
1026
+ async refreshSessionCompressorFromTransport() {
1027
+ if (!this._transportClient || !this.services) {
1028
+ return;
1029
+ }
1030
+ const fresh = await this._transportClient.requestWithAck(TransportStateEventNames.GET_PROVIDER_CONFIG);
1031
+ const retryable = this.createFreshRetryableGenerator(fresh, {
1032
+ httpConfig: this.buildHttpConfig(),
1033
+ httpReferer: this.config.httpReferer,
1034
+ modelFallback: this.stateManager?.getModel() ?? this.config.model,
1035
+ siteName: this.config.siteName,
1036
+ });
1037
+ if (!retryable) {
1038
+ return;
1039
+ }
1040
+ const deduplicator = new MemoryDeduplicator(retryable);
1041
+ this.sessionCompressor = new SessionCompressor(deduplicator, retryable, this.services.memoryManager);
1042
+ }
858
1043
  /**
859
1044
  * Register a session as root-eligible and track it for lifecycle cleanup.
860
1045
  * Routes all root-eligible registrations through a single point.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Agent module - Complete cipher agent implementation following DextoAgent patterns
2
+ * Agent module - Complete cipher agent implementation
3
3
  *
4
4
  * This module provides the full agent architecture with:
5
5
  * - CipherAgent: Main agent class for LLM interactions
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Agent module - Complete cipher agent implementation following DextoAgent patterns
2
+ * Agent module - Complete cipher agent implementation
3
3
  *
4
4
  * This module provides the full agent architecture with:
5
5
  * - CipherAgent: Main agent class for LLM interactions
@@ -4,7 +4,7 @@
4
4
  * This module is responsible for initializing and wiring together all core agent services.
5
5
  * It provides a single entry point for constructing the service graph.
6
6
  *
7
- * Following DextoAgent pattern:
7
+ * Following pattern:
8
8
  * - Config file is source of truth (ValidatedAgentConfig)
9
9
  * - Centralized function (not factory class) for service creation
10
10
  * - Explicit dependency order with numbered steps
@@ -61,7 +61,7 @@ export type { CipherAgentServices, SessionManagerConfig, SessionServices } from
61
61
  * Creates shared services for CipherAgent.
62
62
  * These services are singletons shared across all sessions.
63
63
  *
64
- * Initialization order follows DextoAgent pattern (explicit numbered steps):
64
+ * Initialization order (explicit numbered steps):
65
65
  * 1. Logger (uses provided event bus)
66
66
  * 2. File system service (no dependencies)
67
67
  * 3. Process service (no dependencies)
@@ -76,7 +76,7 @@ export type { CipherAgentServices, SessionManagerConfig, SessionServices } from
76
76
  * 12. Return all services
77
77
  *
78
78
  * @param config - Validated agent configuration (Zod-validated)
79
- * @param agentEventBus - Pre-created event bus from agent constructor (DextoAgent pattern)
79
+ * @param agentEventBus - Pre-created event bus from agent constructor
80
80
  * @returns Initialized shared services
81
81
  */
82
82
  export declare function createCipherAgentServices(config: ValidatedAgentConfig, agentEventBus: AgentEventBus): Promise<CipherAgentServices>;
@@ -4,7 +4,7 @@
4
4
  * This module is responsible for initializing and wiring together all core agent services.
5
5
  * It provides a single entry point for constructing the service graph.
6
6
  *
7
- * Following DextoAgent pattern:
7
+ * Following pattern:
8
8
  * - Config file is source of truth (ValidatedAgentConfig)
9
9
  * - Centralized function (not factory class) for service creation
10
10
  * - Explicit dependency order with numbered steps
@@ -26,6 +26,7 @@ import { createGeneratorForProvider } from '../llm/providers/index.js';
26
26
  import { DEFAULT_RETRY_POLICY } from '../llm/retry/retry-policy.js';
27
27
  import { GeminiTokenizer } from '../llm/tokenizers/gemini-tokenizer.js';
28
28
  import { EventBasedLogger } from '../logger/event-based-logger.js';
29
+ import { AbstractGenerationQueue } from '../map/abstract-queue.js';
29
30
  import { MemoryManager } from '../memory/memory-manager.js';
30
31
  import { ProcessService } from '../process/process-service.js';
31
32
  import { SandboxService } from '../sandbox/sandbox-service.js';
@@ -45,7 +46,7 @@ import { ToolProvider } from '../tools/tool-provider.js';
45
46
  * Creates shared services for CipherAgent.
46
47
  * These services are singletons shared across all sessions.
47
48
  *
48
- * Initialization order follows DextoAgent pattern (explicit numbered steps):
49
+ * Initialization order (explicit numbered steps):
49
50
  * 1. Logger (uses provided event bus)
50
51
  * 2. File system service (no dependencies)
51
52
  * 3. Process service (no dependencies)
@@ -60,11 +61,11 @@ import { ToolProvider } from '../tools/tool-provider.js';
60
61
  * 12. Return all services
61
62
  *
62
63
  * @param config - Validated agent configuration (Zod-validated)
63
- * @param agentEventBus - Pre-created event bus from agent constructor (DextoAgent pattern)
64
+ * @param agentEventBus - Pre-created event bus from agent constructor
64
65
  * @returns Initialized shared services
65
66
  */
66
67
  export async function createCipherAgentServices(config, agentEventBus) {
67
- // 1. Logger (uses provided event bus - DextoAgent pattern)
68
+ // 1. Logger (uses provided event bus )
68
69
  const logger = new EventBasedLogger(agentEventBus, 'CipherAgent');
69
70
  // 2. File system service (no dependencies)
70
71
  const fileSystemService = new FileSystemService(config.fileSystem);
@@ -132,10 +133,13 @@ export async function createCipherAgentServices(config, agentEventBus) {
132
133
  // Priority 16 — right after context tree structure, before memories
133
134
  const mapSelectionContributor = new MapSelectionContributor('mapSelection', 16);
134
135
  systemPromptManager.registerContributor(mapSelectionContributor);
135
- // 7. Tool provider (depends on FileSystemService, ProcessService, MemoryManager, SystemPromptManager)
136
+ // 7. Abstract generation queue (generator injected later via rebindCurateTools)
137
+ const abstractQueue = new AbstractGenerationQueue(workingDirectory);
138
+ // 8. Tool provider (depends on FileSystemService, ProcessService, MemoryManager, SystemPromptManager)
136
139
  const verbose = config.llm.verbose ?? false;
137
140
  const descriptionLoader = new ToolDescriptionLoader();
138
141
  const toolProvider = new ToolProvider({
142
+ abstractQueue,
139
143
  environmentContext,
140
144
  fileSystemService,
141
145
  getToolProvider: () => toolProvider,
@@ -144,14 +148,14 @@ export async function createCipherAgentServices(config, agentEventBus) {
144
148
  sandboxService,
145
149
  }, systemPromptManager, descriptionLoader);
146
150
  await toolProvider.initialize();
147
- // 8. Policy engine with default rules for autonomous execution
151
+ // 9. Policy engine with default rules for autonomous execution
148
152
  const policyEngine = new PolicyEngine({ defaultDecision: 'ALLOW' });
149
153
  policyEngine.addRules(DEFAULT_POLICY_RULES);
150
- // 9. Tool scheduler (orchestrates policy check → execution)
154
+ // 10. Tool scheduler (orchestrates policy check → execution)
151
155
  const toolScheduler = new CoreToolScheduler(toolProvider, policyEngine, undefined, {
152
156
  verbose,
153
157
  });
154
- // 10. Tool manager (with scheduler for policy-based execution)
158
+ // 11. Tool manager (with scheduler for policy-based execution)
155
159
  const toolManager = new ToolManager(toolProvider, toolScheduler);
156
160
  await toolManager.initialize();
157
161
  // 11. History storage - granular file-based storage
@@ -177,6 +181,7 @@ export async function createCipherAgentServices(config, agentEventBus) {
177
181
  workingDirectory,
178
182
  });
179
183
  return {
184
+ abstractQueue,
180
185
  agentEventBus,
181
186
  blobStorage,
182
187
  compactionService,
@@ -191,6 +196,7 @@ export async function createCipherAgentServices(config, agentEventBus) {
191
196
  toolManager,
192
197
  toolProvider,
193
198
  toolScheduler,
199
+ workingDirectory,
194
200
  };
195
201
  }
196
202
  /**
@@ -19,7 +19,6 @@ export interface AgentExecutionContext {
19
19
  /**
20
20
  * Agent event subscriber interface.
21
21
  * Objects implementing this can be registered for event subscription.
22
- * Follows DextoAgent's AgentEventSubscriber pattern.
23
22
  */
24
23
  export interface AgentEventSubscriber {
25
24
  /**