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
|
@@ -2,6 +2,11 @@ import path from 'node:path';
|
|
|
2
2
|
import { FileValidationError } from '../../core/domain/errors/task-error.js';
|
|
3
3
|
import { createFileContentReader, } from '../../utils/file-content-reader.js';
|
|
4
4
|
import { validateFileForCurate } from '../../utils/file-validator.js';
|
|
5
|
+
import { FileContextTreeManifestService } from '../context-tree/file-context-tree-manifest-service.js';
|
|
6
|
+
import { FileContextTreeSnapshotService } from '../context-tree/file-context-tree-snapshot-service.js';
|
|
7
|
+
import { FileContextTreeSummaryService } from '../context-tree/file-context-tree-summary-service.js';
|
|
8
|
+
import { diffStates } from '../context-tree/snapshot-diff.js';
|
|
9
|
+
import { PreCompactionService } from './pre-compaction/pre-compaction-service.js';
|
|
5
10
|
/**
|
|
6
11
|
* CurateExecutor - Executes curate tasks with an injected CipherAgent.
|
|
7
12
|
*
|
|
@@ -26,48 +31,72 @@ export class CurateExecutor {
|
|
|
26
31
|
/** Last curation status — available for future status-check command */
|
|
27
32
|
lastStatus;
|
|
28
33
|
fileContentReader;
|
|
34
|
+
preCompactionService = new PreCompactionService();
|
|
29
35
|
constructor(fileContentReader) {
|
|
30
36
|
this.fileContentReader = fileContentReader ?? createFileContentReader();
|
|
31
37
|
}
|
|
32
38
|
async executeWithAgent(agent, options) {
|
|
33
39
|
const { clientCwd, content, files, taskId } = options;
|
|
34
|
-
//
|
|
35
|
-
const taskSessionId = await agent.createTaskSession(taskId, 'curate');
|
|
36
|
-
// Process file references - reads file contents directly
|
|
40
|
+
// --- Phase 1: Preprocessing (no sessions created yet — safe to throw) ---
|
|
37
41
|
const fileReferenceInstructions = await this.processFileReferences(files ?? [], clientCwd);
|
|
38
|
-
// Build full context (content + optional file references)
|
|
39
42
|
const fullContext = fileReferenceInstructions ? `${content}\n${fileReferenceInstructions}` : content;
|
|
40
|
-
//
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
//
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
type: 'string',
|
|
56
|
-
};
|
|
57
|
-
// Inject context, metadata, and empty history into the TASK session's sandbox
|
|
58
|
-
agent.setSandboxVariableOnSession(taskSessionId, ctxVar, fullContext);
|
|
59
|
-
agent.setSandboxVariableOnSession(taskSessionId, histVar, { entries: [], totalProcessed: 0 });
|
|
60
|
-
agent.setSandboxVariableOnSession(taskSessionId, metaVar, metadata);
|
|
61
|
-
// Prompt with metadata guidance (RLM pattern: LM sees metadata first, peeks via slicing)
|
|
62
|
-
const prompt = [
|
|
63
|
-
`Curate using RLM approach.`,
|
|
64
|
-
`Context variable: ${ctxVar} (${metadata.charCount} chars, ${metadata.lineCount} lines, ${metadata.messageCount} messages)`,
|
|
65
|
-
`History variable: ${histVar}`,
|
|
66
|
-
`Metadata variable: ${metaVar}`,
|
|
67
|
-
`IMPORTANT: Do NOT print raw context. Use slicing to peek at sections (e.g., ${ctxVar}.slice(0, 3000)).`,
|
|
68
|
-
`Use silent mode (silent: true) for variable assignments. Use tools.agentQuery() for chunk processing.`,
|
|
69
|
-
].join('\n');
|
|
43
|
+
// --- Phase 2: Pre-compaction (fail-open, manages its own session lifecycle) ---
|
|
44
|
+
const compactionResult = await this.preCompactionService.compact(agent, fullContext, taskId);
|
|
45
|
+
const effectiveContext = compactionResult.context;
|
|
46
|
+
// --- Phase 3: Curation (session created AFTER preprocessing + compaction) ---
|
|
47
|
+
// Capture pre-curation state for snapshot diff (summary propagation)
|
|
48
|
+
const baseDir = clientCwd ?? process.cwd();
|
|
49
|
+
const snapshotService = new FileContextTreeSnapshotService({ baseDirectory: baseDir });
|
|
50
|
+
let preState;
|
|
51
|
+
try {
|
|
52
|
+
preState = await snapshotService.getCurrentState(baseDir);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
// Fail-open: if snapshot fails, skip summary propagation
|
|
56
|
+
}
|
|
57
|
+
const taskSessionId = await agent.createTaskSession(taskId, 'curate', { mapRootEligible: true });
|
|
70
58
|
try {
|
|
59
|
+
// Task-scoped variable names for RLM pattern.
|
|
60
|
+
// Replace hyphens with underscores: UUIDs have hyphens which are invalid in JS identifiers,
|
|
61
|
+
// so the LLM would naturally use underscores when writing code-exec calls — causing a
|
|
62
|
+
// ReferenceError if the variable was stored under the hyphen version.
|
|
63
|
+
const taskIdSafe = taskId.replaceAll('-', '_');
|
|
64
|
+
const ctxVar = `__curate_ctx_${taskIdSafe}`;
|
|
65
|
+
const histVar = `__curate_hist_${taskIdSafe}`;
|
|
66
|
+
const metaVar = `__curate_meta_${taskIdSafe}`;
|
|
67
|
+
// Compute context metadata (RLM pattern — LM sees metadata, not raw content)
|
|
68
|
+
const contextLines = effectiveContext.split('\n');
|
|
69
|
+
const metadata = {
|
|
70
|
+
charCount: effectiveContext.length,
|
|
71
|
+
lineCount: contextLines.length,
|
|
72
|
+
messageCount: (effectiveContext.match(/\n\n\[(USER|ASSISTANT)\]:/g) || []).length,
|
|
73
|
+
...(compactionResult.preCompacted && {
|
|
74
|
+
originalCharCount: compactionResult.originalCharCount,
|
|
75
|
+
preCompacted: true,
|
|
76
|
+
preCompactionTier: compactionResult.preCompactionTier,
|
|
77
|
+
}),
|
|
78
|
+
preview: effectiveContext.slice(0, 500),
|
|
79
|
+
type: 'string',
|
|
80
|
+
};
|
|
81
|
+
// Inject context, metadata, empty history, and taskId into the TASK session's sandbox
|
|
82
|
+
const taskIdVar = `__taskId_${taskIdSafe}`;
|
|
83
|
+
agent.setSandboxVariableOnSession(taskSessionId, ctxVar, effectiveContext);
|
|
84
|
+
agent.setSandboxVariableOnSession(taskSessionId, histVar, { entries: [], totalProcessed: 0 });
|
|
85
|
+
agent.setSandboxVariableOnSession(taskSessionId, metaVar, metadata);
|
|
86
|
+
agent.setSandboxVariableOnSession(taskSessionId, taskIdVar, taskId);
|
|
87
|
+
// Prompt with curation helpers guidance (tools.curation.* replaces manual infrastructure code)
|
|
88
|
+
const prompt = [
|
|
89
|
+
`Curate using RLM approach.`,
|
|
90
|
+
`Context variable: ${ctxVar} (${metadata.charCount} chars, ${metadata.lineCount} lines, ${metadata.messageCount} messages)`,
|
|
91
|
+
`History variable: ${histVar}`,
|
|
92
|
+
`Metadata variable: ${metaVar}`,
|
|
93
|
+
`Task ID variable: ${taskIdVar} (pass as bare variable, not a string)`,
|
|
94
|
+
`IMPORTANT: Do NOT print raw context. Start with tools.curation.recon(${ctxVar}, ${metaVar}, ${histVar}) to assess.`,
|
|
95
|
+
`For chunked extraction use tools.curation.mapExtract(). Pass taskId: ${taskIdVar} (bare variable).`,
|
|
96
|
+
`IMPORTANT: Any code_exec call containing mapExtract MUST use timeout: 300000 on the code_exec tool call itself (not inside mapExtract options).`,
|
|
97
|
+
`Use tools.curation.groupBySubject() and tools.curation.dedup() to organize extractions.`,
|
|
98
|
+
`Verify via result.applied[].filePath — do NOT call readFile for verification.`,
|
|
99
|
+
].join('\n');
|
|
71
100
|
// Execute on the task session (isolated sandbox + history)
|
|
72
101
|
// Task lifecycle is managed by Transport (task:started, task:completed, task:error)
|
|
73
102
|
const response = await agent.executeOnSession(taskSessionId, prompt, {
|
|
@@ -76,6 +105,25 @@ export class CurateExecutor {
|
|
|
76
105
|
});
|
|
77
106
|
// Parse curation status from agent response for status tracking
|
|
78
107
|
this.lastStatus = this.parseCurationStatus(taskId, response);
|
|
108
|
+
// --- Phase 4: Post-curation summary propagation (fail-open) ---
|
|
109
|
+
if (preState) {
|
|
110
|
+
try {
|
|
111
|
+
const postState = await snapshotService.getCurrentState(baseDir);
|
|
112
|
+
const changedPaths = diffStates(preState, postState);
|
|
113
|
+
if (changedPaths.length > 0) {
|
|
114
|
+
const summaryService = new FileContextTreeSummaryService();
|
|
115
|
+
const results = await summaryService.propagateStaleness(changedPaths, agent, baseDir);
|
|
116
|
+
// Opportunistic manifest rebuild (pre-warm for next query)
|
|
117
|
+
if (results.some((r) => r.actionTaken)) {
|
|
118
|
+
const manifestService = new FileContextTreeManifestService({ baseDirectory: baseDir });
|
|
119
|
+
await manifestService.buildManifest(baseDir);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// Fail-open: summary/manifest errors never block curation
|
|
125
|
+
}
|
|
126
|
+
}
|
|
79
127
|
return response;
|
|
80
128
|
}
|
|
81
129
|
finally {
|
|
@@ -773,7 +773,7 @@ await tools.curate([{
|
|
|
773
773
|
throw new Error(`Failed to write temp file: ${error instanceof Error ? error.message : String(error)}`);
|
|
774
774
|
}
|
|
775
775
|
// Create per-task session for parallel isolation (own sandbox + history + LLM service)
|
|
776
|
-
const taskSessionId = await agent.createTaskSession(taskId, 'curate');
|
|
776
|
+
const taskSessionId = await agent.createTaskSession(taskId, 'curate', { mapRootEligible: true });
|
|
777
777
|
// Step 3: Store full instructions as sandbox variable (lazy prompt loading).
|
|
778
778
|
// This saves ~12-15K tokens by keeping the massive instruction set out of the prompt.
|
|
779
779
|
// The LLM reads instructions on-demand via code_exec.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Re-export from shared utilities.
|
|
3
|
+
* Original implementation moved to src/shared/utils/escalation-utils.ts
|
|
4
|
+
* to allow cross-layer reuse (both server/ and agent/ can import).
|
|
5
|
+
*/
|
|
6
|
+
export { buildDeterministicFallbackCompaction, type CompactionEscalationTier, estimateTokens, isCompactionOutputValid, shouldAcceptCompactionOutput, withAggressiveCompactionDirective, } from '../../../../shared/utils/escalation-utils.js';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Re-export from shared utilities.
|
|
3
|
+
* Original implementation moved to src/shared/utils/escalation-utils.ts
|
|
4
|
+
* to allow cross-layer reuse (both server/ and agent/ can import).
|
|
5
|
+
*/
|
|
6
|
+
export { buildDeterministicFallbackCompaction, estimateTokens, isCompactionOutputValid, shouldAcceptCompactionOutput, withAggressiveCompactionDirective, } from '../../../../shared/utils/escalation-utils.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { PRE_COMPACTION_CHAR_THRESHOLD, PreCompactionService } from './pre-compaction-service.js';
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pre-Compaction Service — Three-Level Escalation for curation context.
|
|
3
|
+
*
|
|
4
|
+
* Compacts large source context BEFORE the curation agent sees it,
|
|
5
|
+
* saving the agent from wasting iterations on chunking/extraction code.
|
|
6
|
+
*
|
|
7
|
+
* Fail-open: any error returns the original context unchanged.
|
|
8
|
+
*/
|
|
9
|
+
import type { ICipherAgent } from '../../../../agent/core/interfaces/i-cipher-agent.js';
|
|
10
|
+
import { type CompactionEscalationTier } from './compaction-escalation.js';
|
|
11
|
+
/**
|
|
12
|
+
* Character threshold below which compaction is skipped.
|
|
13
|
+
* Re-exported from shared constant for backwards compatibility.
|
|
14
|
+
*/
|
|
15
|
+
export declare const PRE_COMPACTION_CHAR_THRESHOLD = 20000;
|
|
16
|
+
/**
|
|
17
|
+
* Result of a pre-compaction operation.
|
|
18
|
+
*/
|
|
19
|
+
export interface PreCompactionResult {
|
|
20
|
+
/** The (possibly compacted) context text */
|
|
21
|
+
context: string;
|
|
22
|
+
/** Original character count before compaction */
|
|
23
|
+
originalCharCount: number;
|
|
24
|
+
/** Whether compaction was actually applied */
|
|
25
|
+
preCompacted: boolean;
|
|
26
|
+
/** Which escalation tier succeeded (only set if preCompacted is true) */
|
|
27
|
+
preCompactionTier?: CompactionEscalationTier;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Service that pre-compacts curation context using three-level escalation.
|
|
31
|
+
*
|
|
32
|
+
* Level 1 (Normal): LLM compaction with standard prompt
|
|
33
|
+
* Level 2 (Aggressive): LLM compaction with aggressive prompt
|
|
34
|
+
* Level 3 (Fallback): Deterministic truncation (no LLM, always converges)
|
|
35
|
+
*/
|
|
36
|
+
export declare class PreCompactionService {
|
|
37
|
+
/**
|
|
38
|
+
* Compact context if it exceeds the character threshold.
|
|
39
|
+
*
|
|
40
|
+
* Fail-open: any error during compaction returns the original context.
|
|
41
|
+
* Deterministic fallback is only used when the LLM responded but with
|
|
42
|
+
* unacceptable output — never when the LLM itself errored.
|
|
43
|
+
* Manages its own session lifecycle (creates + deletes a task session).
|
|
44
|
+
*
|
|
45
|
+
* @param agent - The CipherAgent to use for LLM calls
|
|
46
|
+
* @param context - The source context to compact
|
|
47
|
+
* @param taskId - Parent task ID (compaction uses `${taskId}__compact`)
|
|
48
|
+
* @returns PreCompactionResult with the (possibly compacted) context
|
|
49
|
+
*/
|
|
50
|
+
compact(agent: ICipherAgent, context: string, taskId: string): Promise<PreCompactionResult>;
|
|
51
|
+
/**
|
|
52
|
+
* Execute a single compaction pass via the agent.
|
|
53
|
+
*
|
|
54
|
+
* Returns a discriminated result so the caller can distinguish
|
|
55
|
+
* "LLM responded with bad output" from "LLM errored" — the former
|
|
56
|
+
* should escalate to the next tier, the latter should fail-open.
|
|
57
|
+
*/
|
|
58
|
+
private executeCompactionPass;
|
|
59
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pre-Compaction Service — Three-Level Escalation for curation context.
|
|
3
|
+
*
|
|
4
|
+
* Compacts large source context BEFORE the curation agent sees it,
|
|
5
|
+
* saving the agent from wasting iterations on chunking/extraction code.
|
|
6
|
+
*
|
|
7
|
+
* Fail-open: any error returns the original context unchanged.
|
|
8
|
+
*/
|
|
9
|
+
import { CURATION_CHAR_THRESHOLD } from '../../../../shared/constants/curation.js';
|
|
10
|
+
import { buildDeterministicFallbackCompaction, estimateTokens, isCompactionOutputValid, shouldAcceptCompactionOutput, } from './compaction-escalation.js';
|
|
11
|
+
import { buildCompactionSystemPrompt, buildCompactionUserMessage } from './prompts.js';
|
|
12
|
+
/**
|
|
13
|
+
* Character threshold below which compaction is skipped.
|
|
14
|
+
* Re-exported from shared constant for backwards compatibility.
|
|
15
|
+
*/
|
|
16
|
+
export const PRE_COMPACTION_CHAR_THRESHOLD = CURATION_CHAR_THRESHOLD;
|
|
17
|
+
/**
|
|
18
|
+
* Service that pre-compacts curation context using three-level escalation.
|
|
19
|
+
*
|
|
20
|
+
* Level 1 (Normal): LLM compaction with standard prompt
|
|
21
|
+
* Level 2 (Aggressive): LLM compaction with aggressive prompt
|
|
22
|
+
* Level 3 (Fallback): Deterministic truncation (no LLM, always converges)
|
|
23
|
+
*/
|
|
24
|
+
export class PreCompactionService {
|
|
25
|
+
/**
|
|
26
|
+
* Compact context if it exceeds the character threshold.
|
|
27
|
+
*
|
|
28
|
+
* Fail-open: any error during compaction returns the original context.
|
|
29
|
+
* Deterministic fallback is only used when the LLM responded but with
|
|
30
|
+
* unacceptable output — never when the LLM itself errored.
|
|
31
|
+
* Manages its own session lifecycle (creates + deletes a task session).
|
|
32
|
+
*
|
|
33
|
+
* @param agent - The CipherAgent to use for LLM calls
|
|
34
|
+
* @param context - The source context to compact
|
|
35
|
+
* @param taskId - Parent task ID (compaction uses `${taskId}__compact`)
|
|
36
|
+
* @returns PreCompactionResult with the (possibly compacted) context
|
|
37
|
+
*/
|
|
38
|
+
async compact(agent, context, taskId) {
|
|
39
|
+
const originalCharCount = context.length;
|
|
40
|
+
const failOpen = { context, originalCharCount, preCompacted: false };
|
|
41
|
+
if (originalCharCount <= PRE_COMPACTION_CHAR_THRESHOLD) {
|
|
42
|
+
return failOpen;
|
|
43
|
+
}
|
|
44
|
+
const inputTokens = estimateTokens(context);
|
|
45
|
+
const compactionTaskId = `${taskId}__compact`;
|
|
46
|
+
try {
|
|
47
|
+
const sessionId = await agent.createTaskSession(compactionTaskId, 'query');
|
|
48
|
+
try {
|
|
49
|
+
// --- Pass 1: Normal compaction ---
|
|
50
|
+
const normalPass = await this.executeCompactionPass({ agent, aggressive: false, context, sessionId, taskId: compactionTaskId });
|
|
51
|
+
if (normalPass.errored)
|
|
52
|
+
return failOpen;
|
|
53
|
+
if (normalPass.output && shouldAcceptCompactionOutput(normalPass.output, inputTokens) && isCompactionOutputValid(normalPass.output)) {
|
|
54
|
+
return {
|
|
55
|
+
context: normalPass.output.trim(),
|
|
56
|
+
originalCharCount,
|
|
57
|
+
preCompacted: true,
|
|
58
|
+
preCompactionTier: 'normal',
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
// --- Pass 2: Aggressive compaction ---
|
|
62
|
+
const aggressivePass = await this.executeCompactionPass({ agent, aggressive: true, context, sessionId, taskId: compactionTaskId });
|
|
63
|
+
if (aggressivePass.errored)
|
|
64
|
+
return failOpen;
|
|
65
|
+
if (aggressivePass.output && shouldAcceptCompactionOutput(aggressivePass.output, inputTokens) && isCompactionOutputValid(aggressivePass.output)) {
|
|
66
|
+
return {
|
|
67
|
+
context: aggressivePass.output.trim(),
|
|
68
|
+
originalCharCount,
|
|
69
|
+
preCompacted: true,
|
|
70
|
+
preCompactionTier: 'aggressive',
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
// --- Pass 3: Deterministic fallback ---
|
|
74
|
+
// Only reached when both passes got LLM responses but output was unacceptable
|
|
75
|
+
const fallbackResult = buildDeterministicFallbackCompaction({
|
|
76
|
+
inputTokens,
|
|
77
|
+
sourceText: context,
|
|
78
|
+
suffixLabel: 'pre-curation compaction',
|
|
79
|
+
});
|
|
80
|
+
return {
|
|
81
|
+
context: fallbackResult,
|
|
82
|
+
originalCharCount,
|
|
83
|
+
preCompacted: true,
|
|
84
|
+
preCompactionTier: 'fallback',
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
await agent.deleteTaskSession(sessionId);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
// Fail-open: return original context on ANY error
|
|
93
|
+
return failOpen;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Execute a single compaction pass via the agent.
|
|
98
|
+
*
|
|
99
|
+
* Returns a discriminated result so the caller can distinguish
|
|
100
|
+
* "LLM responded with bad output" from "LLM errored" — the former
|
|
101
|
+
* should escalate to the next tier, the latter should fail-open.
|
|
102
|
+
*/
|
|
103
|
+
async executeCompactionPass(options) {
|
|
104
|
+
try {
|
|
105
|
+
const systemPrompt = buildCompactionSystemPrompt();
|
|
106
|
+
const userMessage = buildCompactionUserMessage(options.context, options.aggressive);
|
|
107
|
+
const prompt = `${systemPrompt}\n\n${userMessage}`;
|
|
108
|
+
const response = await options.agent.executeOnSession(options.sessionId, prompt, {
|
|
109
|
+
executionContext: {
|
|
110
|
+
clearHistory: true,
|
|
111
|
+
commandType: 'query',
|
|
112
|
+
maxIterations: 1,
|
|
113
|
+
maxTokens: 4096,
|
|
114
|
+
temperature: 0.3,
|
|
115
|
+
},
|
|
116
|
+
taskId: options.taskId,
|
|
117
|
+
});
|
|
118
|
+
return { errored: false, output: response || undefined };
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
return { errored: true, output: undefined };
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compaction prompts for pre-curation context compaction.
|
|
3
|
+
*
|
|
4
|
+
* Self-contained prompts that steer the LLM away from query-mode policy
|
|
5
|
+
* (which would try to search the KB). The real guardrail against
|
|
6
|
+
* non-compaction responses is isCompactionOutputValid().
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Build the system prompt for compaction.
|
|
10
|
+
*
|
|
11
|
+
* Opens with a clear, self-contained instruction that overrides
|
|
12
|
+
* query-mode's "answers from KB only" rules. Note: prompt-level override
|
|
13
|
+
* is best-effort; isCompactionOutputValid() is the actual guardrail.
|
|
14
|
+
*/
|
|
15
|
+
export declare function buildCompactionSystemPrompt(): string;
|
|
16
|
+
/**
|
|
17
|
+
* Build the user message for a compaction pass.
|
|
18
|
+
*
|
|
19
|
+
* Wraps the context in <source_content> tags for clear delimitation.
|
|
20
|
+
*
|
|
21
|
+
* @param context - The source text to compact
|
|
22
|
+
* @param aggressive - Whether this is the aggressive (pass 2) attempt
|
|
23
|
+
*/
|
|
24
|
+
export declare function buildCompactionUserMessage(context: string, aggressive: boolean): string;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compaction prompts for pre-curation context compaction.
|
|
3
|
+
*
|
|
4
|
+
* Self-contained prompts that steer the LLM away from query-mode policy
|
|
5
|
+
* (which would try to search the KB). The real guardrail against
|
|
6
|
+
* non-compaction responses is isCompactionOutputValid().
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Build the system prompt for compaction.
|
|
10
|
+
*
|
|
11
|
+
* Opens with a clear, self-contained instruction that overrides
|
|
12
|
+
* query-mode's "answers from KB only" rules. Note: prompt-level override
|
|
13
|
+
* is best-effort; isCompactionOutputValid() is the actual guardrail.
|
|
14
|
+
*/
|
|
15
|
+
export function buildCompactionSystemPrompt() {
|
|
16
|
+
return `You are a knowledge extraction pre-processor. Your ONLY task is to compact the provided text.
|
|
17
|
+
|
|
18
|
+
## Rules
|
|
19
|
+
- PRESERVE: facts, decisions, code examples, API signatures, diagrams (verbatim), tables (all rows), procedures, file paths, configurations, error patterns
|
|
20
|
+
- REMOVE: conversational filler, repeated explanations, verbose tool call descriptions, meta-commentary, acknowledgments
|
|
21
|
+
- Output clean structured markdown
|
|
22
|
+
- Do NOT wrap output in code blocks or XML tags
|
|
23
|
+
- Do NOT search any knowledge base
|
|
24
|
+
- Do NOT answer questions about the content
|
|
25
|
+
- Do NOT use any tools
|
|
26
|
+
- Output ONLY the compacted text`;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Build the user message for a compaction pass.
|
|
30
|
+
*
|
|
31
|
+
* Wraps the context in <source_content> tags for clear delimitation.
|
|
32
|
+
*
|
|
33
|
+
* @param context - The source text to compact
|
|
34
|
+
* @param aggressive - Whether this is the aggressive (pass 2) attempt
|
|
35
|
+
*/
|
|
36
|
+
export function buildCompactionUserMessage(context, aggressive) {
|
|
37
|
+
const instruction = aggressive
|
|
38
|
+
? 'Compact the following text MORE AGGRESSIVELY. A previous compaction attempt was not short enough. Remove all non-essential detail while keeping core facts, decisions, and code.'
|
|
39
|
+
: 'Compact the following text while preserving all knowledge-worthy information — facts, decisions, code, configurations, procedures.';
|
|
40
|
+
return `${instruction}
|
|
41
|
+
|
|
42
|
+
<source_content>
|
|
43
|
+
${context}
|
|
44
|
+
</source_content>
|
|
45
|
+
|
|
46
|
+
Output ONLY the compacted text. Do NOT use any tools.`;
|
|
47
|
+
}
|
|
@@ -7,6 +7,8 @@ import type { IQueryExecutor, QueryExecuteOptions } from '../../core/interfaces/
|
|
|
7
7
|
* All fields are optional — without them, the executor falls back to the original behavior.
|
|
8
8
|
*/
|
|
9
9
|
export interface QueryExecutorDeps {
|
|
10
|
+
/** Base directory for manifest service (e.g., project path) */
|
|
11
|
+
baseDirectory?: string;
|
|
10
12
|
/** Enable query result caching (default: false) */
|
|
11
13
|
enableCache?: boolean;
|
|
12
14
|
/** File system for reading full document content and computing fingerprints */
|
|
@@ -35,6 +37,7 @@ export interface QueryExecutorDeps {
|
|
|
35
37
|
*/
|
|
36
38
|
export declare class QueryExecutor implements IQueryExecutor {
|
|
37
39
|
private static readonly FINGERPRINT_CACHE_TTL_MS;
|
|
40
|
+
private readonly baseDirectory?;
|
|
38
41
|
private readonly cache?;
|
|
39
42
|
private cachedFingerprint?;
|
|
40
43
|
private readonly fileSystem?;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { join } from 'node:path';
|
|
2
2
|
import { BRV_DIR, CONTEXT_FILE_EXTENSION, CONTEXT_TREE_DIR } from '../../constants.js';
|
|
3
|
+
import { isDerivedArtifact } from '../context-tree/derived-artifact.js';
|
|
4
|
+
import { FileContextTreeManifestService } from '../context-tree/file-context-tree-manifest-service.js';
|
|
3
5
|
import { canRespondDirectly, formatDirectResponse, formatNotFoundResponse, } from './direct-search-responder.js';
|
|
4
6
|
import { QueryResultCache } from './query-result-cache.js';
|
|
5
7
|
/** Attribution footer appended to all query responses */
|
|
@@ -29,11 +31,13 @@ const SMART_ROUTING_MAX_DOCS = 5;
|
|
|
29
31
|
*/
|
|
30
32
|
export class QueryExecutor {
|
|
31
33
|
static FINGERPRINT_CACHE_TTL_MS = 30_000;
|
|
34
|
+
baseDirectory;
|
|
32
35
|
cache;
|
|
33
36
|
cachedFingerprint;
|
|
34
37
|
fileSystem;
|
|
35
38
|
searchService;
|
|
36
39
|
constructor(deps) {
|
|
40
|
+
this.baseDirectory = deps?.baseDirectory;
|
|
37
41
|
this.fileSystem = deps?.fileSystem;
|
|
38
42
|
this.searchService = deps?.searchService;
|
|
39
43
|
if (deps?.enableCache) {
|
|
@@ -97,6 +101,28 @@ export class QueryExecutor {
|
|
|
97
101
|
if (searchResult && this.fileSystem) {
|
|
98
102
|
prefetchedContext = this.buildPrefetchedContext(searchResult);
|
|
99
103
|
}
|
|
104
|
+
// Lazy manifest rebuild: provides broad structural awareness for LLM
|
|
105
|
+
let manifestContext;
|
|
106
|
+
if (this.baseDirectory) {
|
|
107
|
+
try {
|
|
108
|
+
const manifestService = new FileContextTreeManifestService({ baseDirectory: this.baseDirectory });
|
|
109
|
+
let manifest = await manifestService.readManifestIfFresh(this.baseDirectory);
|
|
110
|
+
if (!manifest) {
|
|
111
|
+
manifest = await manifestService.buildManifest(this.baseDirectory);
|
|
112
|
+
}
|
|
113
|
+
if (manifest) {
|
|
114
|
+
const resolved = await manifestService.resolveForInjection(manifest, query, this.baseDirectory);
|
|
115
|
+
if (resolved.length > 0) {
|
|
116
|
+
manifestContext = resolved
|
|
117
|
+
.map((e) => `[${e.type} ${e.path}]\n${e.content}`)
|
|
118
|
+
.join('\n\n---\n\n');
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
// Fail-open: proceed without manifest context
|
|
124
|
+
}
|
|
125
|
+
}
|
|
100
126
|
// Create per-task session for parallel isolation (own sandbox + history + LLM service)
|
|
101
127
|
const taskSessionId = await agent.createTaskSession(taskId, 'query');
|
|
102
128
|
// Task-scoped variable names for sandbox injection (RLM pattern).
|
|
@@ -116,6 +142,7 @@ export class QueryExecutor {
|
|
|
116
142
|
agent.setSandboxVariableOnSession(taskSessionId, resultsVar, searchResult?.results ?? []);
|
|
117
143
|
agent.setSandboxVariableOnSession(taskSessionId, metaVar, metadata);
|
|
118
144
|
const prompt = this.buildQueryPrompt(query, {
|
|
145
|
+
manifestContext,
|
|
119
146
|
metadata,
|
|
120
147
|
metaVar,
|
|
121
148
|
prefetchedContext,
|
|
@@ -165,7 +192,7 @@ export class QueryExecutor {
|
|
|
165
192
|
* @param options - Prompt options with variable names and metadata
|
|
166
193
|
*/
|
|
167
194
|
buildQueryPrompt(query, options) {
|
|
168
|
-
const { metadata, metaVar, prefetchedContext, resultsVar } = options;
|
|
195
|
+
const { manifestContext, metadata, metaVar, prefetchedContext, resultsVar } = options;
|
|
169
196
|
const groundingRules = `### Grounding Rules (CRITICAL)
|
|
170
197
|
- ONLY use information from the curated knowledge base (.brv/context-tree/)
|
|
171
198
|
- If no relevant knowledge is found, respond: "This topic is not covered in the knowledge base."
|
|
@@ -177,6 +204,9 @@ export class QueryExecutor {
|
|
|
177
204
|
- **Details**: Key findings with explanations
|
|
178
205
|
- **Sources**: File paths from .brv/context-tree/
|
|
179
206
|
- **Gaps**: Note any aspects not covered`;
|
|
207
|
+
const manifestSection = manifestContext
|
|
208
|
+
? `\n## Structural Context (from manifest)\nThe following provides broad structural awareness of the knowledge base:\n\n${manifestContext}\n`
|
|
209
|
+
: '';
|
|
180
210
|
if (prefetchedContext) {
|
|
181
211
|
return `## User Query
|
|
182
212
|
${query}
|
|
@@ -185,7 +215,7 @@ ${query}
|
|
|
185
215
|
The following relevant knowledge was found in the context tree:
|
|
186
216
|
|
|
187
217
|
${prefetchedContext}
|
|
188
|
-
|
|
218
|
+
${manifestSection}
|
|
189
219
|
## Search Results Variable
|
|
190
220
|
Additional search results: \`${resultsVar}\` (${metadata.resultCount} results, top score: ${metadata.topScore.toFixed(2)})
|
|
191
221
|
Metadata: \`${metaVar}\`
|
|
@@ -202,7 +232,7 @@ ${responseFormat}`;
|
|
|
202
232
|
}
|
|
203
233
|
return `## User Query
|
|
204
234
|
${query}
|
|
205
|
-
|
|
235
|
+
${manifestSection}
|
|
206
236
|
## Search Results Variable
|
|
207
237
|
Search results: \`${resultsVar}\` (${metadata.resultCount} results, top score: ${metadata.topScore.toFixed(2)})
|
|
208
238
|
Metadata: \`${metaVar}\`
|
|
@@ -234,7 +264,12 @@ ${responseFormat}`;
|
|
|
234
264
|
maxResults: 10_000,
|
|
235
265
|
respectGitignore: false,
|
|
236
266
|
});
|
|
237
|
-
|
|
267
|
+
// Filter out non-searchable derived artifacts (_index.md, _manifest.json, .full.md).
|
|
268
|
+
// Stubs (.stub.md) are intentionally kept — archive/restore should invalidate cache.
|
|
269
|
+
// Summary-only churn does NOT invalidate cache (summaries are derivative content).
|
|
270
|
+
const files = globResult.files
|
|
271
|
+
.filter((f) => !isDerivedArtifact(f.path))
|
|
272
|
+
.map((f) => ({
|
|
238
273
|
mtime: f.modified?.getTime() ?? 0,
|
|
239
274
|
path: f.path,
|
|
240
275
|
}));
|
|
@@ -153,6 +153,10 @@ export class AuthenticatedHttpClient {
|
|
|
153
153
|
if ('message' in responseData && typeof responseData.message === 'string') {
|
|
154
154
|
return responseData.message;
|
|
155
155
|
}
|
|
156
|
+
// Some endpoints return 'error' instead of 'message'
|
|
157
|
+
if ('error' in responseData && typeof responseData.error === 'string') {
|
|
158
|
+
return responseData.error;
|
|
159
|
+
}
|
|
156
160
|
// Fallback to HTTP status error
|
|
157
161
|
return `HTTP ${error.response.status}: ${error.response.statusText}`;
|
|
158
162
|
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { PROVIDER_REGISTRY } from '../../core/domain/entities/provider-registry.js';
|
|
8
8
|
import { FileProviderConfigStore } from '../storage/file-provider-config-store.js';
|
|
9
|
-
import { AnthropicModelFetcher, ChatBasedModelFetcher, GoogleModelFetcher,
|
|
9
|
+
import { AnthropicModelFetcher, ChatBasedModelFetcher, GoogleModelFetcher, OpenAICompatibleModelFetcher, OpenAIModelFetcher, OpenRouterModelFetcher, } from './provider-model-fetchers.js';
|
|
10
10
|
/**
|
|
11
11
|
* Singleton instances of model fetchers, lazily created.
|
|
12
12
|
*/
|
|
@@ -63,10 +63,6 @@ export async function getModelFetcher(providerId) {
|
|
|
63
63
|
fetcher = new GoogleModelFetcher();
|
|
64
64
|
break;
|
|
65
65
|
}
|
|
66
|
-
case 'google-vertex': {
|
|
67
|
-
fetcher = new GoogleVertexModelFetcher();
|
|
68
|
-
break;
|
|
69
|
-
}
|
|
70
66
|
case 'minimax': {
|
|
71
67
|
fetcher = new ChatBasedModelFetcher('https://api.minimax.io/v1', 'MiniMax', ['MiniMax-M2', 'MiniMax-M2-Stable']);
|
|
72
68
|
break;
|
|
@@ -50,20 +50,6 @@ export declare class GoogleModelFetcher implements IProviderModelFetcher {
|
|
|
50
50
|
isValid: boolean;
|
|
51
51
|
}>;
|
|
52
52
|
}
|
|
53
|
-
/**
|
|
54
|
-
* Fetches models from Google Vertex AI using the @google/genai SDK with vertexai mode.
|
|
55
|
-
* Uses Application Default Credentials (ADC) instead of API keys.
|
|
56
|
-
*/
|
|
57
|
-
export declare class GoogleVertexModelFetcher implements IProviderModelFetcher {
|
|
58
|
-
private cache;
|
|
59
|
-
private readonly cacheTtlMs;
|
|
60
|
-
constructor(cacheTtlMs?: number);
|
|
61
|
-
fetchModels(apiKey: string, forceRefresh?: boolean): Promise<ProviderModelInfo[]>;
|
|
62
|
-
validateApiKey(apiKey: string): Promise<{
|
|
63
|
-
error?: string;
|
|
64
|
-
isValid: boolean;
|
|
65
|
-
}>;
|
|
66
|
-
}
|
|
67
53
|
/**
|
|
68
54
|
* Generic model fetcher for OpenAI-compatible APIs.
|
|
69
55
|
* Works with xAI (Grok), Groq, and Mistral.
|