salmon-loop 0.3.1 → 0.4.1
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/dist/cli/authorization/non-interactive.js +9 -13
- package/dist/cli/chat.js +12 -6
- package/dist/cli/commands/allowlist.js +1 -1
- package/dist/cli/commands/chat.js +13 -13
- package/dist/cli/commands/parallel.js +1 -1
- package/dist/cli/commands/run/handler.js +6 -3
- package/dist/cli/commands/run/loop-params.js +1 -0
- package/dist/cli/commands/run/parse-options.js +14 -26
- package/dist/cli/commands/run/runtime-llm.js +15 -12
- package/dist/cli/commands/serve.js +14 -1
- package/dist/cli/headless/openai-responses-canonical-applier.js +1 -7
- package/dist/cli/reporters/standard.js +2 -3
- package/dist/cli/reporters/stream-json.js +2 -1
- package/dist/cli/slash/runtime.js +2 -2
- package/dist/cli/ui/components/CommandSuggestionList.js +1 -1
- package/dist/cli/ui/hooks/useLoopEvents.js +1 -1
- package/dist/cli/ui/hooks/useLoopState.js +1 -1
- package/dist/core/ast/parser.js +18 -9
- package/dist/core/config/schema.js +738 -0
- package/dist/core/config/validate.js +11 -922
- package/dist/core/context/gatherers/ast-gatherer.js +4 -12
- package/dist/core/context/gatherers/ghost-dependency-gatherer.js +0 -1
- package/dist/core/context/gatherers/knowledge-gatherer.js +3 -0
- package/dist/core/context/service.js +39 -8
- package/dist/core/context/token/encoding-registry.js +7 -6
- package/dist/core/extensions/index.js +48 -3
- package/dist/core/extensions/load.js +3 -2
- package/dist/core/extensions/merge.js +5 -1
- package/dist/core/extensions/paths.js +6 -0
- package/dist/core/extensions/schemas.js +21 -0
- package/dist/core/facades/cli-command-chat.js +2 -0
- package/dist/core/facades/cli-run-handler.js +1 -0
- package/dist/core/facades/cli-utils-serialize.js +2 -0
- package/dist/core/grizzco/dsl/llm-strategy.js +3 -2
- package/dist/core/grizzco/engine/outcome/loop-result-mapper.js +15 -10
- package/dist/core/grizzco/engine/pipeline/pipeline.js +149 -240
- package/dist/core/grizzco/engine/transaction/attempt-failure.js +5 -4
- package/dist/core/grizzco/engine/transaction/authorization-summary.js +2 -1
- package/dist/core/grizzco/runtime/apply-back-runtime.js +2 -1
- package/dist/core/grizzco/services/registry.js +18 -0
- package/dist/core/grizzco/steps/audit.js +20 -10
- package/dist/core/grizzco/steps/display-report.js +4 -11
- package/dist/core/grizzco/steps/explore.js +9 -2
- package/dist/core/grizzco/steps/patch/prompt-input.js +4 -1
- package/dist/core/grizzco/steps/patch.js +1 -0
- package/dist/core/grizzco/steps/plan.js +58 -49
- package/dist/core/grizzco/steps/tool-runtime.js +3 -0
- package/dist/core/grizzco/workers/strata-sync-worker.js +2 -1
- package/dist/core/llm/ai-sdk/message-mapper.js +24 -18
- package/dist/core/llm/ai-sdk/request-params.js +1 -3
- package/dist/core/llm/ai-sdk/result-mapper.js +14 -8
- package/dist/core/llm/ai-sdk/retry-classifier.js +6 -4
- package/dist/core/llm/contracts/repair.js +16 -8
- package/dist/core/llm/errors.js +13 -10
- package/dist/core/llm/output-policy.js +8 -0
- package/dist/core/llm/redact.js +1 -3
- package/dist/core/llm/sub-agent-factory.js +48 -0
- package/dist/core/llm/tool-calling-stub.js +48 -0
- package/dist/core/llm/utils.js +17 -6
- package/dist/core/mcp/bridge/prompt-command-provider.js +4 -3
- package/dist/core/mcp/bridge/tool-bridge.js +5 -14
- package/dist/core/mcp/client/connection-manager.js +3 -2
- package/dist/core/mcp/host/sampling-provider.js +1 -1
- package/dist/core/mcp/schema/json-schema-to-zod.js +2 -1
- package/dist/core/memory/relevant-retrieval.js +6 -4
- package/dist/core/observability/authorization-decisions.js +13 -12
- package/dist/core/observability/error-mapping.js +2 -1
- package/dist/core/observability/token-usage.js +5 -4
- package/dist/core/plugin/loader.js +5 -4
- package/dist/core/prompts/registry.js +11 -29
- package/dist/core/protocols/a2a/sdk/server.js +2 -3
- package/dist/core/protocols/acp/formal-agent.js +10 -4
- package/dist/core/protocols/acp/stdio-server.js +6 -6
- package/dist/core/runtime/agent-server-runtime.js +3 -2
- package/dist/core/runtime/initialize.js +70 -6
- package/dist/core/session/compaction/index.js +4 -3
- package/dist/core/session/manager.js +41 -47
- package/dist/core/session/token-tracker.js +18 -7
- package/dist/core/skills/parser.js +3 -2
- package/dist/core/skills/runtime/MicroTaskRunner.js +1 -1
- package/dist/core/skills/runtime/SkillRunner.js +5 -2
- package/dist/core/slash/steps/slash-execute.js +7 -5
- package/dist/core/slash/strategy.js +1 -1
- package/dist/core/strata/layers/worktree.js +7 -9
- package/dist/core/strata/runtime/synchronizer.js +10 -9
- package/dist/core/streaming/canonical/parts-from-llm-stream-chunk.js +1 -11
- package/dist/core/structured-output/json-schema-validator.js +1 -13
- package/dist/core/sub-agent/context-snapshot.js +12 -6
- package/dist/core/sub-agent/controller.js +70 -1
- package/dist/core/sub-agent/core/loop.js +25 -3
- package/dist/core/sub-agent/core/manager.js +319 -116
- package/dist/core/sub-agent/registry-defaults.js +12 -0
- package/dist/core/sub-agent/registry.js +8 -0
- package/dist/core/sub-agent/team.js +98 -0
- package/dist/core/sub-agent/tools/task-await.js +109 -0
- package/dist/core/sub-agent/tools/task-spawn.js +49 -7
- package/dist/core/sub-agent/tools/team.js +92 -0
- package/dist/core/sub-agent/types.js +11 -2
- package/dist/core/tools/budget.js +4 -11
- package/dist/core/tools/builtin/code-search/executor.js +46 -43
- package/dist/core/tools/builtin/fs.js +14 -6
- package/dist/core/tools/builtin/index.js +41 -107
- package/dist/core/tools/builtin/interaction.js +13 -15
- package/dist/core/tools/builtin/proposal.js +11 -2
- package/dist/core/tools/capability/executor.js +5 -5
- package/dist/core/tools/headless-payload.js +1 -3
- package/dist/core/tools/mapper.js +8 -42
- package/dist/core/tools/parallel/persistence.js +17 -5
- package/dist/core/tools/parallel/scheduler.js +23 -21
- package/dist/core/tools/permissions/permission-rules.js +66 -114
- package/dist/core/tools/plugins/loader.js +4 -3
- package/dist/core/tools/router.js +24 -53
- package/dist/core/tools/session.js +54 -97
- package/dist/core/tools/streaming/ToolCallAccumulator.js +1 -3
- package/dist/core/tools/tool-visibility.js +2 -1
- package/dist/core/tools/types.js +10 -0
- package/dist/core/utils/error.js +79 -0
- package/dist/core/utils/serialize.js +63 -0
- package/dist/core/utils/zod.js +29 -0
- package/dist/core/workspace/capabilities.js +3 -2
- package/dist/integrations/langfuse/litellm-langfuse-outcome-reporter.js +9 -8
- package/dist/locales/en.js +2 -1
- package/package.json +1 -1
|
@@ -181,25 +181,17 @@ export class AstGatherer {
|
|
|
181
181
|
async gatherCallNames(parsedTree, lang, callsQuery) {
|
|
182
182
|
if (!parsedTree || !lang || !callsQuery)
|
|
183
183
|
return [];
|
|
184
|
-
const
|
|
185
|
-
if (typeof queryFn !== 'function')
|
|
186
|
-
return [];
|
|
187
|
-
const captures = (await queryFn(parsedTree, lang, callsQuery));
|
|
184
|
+
const captures = await AstParser.queryCapturesFromQuery(parsedTree, lang, callsQuery);
|
|
188
185
|
return Array.from(new Set(captures
|
|
189
186
|
.filter((c) => c.name === 'callee' && c.text.trim().length > 0)
|
|
190
187
|
.map((c) => c.text.trim())));
|
|
191
188
|
}
|
|
192
189
|
async gatherDeepAnalysis(primaryText, parsedTree, lang, flowPack) {
|
|
193
|
-
|
|
194
|
-
if (!parsedTree ||
|
|
195
|
-
!lang ||
|
|
196
|
-
!flowPack?.control ||
|
|
197
|
-
!flowPack?.exceptions ||
|
|
198
|
-
typeof queryFn !== 'function') {
|
|
190
|
+
if (!parsedTree || !lang || !flowPack?.control || !flowPack?.exceptions) {
|
|
199
191
|
return summarizeControlFlow(primaryText);
|
|
200
192
|
}
|
|
201
|
-
const controlCaptures =
|
|
202
|
-
const exceptionCaptures =
|
|
193
|
+
const controlCaptures = await AstParser.queryCapturesFromQuery(parsedTree, lang, flowPack.control);
|
|
194
|
+
const exceptionCaptures = await AstParser.queryCapturesFromQuery(parsedTree, lang, flowPack.exceptions);
|
|
203
195
|
const branchCount = controlCaptures.filter((c) => c.name === 'branch').length;
|
|
204
196
|
const loopCount = controlCaptures.filter((c) => c.name === 'loop').length;
|
|
205
197
|
const asyncBoundaryCount = controlCaptures.filter((c) => c.name === 'async').length;
|
|
@@ -50,6 +50,9 @@ export class KnowledgeGatherer {
|
|
|
50
50
|
data.deprecated_rules.forEach((r) => allDeprecated.add(r));
|
|
51
51
|
}
|
|
52
52
|
if (data.architectural_decisions) {
|
|
53
|
+
if (!Array.isArray(aggregated.architectural_decisions)) {
|
|
54
|
+
aggregated.architectural_decisions = [];
|
|
55
|
+
}
|
|
53
56
|
aggregated.architectural_decisions.push(...data.architectural_decisions);
|
|
54
57
|
}
|
|
55
58
|
if (data.user_preferences) {
|
|
@@ -119,6 +119,7 @@ export class ContextService {
|
|
|
119
119
|
expectedTargetSetSignature;
|
|
120
120
|
if (recordedTargetSetSignature !== expectedTargetSetSignature) {
|
|
121
121
|
await this.cacheStore.delete(cacheKey);
|
|
122
|
+
this.deleteUpdater(cacheKey);
|
|
122
123
|
this.cacheMetrics.misses += 1;
|
|
123
124
|
return {
|
|
124
125
|
missReason: 'target_signature_mismatch',
|
|
@@ -128,6 +129,7 @@ export class ContextService {
|
|
|
128
129
|
const nextSignature = await this.computeTrackedFilesSignature(repoPath, entry.trackedFiles);
|
|
129
130
|
if (nextSignature !== entry.signature) {
|
|
130
131
|
await this.cacheStore.delete(cacheKey);
|
|
132
|
+
this.deleteUpdater(cacheKey);
|
|
131
133
|
this.cacheMetrics.misses += 1;
|
|
132
134
|
return { missReason: 'signature_mismatch', targetSetSignature: expectedTargetSetSignature };
|
|
133
135
|
}
|
|
@@ -210,29 +212,55 @@ export class ContextService {
|
|
|
210
212
|
if (!last || Date.now() - last <= this.cacheTtlMs)
|
|
211
213
|
return false;
|
|
212
214
|
await this.cacheStore.delete(cacheKey);
|
|
215
|
+
this.deleteUpdater(cacheKey);
|
|
213
216
|
this.cacheMetrics.evictions += 1;
|
|
214
217
|
return true;
|
|
215
218
|
}
|
|
216
219
|
async evictExpiredEntries() {
|
|
217
|
-
|
|
218
|
-
|
|
220
|
+
const entries = Array.from(await this.cacheStore.entries());
|
|
221
|
+
const now = Date.now();
|
|
222
|
+
const expiredEntries = entries.filter(([, entry]) => {
|
|
223
|
+
const last = this.getEntryTimestamp(entry);
|
|
224
|
+
return last && now - last > this.cacheTtlMs;
|
|
225
|
+
});
|
|
226
|
+
for (let i = 0; i < expiredEntries.length; i += 10) {
|
|
227
|
+
const chunk = expiredEntries.slice(i, i + 10);
|
|
228
|
+
await Promise.all(chunk.map(([key, entry]) => this.isExpired(key, entry)));
|
|
219
229
|
}
|
|
220
230
|
}
|
|
221
231
|
async evictLruIfNeeded() {
|
|
222
|
-
|
|
232
|
+
const size = await this.cacheStore.size();
|
|
233
|
+
if (size <= this.cacheMaxEntries)
|
|
234
|
+
return;
|
|
235
|
+
const excess = size - this.cacheMaxEntries;
|
|
236
|
+
const entries = Array.from(await this.cacheStore.entries());
|
|
237
|
+
if (excess === 1) {
|
|
223
238
|
let victimKey;
|
|
224
239
|
let victimTs = Number.POSITIVE_INFINITY;
|
|
225
|
-
for (const [key, entry] of
|
|
240
|
+
for (const [key, entry] of entries) {
|
|
226
241
|
const ts = this.getEntryTimestamp(entry);
|
|
227
242
|
if (ts < victimTs) {
|
|
228
243
|
victimTs = ts;
|
|
229
244
|
victimKey = key;
|
|
230
245
|
}
|
|
231
246
|
}
|
|
232
|
-
if (
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
247
|
+
if (victimKey) {
|
|
248
|
+
await this.cacheStore.delete(victimKey);
|
|
249
|
+
this.deleteUpdater(victimKey);
|
|
250
|
+
this.cacheMetrics.evictions += 1;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
entries.sort((a, b) => (this.getEntryTimestamp(a[1]) || 0) - (this.getEntryTimestamp(b[1]) || 0));
|
|
255
|
+
const victims = entries.slice(0, excess);
|
|
256
|
+
for (let i = 0; i < victims.length; i += 10) {
|
|
257
|
+
const chunk = victims.slice(i, i + 10);
|
|
258
|
+
await Promise.all(chunk.map(async ([key]) => {
|
|
259
|
+
await this.cacheStore.delete(key);
|
|
260
|
+
this.deleteUpdater(key);
|
|
261
|
+
this.cacheMetrics.evictions += 1;
|
|
262
|
+
}));
|
|
263
|
+
}
|
|
236
264
|
}
|
|
237
265
|
}
|
|
238
266
|
async getCacheStats() {
|
|
@@ -262,6 +290,9 @@ export class ContextService {
|
|
|
262
290
|
}
|
|
263
291
|
return updater;
|
|
264
292
|
}
|
|
293
|
+
deleteUpdater(key) {
|
|
294
|
+
this.updaters.delete(key);
|
|
295
|
+
}
|
|
265
296
|
logDiff(key, diff) {
|
|
266
297
|
if (!diff.addedFiles.length && !diff.modifiedFiles.length && !diff.removedFiles.length) {
|
|
267
298
|
return;
|
|
@@ -24,13 +24,13 @@ class TiktokenEncoding {
|
|
|
24
24
|
this.initialized = true;
|
|
25
25
|
}
|
|
26
26
|
encode(text) {
|
|
27
|
-
this.
|
|
28
|
-
return Array.from(
|
|
27
|
+
const encoder = this.getEncoder();
|
|
28
|
+
return Array.from(encoder.encode(text));
|
|
29
29
|
}
|
|
30
30
|
decode(tokens) {
|
|
31
|
-
this.
|
|
31
|
+
const encoder = this.getEncoder();
|
|
32
32
|
const uint32Tokens = new Uint32Array(tokens);
|
|
33
|
-
const decoded =
|
|
33
|
+
const decoded = encoder.decode(uint32Tokens);
|
|
34
34
|
return new TextDecoder().decode(decoded);
|
|
35
35
|
}
|
|
36
36
|
count(text) {
|
|
@@ -43,10 +43,11 @@ class TiktokenEncoding {
|
|
|
43
43
|
}
|
|
44
44
|
this.initialized = false;
|
|
45
45
|
}
|
|
46
|
-
|
|
47
|
-
if (!this.
|
|
46
|
+
getEncoder() {
|
|
47
|
+
if (!this.encoder) {
|
|
48
48
|
throw new Error(`Encoding ${this.name} not initialized. Call initialize() first.`);
|
|
49
49
|
}
|
|
50
|
+
return this.encoder;
|
|
50
51
|
}
|
|
51
52
|
}
|
|
52
53
|
/**
|
|
@@ -3,9 +3,9 @@ import { buildResolvedMcpServersV2 } from '../mcp/config/index.js';
|
|
|
3
3
|
import { getLogger } from '../observability/logger.js';
|
|
4
4
|
import { loadConfig } from './load.js';
|
|
5
5
|
import { mergeScopedEntries } from './merge.js';
|
|
6
|
-
import { expandHome, getRepoMcpConfigPath, getRepoSkillConfigPath, getRepoToolConfigPath, getUserMcpConfigPath, getUserSkillConfigPath, getUserToolConfigPath, isWithinRoot, resolveRepoRelative, resolveUserRelative, } from './paths.js';
|
|
6
|
+
import { expandHome, getRepoAgentsConfigPath, getRepoMcpConfigPath, getRepoSkillConfigPath, getRepoToolConfigPath, getUserAgentsConfigPath, getUserMcpConfigPath, getUserSkillConfigPath, getUserToolConfigPath, isWithinRoot, resolveRepoRelative, resolveUserRelative, } from './paths.js';
|
|
7
7
|
import { redactExtensions } from './redact.js';
|
|
8
|
-
import { McpConfigSchema, SkillsConfigSchema, ToolsConfigSchema } from './schemas.js';
|
|
8
|
+
import { AgentsConfigSchema, McpConfigSchema, SkillsConfigSchema, ToolsConfigSchema, } from './schemas.js';
|
|
9
9
|
function defaultEnabled(scope) {
|
|
10
10
|
return scope === 'repo';
|
|
11
11
|
}
|
|
@@ -29,6 +29,47 @@ function buildResolvedPlugins(entries, repoRoot) {
|
|
|
29
29
|
};
|
|
30
30
|
});
|
|
31
31
|
}
|
|
32
|
+
function buildResolvedAgentProfiles(user, repo) {
|
|
33
|
+
const seen = new Map();
|
|
34
|
+
// User profiles first (lower priority)
|
|
35
|
+
if (user) {
|
|
36
|
+
for (const agent of user.agents) {
|
|
37
|
+
if (agent.enabled === false)
|
|
38
|
+
continue;
|
|
39
|
+
seen.set(agent.id, toResolvedProfile(agent, 'user'));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// Repo profiles override user profiles (higher priority)
|
|
43
|
+
if (repo) {
|
|
44
|
+
for (const agent of repo.agents) {
|
|
45
|
+
if (agent.enabled === false) {
|
|
46
|
+
seen.delete(agent.id);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
seen.set(agent.id, toResolvedProfile(agent, 'repo'));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return Array.from(seen.values());
|
|
53
|
+
}
|
|
54
|
+
function toResolvedProfile(raw, scope) {
|
|
55
|
+
return {
|
|
56
|
+
id: raw.id,
|
|
57
|
+
name: raw.name,
|
|
58
|
+
role: raw.role,
|
|
59
|
+
description: raw.description,
|
|
60
|
+
allowedTools: raw.allowedTools ?? ['code.search', 'fs.read'],
|
|
61
|
+
readOnly: raw.readOnly ?? false,
|
|
62
|
+
stratagem: raw.stratagem ?? 'investigator',
|
|
63
|
+
toolInheritance: raw.toolInheritance,
|
|
64
|
+
permissionMode: raw.permissionMode,
|
|
65
|
+
systemPrompt: raw.systemPrompt,
|
|
66
|
+
maxTokens: raw.maxTokens,
|
|
67
|
+
maxAttempts: raw.maxAttempts,
|
|
68
|
+
timeoutMs: raw.timeoutMs,
|
|
69
|
+
model: raw.model,
|
|
70
|
+
scope,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
32
73
|
function buildResolvedSkills(user, repo, repoRoot) {
|
|
33
74
|
const repoDiscovery = repo?.discovery;
|
|
34
75
|
const userDiscovery = user?.discovery;
|
|
@@ -73,13 +114,15 @@ function buildResolvedSkills(user, repo, repoRoot) {
|
|
|
73
114
|
}
|
|
74
115
|
export async function resolveExtensions(options) {
|
|
75
116
|
const { repoRoot } = options;
|
|
76
|
-
const [userMcp, repoMcp, userTools, repoTools, userSkills, repoSkills] = await Promise.all([
|
|
117
|
+
const [userMcp, repoMcp, userTools, repoTools, userSkills, repoSkills, userAgents, repoAgents] = await Promise.all([
|
|
77
118
|
loadConfig(getUserMcpConfigPath(), McpConfigSchema),
|
|
78
119
|
loadConfig(getRepoMcpConfigPath(repoRoot), McpConfigSchema),
|
|
79
120
|
loadConfig(getUserToolConfigPath(), ToolsConfigSchema),
|
|
80
121
|
loadConfig(getRepoToolConfigPath(repoRoot), ToolsConfigSchema),
|
|
81
122
|
loadConfig(getUserSkillConfigPath(), SkillsConfigSchema),
|
|
82
123
|
loadConfig(getRepoSkillConfigPath(repoRoot), SkillsConfigSchema),
|
|
124
|
+
loadConfig(getUserAgentsConfigPath(), AgentsConfigSchema),
|
|
125
|
+
loadConfig(getRepoAgentsConfigPath(repoRoot), AgentsConfigSchema),
|
|
83
126
|
]);
|
|
84
127
|
const mergedServers = mergeScopedEntries(userMcp?.config.servers, repoMcp?.config.servers);
|
|
85
128
|
const mergedPlugins = mergeScopedEntries(userTools?.config.plugins, repoTools?.config.plugins);
|
|
@@ -87,11 +130,13 @@ export async function resolveExtensions(options) {
|
|
|
87
130
|
mcpServers: buildResolvedMcpServersV2(mergedServers, repoRoot),
|
|
88
131
|
toolPlugins: buildResolvedPlugins(mergedPlugins, repoRoot),
|
|
89
132
|
skillDiscovery: buildResolvedSkills(userSkills?.config, repoSkills?.config, repoRoot),
|
|
133
|
+
agentProfiles: buildResolvedAgentProfiles(userAgents?.config, repoAgents?.config),
|
|
90
134
|
};
|
|
91
135
|
const rawEffective = {
|
|
92
136
|
mcp: repoMcp?.config ?? userMcp?.config ?? null,
|
|
93
137
|
tools: repoTools?.config ?? userTools?.config ?? null,
|
|
94
138
|
skills: repoSkills?.config ?? userSkills?.config ?? null,
|
|
139
|
+
agents: repoAgents?.config ?? userAgents?.config ?? null,
|
|
95
140
|
};
|
|
96
141
|
return {
|
|
97
142
|
resolved,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { syncFs as fs } from '../adapters/fs/node-fs.js';
|
|
2
|
+
import { errorMessage } from '../utils/error.js';
|
|
2
3
|
export class ExtensionConfigError extends Error {
|
|
3
4
|
path;
|
|
4
5
|
constructor(path, message) {
|
|
@@ -18,7 +19,7 @@ export async function tryLoadJsonFile(path) {
|
|
|
18
19
|
: undefined) === 'ENOENT') {
|
|
19
20
|
return { exists: false };
|
|
20
21
|
}
|
|
21
|
-
throw new ExtensionConfigError(path, (error
|
|
22
|
+
throw new ExtensionConfigError(path, errorMessage(error) || 'Unable to read file');
|
|
22
23
|
}
|
|
23
24
|
}
|
|
24
25
|
export async function loadConfig(path, schema) {
|
|
@@ -30,7 +31,7 @@ export async function loadConfig(path, schema) {
|
|
|
30
31
|
return { path, config };
|
|
31
32
|
}
|
|
32
33
|
catch (error) {
|
|
33
|
-
throw new ExtensionConfigError(path, (error
|
|
34
|
+
throw new ExtensionConfigError(path, errorMessage(error) || 'Schema validation failed');
|
|
34
35
|
}
|
|
35
36
|
}
|
|
36
37
|
//# sourceMappingURL=load.js.map
|
|
@@ -11,7 +11,10 @@ export function mergeScopedEntries(user, repo) {
|
|
|
11
11
|
if (previous) {
|
|
12
12
|
merged.set(key, {
|
|
13
13
|
key,
|
|
14
|
-
entry: {
|
|
14
|
+
entry: {
|
|
15
|
+
...previous.entry,
|
|
16
|
+
...entry,
|
|
17
|
+
},
|
|
15
18
|
scope: 'repo',
|
|
16
19
|
});
|
|
17
20
|
}
|
|
@@ -38,6 +41,7 @@ export function mergeResolvedExtensions(base, overlay) {
|
|
|
38
41
|
: base.skillDiscovery.scope,
|
|
39
42
|
paths: [...base.skillDiscovery.paths, ...overlay.skillDiscovery.paths],
|
|
40
43
|
},
|
|
44
|
+
agentProfiles: [...base.agentProfiles, ...overlay.agentProfiles],
|
|
41
45
|
};
|
|
42
46
|
}
|
|
43
47
|
//# sourceMappingURL=merge.js.map
|
|
@@ -39,6 +39,12 @@ export function getUserToolConfigPath() {
|
|
|
39
39
|
export function getUserSkillConfigPath() {
|
|
40
40
|
return path.join(USER_CONFIG_DIR, 'skills-user.json');
|
|
41
41
|
}
|
|
42
|
+
export function getRepoAgentsConfigPath(repoRoot) {
|
|
43
|
+
return path.join(repoRoot, REPO_CONFIG_DIR, 'agents.json');
|
|
44
|
+
}
|
|
45
|
+
export function getUserAgentsConfigPath() {
|
|
46
|
+
return path.join(USER_CONFIG_DIR, 'agents-user.json');
|
|
47
|
+
}
|
|
42
48
|
/**
|
|
43
49
|
* Check whether a candidate path resides within (or equals) a given root directory.
|
|
44
50
|
*
|
|
@@ -21,4 +21,25 @@ export const SkillsConfigSchema = z
|
|
|
21
21
|
discovery: skillDiscoverySchema.optional().default({}),
|
|
22
22
|
})
|
|
23
23
|
.strict();
|
|
24
|
+
export const AgentProfileConfigSchema = z.object({
|
|
25
|
+
id: z.string().min(1),
|
|
26
|
+
name: z.string().min(1),
|
|
27
|
+
role: z.string().min(1),
|
|
28
|
+
description: z.string(),
|
|
29
|
+
allowedTools: z.array(z.string()).optional(),
|
|
30
|
+
toolInheritance: z.enum(['none', 'safe', 'all']).optional(),
|
|
31
|
+
permissionMode: z.enum(['default', 'plan', 'bypassPermissions']).optional(),
|
|
32
|
+
systemPrompt: z.string().optional(),
|
|
33
|
+
readOnly: z.boolean().optional(),
|
|
34
|
+
stratagem: z.enum(['investigator', 'surgeon', 'janitor']).optional(),
|
|
35
|
+
maxTokens: z.number().positive().optional(),
|
|
36
|
+
maxAttempts: z.number().positive().optional(),
|
|
37
|
+
timeoutMs: z.number().positive().optional(),
|
|
38
|
+
model: z.string().optional(),
|
|
39
|
+
enabled: z.boolean().optional(),
|
|
40
|
+
});
|
|
41
|
+
export const AgentsConfigSchema = z.object({
|
|
42
|
+
version: z.literal(1),
|
|
43
|
+
agents: z.array(AgentProfileConfigSchema),
|
|
44
|
+
});
|
|
24
45
|
//# sourceMappingURL=schemas.js.map
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
export { ConfigError, normalizePermissionMode, resolveConfig } from '../config/index.js';
|
|
2
2
|
export { ExtensionConfigError, resolveExtensions } from '../extensions/index.js';
|
|
3
3
|
export { createRuntimeLlm } from '../llm/factory.js';
|
|
4
|
+
export { createSubAgentLlmFactory } from '../llm/sub-agent-factory.js';
|
|
4
5
|
export { getLogger } from '../observability/logger.js';
|
|
5
6
|
export { PluginLoader } from '../plugin/loader.js';
|
|
6
7
|
export { resolveExecutionProfile } from '../runtime/execution-profile.js';
|
|
7
8
|
export { clearPluginRegistry, createPluginRegistry, setPluginRegistry, } from '../plugin/registry.js';
|
|
8
9
|
export { clearPromptRegistry, createPromptRegistry, setPromptRegistry, } from '../prompts/registry.js';
|
|
10
|
+
export { getString } from '../utils/serialize.js';
|
|
9
11
|
//# sourceMappingURL=cli-command-chat.js.map
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { normalizePermissionMode } from '../config/index.js';
|
|
2
|
+
export { createSubAgentLlmFactory } from '../llm/sub-agent-factory.js';
|
|
2
3
|
export { getLogger, PlainReporter, SilentReporter } from '../observability/logger.js';
|
|
3
4
|
export { createPluginRegistry, setPluginRegistry, } from '../plugin/registry.js';
|
|
4
5
|
export { createPromptRegistry, setPromptRegistry, } from '../prompts/registry.js';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { resolveLlmCapabilities } from '../../llm/capabilities.js';
|
|
2
2
|
import { Phase } from '../../types/runtime.js';
|
|
3
|
+
import { FileStatus, OpType } from '../domain/grizzco-types.js';
|
|
3
4
|
import { DecisionEngine, PlanBuilder } from './DecisionEngine.js';
|
|
4
5
|
function defaultMaxRoundsForPhase(phase) {
|
|
5
6
|
// Explore needs more rounds to navigate the codebase
|
|
@@ -24,7 +25,7 @@ export function resolveLlmToolCallingPolicy(phase, llm) {
|
|
|
24
25
|
repoRoot: '',
|
|
25
26
|
file: {
|
|
26
27
|
path: '',
|
|
27
|
-
status:
|
|
28
|
+
status: FileStatus.CLEAN,
|
|
28
29
|
isBinary: false,
|
|
29
30
|
isSymlink: false,
|
|
30
31
|
isIgnored: false,
|
|
@@ -32,7 +33,7 @@ export function resolveLlmToolCallingPolicy(phase, llm) {
|
|
|
32
33
|
size: 0,
|
|
33
34
|
},
|
|
34
35
|
operation: {
|
|
35
|
-
type:
|
|
36
|
+
type: OpType.PATCH,
|
|
36
37
|
path: '',
|
|
37
38
|
},
|
|
38
39
|
options: {
|
|
@@ -5,6 +5,7 @@ import { buildFailureEnvelope } from '../../../observability/error-envelope.js';
|
|
|
5
5
|
import { getTokenUsageFromAuditTrail } from '../../../observability/token-usage.js';
|
|
6
6
|
import { resolveExecutionProfile } from '../../../runtime/execution-profile.js';
|
|
7
7
|
import { ErrorType, Phase } from '../../../types/runtime.js';
|
|
8
|
+
import { isRecord } from '../../../utils/serialize.js';
|
|
8
9
|
const ROOT_CAUSE_CODES = [
|
|
9
10
|
'LLM_RATE_LIMITED',
|
|
10
11
|
'LLM_UPSTREAM_5XX',
|
|
@@ -34,17 +35,19 @@ export function buildLoopResultFromTransaction({ executionReport, flowMode, opti
|
|
|
34
35
|
: 'NON_RETRYABLE_FAILURE';
|
|
35
36
|
const ctx = executionReport.lastContext ??
|
|
36
37
|
executionReport.flowReport.data;
|
|
38
|
+
const ctxObj = isRecord(ctx) ? ctx : null;
|
|
37
39
|
const contextHash = (() => {
|
|
38
|
-
const
|
|
40
|
+
const contextResult = isRecord(ctxObj?.contextResult) ? ctxObj.contextResult : null;
|
|
41
|
+
const meta = isRecord(contextResult?.meta) ? contextResult.meta : null;
|
|
42
|
+
const hashFromBudget = meta?.contextHash;
|
|
39
43
|
if (typeof hashFromBudget === 'string')
|
|
40
44
|
return hashFromBudget;
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
: undefined;
|
|
45
|
+
const context = isRecord(ctxObj?.context) ? ctxObj.context : null;
|
|
46
|
+
const hashFromContext = context?.contextHash;
|
|
44
47
|
return typeof hashFromContext === 'string' ? hashFromContext : undefined;
|
|
45
48
|
})();
|
|
46
|
-
const verifyArtifact =
|
|
47
|
-
?
|
|
49
|
+
const verifyArtifact = ctxObj && typeof ctxObj.verifyArtifact !== 'undefined'
|
|
50
|
+
? ctxObj.verifyArtifact
|
|
48
51
|
: executionReport.lastVerifyArtifact;
|
|
49
52
|
const artifactHints = (() => {
|
|
50
53
|
const hints = {
|
|
@@ -71,12 +74,14 @@ export function buildLoopResultFromTransaction({ executionReport, flowMode, opti
|
|
|
71
74
|
}
|
|
72
75
|
return hints;
|
|
73
76
|
})();
|
|
77
|
+
const report = isRecord(ctxObj?.report) ? ctxObj.report : null;
|
|
74
78
|
const assistantMessage = ((flowMode === 'answer' || profile.driver === 'agent') &&
|
|
75
|
-
|
|
76
|
-
|
|
79
|
+
typeof report?.summary === 'string' &&
|
|
80
|
+
report.summary.trim()
|
|
81
|
+
? report.summary.trim()
|
|
77
82
|
: undefined) ?? undefined;
|
|
78
|
-
const finalPatch =
|
|
79
|
-
const changedFiles =
|
|
83
|
+
const finalPatch = ctxObj && typeof ctxObj.diff === 'string' ? ctxObj.diff : undefined;
|
|
84
|
+
const changedFiles = Array.isArray(ctxObj?.changedFiles) ? ctxObj.changedFiles : undefined;
|
|
80
85
|
const authorizationDecisions = (() => {
|
|
81
86
|
if (!options.eventPayload?.includeAuthorizationDecisions)
|
|
82
87
|
return undefined;
|