byterover-cli 2.0.0 → 2.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.
- package/README.md +6 -81
- package/dist/agent/core/domain/llm/index.d.ts +1 -1
- package/dist/agent/core/domain/llm/index.js +1 -1
- package/dist/agent/core/domain/llm/registry.d.ts +8 -0
- package/dist/agent/core/domain/llm/registry.js +34 -0
- package/dist/agent/core/domain/sandbox/types.d.ts +2 -0
- package/dist/agent/core/domain/tools/constants.d.ts +3 -0
- package/dist/agent/core/domain/tools/constants.js +3 -0
- package/dist/agent/core/interfaces/cipher-services.d.ts +2 -4
- package/dist/agent/core/interfaces/i-cipher-agent.d.ts +9 -1
- package/dist/agent/core/interfaces/i-sandbox-service.d.ts +8 -0
- package/dist/agent/core/interfaces/i-tool-provider.d.ts +10 -0
- package/dist/agent/core/interfaces/i-tool-scheduler.d.ts +9 -0
- package/dist/agent/infra/agent/agent-schemas.d.ts +0 -9
- package/dist/agent/infra/agent/agent-schemas.js +0 -3
- package/dist/agent/infra/agent/cipher-agent.d.ts +25 -1
- package/dist/agent/infra/agent/cipher-agent.js +138 -11
- package/dist/agent/infra/agent/provider-update-config.d.ts +0 -2
- package/dist/agent/infra/agent/service-initializer.d.ts +2 -6
- package/dist/agent/infra/agent/service-initializer.js +45 -38
- package/dist/agent/infra/blob/blob-storage-factory.d.ts +2 -2
- package/dist/agent/infra/blob/blob-storage-factory.js +4 -4
- package/dist/agent/infra/blob/file-blob-storage.d.ts +96 -0
- package/dist/agent/infra/blob/file-blob-storage.js +454 -0
- package/dist/agent/infra/blob/index.d.ts +2 -3
- package/dist/agent/infra/blob/index.js +4 -6
- package/dist/agent/infra/llm/agent-llm-service.d.ts +3 -0
- package/dist/agent/infra/llm/agent-llm-service.js +34 -52
- package/dist/agent/infra/llm/context/compression/compression-helpers.d.ts +35 -0
- package/dist/agent/infra/llm/context/compression/compression-helpers.js +124 -0
- package/dist/agent/infra/llm/context/compression/escalated-compression.d.ts +62 -0
- package/dist/agent/infra/llm/context/compression/escalated-compression.js +144 -0
- package/dist/agent/infra/llm/context/compression/index.d.ts +3 -0
- package/dist/agent/infra/llm/context/compression/index.js +3 -0
- package/dist/agent/infra/llm/context/compression/reactive-overflow.d.ts +0 -27
- package/dist/agent/infra/llm/context/compression/reactive-overflow.js +5 -122
- package/dist/agent/infra/llm/context/context-manager.d.ts +20 -1
- package/dist/agent/infra/llm/context/context-manager.js +37 -7
- package/dist/agent/infra/llm/providers/index.js +0 -2
- package/dist/agent/infra/llm/providers/types.d.ts +1 -5
- package/dist/agent/infra/map/agentic-map-service.d.ts +97 -0
- package/dist/agent/infra/map/agentic-map-service.js +309 -0
- package/dist/agent/infra/map/context-tree-store.d.ts +94 -0
- package/dist/agent/infra/map/context-tree-store.js +278 -0
- package/dist/agent/infra/map/index.d.ts +4 -0
- package/dist/agent/infra/map/index.js +4 -0
- package/dist/agent/infra/map/llm-map-memory.d.ts +59 -0
- package/dist/agent/infra/map/llm-map-memory.js +187 -0
- package/dist/agent/infra/map/llm-map-service.d.ts +36 -0
- package/dist/agent/infra/map/llm-map-service.js +118 -0
- package/dist/agent/infra/map/map-shared.d.ts +140 -0
- package/dist/agent/infra/map/map-shared.js +325 -0
- package/dist/agent/infra/map/worker-pool.d.ts +45 -0
- package/dist/agent/infra/map/worker-pool.js +73 -0
- package/dist/agent/infra/sandbox/curation-helpers.d.ts +62 -0
- package/dist/agent/infra/sandbox/curation-helpers.js +219 -0
- package/dist/agent/infra/sandbox/sandbox-service.d.ts +12 -0
- package/dist/agent/infra/sandbox/sandbox-service.js +39 -7
- package/dist/agent/infra/sandbox/tools-sdk.d.ts +48 -1
- package/dist/agent/infra/sandbox/tools-sdk.js +52 -1
- package/dist/agent/infra/session/session-manager.d.ts +8 -1
- package/dist/agent/infra/session/session-manager.js +24 -4
- package/dist/agent/infra/storage/file-key-storage.d.ts +142 -0
- package/dist/agent/infra/storage/file-key-storage.js +572 -0
- package/dist/agent/infra/storage/granular-history-storage.d.ts +1 -1
- package/dist/agent/infra/storage/granular-history-storage.js +1 -1
- package/dist/agent/infra/system-prompt/contributors/context-tree-structure-contributor.d.ts +4 -0
- package/dist/agent/infra/system-prompt/contributors/context-tree-structure-contributor.js +42 -14
- package/dist/agent/infra/system-prompt/contributors/map-selection-contributor.d.ts +16 -0
- package/dist/agent/infra/system-prompt/contributors/map-selection-contributor.js +47 -0
- package/dist/agent/infra/tools/core-tool-scheduler.js +3 -1
- package/dist/agent/infra/tools/implementations/agentic-map-tool.d.ts +35 -0
- package/dist/agent/infra/tools/implementations/agentic-map-tool.js +156 -0
- package/dist/agent/infra/tools/implementations/code-exec-tool.js +1 -0
- package/dist/agent/infra/tools/implementations/curate-tool.d.ts +9 -9
- package/dist/agent/infra/tools/implementations/expand-knowledge-tool.d.ts +18 -0
- package/dist/agent/infra/tools/implementations/expand-knowledge-tool.js +43 -0
- package/dist/agent/infra/tools/implementations/llm-map-tool.d.ts +24 -0
- package/dist/agent/infra/tools/implementations/llm-map-tool.js +87 -0
- package/dist/agent/infra/tools/implementations/memory-symbol-tree.d.ts +28 -1
- package/dist/agent/infra/tools/implementations/memory-symbol-tree.js +27 -3
- package/dist/agent/infra/tools/implementations/search-knowledge-service.d.ts +1 -0
- package/dist/agent/infra/tools/implementations/search-knowledge-service.js +83 -12
- package/dist/agent/infra/tools/implementations/search-knowledge-tool.js +2 -2
- package/dist/agent/infra/tools/tool-manager.js +6 -0
- package/dist/agent/infra/tools/tool-provider.d.ts +12 -0
- package/dist/agent/infra/tools/tool-provider.js +78 -0
- package/dist/agent/infra/tools/tool-registry.d.ts +14 -0
- package/dist/agent/infra/tools/tool-registry.js +32 -0
- package/dist/agent/resources/prompts/system-prompt.yml +48 -74
- package/dist/agent/resources/tools/expand_knowledge.txt +20 -0
- package/dist/oclif/commands/curate/index.js +1 -2
- package/dist/oclif/commands/main.js +1 -0
- package/dist/oclif/commands/providers/connect.d.ts +1 -3
- package/dist/oclif/commands/providers/connect.js +7 -29
- package/dist/oclif/commands/query.js +1 -2
- package/dist/server/constants.d.ts +7 -0
- package/dist/server/constants.js +8 -0
- package/dist/server/core/domain/entities/provider-registry.js +1 -15
- package/dist/server/core/domain/knowledge/memory-scoring.js +1 -1
- package/dist/server/core/domain/knowledge/summary-types.d.ts +126 -0
- package/dist/server/core/domain/knowledge/summary-types.js +7 -0
- package/dist/server/core/domain/transport/schemas.d.ts +0 -4
- package/dist/server/core/interfaces/context-tree/i-context-tree-archive-service.d.ts +30 -0
- package/dist/server/core/interfaces/context-tree/i-context-tree-archive-service.js +1 -0
- package/dist/server/core/interfaces/context-tree/i-context-tree-manifest-service.d.ts +30 -0
- package/dist/server/core/interfaces/context-tree/i-context-tree-manifest-service.js +1 -0
- package/dist/server/core/interfaces/context-tree/i-context-tree-summary-service.d.ts +29 -0
- package/dist/server/core/interfaces/context-tree/i-context-tree-summary-service.js +1 -0
- package/dist/server/infra/cogit/context-tree-to-push-context-mapper.js +10 -3
- package/dist/server/infra/connectors/skill/skill-connector.d.ts +4 -0
- package/dist/server/infra/connectors/skill/skill-connector.js +4 -0
- package/dist/server/infra/context-tree/children-hash.d.ts +20 -0
- package/dist/server/infra/context-tree/children-hash.js +22 -0
- package/dist/server/infra/context-tree/derived-artifact.d.ts +28 -0
- package/dist/server/infra/context-tree/derived-artifact.js +48 -0
- package/dist/server/infra/context-tree/file-context-tree-archive-service.d.ts +37 -0
- package/dist/server/infra/context-tree/file-context-tree-archive-service.js +219 -0
- package/dist/server/infra/context-tree/file-context-tree-manifest-service.d.ts +50 -0
- package/dist/server/infra/context-tree/file-context-tree-manifest-service.js +278 -0
- package/dist/server/infra/context-tree/file-context-tree-merger.js +4 -0
- package/dist/server/infra/context-tree/file-context-tree-snapshot-service.js +12 -4
- package/dist/server/infra/context-tree/file-context-tree-summary-service.d.ts +44 -0
- package/dist/server/infra/context-tree/file-context-tree-summary-service.js +313 -0
- package/dist/server/infra/context-tree/file-context-tree-writer-service.js +5 -0
- package/dist/server/infra/context-tree/prompts/summary-generation.d.ts +22 -0
- package/dist/server/infra/context-tree/prompts/summary-generation.js +45 -0
- package/dist/server/infra/context-tree/snapshot-diff.d.ts +19 -0
- package/dist/server/infra/context-tree/snapshot-diff.js +39 -0
- package/dist/server/infra/context-tree/summary-frontmatter.d.ts +24 -0
- package/dist/server/infra/context-tree/summary-frontmatter.js +111 -0
- package/dist/server/infra/daemon/agent-process.js +2 -14
- package/dist/server/infra/executor/curate-executor.d.ts +1 -0
- package/dist/server/infra/executor/curate-executor.js +82 -34
- package/dist/server/infra/executor/folder-pack-executor.js +1 -1
- package/dist/server/infra/executor/pre-compaction/compaction-escalation.d.ts +6 -0
- package/dist/server/infra/executor/pre-compaction/compaction-escalation.js +6 -0
- package/dist/server/infra/executor/pre-compaction/index.d.ts +3 -0
- package/dist/server/infra/executor/pre-compaction/index.js +1 -0
- package/dist/server/infra/executor/pre-compaction/pre-compaction-service.d.ts +59 -0
- package/dist/server/infra/executor/pre-compaction/pre-compaction-service.js +124 -0
- package/dist/server/infra/executor/pre-compaction/prompts.d.ts +24 -0
- package/dist/server/infra/executor/pre-compaction/prompts.js +47 -0
- package/dist/server/infra/executor/query-executor.d.ts +3 -0
- package/dist/server/infra/executor/query-executor.js +39 -4
- package/dist/server/infra/http/authenticated-http-client.js +4 -0
- package/dist/server/infra/http/provider-model-fetcher-registry.js +1 -5
- package/dist/server/infra/http/provider-model-fetchers.d.ts +0 -14
- package/dist/server/infra/http/provider-model-fetchers.js +0 -132
- package/dist/server/infra/provider/provider-config-resolver.js +0 -55
- package/dist/server/utils/curate-result-parser.d.ts +4 -4
- package/dist/shared/constants/curation.d.ts +6 -0
- package/dist/shared/constants/curation.js +6 -0
- package/dist/shared/utils/escalation-utils.d.ts +59 -0
- package/dist/shared/utils/escalation-utils.js +141 -0
- package/dist/tui/components/command-input.js +1 -1
- package/dist/tui/components/inline-prompts/inline-confirm.js +6 -1
- package/dist/tui/features/commands/definitions/exit.d.ts +2 -0
- package/dist/tui/features/commands/definitions/exit.js +9 -0
- package/dist/tui/features/commands/definitions/index.js +3 -0
- package/dist/tui/features/exit/components/exit-flow.d.ts +10 -0
- package/dist/tui/features/exit/components/exit-flow.js +19 -0
- package/dist/tui/features/provider/components/provider-flow.js +1 -21
- package/oclif.manifest.json +100 -109
- package/package.json +11 -4
- package/dist/agent/infra/blob/migrations.d.ts +0 -63
- package/dist/agent/infra/blob/migrations.js +0 -148
- package/dist/agent/infra/blob/sqlite-blob-storage.d.ts +0 -82
- package/dist/agent/infra/blob/sqlite-blob-storage.js +0 -307
- package/dist/agent/infra/llm/providers/google-vertex.d.ts +0 -15
- package/dist/agent/infra/llm/providers/google-vertex.js +0 -36
- package/dist/agent/infra/storage/blob-history-storage.d.ts +0 -81
- package/dist/agent/infra/storage/blob-history-storage.js +0 -193
- package/dist/agent/infra/storage/dual-format-history-storage.d.ts +0 -83
- package/dist/agent/infra/storage/dual-format-history-storage.js +0 -165
- package/dist/agent/infra/storage/sqlite-key-storage.d.ts +0 -113
- package/dist/agent/infra/storage/sqlite-key-storage.js +0 -438
- package/dist/server/infra/provider/vertex-ai-utils.d.ts +0 -10
- package/dist/server/infra/provider/vertex-ai-utils.js +0 -28
- package/dist/tui/features/provider/components/credential-path-dialog.d.ts +0 -30
- package/dist/tui/features/provider/components/credential-path-dialog.js +0 -85
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
/* eslint-disable camelcase */
|
|
2
|
+
/**
|
|
3
|
+
* File-based implementation of IContextTreeSummaryService.
|
|
4
|
+
*
|
|
5
|
+
* Manages hierarchical summary nodes (_index.md) in the context tree.
|
|
6
|
+
* Uses three-tier escalation (normal → aggressive → deterministic fallback)
|
|
7
|
+
* following the same pattern as PreCompactionService.
|
|
8
|
+
*
|
|
9
|
+
* Fail-open: any error returns { actionTaken: false } — never blocks curation.
|
|
10
|
+
*/
|
|
11
|
+
import { readdir, readFile, stat, unlink, writeFile } from 'node:fs/promises';
|
|
12
|
+
import { dirname, join, relative } from 'node:path';
|
|
13
|
+
import { BRV_DIR, CONTEXT_FILE_EXTENSION, CONTEXT_TREE_DIR, SUMMARY_INDEX_FILE } from '../../constants.js';
|
|
14
|
+
import { buildDeterministicFallbackCompaction, estimateTokens, isCompactionOutputValid, shouldAcceptCompactionOutput, } from '../executor/pre-compaction/compaction-escalation.js';
|
|
15
|
+
import { computeChildrenHash } from './children-hash.js';
|
|
16
|
+
import { isArchiveStub, isDerivedArtifact } from './derived-artifact.js';
|
|
17
|
+
import { computeContentHash } from './hash-utils.js';
|
|
18
|
+
import { toUnixPath } from './path-utils.js';
|
|
19
|
+
import { buildSummarySystemPrompt, buildSummaryUserMessage } from './prompts/summary-generation.js';
|
|
20
|
+
import { generateSummaryContent, parseSummaryFrontmatter } from './summary-frontmatter.js';
|
|
21
|
+
const ZERO_RESULT = {
|
|
22
|
+
actionTaken: false,
|
|
23
|
+
compressionRatio: 0,
|
|
24
|
+
tokenCount: 0,
|
|
25
|
+
};
|
|
26
|
+
export class FileContextTreeSummaryService {
|
|
27
|
+
async checkStaleness(directoryPath, directory) {
|
|
28
|
+
const baseDir = directory ?? process.cwd();
|
|
29
|
+
const contextTreeDir = join(baseDir, BRV_DIR, CONTEXT_TREE_DIR);
|
|
30
|
+
const targetDir = join(contextTreeDir, directoryPath);
|
|
31
|
+
const indexPath = join(targetDir, SUMMARY_INDEX_FILE);
|
|
32
|
+
// Collect current children
|
|
33
|
+
const children = await this.collectInputs(targetDir, contextTreeDir);
|
|
34
|
+
const currentHash = children.length > 0
|
|
35
|
+
? computeChildrenHash(children.map((c) => ({ contentHash: c.contentHash, path: c.path })))
|
|
36
|
+
: '';
|
|
37
|
+
// Read existing _index.md
|
|
38
|
+
let storedHash = '';
|
|
39
|
+
try {
|
|
40
|
+
const content = await readFile(indexPath, 'utf8');
|
|
41
|
+
const fm = parseSummaryFrontmatter(content);
|
|
42
|
+
storedHash = fm?.children_hash ?? '';
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
// No _index.md exists
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
currentChildrenHash: currentHash,
|
|
49
|
+
isStale: storedHash !== currentHash || storedHash === '',
|
|
50
|
+
path: directoryPath,
|
|
51
|
+
storedChildrenHash: storedHash,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
async generateSummary(directoryPath, agent, directory) {
|
|
55
|
+
const baseDir = directory ?? process.cwd();
|
|
56
|
+
const contextTreeDir = join(baseDir, BRV_DIR, CONTEXT_TREE_DIR);
|
|
57
|
+
const targetDir = join(contextTreeDir, directoryPath);
|
|
58
|
+
try {
|
|
59
|
+
// Step 1: Collect inputs (summary input set invariant)
|
|
60
|
+
const children = await this.collectInputs(targetDir, contextTreeDir);
|
|
61
|
+
if (children.length === 0) {
|
|
62
|
+
return { ...ZERO_RESULT, path: directoryPath, reason: 'empty_directory' };
|
|
63
|
+
}
|
|
64
|
+
// Step 2: Compute children hash
|
|
65
|
+
const childrenHash = computeChildrenHash(children.map((c) => ({ contentHash: c.contentHash, path: c.path })));
|
|
66
|
+
// Step 3: Determine condensation order from directory depth
|
|
67
|
+
const depth = directoryPath === '.' || directoryPath === ''
|
|
68
|
+
? 0
|
|
69
|
+
: directoryPath.split('/').length;
|
|
70
|
+
const order = this.depthToCondensationOrder(depth);
|
|
71
|
+
const level = `d${order}`;
|
|
72
|
+
// Step 4: Total input tokens
|
|
73
|
+
const totalInputTokens = children.reduce((sum, c) => sum + c.tokens, 0);
|
|
74
|
+
// Step 5: Three-tier escalation via CipherAgent
|
|
75
|
+
const taskId = `summary_${directoryPath.replaceAll('/', '_') || 'root'}`;
|
|
76
|
+
const childEntries = children.map((c) => ({ content: c.content, name: c.name }));
|
|
77
|
+
const summaryText = await this.generateWithEscalation(agent, taskId, childEntries, level, totalInputTokens);
|
|
78
|
+
// Step 6: Write _index.md
|
|
79
|
+
const summaryTokens = estimateTokens(summaryText);
|
|
80
|
+
const frontmatter = {
|
|
81
|
+
children_hash: childrenHash,
|
|
82
|
+
compression_ratio: totalInputTokens > 0 ? summaryTokens / totalInputTokens : 0,
|
|
83
|
+
condensation_order: order,
|
|
84
|
+
covers: children.map((c) => c.name).sort(),
|
|
85
|
+
covers_token_total: totalInputTokens,
|
|
86
|
+
summary_level: level,
|
|
87
|
+
token_count: summaryTokens,
|
|
88
|
+
type: 'summary',
|
|
89
|
+
};
|
|
90
|
+
const indexPath = join(targetDir, SUMMARY_INDEX_FILE);
|
|
91
|
+
await writeFile(indexPath, generateSummaryContent(frontmatter, summaryText), 'utf8');
|
|
92
|
+
return {
|
|
93
|
+
actionTaken: true,
|
|
94
|
+
compressionRatio: frontmatter.compression_ratio,
|
|
95
|
+
path: directoryPath,
|
|
96
|
+
tier: 'normal', // TODO: track actual tier from escalation
|
|
97
|
+
tokenCount: summaryTokens,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
return { ...ZERO_RESULT, path: directoryPath, reason: 'llm_error' };
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
async hasSummary(directoryPath, directory) {
|
|
105
|
+
const baseDir = directory ?? process.cwd();
|
|
106
|
+
const indexPath = join(baseDir, BRV_DIR, CONTEXT_TREE_DIR, directoryPath, SUMMARY_INDEX_FILE);
|
|
107
|
+
try {
|
|
108
|
+
await stat(indexPath);
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
async propagateStaleness(changedPaths, agent, directory) {
|
|
116
|
+
if (changedPaths.length === 0)
|
|
117
|
+
return [];
|
|
118
|
+
// Collect unique parent directory paths, then walk upward to root
|
|
119
|
+
const dirsToCheck = new Set();
|
|
120
|
+
for (const changedPath of changedPaths) {
|
|
121
|
+
let dir = dirname(changedPath);
|
|
122
|
+
while (dir && dir !== '.') {
|
|
123
|
+
dirsToCheck.add(dir);
|
|
124
|
+
dir = dirname(dir);
|
|
125
|
+
}
|
|
126
|
+
// Also include root
|
|
127
|
+
dirsToCheck.add('.');
|
|
128
|
+
}
|
|
129
|
+
// Sort bottom-up (deepest first)
|
|
130
|
+
const sorted = [...dirsToCheck].sort((a, b) => {
|
|
131
|
+
const depthA = a === '.' ? 0 : a.split('/').length;
|
|
132
|
+
const depthB = b === '.' ? 0 : b.split('/').length;
|
|
133
|
+
return depthB - depthA;
|
|
134
|
+
});
|
|
135
|
+
const results = [];
|
|
136
|
+
const stoppedPaths = new Set();
|
|
137
|
+
/* eslint-disable no-await-in-loop */
|
|
138
|
+
for (const dirPath of sorted) {
|
|
139
|
+
// If a descendant of this dir was stopped due to error, skip it
|
|
140
|
+
if (this.hasStoppedDescendant(dirPath, stoppedPaths))
|
|
141
|
+
continue;
|
|
142
|
+
const staleness = await this.checkStaleness(dirPath, directory);
|
|
143
|
+
if (!staleness.isStale)
|
|
144
|
+
continue;
|
|
145
|
+
const result = await this.generateSummary(dirPath, agent, directory);
|
|
146
|
+
results.push(result);
|
|
147
|
+
if (!result.actionTaken) {
|
|
148
|
+
if (result.reason === 'empty_directory') {
|
|
149
|
+
// Delete stale _index.md and continue climbing (parent input set changed)
|
|
150
|
+
try {
|
|
151
|
+
const baseDir = directory ?? process.cwd();
|
|
152
|
+
const indexPath = join(baseDir, BRV_DIR, CONTEXT_TREE_DIR, dirPath, SUMMARY_INDEX_FILE);
|
|
153
|
+
await unlink(indexPath);
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
// Already gone, fine
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
// LLM/IO error: stop climbing from this node
|
|
161
|
+
stoppedPaths.add(dirPath);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/* eslint-enable no-await-in-loop */
|
|
166
|
+
return results;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Collect inputs for a summary (the summary input set invariant):
|
|
170
|
+
* - Leaf .md files in the directory (excluding _index.md, _archived/)
|
|
171
|
+
* - Child directory _index.md files (summaries of subdirectories)
|
|
172
|
+
*/
|
|
173
|
+
async collectInputs(targetDir, contextTreeDir) {
|
|
174
|
+
const children = [];
|
|
175
|
+
let entries;
|
|
176
|
+
try {
|
|
177
|
+
entries = await readdir(targetDir, { withFileTypes: true });
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
return children;
|
|
181
|
+
}
|
|
182
|
+
/* eslint-disable no-await-in-loop */
|
|
183
|
+
for (const entry of entries) {
|
|
184
|
+
const entryName = entry.name;
|
|
185
|
+
const fullPath = join(targetDir, entryName);
|
|
186
|
+
const relativePath = toUnixPath(relative(contextTreeDir, fullPath));
|
|
187
|
+
if (entry.isFile() && entryName.endsWith(CONTEXT_FILE_EXTENSION)) {
|
|
188
|
+
// Skip _index.md itself and derived artifacts
|
|
189
|
+
if (entryName === SUMMARY_INDEX_FILE)
|
|
190
|
+
continue;
|
|
191
|
+
if (isDerivedArtifact(relativePath) || isArchiveStub(relativePath))
|
|
192
|
+
continue;
|
|
193
|
+
try {
|
|
194
|
+
const content = await readFile(fullPath, 'utf8');
|
|
195
|
+
children.push({
|
|
196
|
+
content,
|
|
197
|
+
contentHash: computeContentHash(content),
|
|
198
|
+
name: entryName,
|
|
199
|
+
path: relativePath,
|
|
200
|
+
tokens: estimateTokens(content),
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
// Skip unreadable files
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
else if (entry.isDirectory() && entryName !== '_archived') {
|
|
208
|
+
// Check for child directory _index.md
|
|
209
|
+
const childIndexPath = join(fullPath, SUMMARY_INDEX_FILE);
|
|
210
|
+
try {
|
|
211
|
+
const content = await readFile(childIndexPath, 'utf8');
|
|
212
|
+
const childRelPath = toUnixPath(relative(contextTreeDir, childIndexPath));
|
|
213
|
+
children.push({
|
|
214
|
+
content,
|
|
215
|
+
contentHash: computeContentHash(content),
|
|
216
|
+
name: `${entryName}/${SUMMARY_INDEX_FILE}`,
|
|
217
|
+
path: childRelPath,
|
|
218
|
+
tokens: estimateTokens(content),
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
// No _index.md in child directory, skip
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
/* eslint-enable no-await-in-loop */
|
|
227
|
+
return children;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Determine condensation order from directory depth relative to context tree root.
|
|
231
|
+
* Root = d3, domain = d2, topic = d1, subtopic = d0
|
|
232
|
+
*/
|
|
233
|
+
depthToCondensationOrder(depth) {
|
|
234
|
+
if (depth === 0)
|
|
235
|
+
return 3;
|
|
236
|
+
if (depth === 1)
|
|
237
|
+
return 2;
|
|
238
|
+
if (depth === 2)
|
|
239
|
+
return 1;
|
|
240
|
+
return 0;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Execute a single summary generation pass via the agent.
|
|
244
|
+
*/
|
|
245
|
+
async executeSummaryPass(agent, sessionId, taskId, childEntries, level, aggressive) {
|
|
246
|
+
try {
|
|
247
|
+
const systemPrompt = buildSummarySystemPrompt();
|
|
248
|
+
const userMessage = buildSummaryUserMessage(childEntries, level, aggressive);
|
|
249
|
+
const prompt = `${systemPrompt}\n\n${userMessage}`;
|
|
250
|
+
const response = await agent.executeOnSession(sessionId, prompt, {
|
|
251
|
+
executionContext: {
|
|
252
|
+
clearHistory: true,
|
|
253
|
+
commandType: 'query',
|
|
254
|
+
maxIterations: 1,
|
|
255
|
+
maxTokens: 4096,
|
|
256
|
+
temperature: 0.3,
|
|
257
|
+
},
|
|
258
|
+
taskId,
|
|
259
|
+
});
|
|
260
|
+
return response || undefined;
|
|
261
|
+
}
|
|
262
|
+
catch {
|
|
263
|
+
return undefined;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Three-tier escalation for summary generation.
|
|
268
|
+
* Follows the same pattern as PreCompactionService.compact().
|
|
269
|
+
*/
|
|
270
|
+
async generateWithEscalation(agent, taskId, childEntries, level, inputTokens) {
|
|
271
|
+
const sessionId = await agent.createTaskSession(taskId, 'query');
|
|
272
|
+
try {
|
|
273
|
+
// Pass 1: Normal
|
|
274
|
+
const normalResult = await this.executeSummaryPass(agent, sessionId, taskId, childEntries, level, false);
|
|
275
|
+
if (normalResult && shouldAcceptCompactionOutput(normalResult, inputTokens) && isCompactionOutputValid(normalResult)) {
|
|
276
|
+
return normalResult.trim();
|
|
277
|
+
}
|
|
278
|
+
// Pass 2: Aggressive
|
|
279
|
+
const aggressiveResult = await this.executeSummaryPass(agent, sessionId, taskId, childEntries, level, true);
|
|
280
|
+
if (aggressiveResult && shouldAcceptCompactionOutput(aggressiveResult, inputTokens) && isCompactionOutputValid(aggressiveResult)) {
|
|
281
|
+
return aggressiveResult.trim();
|
|
282
|
+
}
|
|
283
|
+
// Pass 3: Deterministic fallback
|
|
284
|
+
const combinedInput = childEntries.map((e) => `## ${e.name}\n${e.content}`).join('\n\n');
|
|
285
|
+
return buildDeterministicFallbackCompaction({
|
|
286
|
+
inputTokens,
|
|
287
|
+
sourceText: combinedInput,
|
|
288
|
+
suffixLabel: 'summary compaction',
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
finally {
|
|
292
|
+
await agent.deleteTaskSession(sessionId);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Check if any descendant of dirPath was stopped due to LLM/IO error.
|
|
297
|
+
* Since we process bottom-up (deepest first), a stopped child means
|
|
298
|
+
* its parent should also stop to prevent regenerating from stale state.
|
|
299
|
+
*/
|
|
300
|
+
hasStoppedDescendant(dirPath, stoppedPaths) {
|
|
301
|
+
if (stoppedPaths.size === 0)
|
|
302
|
+
return false;
|
|
303
|
+
const prefix = dirPath === '.' ? '' : `${dirPath}/`;
|
|
304
|
+
for (const stopped of stoppedPaths) {
|
|
305
|
+
// dirPath is ancestor of stopped if stopped starts with dirPath/
|
|
306
|
+
// Special case: dirPath '.' is ancestor of everything
|
|
307
|
+
if (prefix === '' || stopped.startsWith(prefix)) {
|
|
308
|
+
return true;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { mkdir, readFile, unlink, writeFile } from 'node:fs/promises';
|
|
3
3
|
import { dirname, join } from 'node:path';
|
|
4
4
|
import { BRV_DIR, CONTEXT_TREE_DIR, README_FILE } from '../../constants.js';
|
|
5
|
+
import { isExcludedFromSync } from './derived-artifact.js';
|
|
5
6
|
import { toUnixPath } from './path-utils.js';
|
|
6
7
|
/**
|
|
7
8
|
* File-based implementation of IContextTreeWriterService.
|
|
@@ -66,6 +67,10 @@ export class FileContextTreeWriterService {
|
|
|
66
67
|
if (normalizedPath === README_FILE) {
|
|
67
68
|
continue;
|
|
68
69
|
}
|
|
70
|
+
// Skip derived artifacts (_index.md, _archived/*.stub.md, _archived/*.full.md, _manifest.json)
|
|
71
|
+
if (isExcludedFromSync(normalizedPath)) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
69
74
|
result.set(normalizedPath, file);
|
|
70
75
|
}
|
|
71
76
|
return result;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompts for hierarchical summary generation (_index.md).
|
|
3
|
+
*
|
|
4
|
+
* Follows the same pattern as pre-compaction prompts: clear system prompt
|
|
5
|
+
* with isCompactionOutputValid() as the actual guardrail.
|
|
6
|
+
*/
|
|
7
|
+
import type { SummaryLevel } from '../../../core/domain/knowledge/summary-types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Build the system prompt for summary generation.
|
|
10
|
+
*/
|
|
11
|
+
export declare function buildSummarySystemPrompt(): string;
|
|
12
|
+
/**
|
|
13
|
+
* Build the user message for a summary generation pass.
|
|
14
|
+
*
|
|
15
|
+
* @param childEntries - Array of { name, content } for each child input
|
|
16
|
+
* @param level - The summary level being generated (d1, d2, d3)
|
|
17
|
+
* @param aggressive - Whether this is the aggressive (pass 2) attempt
|
|
18
|
+
*/
|
|
19
|
+
export declare function buildSummaryUserMessage(childEntries: Array<{
|
|
20
|
+
content: string;
|
|
21
|
+
name: string;
|
|
22
|
+
}>, level: SummaryLevel, aggressive: boolean): string;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompts for hierarchical summary generation (_index.md).
|
|
3
|
+
*
|
|
4
|
+
* Follows the same pattern as pre-compaction prompts: clear system prompt
|
|
5
|
+
* with isCompactionOutputValid() as the actual guardrail.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Build the system prompt for summary generation.
|
|
9
|
+
*/
|
|
10
|
+
export function buildSummarySystemPrompt() {
|
|
11
|
+
return `You are a knowledge summarization engine. Your ONLY task is to create a structural summary of the provided knowledge entries.
|
|
12
|
+
|
|
13
|
+
## Rules
|
|
14
|
+
- Condense child entries into a structural overview preserving key facts, relationships, and patterns
|
|
15
|
+
- Reference child entry names so readers know where to drill down for details
|
|
16
|
+
- Target compression: ~20-30% of input token count
|
|
17
|
+
- PRESERVE: entity names, file paths, API signatures, architectural decisions, key relationships
|
|
18
|
+
- DISCARD: verbose examples, repeated explanations, secondary detail, conversational filler
|
|
19
|
+
- Output clean structured markdown (headings, bullet points, brief prose)
|
|
20
|
+
- Do NOT wrap output in code blocks or XML tags
|
|
21
|
+
- Do NOT search any knowledge base or use any tools
|
|
22
|
+
- Output ONLY the summary text`;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Build the user message for a summary generation pass.
|
|
26
|
+
*
|
|
27
|
+
* @param childEntries - Array of { name, content } for each child input
|
|
28
|
+
* @param level - The summary level being generated (d1, d2, d3)
|
|
29
|
+
* @param aggressive - Whether this is the aggressive (pass 2) attempt
|
|
30
|
+
*/
|
|
31
|
+
export function buildSummaryUserMessage(childEntries, level, aggressive) {
|
|
32
|
+
const instruction = aggressive
|
|
33
|
+
? `Create a MORE CONCISE structural summary at level ${level}. A previous attempt was not short enough. Aggressively compress while keeping only the most critical facts and relationships.`
|
|
34
|
+
: `Create a structural summary at level ${level} from the following knowledge entries. Preserve key facts, architectural decisions, and relationships. Reference entry names for drill-down.`;
|
|
35
|
+
const entriesText = childEntries
|
|
36
|
+
.map((entry) => `### ${entry.name}\n${entry.content}`)
|
|
37
|
+
.join('\n\n---\n\n');
|
|
38
|
+
return `${instruction}
|
|
39
|
+
|
|
40
|
+
<child_entries>
|
|
41
|
+
${entriesText}
|
|
42
|
+
</child_entries>
|
|
43
|
+
|
|
44
|
+
Output ONLY the summary text. Do NOT use any tools.`;
|
|
45
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Snapshot diff utility for detecting context tree changes.
|
|
3
|
+
*
|
|
4
|
+
* Compares pre/post snapshot states to produce a list of changed paths.
|
|
5
|
+
* Used by CurateExecutor to determine which summaries need regeneration.
|
|
6
|
+
*/
|
|
7
|
+
import type { FileState } from '../../core/domain/entities/context-tree-snapshot.js';
|
|
8
|
+
/**
|
|
9
|
+
* Compare two snapshot states and return all changed paths.
|
|
10
|
+
*
|
|
11
|
+
* Returns paths that are:
|
|
12
|
+
* - Added: present in `after` but not in `before`
|
|
13
|
+
* - Modified: present in both but with different hashes
|
|
14
|
+
* - Deleted: present in `before` but not in `after`
|
|
15
|
+
*
|
|
16
|
+
* Derived artifacts (via isExcludedFromSync) are excluded from results
|
|
17
|
+
* since they are generated content that should not trigger summary regeneration.
|
|
18
|
+
*/
|
|
19
|
+
export declare function diffStates(before: Map<string, FileState>, after: Map<string, FileState>): string[];
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Snapshot diff utility for detecting context tree changes.
|
|
3
|
+
*
|
|
4
|
+
* Compares pre/post snapshot states to produce a list of changed paths.
|
|
5
|
+
* Used by CurateExecutor to determine which summaries need regeneration.
|
|
6
|
+
*/
|
|
7
|
+
import { isExcludedFromSync } from './derived-artifact.js';
|
|
8
|
+
/**
|
|
9
|
+
* Compare two snapshot states and return all changed paths.
|
|
10
|
+
*
|
|
11
|
+
* Returns paths that are:
|
|
12
|
+
* - Added: present in `after` but not in `before`
|
|
13
|
+
* - Modified: present in both but with different hashes
|
|
14
|
+
* - Deleted: present in `before` but not in `after`
|
|
15
|
+
*
|
|
16
|
+
* Derived artifacts (via isExcludedFromSync) are excluded from results
|
|
17
|
+
* since they are generated content that should not trigger summary regeneration.
|
|
18
|
+
*/
|
|
19
|
+
export function diffStates(before, after) {
|
|
20
|
+
const changedPaths = [];
|
|
21
|
+
// Detect additions and modifications
|
|
22
|
+
for (const [path, afterState] of after) {
|
|
23
|
+
if (isExcludedFromSync(path))
|
|
24
|
+
continue;
|
|
25
|
+
const beforeState = before.get(path);
|
|
26
|
+
if (!beforeState || beforeState.hash !== afterState.hash) {
|
|
27
|
+
changedPaths.push(path);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// Detect deletions
|
|
31
|
+
for (const path of before.keys()) {
|
|
32
|
+
if (isExcludedFromSync(path))
|
|
33
|
+
continue;
|
|
34
|
+
if (!after.has(path)) {
|
|
35
|
+
changedPaths.push(path);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return changedPaths;
|
|
39
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Summary and archive stub frontmatter parser/writer.
|
|
3
|
+
*
|
|
4
|
+
* Follows the same pattern as MarkdownWriter.parseFrontmatter() using js-yaml.
|
|
5
|
+
*/
|
|
6
|
+
import type { ArchiveStubFrontmatter, SummaryFrontmatter } from '../../core/domain/knowledge/summary-types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Parse summary frontmatter from markdown content.
|
|
9
|
+
* Returns null if no frontmatter found or type !== 'summary'.
|
|
10
|
+
*/
|
|
11
|
+
export declare function parseSummaryFrontmatter(content: string): null | SummaryFrontmatter;
|
|
12
|
+
/**
|
|
13
|
+
* Generate markdown content with summary frontmatter.
|
|
14
|
+
*/
|
|
15
|
+
export declare function generateSummaryContent(frontmatter: SummaryFrontmatter, body: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* Parse archive stub frontmatter from markdown content.
|
|
18
|
+
* Returns null if no frontmatter found or type !== 'archive_stub'.
|
|
19
|
+
*/
|
|
20
|
+
export declare function parseArchiveStubFrontmatter(content: string): ArchiveStubFrontmatter | null;
|
|
21
|
+
/**
|
|
22
|
+
* Generate markdown content with archive stub frontmatter and ghost cue body.
|
|
23
|
+
*/
|
|
24
|
+
export declare function generateArchiveStubContent(frontmatter: ArchiveStubFrontmatter, ghostCue: string): string;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Summary and archive stub frontmatter parser/writer.
|
|
3
|
+
*
|
|
4
|
+
* Follows the same pattern as MarkdownWriter.parseFrontmatter() using js-yaml.
|
|
5
|
+
*/
|
|
6
|
+
/* eslint-disable camelcase */
|
|
7
|
+
import { dump as yamlDump, load as yamlLoad } from 'js-yaml';
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// Summary frontmatter
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
/**
|
|
12
|
+
* Parse summary frontmatter from markdown content.
|
|
13
|
+
* Returns null if no frontmatter found or type !== 'summary'.
|
|
14
|
+
*/
|
|
15
|
+
export function parseSummaryFrontmatter(content) {
|
|
16
|
+
const parsed = parseYamlFrontmatter(content);
|
|
17
|
+
if (!parsed || parsed.type !== 'summary')
|
|
18
|
+
return null;
|
|
19
|
+
const condensationOrder = Number(parsed.condensation_order);
|
|
20
|
+
if (!isValidCondensationOrder(condensationOrder))
|
|
21
|
+
return null;
|
|
22
|
+
return {
|
|
23
|
+
children_hash: String(parsed.children_hash ?? ''),
|
|
24
|
+
compression_ratio: Number(parsed.compression_ratio ?? 0),
|
|
25
|
+
condensation_order: condensationOrder,
|
|
26
|
+
covers: Array.isArray(parsed.covers) ? parsed.covers.map(String) : [],
|
|
27
|
+
covers_token_total: Number(parsed.covers_token_total ?? 0),
|
|
28
|
+
summary_level: (String(parsed.summary_level ?? `d${condensationOrder}`)),
|
|
29
|
+
token_count: Number(parsed.token_count ?? 0),
|
|
30
|
+
type: 'summary',
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Generate markdown content with summary frontmatter.
|
|
35
|
+
*/
|
|
36
|
+
export function generateSummaryContent(frontmatter, body) {
|
|
37
|
+
const fm = {
|
|
38
|
+
children_hash: frontmatter.children_hash,
|
|
39
|
+
compression_ratio: frontmatter.compression_ratio,
|
|
40
|
+
condensation_order: frontmatter.condensation_order,
|
|
41
|
+
covers: frontmatter.covers,
|
|
42
|
+
covers_token_total: frontmatter.covers_token_total,
|
|
43
|
+
summary_level: frontmatter.summary_level,
|
|
44
|
+
token_count: frontmatter.token_count,
|
|
45
|
+
type: 'summary',
|
|
46
|
+
};
|
|
47
|
+
const yamlContent = yamlDump(fm, { flowLevel: 1, lineWidth: -1, sortKeys: true }).trimEnd();
|
|
48
|
+
return `---\n${yamlContent}\n---\n${body}`;
|
|
49
|
+
}
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
// Archive stub frontmatter
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
/**
|
|
54
|
+
* Parse archive stub frontmatter from markdown content.
|
|
55
|
+
* Returns null if no frontmatter found or type !== 'archive_stub'.
|
|
56
|
+
*/
|
|
57
|
+
export function parseArchiveStubFrontmatter(content) {
|
|
58
|
+
const parsed = parseYamlFrontmatter(content);
|
|
59
|
+
if (!parsed || parsed.type !== 'archive_stub')
|
|
60
|
+
return null;
|
|
61
|
+
return {
|
|
62
|
+
evicted_at: String(parsed.evicted_at ?? ''),
|
|
63
|
+
evicted_importance: Number(parsed.evicted_importance ?? 0),
|
|
64
|
+
original_path: String(parsed.original_path ?? ''),
|
|
65
|
+
original_token_count: Number(parsed.original_token_count ?? 0),
|
|
66
|
+
points_to: String(parsed.points_to ?? ''),
|
|
67
|
+
type: 'archive_stub',
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Generate markdown content with archive stub frontmatter and ghost cue body.
|
|
72
|
+
*/
|
|
73
|
+
export function generateArchiveStubContent(frontmatter, ghostCue) {
|
|
74
|
+
const fm = {
|
|
75
|
+
evicted_at: frontmatter.evicted_at,
|
|
76
|
+
evicted_importance: frontmatter.evicted_importance,
|
|
77
|
+
original_path: frontmatter.original_path,
|
|
78
|
+
original_token_count: frontmatter.original_token_count,
|
|
79
|
+
points_to: frontmatter.points_to,
|
|
80
|
+
type: 'archive_stub',
|
|
81
|
+
};
|
|
82
|
+
const yamlContent = yamlDump(fm, { flowLevel: 1, lineWidth: -1, sortKeys: true }).trimEnd();
|
|
83
|
+
return `---\n${yamlContent}\n---\n${ghostCue}`;
|
|
84
|
+
}
|
|
85
|
+
// ---------------------------------------------------------------------------
|
|
86
|
+
// Internal helpers
|
|
87
|
+
// ---------------------------------------------------------------------------
|
|
88
|
+
function parseYamlFrontmatter(content) {
|
|
89
|
+
if (!content.startsWith('---\n') && !content.startsWith('---\r\n')) {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
const endIndex = content.indexOf('\n---\n', 4);
|
|
93
|
+
const endIndexCrlf = content.indexOf('\r\n---\r\n', 5);
|
|
94
|
+
const actualEnd = endIndex === -1 ? endIndexCrlf : endIndex;
|
|
95
|
+
if (actualEnd < 0) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
const yamlBlock = content.slice(4, actualEnd);
|
|
99
|
+
try {
|
|
100
|
+
const parsed = yamlLoad(yamlBlock);
|
|
101
|
+
if (!parsed || typeof parsed !== 'object')
|
|
102
|
+
return null;
|
|
103
|
+
return parsed;
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function isValidCondensationOrder(value) {
|
|
110
|
+
return value === 0 || value === 1 || value === 2 || value === 3;
|
|
111
|
+
}
|
|
@@ -184,10 +184,6 @@ async function start() {
|
|
|
184
184
|
cachedActiveModel = activeModel ?? DEFAULT_LLM_MODEL;
|
|
185
185
|
agentLog(`Provider: ${activeProvider}, Model: ${activeModel ?? 'default'}`);
|
|
186
186
|
// 5. Create CipherAgent with lazy providers + transport client
|
|
187
|
-
// Set GOOGLE_APPLICATION_CREDENTIALS for Vertex AI before creating agent
|
|
188
|
-
if (providerResult.providerCredentialPath) {
|
|
189
|
-
process.env.GOOGLE_APPLICATION_CREDENTIALS = providerResult.providerCredentialPath;
|
|
190
|
-
}
|
|
191
187
|
const envConfig = getCurrentConfig();
|
|
192
188
|
const agentConfig = {
|
|
193
189
|
apiBaseUrl: envConfig.llmApiBaseUrl,
|
|
@@ -208,8 +204,6 @@ async function start() {
|
|
|
208
204
|
providerApiKey: providerResult.providerApiKey,
|
|
209
205
|
providerBaseUrl: providerResult.providerBaseUrl,
|
|
210
206
|
providerHeaders: providerResult.providerHeaders,
|
|
211
|
-
providerLocation: providerResult.providerLocation,
|
|
212
|
-
providerProject: providerResult.providerProject,
|
|
213
207
|
storagePath: configResult.storagePath,
|
|
214
208
|
};
|
|
215
209
|
agent = new CipherAgent(agentConfig, cachedBrvConfig, {
|
|
@@ -289,6 +283,7 @@ async function start() {
|
|
|
289
283
|
await folderPackService.initialize();
|
|
290
284
|
const folderPackExecutor = new FolderPackExecutor(folderPackService);
|
|
291
285
|
const queryExecutor = new QueryExecutor({
|
|
286
|
+
baseDirectory: projectPath,
|
|
292
287
|
enableCache: true,
|
|
293
288
|
fileSystem: fileSystemService,
|
|
294
289
|
searchService,
|
|
@@ -316,8 +311,7 @@ async function executeTask(task, curateExecutor, folderPackExecutor, queryExecut
|
|
|
316
311
|
}
|
|
317
312
|
if (freshProviderConfig.providerKeyMissing) {
|
|
318
313
|
const modelInfo = freshProviderConfig.activeModel ? ` (model: ${freshProviderConfig.activeModel})` : '';
|
|
319
|
-
const errorMessage = freshProviderConfig.
|
|
320
|
-
?? `${freshProviderConfig.activeProvider} API key is missing${modelInfo}. Use /provider in the REPL to reconnect.`;
|
|
314
|
+
const errorMessage = `${freshProviderConfig.activeProvider} API key is missing${modelInfo}. Use /provider in the REPL to reconnect.`;
|
|
321
315
|
const error = serializeTaskError(new TaskError(errorMessage, TaskErrorCode.PROVIDER_NOT_CONFIGURED));
|
|
322
316
|
transport.request(TransportTaskEventNames.ERROR, { clientId, error, taskId });
|
|
323
317
|
return;
|
|
@@ -476,10 +470,6 @@ async function hotSwapProvider(currentAgent, transportClient) {
|
|
|
476
470
|
return {};
|
|
477
471
|
}
|
|
478
472
|
// Phase 2a: Replace SessionManager (if this throws, old SM remains intact)
|
|
479
|
-
// Update GOOGLE_APPLICATION_CREDENTIALS for Vertex AI hot-swap
|
|
480
|
-
if (freshProvider.providerCredentialPath) {
|
|
481
|
-
process.env.GOOGLE_APPLICATION_CREDENTIALS = freshProvider.providerCredentialPath;
|
|
482
|
-
}
|
|
483
473
|
const previousSessionId = currentAgent.sessionId;
|
|
484
474
|
try {
|
|
485
475
|
// Map fields explicitly to prevent accidental field leakage from ProviderConfigResponse
|
|
@@ -491,8 +481,6 @@ async function hotSwapProvider(currentAgent, transportClient) {
|
|
|
491
481
|
providerApiKey: freshProvider.providerApiKey,
|
|
492
482
|
providerBaseUrl: freshProvider.providerBaseUrl,
|
|
493
483
|
providerHeaders: freshProvider.providerHeaders,
|
|
494
|
-
providerLocation: freshProvider.providerLocation,
|
|
495
|
-
providerProject: freshProvider.providerProject,
|
|
496
484
|
});
|
|
497
485
|
}
|
|
498
486
|
catch (error) {
|
|
@@ -26,6 +26,7 @@ export declare class CurateExecutor implements ICurateExecutor {
|
|
|
26
26
|
/** Last curation status — available for future status-check command */
|
|
27
27
|
lastStatus?: CurationStatus;
|
|
28
28
|
private readonly fileContentReader;
|
|
29
|
+
private readonly preCompactionService;
|
|
29
30
|
constructor(fileContentReader?: FileContentReader);
|
|
30
31
|
executeWithAgent(agent: ICipherAgent, options: CurateExecuteOptions): Promise<string>;
|
|
31
32
|
/**
|