salmon-loop 0.2.3 → 0.2.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/argv/headless-detection.js +27 -0
- package/dist/cli/chat-flow.js +11 -0
- package/dist/cli/chat.js +161 -24
- package/dist/cli/commands/chat.js +30 -24
- package/dist/cli/commands/context.js +15 -3
- package/dist/cli/commands/flow-mode.js +63 -0
- package/dist/cli/commands/help-format.js +12 -0
- package/dist/cli/commands/registry.js +6 -7
- package/dist/cli/commands/run/benchmark-artifacts.js +41 -0
- package/dist/cli/commands/run/config-resolution.js +30 -24
- package/dist/cli/commands/run/early-errors.js +23 -0
- package/dist/cli/commands/run/handler.js +131 -44
- package/dist/cli/commands/run/headless-error-writer.js +8 -0
- package/dist/cli/commands/run/loop-params.js +3 -0
- package/dist/cli/commands/run/mode.js +2 -5
- package/dist/cli/commands/run/parse-options.js +18 -2
- package/dist/cli/commands/run/persist-session.js +10 -1
- package/dist/cli/commands/run/preflight.js +10 -0
- package/dist/cli/commands/run/reporter-factory.js +4 -0
- package/dist/cli/commands/run/runtime-llm.js +38 -11
- package/dist/cli/commands/run/runtime-options.js +2 -2
- package/dist/cli/commands/run/validate-options.js +0 -5
- package/dist/cli/commands/run/verbose.js +2 -7
- package/dist/cli/commands/serve.js +117 -90
- package/dist/cli/commands/tool-names.js +78 -78
- package/dist/cli/headless/anthropic-stream-normalized-encoder.js +6 -1
- package/dist/cli/headless/json-protocol.js +37 -0
- package/dist/cli/headless/native-stream-normalized-encoder.js +6 -1
- package/dist/cli/headless/protocol-metadata.js +22 -0
- package/dist/cli/headless/stream-json-protocol.js +34 -1
- package/dist/cli/index.js +6 -4
- package/dist/cli/locales/en.js +32 -6
- package/dist/cli/program-bootstrap.js +14 -4
- package/dist/cli/program-commands.js +9 -1
- package/dist/cli/program-options.js +1 -0
- package/dist/cli/reporters/anthropic-stream.js +7 -1
- package/dist/cli/reporters/json.js +4 -0
- package/dist/cli/reporters/stream-json.js +17 -2
- package/dist/cli/run-cli.js +5 -3
- package/dist/cli/slash/runtime.js +30 -15
- package/dist/cli/ui/components/CommandInput.js +7 -3
- package/dist/cli/ui/components/CommandSuggestionList.js +1 -1
- package/dist/cli/utils/command-option-source.js +13 -0
- package/dist/cli/utils/output-format.js +6 -0
- package/dist/cli/utils/resolve-cli-config.js +98 -0
- package/dist/cli/utils/verbose-level.js +8 -0
- package/dist/cli/utils/verify-resolver.js +8 -4
- package/dist/cli/utils/worktree-prepare-resolver.js +7 -3
- package/dist/core/adapters/fs/file-adapter.js +6 -0
- package/dist/core/adapters/fs/filesystem.js +2 -1
- package/dist/core/adapters/git/git-adapter.js +78 -1
- package/dist/core/benchmark/patch-artifact.js +124 -0
- package/dist/core/benchmark/swe-bench.js +25 -0
- package/dist/core/config/load.js +39 -18
- package/dist/core/config/merge.js +27 -0
- package/dist/core/config/paths.js +24 -5
- package/dist/core/config/resolve-llm.js +12 -0
- package/dist/core/config/resolve.js +7 -5
- package/dist/core/config/resolvers/server.js +0 -6
- package/dist/core/config/validate.js +94 -21
- package/dist/core/context/gatherers/metadata-gatherer.js +1 -0
- package/dist/core/context/gatherers/ripgrep-gatherer.js +84 -2
- package/dist/core/context/keywords.js +18 -4
- package/dist/core/context/service-deps.js +2 -2
- package/dist/core/context/service.js +8 -0
- package/dist/core/context/steps/context-gather.js +38 -0
- package/dist/core/context/summarization/summarizer.js +55 -12
- package/dist/core/context/targeting/target-resolver.js +4 -4
- package/dist/core/extensions/index.js +23 -5
- package/dist/core/extensions/paths.js +31 -0
- package/dist/core/extensions/schemas.js +8 -5
- package/dist/core/facades/cli-chat.js +6 -2
- package/dist/core/facades/cli-command-chat.js +2 -1
- package/dist/core/facades/cli-command-tool-names.js +2 -0
- package/dist/core/facades/cli-context.js +1 -0
- package/dist/core/facades/cli-observability.js +1 -1
- package/dist/core/facades/cli-run-handler.js +4 -2
- package/dist/core/facades/cli-run-persist-session.js +1 -0
- package/dist/core/facades/cli-serve.js +2 -4
- package/dist/core/facades/cli-utils-worktree.js +1 -1
- package/dist/core/failure/diagnostics.js +53 -1
- package/dist/core/grizzco/dsl/llm-strategy.js +4 -1
- package/dist/core/grizzco/engine/outcome/loop-result-mapper.js +67 -9
- package/dist/core/grizzco/engine/pipeline/pipeline.js +6 -2
- package/dist/core/grizzco/engine/transaction/attempt-failure.js +90 -15
- package/dist/core/grizzco/engine/transaction/report-mapper.js +17 -3
- package/dist/core/grizzco/engine/transaction/transaction-runner.js +173 -7
- package/dist/core/grizzco/flows/AutopilotFlow.js +18 -0
- package/dist/core/grizzco/flows/flow-dispatch.js +11 -0
- package/dist/core/grizzco/steps/answer.js +13 -14
- package/dist/core/grizzco/steps/autopilot.js +396 -0
- package/dist/core/grizzco/steps/cache-sharing.js +29 -0
- package/dist/core/grizzco/steps/explore.js +37 -21
- package/dist/core/grizzco/steps/generateReview.js +2 -5
- package/dist/core/grizzco/steps/patch/apply-check.js +10 -0
- package/dist/core/grizzco/steps/patch/diff-normalization.js +70 -0
- package/dist/core/grizzco/steps/patch/diff-salvage.js +46 -0
- package/dist/core/grizzco/steps/patch/prompt-input.js +42 -0
- package/dist/core/grizzco/steps/patch.js +105 -146
- package/dist/core/grizzco/steps/plan.js +101 -25
- package/dist/core/grizzco/steps/preflight.js +5 -3
- package/dist/core/grizzco/steps/request-assembly.js +78 -0
- package/dist/core/grizzco/steps/research.js +39 -36
- package/dist/core/grizzco/steps/tool-runtime.js +47 -0
- package/dist/core/grizzco/steps/verify-shared.js +23 -0
- package/dist/core/grizzco/steps/verify.js +13 -21
- package/dist/core/intent/chat-intent.js +0 -4
- package/dist/core/llm/ai-sdk/chat-executor.js +2 -0
- package/dist/core/llm/ai-sdk/high-level-phase-specs.js +63 -0
- package/dist/core/llm/ai-sdk/message-mapper.js +40 -10
- package/dist/core/llm/ai-sdk/provider-factory.js +14 -0
- package/dist/core/llm/ai-sdk/request-params.js +74 -1
- package/dist/core/llm/ai-sdk/result-mapper.js +16 -0
- package/dist/core/llm/ai-sdk.js +112 -27
- package/dist/core/llm/capabilities.js +12 -0
- package/dist/core/llm/contracts/repair.js +36 -30
- package/dist/core/llm/errors.js +83 -2
- package/dist/core/llm/message-composition.js +7 -22
- package/dist/core/llm/phase-router.js +29 -10
- package/dist/core/llm/redact.js +28 -3
- package/dist/core/llm/registry.js +2 -0
- package/dist/core/llm/request-augmentation.js +55 -0
- package/dist/core/llm/request-envelope.js +334 -0
- package/dist/core/llm/shared-request-assembly.js +35 -0
- package/dist/core/llm/stream-utils.js +13 -4
- package/dist/core/llm/utils.js +18 -29
- package/dist/core/memory/relevant-retrieval.js +144 -0
- package/dist/core/observability/logger.js +11 -2
- package/dist/core/patch/diff.js +1 -0
- package/dist/core/prompts/registry.js +39 -2
- package/dist/core/prompts/runtime.js +50 -12
- package/dist/core/prompts/templates/phases/patch_user.hbs +2 -5
- package/dist/core/prompts/templates/phases/research_user.hbs +11 -0
- package/dist/core/prompts/templates/phases/review_user.hbs +3 -0
- package/dist/core/prompts/templates/system/answer_system.hbs +5 -0
- package/dist/core/prompts/templates/system/autopilot_system.hbs +11 -0
- package/dist/core/prompts/templates/system/explore_system.hbs +14 -23
- package/dist/core/prompts/templates/system/main_system.hbs +4 -16
- package/dist/core/prompts/templates/system/patch_system.hbs +39 -8
- package/dist/core/prompts/templates/system/plan_system.hbs +86 -1
- package/dist/core/prompts/templates/system/research_system.hbs +2 -0
- package/dist/core/protocols/a2a/agent-card.js +3 -2
- package/dist/core/protocols/a2a/sdk/executor.js +8 -6
- package/dist/core/protocols/a2a/sdk/server.js +0 -1
- package/dist/core/protocols/acp/formal-agent.js +221 -55
- package/dist/core/protocols/acp/handlers.js +5 -1
- package/dist/core/protocols/acp/permission-provider.js +21 -1
- package/dist/core/protocols/shared/execution-request.js +24 -0
- package/dist/core/protocols/shared/flow-mode-mapping.js +23 -0
- package/dist/core/public-capabilities/flow-mode-metadata.js +39 -0
- package/dist/core/public-capabilities/projections.js +29 -0
- package/dist/core/public-capabilities/registry.js +26 -0
- package/dist/core/public-capabilities/types.js +2 -0
- package/dist/core/runtime/agent-server-runtime.js +47 -43
- package/dist/core/runtime/execution-profile.js +67 -0
- package/dist/core/session/artifact-state.js +160 -0
- package/dist/core/session/compaction/index.js +183 -0
- package/dist/core/session/compaction/microcompact.js +78 -0
- package/dist/core/session/compaction/tracking.js +48 -0
- package/dist/core/session/compaction/types.js +11 -0
- package/dist/core/session/compression.js +12 -4
- package/dist/core/session/manager.js +247 -10
- package/dist/core/session/pruning-strategy.js +55 -9
- package/dist/core/session/replacement-preview-provider.js +24 -0
- package/dist/core/session/replacement-state.js +131 -0
- package/dist/core/session/resume-repair/pipeline.js +79 -0
- package/dist/core/session/resume-repair/stages/load-raw-archive-state.js +40 -0
- package/dist/core/session/resume-repair/stages/reattach-runtime-state.js +8 -0
- package/dist/core/session/resume-repair/stages/recover-orphaned-branches.js +10 -0
- package/dist/core/session/resume-repair/stages/relink-boundary-and-tail.js +36 -0
- package/dist/core/session/resume-repair/stages/replay-startup-hooks.js +23 -0
- package/dist/core/session/resume-repair/stages/rescue-stale-metadata.js +17 -0
- package/dist/core/session/resume-repair/types.js +2 -0
- package/dist/core/session/summary-sync.js +164 -13
- package/dist/core/session/token-tracker.js +6 -0
- package/dist/core/skills/audit.js +34 -0
- package/dist/core/skills/bridge.js +84 -7
- package/dist/core/skills/discovery.js +94 -0
- package/dist/core/skills/feature-flags.js +52 -0
- package/dist/core/skills/index.js +1 -1
- package/dist/core/skills/loader.js +195 -20
- package/dist/core/skills/parser.js +296 -24
- package/dist/core/skills/permissions.js +117 -0
- package/dist/core/skills/runtime/MicroTaskRunner.js +10 -4
- package/dist/core/skills/runtime/SkillRunner.js +240 -61
- package/dist/core/strata/layers/shadow-driver/shadow-driver.js +37 -7
- package/dist/core/strata/layers/worktree.js +70 -13
- package/dist/core/strata/runtime/synchronizer.js +29 -2
- package/dist/core/streaming/stream-assembler.js +75 -31
- package/dist/core/sub-agent/context-snapshot.js +156 -0
- package/dist/core/sub-agent/core/loop.js +1 -1
- package/dist/core/sub-agent/core/manager.js +119 -20
- package/dist/core/sub-agent/dispatch-policy.js +29 -0
- package/dist/core/sub-agent/prefix-consistency.js +48 -0
- package/dist/core/sub-agent/registry-defaults.js +4 -0
- package/dist/core/sub-agent/tools/task-spawn.js +79 -2
- package/dist/core/sub-agent/types.js +134 -5
- package/dist/core/tools/audit.js +13 -4
- package/dist/core/tools/builtin/ast-grep.js +1 -1
- package/dist/core/tools/builtin/ast.js +1 -1
- package/dist/core/tools/builtin/benchmark.js +360 -0
- package/dist/core/tools/builtin/code-search/backends/rg.js +2 -1
- package/dist/core/tools/builtin/code-search/executor.js +6 -1
- package/dist/core/tools/builtin/code-search/spec.js +26 -2
- package/dist/core/tools/builtin/fs.js +256 -23
- package/dist/core/tools/builtin/git.js +2 -2
- package/dist/core/tools/builtin/index.js +51 -2
- package/dist/core/tools/builtin/interaction.js +8 -1
- package/dist/core/tools/builtin/plan.js +37 -15
- package/dist/core/tools/builtin/shell.js +1 -1
- package/dist/core/tools/loader.js +39 -16
- package/dist/core/tools/mapper.js +17 -3
- package/dist/core/tools/parallel/scheduler.js +35 -4
- package/dist/core/tools/permissions/permission-rules.js +5 -10
- package/dist/core/tools/policy.js +6 -1
- package/dist/core/tools/recoverable-tool-errors.js +10 -0
- package/dist/core/tools/router.js +24 -6
- package/dist/core/tools/session.js +458 -48
- package/dist/core/tools/tool-visibility.js +62 -0
- package/dist/core/tools/types.js +9 -1
- package/dist/core/types/execution.js +4 -0
- package/dist/core/types/flow-mode.js +8 -0
- package/dist/core/utils/path.js +52 -0
- package/dist/core/verification/runner.js +4 -1
- package/dist/interfaces/cli/task-runner.js +4 -3
- package/dist/languages/typescript/index.js +4 -1
- package/dist/locales/en.js +87 -2
- package/dist/utils/eol.js +1 -1
- package/package.json +15 -8
- package/scripts/fix-es-abstract-compat.js +77 -0
- package/dist/core/runtime/fastify-server-bundle.js +0 -26
- package/dist/core/runtime/sidecar-fastify-plugin.js +0 -35
- package/dist/core/runtime/sidecar-paths.js +0 -47
- package/dist/core/runtime/sidecar-route-catalog.js +0 -103
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { text } from '../../../../locales/index.js';
|
|
2
|
+
import { wrapPatchEmpty, wrapPatchInvalid, wrapPatchNotUnifiedDiff } from '../../../llm/errors.js';
|
|
3
|
+
import { extractUnifiedDiffFromLLMContent } from '../../../llm/utils.js';
|
|
4
|
+
import { normalizeDiff, validateDiff } from '../../../patch/diff.js';
|
|
5
|
+
import { DiffValidationError } from '../../../types/errors.js';
|
|
6
|
+
const isCanonicalDiffHeader = (diffText) => diffText.trimStart().startsWith('diff --git ');
|
|
7
|
+
export function assertCanonicalDiffHeader(diffText) {
|
|
8
|
+
if (!diffText.trim()) {
|
|
9
|
+
throw wrapPatchEmpty();
|
|
10
|
+
}
|
|
11
|
+
if (!isCanonicalDiffHeader(diffText)) {
|
|
12
|
+
throw wrapPatchNotUnifiedDiff();
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export function rewriteUniqueBasenameDiffPaths(diffText, plannedFiles) {
|
|
16
|
+
if (plannedFiles.length === 0)
|
|
17
|
+
return diffText;
|
|
18
|
+
const basenameMap = new Map();
|
|
19
|
+
for (const file of plannedFiles.map((item) => item.replace(/\\/g, '/'))) {
|
|
20
|
+
const basename = file.split('/').at(-1);
|
|
21
|
+
if (!basename)
|
|
22
|
+
continue;
|
|
23
|
+
const existing = basenameMap.get(basename);
|
|
24
|
+
if (existing === undefined) {
|
|
25
|
+
basenameMap.set(basename, file);
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
if (existing !== file) {
|
|
29
|
+
basenameMap.set(basename, null);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const resolvePath = (candidate) => {
|
|
33
|
+
const normalized = candidate.replace(/\\/g, '/');
|
|
34
|
+
if (normalized === 'dev/null' || normalized.includes('/'))
|
|
35
|
+
return candidate;
|
|
36
|
+
const mapped = basenameMap.get(normalized);
|
|
37
|
+
return mapped ?? candidate;
|
|
38
|
+
};
|
|
39
|
+
return diffText
|
|
40
|
+
.replace(/^diff --git a\/(.+?) b\/(.+)$/gm, (_, left, right) => `diff --git a/${resolvePath(left)} b/${resolvePath(right)}`)
|
|
41
|
+
.replace(/^--- a\/(.+)$/gm, (_, left) => `--- a/${resolvePath(left)}`)
|
|
42
|
+
.replace(/^\+\+\+ b\/(.+)$/gm, (_, right) => `+++ b/${resolvePath(right)}`);
|
|
43
|
+
}
|
|
44
|
+
export function validatePatchDiff(diffText) {
|
|
45
|
+
assertCanonicalDiffHeader(diffText);
|
|
46
|
+
const normalizedPatch = normalizeDiff(diffText);
|
|
47
|
+
try {
|
|
48
|
+
const diffMeta = validateDiff(normalizedPatch);
|
|
49
|
+
return {
|
|
50
|
+
patch: diffText,
|
|
51
|
+
normalizedPatch,
|
|
52
|
+
diffMeta,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
if (error instanceof DiffValidationError) {
|
|
57
|
+
if (error.message === text.diff.notUnifiedFormat)
|
|
58
|
+
throw wrapPatchNotUnifiedDiff();
|
|
59
|
+
if (error.message.startsWith(text.llm.patchEmpty()))
|
|
60
|
+
throw wrapPatchEmpty();
|
|
61
|
+
throw wrapPatchInvalid(error.message);
|
|
62
|
+
}
|
|
63
|
+
throw error;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export function extractAndValidatePatch(args) {
|
|
67
|
+
const patch = rewriteUniqueBasenameDiffPaths(extractUnifiedDiffFromLLMContent(args.rawContent), args.plannedFiles);
|
|
68
|
+
return validatePatchDiff(patch);
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=diff-normalization.js.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { extractAndValidatePatch } from './diff-normalization.js';
|
|
2
|
+
const SALVAGEABLE_PATCH_CODES = new Set(['LLM_PATCH_NOT_UNIFIED_DIFF', 'LLM_PATCH_EMPTY']);
|
|
3
|
+
function errorMessage(error) {
|
|
4
|
+
if (error instanceof Error)
|
|
5
|
+
return error.message;
|
|
6
|
+
return String(error);
|
|
7
|
+
}
|
|
8
|
+
export function isSalvageablePatchError(error) {
|
|
9
|
+
if (!error || typeof error !== 'object')
|
|
10
|
+
return false;
|
|
11
|
+
const llmCode = error.llmCode;
|
|
12
|
+
return typeof llmCode === 'string' && SALVAGEABLE_PATCH_CODES.has(llmCode);
|
|
13
|
+
}
|
|
14
|
+
export async function salvagePatchDiff(args) {
|
|
15
|
+
if (!isSalvageablePatchError(args.initialError))
|
|
16
|
+
return null;
|
|
17
|
+
args.onAttempt?.({
|
|
18
|
+
reason: errorMessage(args.initialError),
|
|
19
|
+
badContentLength: args.rawContent.length,
|
|
20
|
+
});
|
|
21
|
+
const repaired = await args.repair({ badContent: args.rawContent });
|
|
22
|
+
const repairedContent = repaired.content || '';
|
|
23
|
+
try {
|
|
24
|
+
const validated = extractAndValidatePatch({
|
|
25
|
+
rawContent: repairedContent,
|
|
26
|
+
plannedFiles: args.plannedFiles,
|
|
27
|
+
});
|
|
28
|
+
args.onResult?.({
|
|
29
|
+
ok: true,
|
|
30
|
+
contentLength: repairedContent.length,
|
|
31
|
+
});
|
|
32
|
+
return {
|
|
33
|
+
...validated,
|
|
34
|
+
rawContent: repairedContent,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
catch (salvageError) {
|
|
38
|
+
args.onResult?.({
|
|
39
|
+
ok: false,
|
|
40
|
+
contentLength: repairedContent.length,
|
|
41
|
+
error: errorMessage(salvageError).slice(0, 400),
|
|
42
|
+
});
|
|
43
|
+
throw args.initialError;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=diff-salvage.js.map
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { LIMITS } from '../../../config/limits.js';
|
|
2
|
+
import { getPatchPrompt, getPatchSystemPrompt } from '../../../prompts/runtime.js';
|
|
3
|
+
import { SessionReplacementPreviewProvider } from '../../../session/replacement-preview-provider.js';
|
|
4
|
+
import { Phase } from '../../../types/runtime.js';
|
|
5
|
+
import { buildPhaseRequestEnvelope } from '../request-assembly.js';
|
|
6
|
+
export async function buildPatchPromptInput(args) {
|
|
7
|
+
const planStr = JSON.stringify(args.plan, null, 2);
|
|
8
|
+
const systemPrompt = await getPatchSystemPrompt(args.promptVisibleTools, {
|
|
9
|
+
plan: args.planRuntime,
|
|
10
|
+
});
|
|
11
|
+
const requestEnvelope = await buildPhaseRequestEnvelope({
|
|
12
|
+
phase: args.phase ?? Phase.PATCH,
|
|
13
|
+
defaultNamespace: 'patch',
|
|
14
|
+
context: args.context,
|
|
15
|
+
contextResult: args.contextResult,
|
|
16
|
+
cacheSharing: args.cacheSharing,
|
|
17
|
+
onCacheMismatch: args.onCacheMismatch,
|
|
18
|
+
systemPrompt,
|
|
19
|
+
buildUserPrompt: (contextPrompt) => getPatchPrompt(planStr, contextPrompt, LIMITS.maxFilesChanged, LIMITS.maxDiffLines, args.lastError),
|
|
20
|
+
conversationContext: args.conversationContext,
|
|
21
|
+
artifactHints: args.artifactHints,
|
|
22
|
+
previewProvider: new SessionReplacementPreviewProvider(args.replacementState),
|
|
23
|
+
toolCallingAudit: args.toolCallingAudit,
|
|
24
|
+
toolVisibility: args.toolVisibility,
|
|
25
|
+
extraAttachments: [
|
|
26
|
+
{
|
|
27
|
+
key: 'plan-json',
|
|
28
|
+
kind: 'plan',
|
|
29
|
+
label: 'Plan JSON',
|
|
30
|
+
content: planStr,
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
});
|
|
34
|
+
return {
|
|
35
|
+
planStr,
|
|
36
|
+
systemPrompt,
|
|
37
|
+
envelope: requestEnvelope.envelope,
|
|
38
|
+
baseMessages: requestEnvelope.baseMessages,
|
|
39
|
+
cacheSurface: requestEnvelope.cacheSurface,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=prompt-input.js.map
|
|
@@ -1,98 +1,116 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { GitAdapter } from '../../adapters/git/git-adapter.js';
|
|
3
|
-
import { LIMITS } from '../../config/limits.js';
|
|
1
|
+
import { supportsLlmStreaming } from '../../llm/capabilities.js';
|
|
4
2
|
import { repairToUnifiedDiff } from '../../llm/contracts/repair.js';
|
|
5
|
-
import { wrapPatchEmpty, wrapPatchInvalid, wrapPatchNotUnifiedDiff } from '../../llm/errors.js';
|
|
6
|
-
import { composeChatMessages } from '../../llm/message-composition.js';
|
|
7
3
|
import { emitLlmOutput } from '../../llm/output-policy.js';
|
|
8
|
-
import {
|
|
9
|
-
import { normalizeDiff, validateDiff } from '../../patch/diff.js';
|
|
10
|
-
import { getPatchPrompt, getPatchSystemPrompt } from '../../prompts/runtime.js';
|
|
4
|
+
import { recordAuditEvent } from '../../observability/audit-trail.js';
|
|
11
5
|
import { chatWithTools, chatWithToolsStreaming } from '../../tools/session.js';
|
|
12
|
-
import {
|
|
6
|
+
import { resolveVisibleToolSpecs } from '../../tools/tool-visibility.js';
|
|
13
7
|
import { Phase } from '../../types/runtime.js';
|
|
14
8
|
import { resolveLlmToolCallingPolicy } from '../dsl/llm-strategy.js';
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
9
|
+
import { checkPatchApplies } from './patch/apply-check.js';
|
|
10
|
+
import { extractAndValidatePatch } from './patch/diff-normalization.js';
|
|
11
|
+
import { salvagePatchDiff } from './patch/diff-salvage.js';
|
|
12
|
+
import { buildPatchPromptInput } from './patch/prompt-input.js';
|
|
13
|
+
import { buildPhaseToolRuntimeContext, buildToolVisibilityRuntime } from './tool-runtime.js';
|
|
14
|
+
const recordPatchSalvageAttempt = (args) => {
|
|
15
|
+
recordAuditEvent('patch.salvage.attempt', {
|
|
16
|
+
reason: args.reason,
|
|
17
|
+
badContentLength: args.badContentLength,
|
|
18
|
+
toolsDisabled: true,
|
|
19
|
+
}, { source: 'patch', severity: 'low', scope: 'session', phase: 'PATCH' });
|
|
20
|
+
};
|
|
21
|
+
const recordPatchSalvageResult = (args) => {
|
|
22
|
+
recordAuditEvent('patch.salvage.result', {
|
|
23
|
+
ok: args.ok,
|
|
24
|
+
contentLength: args.contentLength,
|
|
25
|
+
error: args.error,
|
|
26
|
+
}, {
|
|
27
|
+
source: 'patch',
|
|
28
|
+
severity: args.ok ? 'low' : 'medium',
|
|
29
|
+
scope: 'session',
|
|
30
|
+
phase: 'PATCH',
|
|
21
31
|
});
|
|
22
|
-
}
|
|
32
|
+
};
|
|
23
33
|
export const generatePatch = async (ctx) => {
|
|
24
34
|
const toolstack = ctx.toolstack;
|
|
25
35
|
const toolPolicy = resolveLlmToolCallingPolicy(Phase.PATCH, ctx.options.llm);
|
|
26
36
|
// Backwards-compatible fallback for non-tool-capable LLMs.
|
|
27
37
|
if (!toolstack || !toolPolicy.enabled) {
|
|
28
|
-
const
|
|
38
|
+
const legacyPatch = await ctx.options.llm.createPatch(ctx.context, ctx.plan, ctx.lastError, ctx.options.signal);
|
|
29
39
|
emitLlmOutput({
|
|
30
40
|
emit: ctx.emit,
|
|
31
41
|
policy: ctx.options.llmOutput,
|
|
32
42
|
kind: 'patch',
|
|
33
43
|
step: 'PATCH',
|
|
34
|
-
content:
|
|
44
|
+
content: legacyPatch,
|
|
45
|
+
});
|
|
46
|
+
const validated = extractAndValidatePatch({
|
|
47
|
+
rawContent: legacyPatch,
|
|
48
|
+
plannedFiles: ctx.plan.files,
|
|
35
49
|
});
|
|
36
|
-
const normalizedPatch = normalizeDiff(patch);
|
|
37
|
-
let diffMeta;
|
|
38
|
-
try {
|
|
39
|
-
diffMeta = validateDiff(normalizedPatch);
|
|
40
|
-
}
|
|
41
|
-
catch (e) {
|
|
42
|
-
if (e instanceof DiffValidationError) {
|
|
43
|
-
if (e.message === text.diff.notUnifiedFormat)
|
|
44
|
-
throw wrapPatchNotUnifiedDiff();
|
|
45
|
-
if (e.message.startsWith(text.llm.patchEmpty()))
|
|
46
|
-
throw wrapPatchEmpty();
|
|
47
|
-
throw wrapPatchInvalid(e.message);
|
|
48
|
-
}
|
|
49
|
-
throw e;
|
|
50
|
-
}
|
|
51
50
|
ctx.emit({
|
|
52
51
|
type: 'log',
|
|
53
52
|
level: 'debug',
|
|
54
|
-
message: `Patch generated: ${diffMeta.changedFiles.length} files changed`,
|
|
53
|
+
message: `Patch generated: ${validated.diffMeta.changedFiles.length} files changed`,
|
|
55
54
|
timestamp: new Date(),
|
|
56
55
|
});
|
|
57
56
|
return {
|
|
58
57
|
...ctx,
|
|
59
|
-
diff: normalizedPatch,
|
|
60
|
-
diffMeta,
|
|
61
|
-
changedFiles: diffMeta.changedFiles,
|
|
58
|
+
diff: validated.normalizedPatch,
|
|
59
|
+
diffMeta: validated.diffMeta,
|
|
60
|
+
changedFiles: validated.diffMeta.changedFiles,
|
|
62
61
|
};
|
|
63
62
|
}
|
|
64
|
-
const
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
63
|
+
const toolVisibility = buildToolVisibilityRuntime(ctx);
|
|
64
|
+
const promptVisibleTools = resolveVisibleToolSpecs({
|
|
65
|
+
phase: Phase.PATCH,
|
|
66
|
+
toolstack,
|
|
67
|
+
worktreeRoot: ctx.workspace.strategy === 'worktree' ? ctx.workspace.workPath : undefined,
|
|
68
|
+
flowMode: ctx.mode,
|
|
69
|
+
runtime: toolVisibility,
|
|
70
|
+
});
|
|
71
|
+
const patchPromptInput = await buildPatchPromptInput({
|
|
72
|
+
context: ctx.context,
|
|
73
|
+
contextResult: ctx.contextResult,
|
|
74
|
+
plan: ctx.plan,
|
|
75
|
+
planRuntime: ctx.planRuntime,
|
|
76
|
+
lastError: ctx.lastError,
|
|
77
|
+
promptVisibleTools,
|
|
78
|
+
toolVisibility: {
|
|
79
|
+
toolstack,
|
|
80
|
+
runtime: toolVisibility,
|
|
81
|
+
worktreeRoot: ctx.workspace.strategy === 'worktree' ? ctx.workspace.workPath : undefined,
|
|
82
|
+
flowMode: ctx.mode,
|
|
83
|
+
},
|
|
84
|
+
phase: Phase.PATCH,
|
|
85
|
+
cacheSharing: ctx.cacheSharing,
|
|
86
|
+
onCacheMismatch: (mismatch) => {
|
|
87
|
+
recordAuditEvent('request.cache_sharing_hash_mismatch', mismatch, {
|
|
88
|
+
source: 'llm',
|
|
89
|
+
severity: 'low',
|
|
90
|
+
scope: 'session',
|
|
91
|
+
phase: Phase.PATCH,
|
|
92
|
+
});
|
|
93
|
+
},
|
|
70
94
|
conversationContext: ctx.options.conversationContext,
|
|
95
|
+
artifactHints: ctx.artifactHints,
|
|
96
|
+
replacementState: ctx.replacementState,
|
|
97
|
+
toolCallingAudit: ctx.toolCallingAudit,
|
|
71
98
|
});
|
|
72
|
-
const
|
|
99
|
+
const { cacheSurface, envelope, baseMessages } = patchPromptInput;
|
|
100
|
+
const supportsStreaming = supportsLlmStreaming(ctx.options.llm, Phase.PATCH);
|
|
73
101
|
const llmOutput = {
|
|
74
102
|
policy: ctx.options.llmOutput,
|
|
75
103
|
kind: 'patch',
|
|
76
104
|
step: 'PATCH',
|
|
77
105
|
};
|
|
78
106
|
const response = await (supportsStreaming ? chatWithToolsStreaming : chatWithTools)(baseMessages, {
|
|
107
|
+
providerHints: envelope.providerHints,
|
|
79
108
|
signal: ctx.options.signal,
|
|
80
109
|
}, {
|
|
81
110
|
phase: Phase.PATCH,
|
|
82
111
|
llm: ctx.options.llm,
|
|
83
|
-
runtime:
|
|
84
|
-
|
|
85
|
-
persistenceRoot: ctx.workspace.baseRepoPath || ctx.workspace.workPath,
|
|
86
|
-
worktreeRoot: ctx.workspace.strategy === 'worktree' ? ctx.workspace.workPath : undefined,
|
|
87
|
-
attemptId: ctx.attempt ?? 1,
|
|
88
|
-
dryRun: Boolean(ctx.options?.dryRun),
|
|
89
|
-
llm: ctx.options.llm,
|
|
90
|
-
model: ctx.options.llm.getModelId?.() || process.env.SALMONLOOP_MODEL || process.env.S8P_MODEL,
|
|
91
|
-
userInputProvider: ctx.options.userInputProvider,
|
|
92
|
-
agentKind: ctx.options.agentKind ?? 'primary',
|
|
93
|
-
languagePlugins: ctx.options.languagePlugins,
|
|
94
|
-
subAgentController: ctx.options.subAgentController,
|
|
95
|
-
},
|
|
112
|
+
runtime: buildPhaseToolRuntimeContext(ctx, Phase.PATCH, cacheSurface),
|
|
113
|
+
toolVisibility,
|
|
96
114
|
toolstack,
|
|
97
115
|
eventPayload: ctx.options.eventPayload,
|
|
98
116
|
toolCallingAudit: {
|
|
@@ -107,114 +125,55 @@ export const generatePatch = async (ctx) => {
|
|
|
107
125
|
emit: (event) => ctx.emit({ ...event, timestamp: event.timestamp ?? new Date() }),
|
|
108
126
|
});
|
|
109
127
|
let rawContent = response.content || '';
|
|
110
|
-
let
|
|
111
|
-
let normalizedPatch = '';
|
|
112
|
-
let diffMeta;
|
|
113
|
-
const validateWithLlmErrors = (diffText) => {
|
|
114
|
-
const normalized = normalizeDiff(diffText);
|
|
115
|
-
try {
|
|
116
|
-
return validateDiff(normalized);
|
|
117
|
-
}
|
|
118
|
-
catch (e) {
|
|
119
|
-
if (e instanceof DiffValidationError) {
|
|
120
|
-
if (e.message === text.diff.notUnifiedFormat)
|
|
121
|
-
throw wrapPatchNotUnifiedDiff();
|
|
122
|
-
if (e.message.startsWith(text.llm.patchEmpty()))
|
|
123
|
-
throw wrapPatchEmpty();
|
|
124
|
-
throw wrapPatchInvalid(e.message);
|
|
125
|
-
}
|
|
126
|
-
throw e;
|
|
127
|
-
}
|
|
128
|
-
};
|
|
128
|
+
let parsedPatch;
|
|
129
129
|
try {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
130
|
+
parsedPatch = extractAndValidatePatch({
|
|
131
|
+
rawContent,
|
|
132
|
+
plannedFiles: ctx.plan.files,
|
|
133
|
+
});
|
|
133
134
|
}
|
|
134
135
|
catch (e) {
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
chatOptions: { signal: ctx.options.signal },
|
|
146
|
-
badContent: rawContent,
|
|
147
|
-
reason: asLlmError.message,
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
catch {
|
|
151
|
-
throw asLlmError;
|
|
152
|
-
}
|
|
153
|
-
rawContent = repaired.content || '';
|
|
154
|
-
patch = extractUnifiedDiffFromLLMContent(rawContent);
|
|
155
|
-
normalizedPatch = normalizeDiff(patch);
|
|
156
|
-
diffMeta = validateWithLlmErrors(patch);
|
|
157
|
-
emitLlmOutput({
|
|
158
|
-
emit: ctx.emit,
|
|
159
|
-
policy: ctx.options.llmOutput,
|
|
160
|
-
kind: 'patch',
|
|
161
|
-
step: 'PATCH',
|
|
162
|
-
content: patch,
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
else {
|
|
166
|
-
throw asLlmError;
|
|
136
|
+
const salvaged = await salvagePatchDiff({
|
|
137
|
+
initialError: e,
|
|
138
|
+
rawContent,
|
|
139
|
+
plannedFiles: ctx.plan.files,
|
|
140
|
+
repair: ({ badContent }) => repairToUnifiedDiff({ badContent }),
|
|
141
|
+
onAttempt: recordPatchSalvageAttempt,
|
|
142
|
+
onResult: recordPatchSalvageResult,
|
|
143
|
+
});
|
|
144
|
+
if (!salvaged) {
|
|
145
|
+
throw e;
|
|
167
146
|
}
|
|
147
|
+
rawContent = salvaged.rawContent;
|
|
148
|
+
parsedPatch = salvaged;
|
|
149
|
+
emitLlmOutput({
|
|
150
|
+
emit: ctx.emit,
|
|
151
|
+
policy: ctx.options.llmOutput,
|
|
152
|
+
kind: 'patch',
|
|
153
|
+
step: 'PATCH',
|
|
154
|
+
content: salvaged.patch,
|
|
155
|
+
});
|
|
168
156
|
}
|
|
169
157
|
// Deterministic contract: the patch should be applicable (git apply --check) before moving on.
|
|
170
158
|
// When this fails, attempt a single LLM repair pass using the git error message as feedback.
|
|
171
159
|
const applyCheck = await checkPatchApplies({
|
|
172
160
|
repoRoot: ctx.workspace.workPath,
|
|
173
|
-
diff: normalizedPatch,
|
|
161
|
+
diff: parsedPatch.normalizedPatch,
|
|
174
162
|
});
|
|
175
163
|
if (!applyCheck.ok) {
|
|
176
|
-
|
|
177
|
-
try {
|
|
178
|
-
const repaired = await repairToUnifiedDiff({
|
|
179
|
-
llm: ctx.options.llm,
|
|
180
|
-
baseMessages,
|
|
181
|
-
chatOptions: { signal: ctx.options.signal },
|
|
182
|
-
badContent: patch,
|
|
183
|
-
reason: `Patch does not apply cleanly: ${details.slice(0, 1200)}`,
|
|
184
|
-
});
|
|
185
|
-
rawContent = repaired.content || '';
|
|
186
|
-
patch = extractUnifiedDiffFromLLMContent(rawContent);
|
|
187
|
-
normalizedPatch = normalizeDiff(patch);
|
|
188
|
-
diffMeta = validateWithLlmErrors(patch);
|
|
189
|
-
const applyCheck2 = await checkPatchApplies({
|
|
190
|
-
repoRoot: ctx.workspace.workPath,
|
|
191
|
-
diff: normalizedPatch,
|
|
192
|
-
});
|
|
193
|
-
if (applyCheck2.ok) {
|
|
194
|
-
emitLlmOutput({
|
|
195
|
-
emit: ctx.emit,
|
|
196
|
-
policy: ctx.options.llmOutput,
|
|
197
|
-
kind: 'patch',
|
|
198
|
-
step: 'PATCH',
|
|
199
|
-
content: patch,
|
|
200
|
-
});
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
catch {
|
|
204
|
-
// Preserve the original patch and let VALIDATE provide the canonical failure if needed.
|
|
205
|
-
}
|
|
164
|
+
// Preserve the original patch and let VALIDATE provide the canonical failure if needed.
|
|
206
165
|
}
|
|
207
166
|
ctx.emit({
|
|
208
167
|
type: 'log',
|
|
209
168
|
level: 'debug',
|
|
210
|
-
message: `Patch generated: ${diffMeta.changedFiles.length} files changed`,
|
|
169
|
+
message: `Patch generated: ${parsedPatch.diffMeta.changedFiles.length} files changed`,
|
|
211
170
|
timestamp: new Date(),
|
|
212
171
|
});
|
|
213
172
|
return {
|
|
214
173
|
...ctx,
|
|
215
|
-
diff: normalizedPatch,
|
|
216
|
-
diffMeta,
|
|
217
|
-
changedFiles: diffMeta.changedFiles,
|
|
174
|
+
diff: parsedPatch.normalizedPatch,
|
|
175
|
+
diffMeta: parsedPatch.diffMeta,
|
|
176
|
+
changedFiles: parsedPatch.diffMeta.changedFiles,
|
|
218
177
|
};
|
|
219
178
|
};
|
|
220
179
|
//# sourceMappingURL=patch.js.map
|