salmon-loop 0.2.13 → 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 +160 -24
- package/dist/cli/commands/chat.js +14 -7
- package/dist/cli/commands/flow-mode.js +63 -0
- package/dist/cli/commands/registry.js +2 -0
- package/dist/cli/commands/run/benchmark-artifacts.js +41 -0
- package/dist/cli/commands/run/early-errors.js +23 -0
- package/dist/cli/commands/run/handler.js +115 -27
- package/dist/cli/commands/run/headless-error-writer.js +8 -0
- package/dist/cli/commands/run/loop-params.js +2 -0
- package/dist/cli/commands/run/mode.js +2 -5
- package/dist/cli/commands/run/parse-options.js +16 -0
- 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/serve.js +91 -71
- 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 +30 -6
- package/dist/cli/program-bootstrap.js +8 -3
- package/dist/cli/program-commands.js +5 -1
- 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 +27 -12
- 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/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 +18 -11
- package/dist/core/config/resolve-llm.js +12 -0
- package/dist/core/config/resolvers/server.js +0 -6
- package/dist/core/config/validate.js +73 -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 +1 -0
- package/dist/core/facades/cli-command-tool-names.js +2 -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 +165 -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 -6
- 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/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 +73 -0
- 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 +2 -1
- package/dist/core/protocols/a2a/sdk/server.js +0 -1
- package/dist/core/protocols/acp/formal-agent.js +74 -51
- package/dist/core/protocols/acp/handlers.js +5 -1
- package/dist/core/protocols/acp/permission-provider.js +1 -1
- 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 +8 -0
- package/dist/core/session/manager.js +244 -8
- 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 +67 -10
- 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/languages/typescript/index.js +4 -1
- package/dist/locales/en.js +35 -2
- package/dist/utils/eol.js +1 -1
- package/package.json +13 -6
- 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,78 @@
|
|
|
1
|
+
import { augmentPromptWithRelevantMemory } from '../../llm/request-augmentation.js';
|
|
2
|
+
import { buildSharedRequestEnvelope as buildSharedRequestEnvelopeCore, } from '../../llm/shared-request-assembly.js';
|
|
3
|
+
import { formatContextForPrompt } from '../../llm/utils.js';
|
|
4
|
+
import { buildRelevantMemoryCandidates, selectRelevantMemory, } from '../../memory/relevant-retrieval.js';
|
|
5
|
+
import { resolveVisibleToolNames, } from '../../tools/tool-visibility.js';
|
|
6
|
+
import { resolveCacheSharingSurface, } from './cache-sharing.js';
|
|
7
|
+
export function buildSharedRequestEnvelope(args) {
|
|
8
|
+
return buildSharedRequestEnvelopeCore(args);
|
|
9
|
+
}
|
|
10
|
+
export async function buildAugmentedRequestEnvelope(args) {
|
|
11
|
+
const baseContextPrompt = args.baseContextPrompt ?? args.contextResult?.prompt ?? formatContextForPrompt(args.context);
|
|
12
|
+
const localContextHash = args.contextResult?.meta?.contextHash ?? args.context.contextHash;
|
|
13
|
+
const cacheSurface = resolveCacheSharingSurface({
|
|
14
|
+
phase: args.phase,
|
|
15
|
+
defaultNamespace: args.defaultNamespace,
|
|
16
|
+
localContextHash,
|
|
17
|
+
cacheSharing: args.cacheSharing,
|
|
18
|
+
mismatchPolicy: args.cacheMismatchPolicy,
|
|
19
|
+
onMismatch: args.onCacheMismatch,
|
|
20
|
+
});
|
|
21
|
+
const relevantMemory = selectRelevantMemory({
|
|
22
|
+
instruction: args.context.instruction,
|
|
23
|
+
candidates: args.relevantMemory?.entries ?? buildRelevantMemoryCandidates(args.context),
|
|
24
|
+
activeToolNames: resolveVisibleToolNames({
|
|
25
|
+
phase: args.phase,
|
|
26
|
+
toolstack: args.toolVisibility?.toolstack,
|
|
27
|
+
runtime: args.toolVisibility?.runtime,
|
|
28
|
+
worktreeRoot: args.toolVisibility?.worktreeRoot,
|
|
29
|
+
flowMode: args.toolVisibility?.flowMode,
|
|
30
|
+
}),
|
|
31
|
+
maxItems: args.relevantMemory?.maxItems,
|
|
32
|
+
alreadySurfacedText: [
|
|
33
|
+
baseContextPrompt,
|
|
34
|
+
...(Array.isArray(args.systemPrompt) ? args.systemPrompt : [args.systemPrompt]),
|
|
35
|
+
...(args.conversationContext ?? []).map((message) => message.content),
|
|
36
|
+
],
|
|
37
|
+
});
|
|
38
|
+
const contextPrompt = augmentPromptWithRelevantMemory({
|
|
39
|
+
basePrompt: baseContextPrompt,
|
|
40
|
+
selectedEntries: relevantMemory,
|
|
41
|
+
budgetTokens: args.relevantMemory?.budgetTokens,
|
|
42
|
+
countTokens: args.relevantMemory?.countTokens,
|
|
43
|
+
}).prompt;
|
|
44
|
+
const userPrompt = await args.buildUserPrompt(contextPrompt);
|
|
45
|
+
const shared = buildSharedRequestEnvelope({
|
|
46
|
+
defaultNamespace: cacheSurface.namespace,
|
|
47
|
+
contextHash: cacheSurface.contextHash,
|
|
48
|
+
systemPrompt: args.systemPrompt,
|
|
49
|
+
userPrompt,
|
|
50
|
+
conversationContext: args.conversationContext,
|
|
51
|
+
artifactHints: args.artifactHints,
|
|
52
|
+
toolCallingAudit: args.toolCallingAudit,
|
|
53
|
+
previewProvider: args.previewProvider,
|
|
54
|
+
attachments: [
|
|
55
|
+
{
|
|
56
|
+
key: 'context-prompt',
|
|
57
|
+
kind: 'context',
|
|
58
|
+
label: 'Context prompt',
|
|
59
|
+
content: contextPrompt,
|
|
60
|
+
cacheSafe: true,
|
|
61
|
+
},
|
|
62
|
+
...(args.extraAttachments ?? []),
|
|
63
|
+
],
|
|
64
|
+
providerHints: args.providerHints,
|
|
65
|
+
});
|
|
66
|
+
return {
|
|
67
|
+
contextPrompt,
|
|
68
|
+
userPrompt,
|
|
69
|
+
cacheSurface,
|
|
70
|
+
resolvedArtifactHints: shared.resolvedArtifactHints,
|
|
71
|
+
envelope: shared.envelope,
|
|
72
|
+
baseMessages: shared.baseMessages,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
export async function buildPhaseRequestEnvelope(args) {
|
|
76
|
+
return buildAugmentedRequestEnvelope(args);
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=request-assembly.js.map
|
|
@@ -1,23 +1,14 @@
|
|
|
1
1
|
import { text } from '../../../locales/index.js';
|
|
2
|
-
import {
|
|
2
|
+
import { supportsLlmStreaming } from '../../llm/capabilities.js';
|
|
3
3
|
import { emitLlmOutput } from '../../llm/output-policy.js';
|
|
4
|
-
import {
|
|
4
|
+
import { recordAuditEvent } from '../../observability/audit-trail.js';
|
|
5
|
+
import { getResearchPrompt, getResearchSystemPrompt } from '../../prompts/runtime.js';
|
|
6
|
+
import { SessionReplacementPreviewProvider } from '../../session/replacement-preview-provider.js';
|
|
5
7
|
import { chatWithTools, chatWithToolsStreaming } from '../../tools/session.js';
|
|
6
8
|
import { Phase } from '../../types/runtime.js';
|
|
7
9
|
import { resolveLlmToolCallingPolicy } from '../dsl/llm-strategy.js';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
'You are running in deep research mode.',
|
|
11
|
-
'Use available tools to gather external information as needed.',
|
|
12
|
-
'Return JSON with keys: researchNotes, researchFindings, sources, researchText.',
|
|
13
|
-
'Each researchFinding should include: summary, confidence (0-1), uncertainty (string).',
|
|
14
|
-
'Each source should include: toolName, summary, ok, timestamp (epoch ms).',
|
|
15
|
-
'',
|
|
16
|
-
`Instruction:\n${instruction}`,
|
|
17
|
-
'',
|
|
18
|
-
`Context:\n${contextText}`,
|
|
19
|
-
].join('\n');
|
|
20
|
-
}
|
|
10
|
+
import { buildPhaseRequestEnvelope } from './request-assembly.js';
|
|
11
|
+
import { buildPhaseToolRuntimeContext, buildToolVisibilityRuntime } from './tool-runtime.js';
|
|
21
12
|
function normalizeFindings(value) {
|
|
22
13
|
if (!value)
|
|
23
14
|
return [];
|
|
@@ -88,20 +79,43 @@ function buildSourcesFromAudit(entries) {
|
|
|
88
79
|
}));
|
|
89
80
|
}
|
|
90
81
|
export async function generateResearch(ctx) {
|
|
91
|
-
const
|
|
92
|
-
const
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
82
|
+
const systemPrompt = await getResearchSystemPrompt();
|
|
83
|
+
const toolVisibility = buildToolVisibilityRuntime(ctx);
|
|
84
|
+
const requestEnvelope = await buildPhaseRequestEnvelope({
|
|
85
|
+
phase: Phase.RESEARCH,
|
|
86
|
+
defaultNamespace: 'research',
|
|
87
|
+
context: ctx.context,
|
|
88
|
+
contextResult: ctx.contextResult,
|
|
89
|
+
cacheSharing: ctx.cacheSharing,
|
|
90
|
+
onCacheMismatch: (mismatch) => {
|
|
91
|
+
recordAuditEvent('request.cache_sharing_hash_mismatch', mismatch, {
|
|
92
|
+
source: 'llm',
|
|
93
|
+
severity: 'low',
|
|
94
|
+
scope: 'session',
|
|
95
|
+
phase: Phase.RESEARCH,
|
|
96
|
+
});
|
|
97
|
+
},
|
|
98
|
+
systemPrompt,
|
|
99
|
+
buildUserPrompt: async (contextText) => await getResearchPrompt(contextText, ctx.options.instruction),
|
|
97
100
|
conversationContext: ctx.options.conversationContext,
|
|
101
|
+
artifactHints: ctx.artifactHints,
|
|
102
|
+
toolCallingAudit: ctx.toolCallingAudit,
|
|
103
|
+
previewProvider: new SessionReplacementPreviewProvider(ctx.replacementState),
|
|
104
|
+
toolVisibility: {
|
|
105
|
+
toolstack: ctx.toolstack,
|
|
106
|
+
runtime: toolVisibility,
|
|
107
|
+
worktreeRoot: ctx.workspace.strategy === 'worktree' ? ctx.workspace.workPath : undefined,
|
|
108
|
+
flowMode: ctx.mode,
|
|
109
|
+
},
|
|
98
110
|
});
|
|
111
|
+
const { cacheSurface, envelope, baseMessages } = requestEnvelope;
|
|
99
112
|
const toolPolicy = resolveLlmToolCallingPolicy(Phase.RESEARCH, ctx.options.llm);
|
|
100
|
-
const supportsStreaming =
|
|
113
|
+
const supportsStreaming = supportsLlmStreaming(ctx.options.llm, Phase.RESEARCH);
|
|
101
114
|
const localAudit = [];
|
|
102
115
|
const sourcesFromAudit = () => buildSourcesFromAudit(localAudit);
|
|
103
116
|
if (!ctx.toolstack || !toolPolicy.enabled) {
|
|
104
117
|
const response = await ctx.options.llm.chat(baseMessages, {
|
|
118
|
+
providerHints: envelope.providerHints,
|
|
105
119
|
signal: ctx.options.signal,
|
|
106
120
|
phase: Phase.RESEARCH,
|
|
107
121
|
});
|
|
@@ -133,22 +147,11 @@ export async function generateResearch(ctx) {
|
|
|
133
147
|
kind: 'research',
|
|
134
148
|
step: 'RESEARCH',
|
|
135
149
|
};
|
|
136
|
-
const response = await (supportsStreaming ? chatWithToolsStreaming : chatWithTools)(baseMessages, { signal: ctx.options.signal }, {
|
|
150
|
+
const response = await (supportsStreaming ? chatWithToolsStreaming : chatWithTools)(baseMessages, { providerHints: envelope.providerHints, signal: ctx.options.signal }, {
|
|
137
151
|
phase: Phase.RESEARCH,
|
|
138
152
|
llm: ctx.options.llm,
|
|
139
|
-
runtime:
|
|
140
|
-
|
|
141
|
-
persistenceRoot: ctx.workspace.baseRepoPath || ctx.workspace.workPath,
|
|
142
|
-
worktreeRoot: ctx.workspace.strategy === 'worktree' ? ctx.workspace.workPath : undefined,
|
|
143
|
-
attemptId: ctx.attempt ?? 1,
|
|
144
|
-
dryRun: Boolean(ctx.options?.dryRun),
|
|
145
|
-
llm: ctx.options.llm,
|
|
146
|
-
model: ctx.options.llm.getModelId?.() || process.env.SALMONLOOP_MODEL || process.env.S8P_MODEL,
|
|
147
|
-
userInputProvider: ctx.options.userInputProvider,
|
|
148
|
-
agentKind: ctx.options.agentKind ?? 'primary',
|
|
149
|
-
languagePlugins: ctx.options.languagePlugins,
|
|
150
|
-
subAgentController: ctx.options.subAgentController,
|
|
151
|
-
},
|
|
153
|
+
runtime: buildPhaseToolRuntimeContext(ctx, Phase.RESEARCH, cacheSurface),
|
|
154
|
+
toolVisibility,
|
|
152
155
|
toolstack: ctx.toolstack,
|
|
153
156
|
eventPayload: ctx.options.eventPayload,
|
|
154
157
|
toolCallingAudit: {
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { buildSystemPrefixDigest, buildToolSchemaHash, } from '../../sub-agent/prefix-consistency.js';
|
|
2
|
+
export function buildPhaseToolRuntimeContext(ctx, phase, cacheSurface) {
|
|
3
|
+
return {
|
|
4
|
+
repoRoot: ctx.workspace.workPath,
|
|
5
|
+
persistenceRoot: ctx.workspace.baseRepoPath || ctx.workspace.workPath,
|
|
6
|
+
worktreeRoot: ctx.workspace.strategy === 'worktree' ? ctx.workspace.workPath : undefined,
|
|
7
|
+
flowMode: ctx.mode,
|
|
8
|
+
attemptId: ctx.attempt ?? 1,
|
|
9
|
+
dryRun: Boolean(ctx.options?.dryRun),
|
|
10
|
+
llm: ctx.options.llm,
|
|
11
|
+
model: ctx.options.llm.getModelId?.() || process.env.SALMONLOOP_MODEL || process.env.S8P_MODEL,
|
|
12
|
+
userInputProvider: ctx.options.userInputProvider,
|
|
13
|
+
agentKind: ctx.options.agentKind ?? 'primary',
|
|
14
|
+
languagePlugins: ctx.options.languagePlugins,
|
|
15
|
+
subAgentController: ctx.options.subAgentController,
|
|
16
|
+
phase,
|
|
17
|
+
contextSnapshot: {
|
|
18
|
+
conversationContext: ctx.options.conversationContext,
|
|
19
|
+
artifactHints: ctx.artifactHints,
|
|
20
|
+
toolCallingAudit: ctx.toolCallingAudit,
|
|
21
|
+
replacementState: ctx.replacementState,
|
|
22
|
+
planRuntime: ctx.planRuntime,
|
|
23
|
+
cacheSharing: {
|
|
24
|
+
namespace: cacheSurface.namespace,
|
|
25
|
+
contextHash: cacheSurface.contextHash,
|
|
26
|
+
toolSchemaHash: buildToolSchemaHash({
|
|
27
|
+
phase,
|
|
28
|
+
allowedToolNames: ctx.options.allowedToolNames,
|
|
29
|
+
}),
|
|
30
|
+
systemPrefixDigest: buildSystemPrefixDigest({
|
|
31
|
+
phase,
|
|
32
|
+
namespace: cacheSurface.namespace,
|
|
33
|
+
contextHash: cacheSurface.contextHash,
|
|
34
|
+
}),
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export function buildToolVisibilityRuntime(ctx) {
|
|
40
|
+
if (!ctx.planRuntime) {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
plan: ctx.planRuntime,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=tool-runtime.js.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ArtifactStore } from '../../sub-agent/artifacts/store.js';
|
|
2
|
+
import { runVerify as runVerifyCommand } from '../../verification/runner.js';
|
|
3
|
+
export async function executeVerifyForWorkspace(params) {
|
|
4
|
+
const verifyResult = await runVerifyCommand(params.workspacePath, params.verify, undefined, params.signal);
|
|
5
|
+
let verifyArtifact;
|
|
6
|
+
if (!verifyResult.ok && verifyResult.output) {
|
|
7
|
+
try {
|
|
8
|
+
verifyArtifact = await ArtifactStore.saveText({
|
|
9
|
+
content: verifyResult.output,
|
|
10
|
+
mimeType: 'text/plain',
|
|
11
|
+
fileExt: 'log',
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
// Best-effort only; keep verifyResult.output in-memory for shrink/error classification.
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
verifyResult,
|
|
20
|
+
...(verifyArtifact ? { verifyArtifact } : {}),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=verify-shared.js.map
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { text } from '../../../locales/index.js';
|
|
2
2
|
import { collectBudgetMetrics, evaluateBudgetAlert, getGlobalAdjuster, recordBudgetAlert, } from '../../context/budget/integration.js';
|
|
3
3
|
import { recordAuditEvent } from '../../observability/audit-trail.js';
|
|
4
|
-
import {
|
|
5
|
-
import { runVerify as runVerifyCommand } from '../../verification/runner.js';
|
|
4
|
+
import { executeVerifyForWorkspace } from './verify-shared.js';
|
|
6
5
|
function extractCommandProgram(command) {
|
|
7
6
|
const trimmed = command.trim();
|
|
8
7
|
if (!trimmed)
|
|
@@ -16,8 +15,11 @@ export const runVerify = async (ctx) => {
|
|
|
16
15
|
verifyResult: { ok: true, output: text.loop.verificationSkipped, exitCode: null },
|
|
17
16
|
};
|
|
18
17
|
}
|
|
19
|
-
const verifyResult = await
|
|
20
|
-
|
|
18
|
+
const { verifyResult, verifyArtifact } = await executeVerifyForWorkspace({
|
|
19
|
+
workspacePath: ctx.workspace.workPath,
|
|
20
|
+
verify: ctx.options.verify,
|
|
21
|
+
signal: ctx.options.signal,
|
|
22
|
+
});
|
|
21
23
|
recordAuditEvent('verify.summary', {
|
|
22
24
|
ok: verifyResult.ok,
|
|
23
25
|
exitCode: verifyResult.exitCode,
|
|
@@ -92,23 +94,13 @@ export const runVerify = async (ctx) => {
|
|
|
92
94
|
message: text.loop.verificationFailedSummary,
|
|
93
95
|
timestamp: new Date(),
|
|
94
96
|
});
|
|
95
|
-
if (
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
ctx.emit({
|
|
103
|
-
type: 'log',
|
|
104
|
-
level: 'debug',
|
|
105
|
-
message: text.loop.verificationOutputStored(verifyArtifact.handle),
|
|
106
|
-
timestamp: new Date(),
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
catch {
|
|
110
|
-
// Best-effort only; keep verifyResult.output in-memory for shrink/error classification.
|
|
111
|
-
}
|
|
97
|
+
if (verifyArtifact) {
|
|
98
|
+
ctx.emit({
|
|
99
|
+
type: 'log',
|
|
100
|
+
level: 'debug',
|
|
101
|
+
message: text.loop.verificationOutputStored(verifyArtifact.handle),
|
|
102
|
+
timestamp: new Date(),
|
|
103
|
+
});
|
|
112
104
|
}
|
|
113
105
|
// We don't throw here, because we want to trigger rollback/shrink in the pipeline
|
|
114
106
|
// But wait, the Pipeline abstraction propagates errors immediately.
|
|
@@ -34,6 +34,7 @@ export async function executeAiSdkChatRequest(input) {
|
|
|
34
34
|
options: input.options,
|
|
35
35
|
headers: attemptCtx.langfuseHeaders,
|
|
36
36
|
abortSignal: attemptCtx.abortSignal,
|
|
37
|
+
providerOptionsKey: input.providerOptionsKey,
|
|
37
38
|
}));
|
|
38
39
|
const usage = extractUsageFromAiSdkResult(result);
|
|
39
40
|
if (usage) {
|
|
@@ -74,6 +75,7 @@ export async function* executeAiSdkChatStreamRequest(input) {
|
|
|
74
75
|
options: input.options,
|
|
75
76
|
headers: attemptCtx.langfuseHeaders,
|
|
76
77
|
abortSignal: attemptCtx.abortSignal,
|
|
78
|
+
providerOptionsKey: input.providerOptionsKey,
|
|
77
79
|
}));
|
|
78
80
|
yield* mapAiSdkStreamResultToChunks(result.fullStream);
|
|
79
81
|
},
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { LIMITS } from '../../config/limits.js';
|
|
2
|
+
import { getPatchPrompt, getPlanPrompt } from '../../prompts/runtime.js';
|
|
3
|
+
import { wrapPlanEmpty, sanitizeError, LlmError } from '../errors.js';
|
|
4
|
+
import { extractUnifiedDiffFromLLMContent, parsePlanFromLLMContent } from '../utils.js';
|
|
5
|
+
export const HIGH_LEVEL_PHASE_NAMES = [
|
|
6
|
+
'plan',
|
|
7
|
+
'patch',
|
|
8
|
+
];
|
|
9
|
+
function buildContextPromptAttachment(contextPrompt) {
|
|
10
|
+
return {
|
|
11
|
+
key: 'context-prompt',
|
|
12
|
+
kind: 'context',
|
|
13
|
+
label: 'Context prompt',
|
|
14
|
+
content: contextPrompt,
|
|
15
|
+
cacheSafe: true,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function buildPatchAttachments(contextPrompt, planStr) {
|
|
19
|
+
return [
|
|
20
|
+
buildContextPromptAttachment(contextPrompt),
|
|
21
|
+
{
|
|
22
|
+
key: 'plan-json',
|
|
23
|
+
kind: 'plan',
|
|
24
|
+
label: 'Plan JSON',
|
|
25
|
+
content: planStr,
|
|
26
|
+
},
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
function parsePlanResult(content) {
|
|
30
|
+
if (!content) {
|
|
31
|
+
throw wrapPlanEmpty();
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
return parsePlanFromLLMContent(content);
|
|
35
|
+
}
|
|
36
|
+
catch (e) {
|
|
37
|
+
throw new LlmError('LLM plan parsing failed', 'LLM_PLAN_INVALID_JSON', {
|
|
38
|
+
causeMessage: sanitizeError(e),
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function parsePatchResult(content) {
|
|
43
|
+
return extractUnifiedDiffFromLLMContent(content ?? '');
|
|
44
|
+
}
|
|
45
|
+
export const HIGH_LEVEL_PHASE_SPECS = {
|
|
46
|
+
plan: {
|
|
47
|
+
name: 'plan',
|
|
48
|
+
namespace: 'plan',
|
|
49
|
+
observationName: 'PLAN:plan-json',
|
|
50
|
+
buildPrompt: async ({ contextPrompt, instruction, lastError }) => getPlanPrompt(contextPrompt, instruction, LIMITS.maxFilesChanged, lastError),
|
|
51
|
+
buildAttachments: ({ contextPrompt }) => [buildContextPromptAttachment(contextPrompt)],
|
|
52
|
+
parseResult: (content) => parsePlanResult(content),
|
|
53
|
+
},
|
|
54
|
+
patch: {
|
|
55
|
+
name: 'patch',
|
|
56
|
+
namespace: 'patch',
|
|
57
|
+
observationName: 'PATCH:unified-diff',
|
|
58
|
+
buildPrompt: async ({ planStr, contextPrompt, lastError }) => getPatchPrompt(planStr, contextPrompt, LIMITS.maxFilesChanged, LIMITS.maxDiffLines, lastError),
|
|
59
|
+
buildAttachments: ({ contextPrompt, planStr }) => buildPatchAttachments(contextPrompt, planStr),
|
|
60
|
+
parseResult: (content) => parsePatchResult(content),
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
//# sourceMappingURL=high-level-phase-specs.js.map
|
|
@@ -129,12 +129,32 @@ export function toAiSdkMessages(messages) {
|
|
|
129
129
|
],
|
|
130
130
|
};
|
|
131
131
|
}
|
|
132
|
-
if (m.role === 'assistant'
|
|
132
|
+
if (m.role === 'assistant') {
|
|
133
|
+
const hasToolCalls = Array.isArray(m.tool_calls) && m.tool_calls.length > 0;
|
|
134
|
+
const reasoningContent = typeof m.reasoning_content === 'string' && m.reasoning_content.length > 0
|
|
135
|
+
? m.reasoning_content
|
|
136
|
+
: undefined;
|
|
137
|
+
if (!hasToolCalls && !reasoningContent) {
|
|
138
|
+
let content = m.content;
|
|
139
|
+
if (content === undefined || content === null) {
|
|
140
|
+
content = '';
|
|
141
|
+
}
|
|
142
|
+
if (typeof content !== 'string') {
|
|
143
|
+
content = JSON.stringify(content);
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
role: m.role,
|
|
147
|
+
content: content,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
133
150
|
const parts = [];
|
|
151
|
+
if (reasoningContent) {
|
|
152
|
+
parts.push({ type: 'reasoning', text: reasoningContent });
|
|
153
|
+
}
|
|
134
154
|
if (m.content && typeof m.content === 'string') {
|
|
135
155
|
parts.push({ type: 'text', text: m.content });
|
|
136
156
|
}
|
|
137
|
-
for (const call of m.tool_calls) {
|
|
157
|
+
for (const call of hasToolCalls ? m.tool_calls || [] : []) {
|
|
138
158
|
const toolCallId = call?.id || 'unknown';
|
|
139
159
|
const toolName = call?.function?.name || call?.name || 'unknown';
|
|
140
160
|
const rawArgs = call?.function?.arguments;
|
|
@@ -143,11 +163,15 @@ export function toAiSdkMessages(messages) {
|
|
|
143
163
|
? safeParseJsonObject(rawArgs)
|
|
144
164
|
: {}
|
|
145
165
|
: (call?.input ?? call?.args ?? {});
|
|
166
|
+
const providerOptions = isObjectRecord(call?.providerMetadata)
|
|
167
|
+
? deepCloneJson(call.providerMetadata, {})
|
|
168
|
+
: undefined;
|
|
146
169
|
parts.push({
|
|
147
170
|
type: 'tool-call',
|
|
148
171
|
toolCallId,
|
|
149
172
|
toolName,
|
|
150
173
|
input: deepCloneJson(input, {}),
|
|
174
|
+
...(providerOptions ? { providerOptions } : {}),
|
|
151
175
|
});
|
|
152
176
|
}
|
|
153
177
|
return {
|
|
@@ -228,13 +252,19 @@ export function toOpenAiToolCalls(toolCalls) {
|
|
|
228
252
|
return raw;
|
|
229
253
|
}
|
|
230
254
|
};
|
|
231
|
-
return toolCalls.map((c) =>
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
255
|
+
return toolCalls.map((c) => {
|
|
256
|
+
const providerMetadata = isObjectRecord(c?.providerMetadata)
|
|
257
|
+
? deepCloneJson(c.providerMetadata, {})
|
|
258
|
+
: undefined;
|
|
259
|
+
return {
|
|
260
|
+
id: c?.toolCallId || c?.id || 'unknown',
|
|
261
|
+
type: 'function',
|
|
262
|
+
function: {
|
|
263
|
+
name: c?.toolName || c?.name || 'unknown',
|
|
264
|
+
arguments: JSON.stringify(normalizeToolInput(c?.input ?? c?.args ?? {})),
|
|
265
|
+
},
|
|
266
|
+
...(providerMetadata ? { providerMetadata } : {}),
|
|
267
|
+
};
|
|
268
|
+
});
|
|
239
269
|
}
|
|
240
270
|
//# sourceMappingURL=message-mapper.js.map
|
|
@@ -1,9 +1,23 @@
|
|
|
1
1
|
import { createOpenAI } from '@ai-sdk/openai';
|
|
2
2
|
import { createOpenAICompatible } from '@ai-sdk/openai-compatible';
|
|
3
3
|
import { resolveBaseUrl } from '../base-url.js';
|
|
4
|
+
function toProviderOptionsKey(value) {
|
|
5
|
+
const normalized = value.trim();
|
|
6
|
+
if (!normalized)
|
|
7
|
+
return 'openaiCompatible';
|
|
8
|
+
return normalized
|
|
9
|
+
.replace(/[-_\s]+(.)?/g, (_, char) => (char ? char.toUpperCase() : ''))
|
|
10
|
+
.replace(/^[A-Z]/, (char) => char.toLowerCase());
|
|
11
|
+
}
|
|
4
12
|
export function resolveAiSdkModelId(modelId) {
|
|
5
13
|
return modelId || process.env.SALMONLOOP_MODEL || process.env.S8P_MODEL || 'gpt-4o';
|
|
6
14
|
}
|
|
15
|
+
export function resolveAiSdkProviderOptionsKey(cfg) {
|
|
16
|
+
if (cfg.clientPackage === '@ai-sdk/openai') {
|
|
17
|
+
return 'openai';
|
|
18
|
+
}
|
|
19
|
+
return toProviderOptionsKey(cfg.providerName || 'openaiCompatible');
|
|
20
|
+
}
|
|
7
21
|
export function createAiSdkChatModel(cfg, modelId) {
|
|
8
22
|
if (cfg.clientPackage === '@ai-sdk/openai') {
|
|
9
23
|
const provider = createOpenAI({
|
|
@@ -1,3 +1,70 @@
|
|
|
1
|
+
function isRecord(value) {
|
|
2
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
3
|
+
}
|
|
4
|
+
function isJsonValue(value) {
|
|
5
|
+
if (value === null ||
|
|
6
|
+
typeof value === 'string' ||
|
|
7
|
+
typeof value === 'number' ||
|
|
8
|
+
typeof value === 'boolean') {
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
if (Array.isArray(value)) {
|
|
12
|
+
return value.every((item) => isJsonValue(item));
|
|
13
|
+
}
|
|
14
|
+
if (!isRecord(value)) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
return Object.values(value).every((item) => isJsonValue(item));
|
|
18
|
+
}
|
|
19
|
+
function toJsonObject(value) {
|
|
20
|
+
if (!isRecord(value))
|
|
21
|
+
return undefined;
|
|
22
|
+
const out = {};
|
|
23
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
24
|
+
if (!isJsonValue(entry))
|
|
25
|
+
return undefined;
|
|
26
|
+
out[key] = entry;
|
|
27
|
+
}
|
|
28
|
+
return out;
|
|
29
|
+
}
|
|
30
|
+
function buildOpenAICacheHintFromPolicy(policy) {
|
|
31
|
+
if (!policy || policy.eligibility !== 'eligible')
|
|
32
|
+
return undefined;
|
|
33
|
+
if (!policy.contextHash || !policy.cacheSafeFingerprint)
|
|
34
|
+
return undefined;
|
|
35
|
+
const namespace = typeof policy.namespace === 'string' && policy.namespace.trim()
|
|
36
|
+
? policy.namespace
|
|
37
|
+
: 'request-envelope';
|
|
38
|
+
const components = [policy.contextHash, `stable:${policy.cacheSafeFingerprint}`];
|
|
39
|
+
if (policy.mode === 'strict_full_prompt' && policy.lateInjectionFingerprint) {
|
|
40
|
+
components.push(`late:${policy.lateInjectionFingerprint}`);
|
|
41
|
+
}
|
|
42
|
+
return `cache:${JSON.stringify({ namespace, components })}`;
|
|
43
|
+
}
|
|
44
|
+
function mergeProviderOptions(params) {
|
|
45
|
+
const merged = isRecord(params.providerOptions)
|
|
46
|
+
? { ...params.providerOptions }
|
|
47
|
+
: {};
|
|
48
|
+
const cacheHint = params.providerHints?.openAICacheHint ??
|
|
49
|
+
buildOpenAICacheHintFromPolicy(params.providerHints?.openAICachePolicy);
|
|
50
|
+
if (cacheHint) {
|
|
51
|
+
const existing = toJsonObject(merged[params.providerOptionsKey]) ?? {};
|
|
52
|
+
if (typeof existing.user !== 'string' || !existing.user.trim()) {
|
|
53
|
+
existing.user = cacheHint;
|
|
54
|
+
}
|
|
55
|
+
merged[params.providerOptionsKey] = existing;
|
|
56
|
+
}
|
|
57
|
+
return Object.keys(merged).length > 0 ? merged : undefined;
|
|
58
|
+
}
|
|
59
|
+
function resolveResponseFormat(options) {
|
|
60
|
+
if (options.responseFormat === 'json_object') {
|
|
61
|
+
return options.responseFormatJsonObjectSupported === false ? undefined : { type: 'json' };
|
|
62
|
+
}
|
|
63
|
+
if (options.responseFormat === 'text') {
|
|
64
|
+
return { type: 'text' };
|
|
65
|
+
}
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
1
68
|
export function buildAiSdkRequestParams(params) {
|
|
2
69
|
return {
|
|
3
70
|
model: params.model,
|
|
@@ -6,11 +73,17 @@ export function buildAiSdkRequestParams(params) {
|
|
|
6
73
|
temperature: params.options.temperature,
|
|
7
74
|
maxOutputTokens: params.options.maxTokens != null ? Number(params.options.maxTokens) : undefined,
|
|
8
75
|
stopSequences: params.options.stop,
|
|
76
|
+
responseFormat: resolveResponseFormat(params.options),
|
|
9
77
|
toolChoice: (params.options.toolChoice === 'none'
|
|
10
78
|
? 'none'
|
|
11
79
|
: params.tools
|
|
12
80
|
? 'auto'
|
|
13
81
|
: undefined),
|
|
82
|
+
providerOptions: mergeProviderOptions({
|
|
83
|
+
providerOptions: params.options.providerOptions,
|
|
84
|
+
providerHints: params.options.providerHints,
|
|
85
|
+
providerOptionsKey: params.providerOptionsKey,
|
|
86
|
+
}),
|
|
14
87
|
headers: params.headers,
|
|
15
88
|
abortSignal: params.abortSignal,
|
|
16
89
|
};
|
|
@@ -1,9 +1,25 @@
|
|
|
1
1
|
import { mapAiSdkStreamPartToChunk } from '../stream-utils.js';
|
|
2
2
|
import { toOpenAiToolCalls } from './message-mapper.js';
|
|
3
|
+
function extractReasoningContent(result) {
|
|
4
|
+
if (typeof result?.reasoningText === 'string' && result.reasoningText.length > 0) {
|
|
5
|
+
return result.reasoningText;
|
|
6
|
+
}
|
|
7
|
+
const reasoningParts = Array.isArray(result?.reasoning)
|
|
8
|
+
? result.reasoning
|
|
9
|
+
: Array.isArray(result?.content)
|
|
10
|
+
? result.content.filter((part) => part?.type === 'reasoning')
|
|
11
|
+
: [];
|
|
12
|
+
const text = reasoningParts
|
|
13
|
+
.map((part) => (typeof part?.text === 'string' ? part.text : ''))
|
|
14
|
+
.join('');
|
|
15
|
+
return text.length > 0 ? text : undefined;
|
|
16
|
+
}
|
|
3
17
|
export function mapAiSdkGenerateResultToMessage(result) {
|
|
18
|
+
const reasoningContent = extractReasoningContent(result);
|
|
4
19
|
return {
|
|
5
20
|
role: 'assistant',
|
|
6
21
|
content: result?.text || '',
|
|
22
|
+
...(reasoningContent ? { reasoning_content: reasoningContent } : {}),
|
|
7
23
|
tool_calls: toOpenAiToolCalls(result?.toolCalls),
|
|
8
24
|
};
|
|
9
25
|
}
|