salmon-loop 0.3.2 → 0.5.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/dist/cli/authorization/non-interactive.js +9 -13
- package/dist/cli/authorization/provider.js +2 -10
- 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/config.js +2 -2
- package/dist/cli/commands/mode.js +2 -2
- package/dist/cli/commands/parallel.js +1 -1
- package/dist/cli/commands/run/handler.js +9 -4
- package/dist/cli/commands/run/loop-params.js +2 -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/run/runtime-options.js +3 -1
- package/dist/cli/config.js +0 -8
- package/dist/cli/headless/openai-responses-canonical-applier.js +1 -7
- package/dist/cli/locales/en.js +2 -2
- package/dist/cli/reporters/standard.js +12 -3
- package/dist/cli/reporters/stream-json.js +2 -1
- package/dist/cli/slash/runtime.js +2 -2
- package/dist/cli/ui/hooks/useLoopEvents.js +1 -1
- package/dist/cli/ui/hooks/useLoopState.js +1 -1
- package/dist/core/adapters/fs/file-adapter.js +3 -1
- package/dist/core/adapters/git/git-adapter.js +6 -3
- package/dist/core/adapters/git/git-runner.js +5 -2
- package/dist/core/adapters/git/lock-manager.js +7 -4
- package/dist/core/ast/parser.js +18 -9
- package/dist/core/checkpoint-domain/manifest-store.js +21 -13
- package/dist/core/checkpoint-domain/service.js +3 -1
- package/dist/core/config/limits.js +1 -1
- package/dist/core/config/model-pricing.js +61 -0
- package/dist/core/config/schema.js +738 -0
- package/dist/core/config/validate.js +11 -922
- package/dist/core/context/ast/skeleton-extractor.js +225 -0
- package/dist/core/context/ast/source-outline.js +24 -1
- package/dist/core/context/budget/dynamic-adjuster.js +20 -5
- package/dist/core/context/builder.js +7 -3
- package/dist/core/context/cache/store-factory.js +3 -1
- package/dist/core/context/dependencies.js +2 -1
- package/dist/core/context/effectiveness/persistence.js +50 -0
- package/dist/core/context/effectiveness/tracker.js +24 -0
- package/dist/core/context/gatherers/architecture-gatherer.js +2 -1
- package/dist/core/context/gatherers/artifact-gatherer.js +7 -4
- package/dist/core/context/gatherers/ast-gatherer.js +34 -40
- package/dist/core/context/gatherers/ghost-dependency-gatherer.js +0 -1
- package/dist/core/context/gatherers/git-history-gatherer.js +3 -1
- package/dist/core/context/gatherers/knowledge-gatherer.js +21 -2
- package/dist/core/context/gatherers/metadata-gatherer.js +12 -7
- package/dist/core/context/gatherers/ripgrep-gatherer.js +6 -3
- package/dist/core/context/service.js +12 -2
- package/dist/core/context/steps/context-gather.js +14 -3
- package/dist/core/context/steps/context-targets.js +1 -0
- package/dist/core/context/targeting/target-resolver.js +29 -11
- package/dist/core/context/token/cache.js +5 -2
- package/dist/core/context/token/encoding-registry.js +7 -6
- package/dist/core/context/truncation/strategies/json.js +5 -2
- package/dist/core/context/truncation/type-detector.js +3 -1
- 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 +8 -2
- package/dist/core/extensions/schemas.js +21 -0
- package/dist/core/facades/cli-authorization-provider.js +1 -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/feedback/parsers.js +290 -1
- package/dist/core/grizzco/dsl/llm-strategy.js +4 -3
- package/dist/core/grizzco/engine/observability/loop-telemetry.js +5 -2
- package/dist/core/grizzco/engine/outcome/loop-result-mapper.js +30 -13
- package/dist/core/grizzco/engine/pipeline/pipeline.js +149 -240
- package/dist/core/grizzco/engine/transaction/attempt-failure.js +49 -24
- package/dist/core/grizzco/engine/transaction/authorization-summary.js +2 -1
- package/dist/core/grizzco/engine/transaction/transaction-runner.js +40 -34
- package/dist/core/grizzco/execution/RejectionManager.js +7 -5
- package/dist/core/grizzco/runtime/apply-back-runtime.js +5 -2
- package/dist/core/grizzco/services/implementations/default/GitConfigService.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/autopilot.js +21 -32
- package/dist/core/grizzco/steps/display-report.js +4 -11
- package/dist/core/grizzco/steps/explore.js +14 -4
- package/dist/core/grizzco/steps/generateReview.js +3 -1
- 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/research.js +3 -1
- package/dist/core/grizzco/steps/tool-runtime.js +3 -0
- package/dist/core/grizzco/steps/verify.js +7 -1
- package/dist/core/grizzco/validation/AstValidationService.js +3 -1
- package/dist/core/grizzco/workers/strata-sync-worker.js +2 -1
- package/dist/core/history/input-history.js +3 -1
- package/dist/core/intent/chat-intent.js +3 -1
- package/dist/core/llm/ai-sdk/message-mapper.js +37 -26
- package/dist/core/llm/ai-sdk/request-params.js +2 -6
- package/dist/core/llm/ai-sdk/result-mapper.js +14 -8
- package/dist/core/llm/ai-sdk/retry-classifier.js +17 -7
- package/dist/core/llm/ai-sdk/retry-executor.js +1 -1
- package/dist/core/llm/contracts/repair.js +16 -8
- package/dist/core/llm/errors.js +18 -14
- package/dist/core/llm/output-policy.js +8 -0
- package/dist/core/llm/redact.js +1 -3
- package/dist/core/llm/retry-utils.js +8 -2
- package/dist/core/llm/stream-utils.js +5 -3
- package/dist/core/llm/sub-agent-factory.js +51 -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/resource-context-provider.js +3 -1
- package/dist/core/mcp/bridge/tool-bridge.js +5 -14
- package/dist/core/mcp/catalog/discovery.js +3 -1
- package/dist/core/mcp/client/connection-manager.js +7 -4
- package/dist/core/mcp/client/transport-factory.js +7 -3
- 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/audit-file.js +2 -1
- package/dist/core/observability/audit-trail.js +3 -1
- package/dist/core/observability/authorization-decisions.js +13 -12
- package/dist/core/observability/error-mapping.js +2 -1
- package/dist/core/observability/logger.js +2 -1
- package/dist/core/observability/monitor.js +24 -0
- package/dist/core/observability/run-outcome-reporter.js +1 -0
- package/dist/core/observability/token-usage.js +5 -4
- package/dist/core/permission-gate/default-gate.js +5 -8
- package/dist/core/plan/storage.js +7 -4
- package/dist/core/plugin/loader.js +8 -5
- package/dist/core/prompts/registry.js +12 -30
- package/dist/core/prompts/runtime.js +3 -1
- package/dist/core/prompts/templates/system/autopilot_system.hbs +28 -4
- package/dist/core/protocols/a2a/sdk/executor.js +3 -1
- package/dist/core/protocols/a2a/sdk/server.js +5 -4
- package/dist/core/protocols/acp/acp-command-runner.js +7 -6
- package/dist/core/protocols/acp/acp-session-persistence.js +13 -10
- package/dist/core/protocols/acp/formal-agent.js +13 -6
- package/dist/core/protocols/acp/permission-provider.js +3 -2
- package/dist/core/protocols/acp/stdio-server.js +6 -6
- package/dist/core/reflection/engine.js +114 -14
- package/dist/core/runtime/agent-server-runtime.js +3 -2
- package/dist/core/runtime/batch-runner.js +81 -0
- package/dist/core/runtime/initialize.js +71 -6
- package/dist/core/runtime/loop-finalize.js +3 -0
- package/dist/core/runtime/loop-session-runner.js +5 -0
- package/dist/core/runtime/loop.js +4 -0
- package/dist/core/runtime/paths.js +9 -6
- package/dist/core/runtime/spawn-interactive.js +5 -4
- package/dist/core/security/redaction.js +3 -2
- package/dist/core/session/compaction/index.js +4 -3
- package/dist/core/session/compression.js +3 -1
- package/dist/core/session/manager.js +26 -38
- package/dist/core/session/pruning-strategy.js +2 -1
- package/dist/core/session/token-tracker.js +27 -9
- package/dist/core/skills/parser.js +3 -2
- package/dist/core/skills/permissions.js +2 -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/checkpoint/manager.js +16 -10
- package/dist/core/strata/checkpoint/snapshot-create.js +5 -4
- package/dist/core/strata/checkpoint/snapshot-write-tree.js +7 -3
- package/dist/core/strata/engine/shadow-merge-engine.js +4 -2
- package/dist/core/strata/interaction/file-system-provider.js +2 -1
- package/dist/core/strata/layers/file-state-resolver.js +9 -7
- package/dist/core/strata/layers/immutable-git-layer.js +3 -1
- package/dist/core/strata/layers/shadow-driver/readonly-lock.js +8 -6
- package/dist/core/strata/layers/shadow-driver/shadow-driver.js +2 -1
- package/dist/core/strata/layers/worktree.js +9 -10
- package/dist/core/strata/runtime/environment.js +2 -1
- package/dist/core/strata/runtime/synchronizer.js +28 -26
- package/dist/core/streaming/canonical/parts-from-llm-stream-chunk.js +1 -11
- package/dist/core/structured-output/json-extract.js +3 -1
- package/dist/core/structured-output/json-schema-validator.js +1 -13
- package/dist/core/sub-agent/artifacts/store.js +2 -1
- 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 +343 -117
- package/dist/core/sub-agent/registry-defaults.js +12 -0
- package/dist/core/sub-agent/registry.js +8 -0
- package/dist/core/sub-agent/summary.js +96 -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 +52 -7
- package/dist/core/sub-agent/tools/team.js +92 -0
- package/dist/core/sub-agent/types.js +11 -2
- package/dist/core/target-runtime/profile.js +3 -1
- package/dist/core/tools/audit.js +3 -2
- package/dist/core/tools/budget.js +7 -12
- package/dist/core/tools/builtin/ast.js +144 -0
- package/dist/core/tools/builtin/code-search/backends/powershell.js +3 -1
- package/dist/core/tools/builtin/code-search/backends/rg.js +3 -1
- package/dist/core/tools/builtin/code-search/executor.js +46 -43
- package/dist/core/tools/builtin/code-search/parse/plain-grep.js +3 -1
- package/dist/core/tools/builtin/code-search/parse/rg-json.js +3 -1
- package/dist/core/tools/builtin/fs.js +90 -7
- package/dist/core/tools/builtin/git.js +242 -0
- package/dist/core/tools/builtin/glob.js +79 -0
- package/dist/core/tools/builtin/index.js +53 -111
- package/dist/core/tools/builtin/interaction.js +13 -15
- package/dist/core/tools/builtin/knowledge.js +146 -4
- package/dist/core/tools/builtin/proposal.js +14 -3
- package/dist/core/tools/builtin/verify.js +35 -3
- 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 +69 -115
- package/dist/core/tools/plugins/loader.js +4 -3
- package/dist/core/tools/router.js +112 -58
- package/dist/core/tools/session.js +64 -102
- 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/types/batch.js +2 -0
- package/dist/core/utils/error.js +79 -0
- package/dist/core/utils/sanitizer.js +5 -2
- package/dist/core/utils/serialize.js +66 -0
- package/dist/core/utils/zod.js +29 -0
- package/dist/core/verification/detect-runner.js +86 -0
- package/dist/core/verification/runner.js +76 -0
- package/dist/core/version.js +3 -1
- package/dist/core/workspace/capabilities.js +3 -2
- package/dist/integrations/langfuse/litellm-langfuse-outcome-reporter.js +9 -8
- package/dist/languages/python/index.js +154 -0
- package/dist/locales/en.js +8 -1
- package/package.json +2 -1
|
@@ -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,3 +1,4 @@
|
|
|
1
|
+
import { getLogger } from '../observability/logger.js';
|
|
1
2
|
export function parseTscOutput(output) {
|
|
2
3
|
const diagnostics = [];
|
|
3
4
|
const lines = output.split('\n');
|
|
@@ -46,8 +47,296 @@ export function parsePythonError(output) {
|
|
|
46
47
|
}
|
|
47
48
|
return diagnostics;
|
|
48
49
|
}
|
|
50
|
+
export function parsePytestOutput(output) {
|
|
51
|
+
const diagnostics = [];
|
|
52
|
+
const lines = output.split('\n');
|
|
53
|
+
// Pattern 1: FAILED lines (--tb=short -q format)
|
|
54
|
+
// e.g. FAILED tests/test_foo.py::test_bar - AssertionError: expected 5, got 3
|
|
55
|
+
// e.g. FAILED tests/test_foo.py::TestClass::test_method - ValueError: bad value
|
|
56
|
+
const failedRegex = /^FAILED\s+(\S+?)\s+-\s+(.+)$/;
|
|
57
|
+
// Pattern 2: Assertion detail lines (E prefix)
|
|
58
|
+
// e.g. E AssertionError: expected 5, got 3
|
|
59
|
+
const assertionRegex = /^\s*E\s{2,}(\w+(?:Error|Exception)?):\s*(.+)$/;
|
|
60
|
+
// Pattern 3: File:line reference in traceback
|
|
61
|
+
// e.g. tests/test_module.py:42: in test_function
|
|
62
|
+
const fileLineRegex = /^\s*(\S+\.py):(\d+): in /;
|
|
63
|
+
// Pattern 4: One-line format (--tb=line)
|
|
64
|
+
// e.g. tests/test_module.py:42: AssertionError
|
|
65
|
+
const lineFormatRegex = /^(\S+\.py):(\d+):\s+(\w+(?:Error|Exception)?)$/;
|
|
66
|
+
// Track current file context for enhancing FAILED diagnostics
|
|
67
|
+
let currentFile = null;
|
|
68
|
+
let currentLine = null;
|
|
69
|
+
// Map test_id -> { file, line, assertion } for merging
|
|
70
|
+
const assertionMap = new Map();
|
|
71
|
+
for (let i = 0; i < lines.length; i++) {
|
|
72
|
+
const line = lines[i];
|
|
73
|
+
// Collect file:line context from tracebacks
|
|
74
|
+
const fileMatch = line.match(fileLineRegex);
|
|
75
|
+
if (fileMatch) {
|
|
76
|
+
currentFile = fileMatch[1];
|
|
77
|
+
currentLine = parseInt(fileMatch[2]);
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
// Collect assertion details
|
|
81
|
+
const assertionMatch = line.match(assertionRegex);
|
|
82
|
+
if (assertionMatch && currentFile) {
|
|
83
|
+
// Associate with the most recent file context
|
|
84
|
+
const key = `${currentFile}:${currentLine}`;
|
|
85
|
+
if (!assertionMap.has(key)) {
|
|
86
|
+
assertionMap.set(key, {
|
|
87
|
+
file: currentFile,
|
|
88
|
+
line: currentLine ?? undefined,
|
|
89
|
+
assertion: `${assertionMatch[1]}: ${assertionMatch[2]}`,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
// Parse FAILED lines — the primary signal
|
|
95
|
+
const failedMatch = line.match(failedRegex);
|
|
96
|
+
if (failedMatch) {
|
|
97
|
+
const testId = failedMatch[1]; // e.g. tests/test_foo.py::test_bar
|
|
98
|
+
const errorMessage = failedMatch[2];
|
|
99
|
+
// Extract file from test_id (everything before ::)
|
|
100
|
+
const testFile = testId.split('::')[0];
|
|
101
|
+
diagnostics.push({
|
|
102
|
+
file: testFile,
|
|
103
|
+
severity: 'error',
|
|
104
|
+
message: errorMessage,
|
|
105
|
+
source: 'pytest',
|
|
106
|
+
});
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
// Parse one-line format
|
|
110
|
+
const lineFormatMatch = line.match(lineFormatRegex);
|
|
111
|
+
if (lineFormatMatch) {
|
|
112
|
+
diagnostics.push({
|
|
113
|
+
file: lineFormatMatch[1],
|
|
114
|
+
line: parseInt(lineFormatMatch[2]),
|
|
115
|
+
severity: 'error',
|
|
116
|
+
message: lineFormatMatch[3],
|
|
117
|
+
source: 'pytest',
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// Enhance FAILED diagnostics with file:line info from tracebacks
|
|
122
|
+
if (diagnostics.length > 0 && assertionMap.size > 0) {
|
|
123
|
+
for (const diag of diagnostics) {
|
|
124
|
+
if (diag.source === 'pytest' && !diag.line) {
|
|
125
|
+
// Find matching assertion detail by file
|
|
126
|
+
for (const [, info] of assertionMap) {
|
|
127
|
+
if (info.file === diag.file && info.line) {
|
|
128
|
+
diag.line = info.line;
|
|
129
|
+
if (info.assertion && diag.message.length < info.assertion.length) {
|
|
130
|
+
diag.message = info.assertion;
|
|
131
|
+
}
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return diagnostics;
|
|
139
|
+
}
|
|
140
|
+
export function parseJestOutput(output) {
|
|
141
|
+
const diagnostics = [];
|
|
142
|
+
const lines = output.split('\n');
|
|
143
|
+
// Pattern 1: FAIL src/foo.test.ts
|
|
144
|
+
const suiteFailRegex = /^(?:FAIL|✗|✘)\s+(\S+)$/;
|
|
145
|
+
// Pattern 2: ● Test suite failed to run / ● test_name
|
|
146
|
+
const bulletRegex = /^\s*●\s+(.+)$/;
|
|
147
|
+
// Pattern 3: inline error: src/foo.ts:10:5 - error TS2322: ...
|
|
148
|
+
const inlineRegex = /^(\S+\.tsx?):(\d+):(\d+)\s+-\s+(error|warning)\s+(.+)$/;
|
|
149
|
+
let currentSuite = null;
|
|
150
|
+
for (const line of lines) {
|
|
151
|
+
const suiteMatch = line.match(suiteFailRegex);
|
|
152
|
+
if (suiteMatch) {
|
|
153
|
+
currentSuite = suiteMatch[1];
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
const inlineMatch = line.match(inlineRegex);
|
|
157
|
+
if (inlineMatch) {
|
|
158
|
+
diagnostics.push({
|
|
159
|
+
file: inlineMatch[1],
|
|
160
|
+
line: parseInt(inlineMatch[2]),
|
|
161
|
+
column: parseInt(inlineMatch[3]),
|
|
162
|
+
severity: inlineMatch[4],
|
|
163
|
+
message: inlineMatch[5],
|
|
164
|
+
source: 'jest',
|
|
165
|
+
});
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
const bulletMatch = line.match(bulletRegex);
|
|
169
|
+
if (bulletMatch && currentSuite) {
|
|
170
|
+
diagnostics.push({
|
|
171
|
+
file: currentSuite,
|
|
172
|
+
severity: 'error',
|
|
173
|
+
message: bulletMatch[1],
|
|
174
|
+
source: 'jest',
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return diagnostics;
|
|
179
|
+
}
|
|
180
|
+
// ── Structured JSON parsers ──────────────────────────────────────────────────
|
|
181
|
+
/** Parse jest --json output (single JSON object). */
|
|
182
|
+
export function parseJestJson(output) {
|
|
183
|
+
const diagnostics = [];
|
|
184
|
+
let parsed;
|
|
185
|
+
try {
|
|
186
|
+
parsed = JSON.parse(output);
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
getLogger().debug(`[Parsers] Failed to parse jest JSON output: ${error instanceof Error ? error.message : String(error)}`);
|
|
190
|
+
return [];
|
|
191
|
+
}
|
|
192
|
+
for (const suite of parsed.testResults ?? []) {
|
|
193
|
+
for (const assertion of suite.assertionResults ?? []) {
|
|
194
|
+
if (assertion.status === 'failed') {
|
|
195
|
+
diagnostics.push({
|
|
196
|
+
file: suite.name,
|
|
197
|
+
severity: 'error',
|
|
198
|
+
message: (assertion.failureMessages ?? []).join('\n') ||
|
|
199
|
+
`Test failed: ${(assertion.ancestorTitles ?? []).join(' > ')} > ${assertion.fullName ?? assertion.title}`,
|
|
200
|
+
source: 'jest',
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return diagnostics;
|
|
206
|
+
}
|
|
207
|
+
/** Extract test summary from jest --json output. */
|
|
208
|
+
export function parseJestJsonSummary(output) {
|
|
209
|
+
try {
|
|
210
|
+
const parsed = JSON.parse(output);
|
|
211
|
+
if (typeof parsed.numTotalTests === 'number') {
|
|
212
|
+
const passed = parsed.numPassedTests ?? 0;
|
|
213
|
+
const failed = parsed.numFailedTests ?? 0;
|
|
214
|
+
const total = parsed.numTotalTests;
|
|
215
|
+
return { total, passed, failed, skipped: total - passed - failed };
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
catch (error) {
|
|
219
|
+
/* not JSON */
|
|
220
|
+
getLogger().debug(`[Parsers] Failed to parse jest JSON summary: ${error instanceof Error ? error.message : String(error)}`);
|
|
221
|
+
}
|
|
222
|
+
return undefined;
|
|
223
|
+
}
|
|
224
|
+
/** Parse eslint --format json output (JSON array). */
|
|
225
|
+
export function parseEslintJson(output) {
|
|
226
|
+
const diagnostics = [];
|
|
227
|
+
let parsed;
|
|
228
|
+
try {
|
|
229
|
+
parsed = JSON.parse(output);
|
|
230
|
+
}
|
|
231
|
+
catch (error) {
|
|
232
|
+
getLogger().debug(`[Parsers] Failed to parse eslint JSON output: ${error instanceof Error ? error.message : String(error)}`);
|
|
233
|
+
return [];
|
|
234
|
+
}
|
|
235
|
+
if (!Array.isArray(parsed))
|
|
236
|
+
return [];
|
|
237
|
+
for (const file of parsed) {
|
|
238
|
+
for (const msg of file.messages ?? []) {
|
|
239
|
+
diagnostics.push({
|
|
240
|
+
file: file.filePath,
|
|
241
|
+
line: msg.line,
|
|
242
|
+
column: msg.column,
|
|
243
|
+
severity: msg.severity === 2 ? 'error' : 'warning',
|
|
244
|
+
message: msg.message + (msg.ruleId ? ` (${msg.ruleId})` : ''),
|
|
245
|
+
source: 'eslint',
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return diagnostics;
|
|
250
|
+
}
|
|
251
|
+
/** Parse bun test --json NDJSON output. */
|
|
252
|
+
export function parseBunTestNdjson(output) {
|
|
253
|
+
const diagnostics = [];
|
|
254
|
+
for (const line of output.split('\n')) {
|
|
255
|
+
const trimmed = line.trim();
|
|
256
|
+
if (!trimmed.startsWith('{'))
|
|
257
|
+
continue;
|
|
258
|
+
try {
|
|
259
|
+
const evt = JSON.parse(trimmed);
|
|
260
|
+
if (evt.type === 'test-fail' || evt.data?.status === 'fail') {
|
|
261
|
+
const data = evt.data ?? {};
|
|
262
|
+
diagnostics.push({
|
|
263
|
+
file: data.file ?? data.sourceFile ?? 'unknown',
|
|
264
|
+
severity: 'error',
|
|
265
|
+
message: data.error?.message ?? data.message ?? 'Test failed',
|
|
266
|
+
source: 'bun',
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
catch (error) {
|
|
271
|
+
/* skip non-JSON lines */
|
|
272
|
+
getLogger().debug(`[Parsers] Failed to parse bun test NDJSON line: ${error instanceof Error ? error.message : String(error)}`);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return diagnostics;
|
|
276
|
+
}
|
|
277
|
+
/** Parse go test -json NDJSON output. */
|
|
278
|
+
export function parseGoTestNdjson(output) {
|
|
279
|
+
const diagnostics = [];
|
|
280
|
+
for (const line of output.split('\n')) {
|
|
281
|
+
const trimmed = line.trim();
|
|
282
|
+
if (!trimmed.startsWith('{'))
|
|
283
|
+
continue;
|
|
284
|
+
try {
|
|
285
|
+
const evt = JSON.parse(trimmed);
|
|
286
|
+
if (evt.Action === 'fail' && evt.Test) {
|
|
287
|
+
diagnostics.push({
|
|
288
|
+
file: evt.Package ?? 'unknown',
|
|
289
|
+
severity: 'error',
|
|
290
|
+
message: `Test failed: ${evt.Test}`,
|
|
291
|
+
source: 'go',
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
catch (error) {
|
|
296
|
+
/* skip non-JSON lines */
|
|
297
|
+
getLogger().debug(`[Parsers] Failed to parse go test NDJSON line: ${error instanceof Error ? error.message : String(error)}`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return diagnostics;
|
|
301
|
+
}
|
|
302
|
+
/** Dispatch to the correct structured parser based on runner type. */
|
|
303
|
+
export function parseRunnerOutput(output, runner) {
|
|
304
|
+
switch (runner) {
|
|
305
|
+
case 'jest':
|
|
306
|
+
case 'vitest':
|
|
307
|
+
return parseJestJson(output);
|
|
308
|
+
case 'eslint':
|
|
309
|
+
return parseEslintJson(output);
|
|
310
|
+
case 'bun':
|
|
311
|
+
return parseBunTestNdjson(output);
|
|
312
|
+
case 'go':
|
|
313
|
+
return parseGoTestNdjson(output);
|
|
314
|
+
case 'pytest':
|
|
315
|
+
case 'tsc':
|
|
316
|
+
case 'unknown':
|
|
317
|
+
default:
|
|
318
|
+
return parseGenericOutput(output);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
/** Extract test summary from structured JSON output when available. */
|
|
322
|
+
export function parseStructuredSummary(output, runner) {
|
|
323
|
+
switch (runner) {
|
|
324
|
+
case 'jest':
|
|
325
|
+
case 'vitest':
|
|
326
|
+
return parseJestJsonSummary(output);
|
|
327
|
+
default:
|
|
328
|
+
return undefined;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
// ── Text-based heuristic dispatcher (fallback) ──────────────────────────────
|
|
49
332
|
export function parseGenericOutput(output) {
|
|
50
|
-
//
|
|
333
|
+
// Try pytest first (SWE-bench's primary test runner)
|
|
334
|
+
const pytest = parsePytestOutput(output);
|
|
335
|
+
if (pytest.length > 0)
|
|
336
|
+
return pytest;
|
|
337
|
+
const jest = parseJestOutput(output);
|
|
338
|
+
if (jest.length > 0)
|
|
339
|
+
return jest;
|
|
51
340
|
const tsc = parseTscOutput(output);
|
|
52
341
|
if (tsc.length > 0)
|
|
53
342
|
return tsc;
|
|
@@ -1,12 +1,13 @@
|
|
|
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
|
|
6
7
|
if (phase === Phase.EXPLORE)
|
|
7
8
|
return 8;
|
|
8
9
|
if (phase === Phase.AUTOPILOT)
|
|
9
|
-
return
|
|
10
|
+
return 12;
|
|
10
11
|
if (phase === Phase.RESEARCH)
|
|
11
12
|
return 8;
|
|
12
13
|
if (phase === Phase.PLAN)
|
|
@@ -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: {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { LIMITS } from '../../../config/limits.js';
|
|
2
|
+
import { getLogger } from '../../../observability/logger.js';
|
|
2
3
|
export class LoopTelemetry {
|
|
3
4
|
now;
|
|
4
5
|
logs = [];
|
|
@@ -16,11 +17,13 @@ export class LoopTelemetry {
|
|
|
16
17
|
try {
|
|
17
18
|
return JSON.stringify(output);
|
|
18
19
|
}
|
|
19
|
-
catch {
|
|
20
|
+
catch (error) {
|
|
21
|
+
getLogger().debug(`[LoopTelemetry] JSON.stringify failed, falling back to String(): ${error instanceof Error ? error.message : String(error)}`);
|
|
20
22
|
try {
|
|
21
23
|
return String(output);
|
|
22
24
|
}
|
|
23
|
-
catch {
|
|
25
|
+
catch (stringError) {
|
|
26
|
+
getLogger().debug(`[LoopTelemetry] String() conversion also failed: ${stringError instanceof Error ? stringError.message : String(stringError)}`);
|
|
24
27
|
return '[Unserializable]';
|
|
25
28
|
}
|
|
26
29
|
}
|
|
@@ -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',
|
|
@@ -22,6 +23,12 @@ function toRootCauseCode(code) {
|
|
|
22
23
|
? code
|
|
23
24
|
: undefined;
|
|
24
25
|
}
|
|
26
|
+
function applyPassthroughFields(result, options) {
|
|
27
|
+
if (options.tags)
|
|
28
|
+
result.tags = options.tags;
|
|
29
|
+
if (options.providerMeta)
|
|
30
|
+
result.providerMeta = options.providerMeta;
|
|
31
|
+
}
|
|
25
32
|
export function buildLoopResultFromTransaction({ executionReport, flowMode, options, telemetry, auditPath, }) {
|
|
26
33
|
const profile = resolveExecutionProfile(flowMode);
|
|
27
34
|
const rootCause = toRootCauseCode(executionReport.lastErrorCode);
|
|
@@ -34,17 +41,19 @@ export function buildLoopResultFromTransaction({ executionReport, flowMode, opti
|
|
|
34
41
|
: 'NON_RETRYABLE_FAILURE';
|
|
35
42
|
const ctx = executionReport.lastContext ??
|
|
36
43
|
executionReport.flowReport.data;
|
|
44
|
+
const ctxObj = isRecord(ctx) ? ctx : null;
|
|
37
45
|
const contextHash = (() => {
|
|
38
|
-
const
|
|
46
|
+
const contextResult = isRecord(ctxObj?.contextResult) ? ctxObj.contextResult : null;
|
|
47
|
+
const meta = isRecord(contextResult?.meta) ? contextResult.meta : null;
|
|
48
|
+
const hashFromBudget = meta?.contextHash;
|
|
39
49
|
if (typeof hashFromBudget === 'string')
|
|
40
50
|
return hashFromBudget;
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
: undefined;
|
|
51
|
+
const context = isRecord(ctxObj?.context) ? ctxObj.context : null;
|
|
52
|
+
const hashFromContext = context?.contextHash;
|
|
44
53
|
return typeof hashFromContext === 'string' ? hashFromContext : undefined;
|
|
45
54
|
})();
|
|
46
|
-
const verifyArtifact =
|
|
47
|
-
?
|
|
55
|
+
const verifyArtifact = ctxObj && typeof ctxObj.verifyArtifact !== 'undefined'
|
|
56
|
+
? ctxObj.verifyArtifact
|
|
48
57
|
: executionReport.lastVerifyArtifact;
|
|
49
58
|
const artifactHints = (() => {
|
|
50
59
|
const hints = {
|
|
@@ -71,12 +80,14 @@ export function buildLoopResultFromTransaction({ executionReport, flowMode, opti
|
|
|
71
80
|
}
|
|
72
81
|
return hints;
|
|
73
82
|
})();
|
|
83
|
+
const report = isRecord(ctxObj?.report) ? ctxObj.report : null;
|
|
74
84
|
const assistantMessage = ((flowMode === 'answer' || profile.driver === 'agent') &&
|
|
75
|
-
|
|
76
|
-
|
|
85
|
+
typeof report?.summary === 'string' &&
|
|
86
|
+
report.summary.trim()
|
|
87
|
+
? report.summary.trim()
|
|
77
88
|
: undefined) ?? undefined;
|
|
78
|
-
const finalPatch =
|
|
79
|
-
const changedFiles =
|
|
89
|
+
const finalPatch = ctxObj && typeof ctxObj.diff === 'string' ? ctxObj.diff : undefined;
|
|
90
|
+
const changedFiles = Array.isArray(ctxObj?.changedFiles) ? ctxObj.changedFiles : undefined;
|
|
80
91
|
const authorizationDecisions = (() => {
|
|
81
92
|
if (!options.eventPayload?.includeAuthorizationDecisions)
|
|
82
93
|
return undefined;
|
|
@@ -88,7 +99,7 @@ export function buildLoopResultFromTransaction({ executionReport, flowMode, opti
|
|
|
88
99
|
const usage = getTokenUsageFromAuditTrail() ?? undefined;
|
|
89
100
|
const budgetSummary = getBudgetRunSummary() ?? undefined;
|
|
90
101
|
if (options.dryRun || profile.readOnly) {
|
|
91
|
-
|
|
102
|
+
const result = {
|
|
92
103
|
success: true,
|
|
93
104
|
reason: text.loop.operationCompleted,
|
|
94
105
|
reasonCode: options.dryRun ? 'DRY_RUN' : 'SUCCESS',
|
|
@@ -110,8 +121,10 @@ export function buildLoopResultFromTransaction({ executionReport, flowMode, opti
|
|
|
110
121
|
fsMode: executionReport.flowReport.fsMode ?? flowMode,
|
|
111
122
|
budgetSummary,
|
|
112
123
|
};
|
|
124
|
+
applyPassthroughFields(result, options);
|
|
125
|
+
return result;
|
|
113
126
|
}
|
|
114
|
-
|
|
127
|
+
const result = {
|
|
115
128
|
success: true,
|
|
116
129
|
reason: text.loop.operationCompleted,
|
|
117
130
|
reasonCode: 'SUCCESS',
|
|
@@ -133,6 +146,8 @@ export function buildLoopResultFromTransaction({ executionReport, flowMode, opti
|
|
|
133
146
|
fsMode: executionReport.flowReport.fsMode ?? flowMode,
|
|
134
147
|
budgetSummary,
|
|
135
148
|
};
|
|
149
|
+
applyPassthroughFields(result, options);
|
|
150
|
+
return result;
|
|
136
151
|
}
|
|
137
152
|
const retryFailureReason = executionReport.history.at(-1)?.error ?? text.loop.loopExecutionFailed;
|
|
138
153
|
const failureReason = executionReport.retryExhausted
|
|
@@ -159,7 +174,7 @@ export function buildLoopResultFromTransaction({ executionReport, flowMode, opti
|
|
|
159
174
|
remediationSteps,
|
|
160
175
|
fallbackMessage: failureReason,
|
|
161
176
|
});
|
|
162
|
-
|
|
177
|
+
const result = {
|
|
163
178
|
success: false,
|
|
164
179
|
reason: resultReason,
|
|
165
180
|
reasonCode,
|
|
@@ -190,6 +205,8 @@ export function buildLoopResultFromTransaction({ executionReport, flowMode, opti
|
|
|
190
205
|
? executionReport.terminalInputRequired
|
|
191
206
|
: undefined,
|
|
192
207
|
};
|
|
208
|
+
applyPassthroughFields(result, options);
|
|
209
|
+
return result;
|
|
193
210
|
}
|
|
194
211
|
export function buildLoopFailureResult({ message, flowMode, telemetry, auditPath, reasonCode, failurePhase, errorCode, }) {
|
|
195
212
|
const usage = getTokenUsageFromAuditTrail() ?? undefined;
|