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
|
@@ -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,16 +1,89 @@
|
|
|
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,
|
|
4
71
|
messages: params.messages,
|
|
5
72
|
tools: params.tools,
|
|
6
73
|
temperature: params.options.temperature,
|
|
7
|
-
maxOutputTokens: params.options.maxTokens,
|
|
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
|
}
|
package/dist/core/llm/ai-sdk.js
CHANGED
|
@@ -1,59 +1,101 @@
|
|
|
1
1
|
import { randomUUID } from 'crypto';
|
|
2
|
-
import { LIMITS } from '../config/limits.js';
|
|
3
|
-
import { getPatchPrompt, getPlanPrompt } from '../prompts/runtime.js';
|
|
4
2
|
import { executeAiSdkChatRequest, executeAiSdkChatStreamRequest } from './ai-sdk/chat-executor.js';
|
|
3
|
+
import { HIGH_LEVEL_PHASE_SPECS, } from './ai-sdk/high-level-phase-specs.js';
|
|
5
4
|
import { toAiSdkMessages, toAiSdkToolSet } from './ai-sdk/message-mapper.js';
|
|
6
5
|
import { withAuditObservationName } from './ai-sdk/observation-context.js';
|
|
7
|
-
import { createAiSdkChatModel, resolveAiSdkModelId } from './ai-sdk/provider-factory.js';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
6
|
+
import { createAiSdkChatModel, resolveAiSdkModelId, resolveAiSdkProviderOptionsKey, } from './ai-sdk/provider-factory.js';
|
|
7
|
+
import { repairToJsonObject } from './contracts/repair.js';
|
|
8
|
+
import { buildSharedRequestEnvelope } from './shared-request-assembly.js';
|
|
9
|
+
import { formatContextForPrompt } from './utils.js';
|
|
10
10
|
export class AiSdkLLM {
|
|
11
11
|
cfg;
|
|
12
12
|
model;
|
|
13
13
|
modelId;
|
|
14
|
+
providerOptionsKey;
|
|
14
15
|
timeoutMs;
|
|
15
16
|
constructor(cfg) {
|
|
16
17
|
this.cfg = cfg;
|
|
17
18
|
this.modelId = resolveAiSdkModelId(cfg.modelId);
|
|
19
|
+
this.providerOptionsKey = resolveAiSdkProviderOptionsKey(cfg);
|
|
18
20
|
this.timeoutMs = cfg.timeoutMs;
|
|
19
21
|
this.model = createAiSdkChatModel(cfg, this.modelId);
|
|
20
22
|
}
|
|
21
23
|
getModelId() {
|
|
22
24
|
return this.modelId;
|
|
23
25
|
}
|
|
24
|
-
getCapabilities() {
|
|
26
|
+
getCapabilities(_options) {
|
|
25
27
|
return {
|
|
26
28
|
toolCalling: true,
|
|
27
29
|
responseFormatJsonObject: true,
|
|
28
30
|
streaming: true,
|
|
31
|
+
...this.cfg.capabilities,
|
|
29
32
|
};
|
|
30
33
|
}
|
|
34
|
+
applyCapabilityOptions(options = {}) {
|
|
35
|
+
const capabilities = this.getCapabilities({ phase: options.phase });
|
|
36
|
+
const requestOptions = {
|
|
37
|
+
...options,
|
|
38
|
+
responseFormatJsonObjectSupported: capabilities.responseFormatJsonObject !== false,
|
|
39
|
+
};
|
|
40
|
+
if (capabilities.toolCalling === false) {
|
|
41
|
+
requestOptions.tools = undefined;
|
|
42
|
+
requestOptions.toolSpecs = undefined;
|
|
43
|
+
requestOptions.toolChoice = 'none';
|
|
44
|
+
}
|
|
45
|
+
return requestOptions;
|
|
46
|
+
}
|
|
47
|
+
async *chatStreamFromChat(messages, options = {}) {
|
|
48
|
+
const response = await this.chat(messages, options);
|
|
49
|
+
if (response.reasoning_content) {
|
|
50
|
+
yield {
|
|
51
|
+
role: 'assistant',
|
|
52
|
+
source: 'synthesized',
|
|
53
|
+
reasoningDelta: response.reasoning_content,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
if (response.content) {
|
|
57
|
+
yield { role: 'assistant', source: 'synthesized', contentDelta: response.content };
|
|
58
|
+
}
|
|
59
|
+
if (Array.isArray(response.tool_calls) && response.tool_calls.length > 0) {
|
|
60
|
+
yield { role: 'assistant', source: 'synthesized', tool_calls: response.tool_calls };
|
|
61
|
+
}
|
|
62
|
+
yield { role: 'assistant', source: 'synthesized', done: true, finishReason: 'stop' };
|
|
63
|
+
}
|
|
31
64
|
async chat(messages, options = {}) {
|
|
32
65
|
const aiMessages = toAiSdkMessages(messages);
|
|
33
|
-
const
|
|
66
|
+
const requestOptions = this.applyCapabilityOptions(options);
|
|
67
|
+
const tools = toAiSdkToolSet(requestOptions.tools, requestOptions.toolSpecs);
|
|
34
68
|
return executeAiSdkChatRequest({
|
|
35
69
|
model: this.model,
|
|
36
70
|
modelId: this.modelId,
|
|
71
|
+
providerOptionsKey: this.providerOptionsKey,
|
|
37
72
|
timeoutMs: this.timeoutMs,
|
|
38
73
|
langfuseEnabled: Boolean(this.cfg.langfuseEnabled),
|
|
39
74
|
requestId: randomUUID(),
|
|
40
75
|
messages: aiMessages,
|
|
41
76
|
tools,
|
|
42
|
-
options,
|
|
77
|
+
options: requestOptions,
|
|
43
78
|
});
|
|
44
79
|
}
|
|
45
80
|
async *chatStream(messages, options = {}) {
|
|
81
|
+
const requestOptions = this.applyCapabilityOptions(options);
|
|
82
|
+
const capabilities = this.getCapabilities({ phase: requestOptions.phase });
|
|
83
|
+
if (capabilities.streaming === false) {
|
|
84
|
+
yield* this.chatStreamFromChat(messages, requestOptions);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
46
87
|
const aiMessages = toAiSdkMessages(messages);
|
|
47
|
-
const tools = toAiSdkToolSet(
|
|
88
|
+
const tools = toAiSdkToolSet(requestOptions.tools, requestOptions.toolSpecs);
|
|
48
89
|
yield* executeAiSdkChatStreamRequest({
|
|
49
90
|
model: this.model,
|
|
50
91
|
modelId: this.modelId,
|
|
92
|
+
providerOptionsKey: this.providerOptionsKey,
|
|
51
93
|
timeoutMs: this.timeoutMs,
|
|
52
94
|
langfuseEnabled: Boolean(this.cfg.langfuseEnabled),
|
|
53
95
|
requestId: randomUUID(),
|
|
54
96
|
messages: aiMessages,
|
|
55
97
|
tools,
|
|
56
|
-
options,
|
|
98
|
+
options: requestOptions,
|
|
57
99
|
});
|
|
58
100
|
}
|
|
59
101
|
/**
|
|
@@ -66,27 +108,70 @@ export class AiSdkLLM {
|
|
|
66
108
|
yield* this.chatStream(messages, options);
|
|
67
109
|
}
|
|
68
110
|
async createPlan(context, instruction, lastError, signal) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
111
|
+
return this.runHighLevelPhase(HIGH_LEVEL_PHASE_SPECS.plan, {
|
|
112
|
+
context,
|
|
113
|
+
instruction,
|
|
114
|
+
lastError,
|
|
115
|
+
signal,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
async createPatch(context, plan, lastError, signal) {
|
|
119
|
+
const planStr = JSON.stringify(plan, null, 2);
|
|
120
|
+
return this.runHighLevelPhase(HIGH_LEVEL_PHASE_SPECS.patch, {
|
|
121
|
+
context,
|
|
122
|
+
planStr,
|
|
123
|
+
lastError,
|
|
124
|
+
signal,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
async runHighLevelPhase(spec, input) {
|
|
128
|
+
const contextPrompt = formatContextForPrompt(input.context);
|
|
129
|
+
const userPrompt = await spec.buildPrompt({ ...input, contextPrompt });
|
|
130
|
+
const attachments = spec.buildAttachments({ ...input, contextPrompt });
|
|
131
|
+
const content = await this.executeHighLevelPrompt({
|
|
132
|
+
phase: spec.name,
|
|
133
|
+
defaultNamespace: spec.namespace,
|
|
134
|
+
contextHash: input.context.contextHash,
|
|
135
|
+
userPrompt,
|
|
136
|
+
attachments,
|
|
137
|
+
observationName: spec.observationName,
|
|
138
|
+
signal: input.signal,
|
|
139
|
+
});
|
|
140
|
+
return spec.parseResult(content);
|
|
141
|
+
}
|
|
142
|
+
async executeHighLevelPrompt(params) {
|
|
143
|
+
const sharedEnvelope = buildSharedRequestEnvelope({
|
|
144
|
+
defaultNamespace: params.defaultNamespace,
|
|
145
|
+
contextHash: params.contextHash,
|
|
146
|
+
systemPrompt: '',
|
|
147
|
+
userPrompt: params.userPrompt,
|
|
148
|
+
attachments: params.attachments,
|
|
149
|
+
});
|
|
150
|
+
const response = await withAuditObservationName(params.observationName, async () => this.chat(sharedEnvelope.baseMessages, {
|
|
151
|
+
providerHints: sharedEnvelope.envelope.providerHints,
|
|
152
|
+
responseFormat: params.phase === 'plan' ? 'json_object' : undefined,
|
|
153
|
+
signal: params.signal,
|
|
154
|
+
}));
|
|
155
|
+
if (params.phase !== 'plan') {
|
|
156
|
+
return response.content;
|
|
74
157
|
}
|
|
75
158
|
try {
|
|
76
|
-
|
|
159
|
+
HIGH_LEVEL_PHASE_SPECS.plan.parseResult(response.content);
|
|
160
|
+
return response.content;
|
|
77
161
|
}
|
|
78
|
-
catch (
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
162
|
+
catch (error) {
|
|
163
|
+
const repair = await withAuditObservationName('PLAN:plan-json-repair', async () => repairToJsonObject({
|
|
164
|
+
llm: this,
|
|
165
|
+
baseMessages: sharedEnvelope.baseMessages,
|
|
166
|
+
chatOptions: {
|
|
167
|
+
providerHints: sharedEnvelope.envelope.providerHints,
|
|
168
|
+
signal: params.signal,
|
|
169
|
+
},
|
|
170
|
+
badContent: response.content ?? '',
|
|
171
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
172
|
+
}));
|
|
173
|
+
return repair.content;
|
|
82
174
|
}
|
|
83
175
|
}
|
|
84
|
-
async createPatch(context, plan, lastError, signal) {
|
|
85
|
-
const planStr = JSON.stringify(plan, null, 2);
|
|
86
|
-
const formattedContext = formatContextForPrompt(context);
|
|
87
|
-
const prompt = await getPatchPrompt(planStr, formattedContext, LIMITS.maxFilesChanged, LIMITS.maxDiffLines, lastError);
|
|
88
|
-
const response = await withAuditObservationName('PATCH:unified-diff', async () => this.chat([{ role: 'user', content: prompt }], { signal }));
|
|
89
|
-
return extractUnifiedDiffFromLLMContent(response.content || '');
|
|
90
|
-
}
|
|
91
176
|
}
|
|
92
177
|
//# sourceMappingURL=ai-sdk.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function resolveLlmCapabilities(llm, phase) {
|
|
2
|
+
return llm.getCapabilities?.({ phase }) ?? {};
|
|
3
|
+
}
|
|
4
|
+
export function supportsLlmStreaming(llm, phase) {
|
|
5
|
+
const capabilities = resolveLlmCapabilities(llm, phase);
|
|
6
|
+
if (capabilities.streaming === false)
|
|
7
|
+
return false;
|
|
8
|
+
if (capabilities.streaming === true)
|
|
9
|
+
return typeof llm.chatStream === 'function';
|
|
10
|
+
return typeof llm.chatStream === 'function';
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=capabilities.js.map
|
|
@@ -13,10 +13,11 @@ export async function repairToJsonObject(args) {
|
|
|
13
13
|
'Your previous response did not satisfy the contract.',
|
|
14
14
|
`Reason: ${reason}`,
|
|
15
15
|
'',
|
|
16
|
-
'Return
|
|
17
|
-
'-
|
|
18
|
-
'-
|
|
19
|
-
'
|
|
16
|
+
'Return exactly one JSON object and nothing else.',
|
|
17
|
+
'The first non-whitespace character must be {.',
|
|
18
|
+
'The last non-whitespace character must be }.',
|
|
19
|
+
'',
|
|
20
|
+
'Forbidden: Markdown fences, commentary, labels, multiple objects, or any leading/trailing text.',
|
|
20
21
|
'',
|
|
21
22
|
'The JSON object MUST include keys: goal, files, changes, verify.',
|
|
22
23
|
'',
|
|
@@ -38,31 +39,36 @@ export async function repairToJsonObject(args) {
|
|
|
38
39
|
});
|
|
39
40
|
}
|
|
40
41
|
export async function repairToUnifiedDiff(args) {
|
|
41
|
-
const {
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
42
|
+
const { badContent } = args;
|
|
43
|
+
const extractCanonicalDiff = (input) => {
|
|
44
|
+
if (!input)
|
|
45
|
+
return '';
|
|
46
|
+
const fromText = (value) => {
|
|
47
|
+
const start = value.search(/^\s*diff --git /m);
|
|
48
|
+
if (start === -1)
|
|
49
|
+
return '';
|
|
50
|
+
const section = value.slice(start).trim();
|
|
51
|
+
const fenceClose = section.search(/\n```/);
|
|
52
|
+
if (fenceClose !== -1)
|
|
53
|
+
return section.slice(0, fenceClose).trim();
|
|
54
|
+
return section;
|
|
55
|
+
};
|
|
56
|
+
const fencedBlocks = [];
|
|
57
|
+
const fenceRegex = /```(?:diff)?\s*\n([\s\S]*?)\n```/gi;
|
|
58
|
+
let match = null;
|
|
59
|
+
while ((match = fenceRegex.exec(input)) !== null) {
|
|
60
|
+
const block = match[1];
|
|
61
|
+
const extracted = fromText(block);
|
|
62
|
+
if (extracted)
|
|
63
|
+
fencedBlocks.push(extracted);
|
|
64
|
+
}
|
|
65
|
+
if (fencedBlocks.length > 0)
|
|
66
|
+
return fencedBlocks[fencedBlocks.length - 1];
|
|
67
|
+
return fromText(input);
|
|
68
|
+
};
|
|
69
|
+
return {
|
|
70
|
+
role: 'assistant',
|
|
71
|
+
content: extractCanonicalDiff(badContent || ''),
|
|
72
|
+
};
|
|
67
73
|
}
|
|
68
74
|
//# sourceMappingURL=repair.js.map
|
package/dist/core/llm/errors.js
CHANGED
|
@@ -26,6 +26,11 @@ function extractProviderDetails(err) {
|
|
|
26
26
|
if (typeof candidate.statusCode === 'number') {
|
|
27
27
|
details.statusCode = candidate.statusCode;
|
|
28
28
|
}
|
|
29
|
+
// Align with AI SDK error shapes that store HTTP status in response.status
|
|
30
|
+
const response = candidate.response;
|
|
31
|
+
if (typeof details.statusCode !== 'number' && response && typeof response.status === 'number') {
|
|
32
|
+
details.statusCode = response.status;
|
|
33
|
+
}
|
|
29
34
|
if (typeof candidate.responseBody === 'string') {
|
|
30
35
|
// Apply sanitization to responseBody immediately after truncation
|
|
31
36
|
details.responseBody = sanitizeError(truncate(candidate.responseBody));
|
|
@@ -75,6 +80,42 @@ function extractProviderDetails(err) {
|
|
|
75
80
|
}
|
|
76
81
|
return details;
|
|
77
82
|
}
|
|
83
|
+
function extractNetworkCode(err) {
|
|
84
|
+
if (!err || typeof err !== 'object')
|
|
85
|
+
return undefined;
|
|
86
|
+
const candidate = err;
|
|
87
|
+
const direct = candidate.code;
|
|
88
|
+
if (typeof direct === 'string' && direct.trim())
|
|
89
|
+
return direct;
|
|
90
|
+
const cause = candidate.cause;
|
|
91
|
+
if (cause && typeof cause === 'object' && typeof cause.code === 'string') {
|
|
92
|
+
const code = String(cause.code);
|
|
93
|
+
return code.trim() ? code : undefined;
|
|
94
|
+
}
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
function isAuthenticationFailure(input) {
|
|
98
|
+
if (input.statusCode === 401)
|
|
99
|
+
return true;
|
|
100
|
+
const lower = `${input.message} ${input.providerMessage ?? ''} ${input.sanitizedMessage}`.toLowerCase();
|
|
101
|
+
const authHints = [
|
|
102
|
+
'unauthorized',
|
|
103
|
+
'forbidden',
|
|
104
|
+
'authentication failed',
|
|
105
|
+
'auth failed',
|
|
106
|
+
'invalid api key',
|
|
107
|
+
'invalid api-key',
|
|
108
|
+
'access denied',
|
|
109
|
+
'permission denied',
|
|
110
|
+
'credential',
|
|
111
|
+
'appidnoautherror',
|
|
112
|
+
'noautherror',
|
|
113
|
+
];
|
|
114
|
+
if (authHints.some((hint) => lower.includes(hint))) {
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
return input.statusCode === 403 && /auth|access|permission|credential|forbidden/i.test(lower);
|
|
118
|
+
}
|
|
78
119
|
/**
|
|
79
120
|
* Sanitizes an error message using the shared utility to prevent leakage
|
|
80
121
|
* of sensitive technical data.
|
|
@@ -83,8 +124,16 @@ export function sanitizeError(err) {
|
|
|
83
124
|
return sanitizeErrorMessage(err);
|
|
84
125
|
}
|
|
85
126
|
export function toLlmError(err, provider) {
|
|
86
|
-
let name = err instanceof Error
|
|
87
|
-
|
|
127
|
+
let name = err instanceof Error
|
|
128
|
+
? err.name
|
|
129
|
+
: typeof err?.name === 'string'
|
|
130
|
+
? String(err.name)
|
|
131
|
+
: 'UnknownError';
|
|
132
|
+
let message = err instanceof Error
|
|
133
|
+
? err.message
|
|
134
|
+
: typeof err?.message === 'string'
|
|
135
|
+
? String(err.message)
|
|
136
|
+
: String(err);
|
|
88
137
|
// Unwrap RetryError to get the last error's message if available
|
|
89
138
|
if (name === 'AI_RetryError' || err?.lastError) {
|
|
90
139
|
const lastError = err.lastError;
|
|
@@ -137,6 +186,38 @@ export function toLlmError(err, provider) {
|
|
|
137
186
|
})) {
|
|
138
187
|
return new LlmError('LLM context length exceeded', 'LLM_CONTEXT_LENGTH_EXCEEDED', meta);
|
|
139
188
|
}
|
|
189
|
+
const lower = `${message} ${meta.providerMessage ?? ''} ${sanitizedMessage}`.toLowerCase();
|
|
190
|
+
const statusCode = meta.statusCode;
|
|
191
|
+
const networkCode = extractNetworkCode(err)?.toUpperCase();
|
|
192
|
+
if (isAuthenticationFailure({
|
|
193
|
+
statusCode,
|
|
194
|
+
message,
|
|
195
|
+
providerMessage: meta.providerMessage,
|
|
196
|
+
sanitizedMessage,
|
|
197
|
+
})) {
|
|
198
|
+
return new LlmError('LLM authentication failed', 'LLM_AUTHENTICATION_FAILED', meta);
|
|
199
|
+
}
|
|
200
|
+
if (statusCode === 429 || lower.includes('rate limit') || lower.includes('too many requests')) {
|
|
201
|
+
return new LlmError('LLM rate limited', 'LLM_RATE_LIMITED', meta);
|
|
202
|
+
}
|
|
203
|
+
if (statusCode === 408 || lower.includes('timeout') || networkCode === 'ETIMEDOUT') {
|
|
204
|
+
return new LlmError('LLM request timed out', 'LLM_REQUEST_TIMEOUT', meta);
|
|
205
|
+
}
|
|
206
|
+
if (typeof statusCode === 'number' && statusCode >= 500 && statusCode < 600) {
|
|
207
|
+
return new LlmError('LLM upstream server error', 'LLM_UPSTREAM_5XX', meta);
|
|
208
|
+
}
|
|
209
|
+
if (typeof networkCode === 'string') {
|
|
210
|
+
const unreachable = new Set([
|
|
211
|
+
'ECONNRESET',
|
|
212
|
+
'ETIMEDOUT',
|
|
213
|
+
'EAI_AGAIN',
|
|
214
|
+
'ENOTFOUND',
|
|
215
|
+
'ECONNREFUSED',
|
|
216
|
+
]);
|
|
217
|
+
if (unreachable.has(networkCode)) {
|
|
218
|
+
return new LlmError('LLM network request failed', 'LLM_NETWORK_UNREACHABLE', meta);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
140
221
|
return new LlmError('LLM request failed', 'LLM_HTTP_REQUEST_FAILED', meta);
|
|
141
222
|
}
|
|
142
223
|
function isContextLengthExceeded(input) {
|
|
@@ -1,25 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
if (!msg || typeof msg !== 'object')
|
|
3
|
-
return null;
|
|
4
|
-
if (msg.role !== 'user' && msg.role !== 'assistant')
|
|
5
|
-
return null;
|
|
6
|
-
if (typeof msg.content !== 'string')
|
|
7
|
-
return null;
|
|
8
|
-
const content = msg.content.trimEnd();
|
|
9
|
-
if (!content)
|
|
10
|
-
return null;
|
|
11
|
-
return { role: msg.role, content };
|
|
12
|
-
}
|
|
1
|
+
import { buildSharedRequestEnvelope } from './shared-request-assembly.js';
|
|
13
2
|
export function composeChatMessages(params) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
out.push({ role: 'user', content: String(params.user ?? '') });
|
|
23
|
-
return out;
|
|
3
|
+
return buildSharedRequestEnvelope({
|
|
4
|
+
defaultNamespace: 'chat',
|
|
5
|
+
systemPrompt: params.system,
|
|
6
|
+
userPrompt: params.user,
|
|
7
|
+
conversationContext: params.conversationContext,
|
|
8
|
+
}).baseMessages;
|
|
24
9
|
}
|
|
25
10
|
//# sourceMappingURL=message-composition.js.map
|