@jsonstudio/llms 0.6.795 → 0.6.938
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/bridge/routecodex-adapter.d.ts +74 -0
- package/dist/config-unified/enhanced-path-resolver.d.ts +5 -0
- package/dist/config-unified/unified-config.d.ts +26 -0
- package/dist/conversion/codec-registry.d.ts +10 -0
- package/dist/conversion/codecs/gemini-openai-codec.d.ts +16 -0
- package/dist/conversion/codecs/openai-openai-codec.d.ts +12 -0
- package/dist/conversion/codecs/responses-openai-codec.d.ts +12 -0
- package/dist/conversion/compat/profiles/chat-gemini.json +12 -0
- package/dist/conversion/config/config-manager.d.ts +212 -0
- package/dist/conversion/hub/config/types.d.ts +26 -0
- package/dist/conversion/hub/core/detour-registry.d.ts +9 -0
- package/dist/conversion/hub/core/hub-context.d.ts +21 -0
- package/dist/conversion/hub/core/index.d.ts +3 -0
- package/dist/conversion/hub/core/stage-driver.d.ts +30 -0
- package/dist/conversion/hub/format-adapters/anthropic-format-adapter.d.ts +16 -0
- package/dist/conversion/hub/format-adapters/chat-format-adapter.d.ts +17 -0
- package/dist/conversion/hub/format-adapters/gemini-format-adapter.d.ts +16 -0
- package/dist/conversion/hub/format-adapters/index.d.ts +21 -0
- package/dist/conversion/hub/hub-feature.d.ts +1 -0
- package/dist/conversion/hub/node-support.d.ts +19 -0
- package/dist/conversion/hub/pipeline/compat/compat-pipeline-executor.js +11 -0
- package/dist/conversion/hub/pipeline/compat/compat-types.d.ts +3 -0
- package/dist/conversion/hub/pipeline/hub-pipeline.d.ts +7 -0
- package/dist/conversion/hub/pipeline/hub-pipeline.js +71 -14
- package/dist/conversion/hub/pipeline/stages/req_process/req_process_stage1_tool_governance/index.js +4 -0
- package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.js +23 -1
- package/dist/conversion/hub/pipelines/inbound.d.ts +22 -0
- package/dist/conversion/hub/pipelines/outbound.d.ts +22 -0
- package/dist/conversion/hub/policy/policy-engine.d.ts +46 -0
- package/dist/conversion/hub/policy/policy-engine.js +176 -0
- package/dist/conversion/hub/policy/protocol-spec.d.ts +50 -0
- package/dist/conversion/hub/policy/protocol-spec.js +105 -0
- package/dist/conversion/hub/process/chat-process.d.ts +32 -0
- package/dist/conversion/hub/registry.d.ts +28 -0
- package/dist/conversion/hub/response/chat-response-utils.d.ts +6 -0
- package/dist/conversion/hub/response/provider-response.js +31 -0
- package/dist/conversion/hub/semantic-mappers/gemini-mapper.d.ts +7 -0
- package/dist/conversion/hub/semantic-mappers/gemini-mapper.js +87 -1
- package/dist/conversion/hub/semantic-mappers/index.d.ts +4 -0
- package/dist/conversion/hub/semantic-mappers/responses-mapper.d.ts +21 -0
- package/dist/conversion/hub/standardized-bridge.d.ts +12 -0
- package/dist/conversion/hub/types/chat-schema.d.ts +112 -0
- package/dist/conversion/hub/types/errors.d.ts +5 -0
- package/dist/conversion/hub/types/format-envelope.d.ts +7 -0
- package/dist/conversion/hub/types/index.d.ts +6 -0
- package/dist/conversion/hub/types/json.d.ts +9 -0
- package/dist/conversion/hub/types/node.d.ts +31 -0
- package/dist/conversion/responses/responses-openai-bridge.js +263 -10
- package/dist/conversion/schema-validator.d.ts +7 -0
- package/dist/conversion/shared/args-mapping.d.ts +18 -0
- package/dist/conversion/shared/chat-request-filters.d.ts +9 -0
- package/dist/conversion/shared/errors.d.ts +1 -1
- package/dist/conversion/shared/gemini-tool-utils.js +61 -0
- package/dist/conversion/shared/jsonish.d.ts +3 -0
- package/dist/conversion/shared/mcp-injection.d.ts +2 -0
- package/dist/conversion/shared/media.d.ts +1 -0
- package/dist/conversion/shared/openai-message-normalize.d.ts +1 -0
- package/dist/conversion/shared/payload-budget.d.ts +13 -0
- package/dist/conversion/shared/reasoning-mapping.d.ts +5 -0
- package/dist/conversion/shared/responses-request-adapter.d.ts +1 -28
- package/dist/conversion/shared/responses-request-adapter.js +1 -430
- package/dist/conversion/shared/snapshot-hooks.js +112 -4
- package/dist/conversion/shared/tool-governor.js +8 -2
- package/dist/conversion/shared/tool-harvester.d.ts +31 -0
- package/dist/conversion/shared/tool-mapping.js +10 -29
- package/dist/conversion/types.d.ts +33 -0
- package/dist/filters/builtin/add-fields-filter.d.ts +8 -0
- package/dist/filters/builtin/blacklist-filter.d.ts +8 -0
- package/dist/filters/builtin/whitelist-filter.d.ts +8 -0
- package/dist/filters/engine.d.ts +16 -0
- package/dist/filters/special/request-tool-choice-policy.d.ts +11 -0
- package/dist/filters/special/response-finish-invariants.d.ts +11 -0
- package/dist/filters/special/response-openai-to-responses-bridge.d.ts +13 -0
- package/dist/filters/special/response-tool-arguments-blacklist.d.ts +12 -0
- package/dist/filters/special/response-tool-arguments-schema-converge.d.ts +13 -0
- package/dist/filters/special/response-tool-arguments-stringify.d.ts +9 -0
- package/dist/filters/special/response-tool-arguments-whitelist.d.ts +11 -0
- package/dist/filters/special/tool-filter-hooks.d.ts +19 -0
- package/dist/filters/special/tool-post-constraints.d.ts +31 -0
- package/dist/filters/types.d.ts +68 -0
- package/dist/filters/utils/fieldmap-loader.d.ts +2 -0
- package/dist/filters/utils/snapshot-writer.d.ts +10 -0
- package/dist/guidance/index.d.ts +3 -0
- package/dist/guidance/index.js +78 -83
- package/dist/http/sse-response.d.ts +22 -0
- package/dist/router/virtual-router/bootstrap.d.ts +6 -0
- package/dist/router/virtual-router/bootstrap.js +49 -5
- package/dist/router/virtual-router/classifier.d.ts +10 -0
- package/dist/router/virtual-router/engine-selection.js +147 -15
- package/dist/router/virtual-router/engine.js +177 -31
- package/dist/router/virtual-router/error-center.d.ts +10 -0
- package/dist/router/virtual-router/features.d.ts +3 -0
- package/dist/router/virtual-router/routing-instructions.d.ts +23 -1
- package/dist/router/virtual-router/routing-instructions.js +120 -30
- package/dist/router/virtual-router/types.d.ts +11 -0
- package/dist/servertool/engine.js +189 -16
- package/dist/servertool/handlers/apply-patch-guard.js +269 -0
- package/dist/servertool/handlers/exec-command-guard.js +558 -0
- package/dist/servertool/handlers/followup-message-trimmer.d.ts +16 -0
- package/dist/servertool/handlers/followup-message-trimmer.js +198 -0
- package/dist/servertool/handlers/followup-request-builder.d.ts +17 -0
- package/dist/servertool/handlers/followup-request-builder.js +122 -0
- package/dist/servertool/handlers/gemini-empty-reply-continue.js +252 -51
- package/dist/servertool/handlers/iflow-model-error-retry.js +12 -22
- package/dist/servertool/handlers/stop-message-auto.js +237 -75
- package/dist/servertool/handlers/vision.js +15 -27
- package/dist/servertool/handlers/web-search.js +17 -43
- package/dist/servertool/server-side-tools.d.ts +3 -0
- package/dist/servertool/server-side-tools.js +3 -0
- package/dist/sse/json-to-sse/anthropic-json-to-sse-converter.d.ts +2 -1
- package/dist/sse/json-to-sse/chat-json-to-sse-converter.d.ts +80 -0
- package/dist/sse/json-to-sse/event-generators/chat.d.ts +55 -0
- package/dist/sse/json-to-sse/event-generators/responses.d.ts +99 -0
- package/dist/sse/json-to-sse/gemini-json-to-sse-converter.d.ts +2 -1
- package/dist/sse/json-to-sse/responses-json-to-sse-converter.d.ts +80 -0
- package/dist/sse/json-to-sse/sequencers/anthropic-sequencer.d.ts +1 -1
- package/dist/sse/json-to-sse/sequencers/chat-sequencer.d.ts +2 -2
- package/dist/sse/json-to-sse/sequencers/gemini-sequencer.d.ts +1 -1
- package/dist/sse/json-to-sse/sequencers/responses-sequencer.d.ts +40 -0
- package/dist/sse/shared/chat-serializer.d.ts +4 -0
- package/dist/sse/shared/constants.d.ts +272 -0
- package/dist/sse/shared/serializers/anthropic-event-serializer.d.ts +1 -1
- package/dist/sse/shared/serializers/base-serializer.d.ts +158 -0
- package/dist/sse/shared/serializers/chat-event-serializer.d.ts +82 -0
- package/dist/sse/shared/serializers/gemini-event-serializer.d.ts +1 -1
- package/dist/sse/shared/serializers/index.d.ts +2 -1
- package/dist/sse/shared/serializers/responses-event-serializer.d.ts +123 -0
- package/dist/sse/shared/serializers/types.d.ts +51 -0
- package/dist/sse/shared/utils.d.ts +254 -0
- package/dist/sse/shared/writer.d.ts +2 -2
- package/dist/sse/sse-to-json/anthropic-sse-to-json-converter.d.ts +1 -1
- package/dist/sse/sse-to-json/builders/anthropic-response-builder.d.ts +1 -1
- package/dist/sse/sse-to-json/builders/response-builder.d.ts +1 -1
- package/dist/sse/sse-to-json/chat-sse-to-json-converter.d.ts +2 -1
- package/dist/sse/sse-to-json/gemini-sse-to-json-converter.d.ts +2 -1
- package/dist/sse/sse-to-json/parsers/sse-parser.d.ts +73 -0
- package/dist/sse/sse-to-json/responses-sse-to-json-converter.d.ts +1 -1
- package/dist/sse/types/chat-types.d.ts +1 -1
- package/dist/sse/types/responses-types.d.ts +1 -1
- package/dist/tools/apply-patch/execution-capturer.d.ts +13 -0
- package/dist/tools/apply-patch/execution-capturer.js +158 -0
- package/dist/tools/apply-patch/regression-capturer.d.ts +1 -0
- package/dist/tools/apply-patch/regression-capturer.js +5 -4
- package/dist/tools/apply-patch/structured.js +109 -13
- package/dist/tools/apply-patch/validator.js +261 -17
- package/dist/tools/tool-registry.d.ts +8 -0
- package/dist/tools/tool-registry.js +2 -1
- package/package.json +4 -4
- package/dist/conversion/compat/actions/apply-patch-format-fixer.js +0 -233
- package/dist/conversion/config/compat-profiles.json +0 -38
- package/dist/conversion/hub/response/server-side-tools.d.ts +0 -26
- package/dist/conversion/hub/response/server-side-tools.js +0 -383
- package/dist/conversion/shared/bridge-conversation-store.d.ts +0 -41
- package/dist/conversion/shared/bridge-conversation-store.js +0 -279
- package/dist/conversion/shared/bridge-request-adapter.d.ts +0 -28
- package/dist/conversion/shared/bridge-request-adapter.js +0 -430
- package/dist/conversion/shared/responses-id-utils.js +0 -42
- package/dist/conversion/shared/responses-instructions.js +0 -113
- package/dist/conversion/shared/responses-message-utils.d.ts +0 -15
- package/dist/conversion/shared/responses-message-utils.js +0 -206
- package/dist/conversion/shared/responses-metadata.js +0 -1
- package/dist/conversion/shared/responses-output-utils.d.ts +0 -7
- package/dist/conversion/shared/responses-output-utils.js +0 -108
- package/dist/conversion/shared/responses-types.d.ts +0 -33
- package/dist/conversion/shared/tool-normalizers.d.ts +0 -4
- package/dist/conversion/shared/tool-normalizers.js +0 -84
- package/dist/filters/special/request-streaming-to-nonstreaming.d.ts +0 -13
- package/dist/filters/special/request-streaming-to-nonstreaming.js +0 -39
- package/dist/filters/special/response-apply-patch-toon-decode.d.ts +0 -23
- package/dist/filters/special/response-apply-patch-toon-decode.js +0 -460
- package/dist/filters/special/response-tool-arguments-toon-decode.d.ts +0 -10
- package/dist/filters/special/response-tool-arguments-toon-decode.js +0 -154
- package/dist/servertool/flow-types.d.ts +0 -40
- package/dist/servertool/flow-types.js +0 -1
- package/dist/servertool/orchestration-types.d.ts +0 -33
- package/dist/servertool/orchestration-types.js +0 -1
- package/dist/servertool/vision-tool.d.ts +0 -2
- package/dist/servertool/vision-tool.js +0 -185
- package/dist/tools/patch-args-normalizer.d.ts +0 -15
- package/dist/tools/patch-args-normalizer.js +0 -472
- package/dist/utils/toon.d.ts +0 -4
- package/dist/utils/toon.js +0 -75
- /package/dist/{conversion/compat/actions/apply-patch-format-fixer.d.ts → servertool/handlers/apply-patch-guard.d.ts} +0 -0
- /package/dist/{conversion/shared/responses-types.js → servertool/handlers/exec-command-guard.d.ts} +0 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import { registerServerToolHandler } from '../registry.js';
|
|
2
|
+
import { cloneJson } from '../server-side-tools.js';
|
|
3
|
+
import { validateToolCall } from '../../tools/tool-registry.js';
|
|
4
|
+
import { buildEntryAwareFollowupPayload, extractCapturedChatSeed } from './followup-request-builder.js';
|
|
5
|
+
const FLOW_ID = 'apply_patch_guard';
|
|
6
|
+
const handler = async (ctx) => {
|
|
7
|
+
const toolCall = ctx.toolCall;
|
|
8
|
+
if (!toolCall) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
if (!ctx.options.reenterPipeline) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
const rawArgs = typeof toolCall.arguments === 'string' ? toolCall.arguments : '';
|
|
15
|
+
const validation = validateToolCall('apply_patch', rawArgs);
|
|
16
|
+
if (validation?.ok) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
const reason = typeof validation?.reason === 'string' && validation.reason.trim()
|
|
20
|
+
? validation.reason.trim()
|
|
21
|
+
: 'unknown';
|
|
22
|
+
const snippet = rawArgs && rawArgs.trim().length
|
|
23
|
+
? rawArgs.trim().slice(0, 200).replace(/\s+/g, ' ')
|
|
24
|
+
: '';
|
|
25
|
+
const isExecCommandShape = extractLikelyExecCommandShape(rawArgs);
|
|
26
|
+
// For obviously wrong shapes (e.g. exec_command-like payload passed into apply_patch),
|
|
27
|
+
// do NOT attempt a followup "recovery" loop. Return a plain assistant message instead.
|
|
28
|
+
if (isExecCommandShape && (reason === 'missing_changes' || reason === 'missing_payload' || reason === 'invalid_json')) {
|
|
29
|
+
const patched = injectApplyPatchHardFailureMessage(ctx.base, toolCall, {
|
|
30
|
+
reason,
|
|
31
|
+
snippet,
|
|
32
|
+
rawArgs
|
|
33
|
+
});
|
|
34
|
+
return {
|
|
35
|
+
chatResponse: patched,
|
|
36
|
+
execution: { flowId: FLOW_ID }
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
const patched = injectApplyPatchRejectedToolResult(ctx.base, toolCall, {
|
|
40
|
+
reason,
|
|
41
|
+
snippet,
|
|
42
|
+
rawArgs
|
|
43
|
+
});
|
|
44
|
+
const followupPayload = buildToolFollowupPayload(ctx.adapterContext, patched, ctx.options.entryEndpoint || ctx.adapterContext?.entryEndpoint || '/v1/chat/completions');
|
|
45
|
+
if (!followupPayload) {
|
|
46
|
+
// Fail-closed: if we cannot perform reenter, do not intercept.
|
|
47
|
+
// (This should be rare because HubPipeline always provides capturedChatRequest.)
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
chatResponse: patched,
|
|
52
|
+
execution: {
|
|
53
|
+
flowId: FLOW_ID,
|
|
54
|
+
followup: {
|
|
55
|
+
requestIdSuffix: ':apply_patch_guard_followup',
|
|
56
|
+
payload: followupPayload
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
registerServerToolHandler('apply_patch', handler);
|
|
62
|
+
function injectApplyPatchHardFailureMessage(base, toolCall, options) {
|
|
63
|
+
const cloned = cloneJson(base);
|
|
64
|
+
const choices = Array.isArray(cloned.choices)
|
|
65
|
+
? cloned.choices
|
|
66
|
+
: [];
|
|
67
|
+
if (!choices.length) {
|
|
68
|
+
return cloned;
|
|
69
|
+
}
|
|
70
|
+
const first = choices[0];
|
|
71
|
+
if (!first || typeof first !== 'object' || Array.isArray(first)) {
|
|
72
|
+
return cloned;
|
|
73
|
+
}
|
|
74
|
+
const message = first.message;
|
|
75
|
+
if (!message || typeof message !== 'object' || Array.isArray(message)) {
|
|
76
|
+
return cloned;
|
|
77
|
+
}
|
|
78
|
+
// Replace tool-call response with a plain assistant message.
|
|
79
|
+
const guidance = buildApplyPatchGuidance(options.rawArgs);
|
|
80
|
+
const text = `[apply_patch rejected] reason=${options.reason}` +
|
|
81
|
+
(options.snippet ? ` args=${options.snippet}` : '') +
|
|
82
|
+
`\n\n${guidance}`;
|
|
83
|
+
message.content = text;
|
|
84
|
+
if (Object.prototype.hasOwnProperty.call(message, 'tool_calls')) {
|
|
85
|
+
delete message.tool_calls;
|
|
86
|
+
}
|
|
87
|
+
if (typeof first.finish_reason === 'string' && first.finish_reason === 'tool_calls') {
|
|
88
|
+
first.finish_reason = 'stop';
|
|
89
|
+
}
|
|
90
|
+
// Remove tool_outputs to avoid confusing clients that don't implement tool loops.
|
|
91
|
+
if (Object.prototype.hasOwnProperty.call(cloned, 'tool_outputs')) {
|
|
92
|
+
delete cloned.tool_outputs;
|
|
93
|
+
}
|
|
94
|
+
return cloned;
|
|
95
|
+
}
|
|
96
|
+
function injectApplyPatchRejectedToolResult(base, toolCall, options) {
|
|
97
|
+
const cloned = cloneJson(base);
|
|
98
|
+
const existingOutputs = Array.isArray(cloned.tool_outputs)
|
|
99
|
+
? cloned.tool_outputs
|
|
100
|
+
: [];
|
|
101
|
+
const payload = {
|
|
102
|
+
ok: false,
|
|
103
|
+
tool: 'apply_patch',
|
|
104
|
+
reason: options.reason,
|
|
105
|
+
...(options.snippet ? { argsSnippet: options.snippet } : {}),
|
|
106
|
+
guidance: buildApplyPatchGuidance(options.rawArgs)
|
|
107
|
+
};
|
|
108
|
+
cloned.tool_outputs = [
|
|
109
|
+
...existingOutputs,
|
|
110
|
+
{
|
|
111
|
+
tool_call_id: toolCall.id,
|
|
112
|
+
name: 'apply_patch',
|
|
113
|
+
content: JSON.stringify(payload)
|
|
114
|
+
}
|
|
115
|
+
];
|
|
116
|
+
return cloned;
|
|
117
|
+
}
|
|
118
|
+
function buildApplyPatchGuidance(rawArgs) {
|
|
119
|
+
const base = 'apply_patch 参数预检失败。请改用统一 diff(*** Begin Patch ... *** End Patch),' +
|
|
120
|
+
'或使用结构化 JSON:{ file, changes:[{ file, kind, target/anchor, lines/newText, ... }] }。';
|
|
121
|
+
const schemaHint = extractLikelyExecCommandShape(rawArgs);
|
|
122
|
+
if (schemaHint) {
|
|
123
|
+
return (base +
|
|
124
|
+
'\n\n' +
|
|
125
|
+
'你传入的参数看起来像 exec_command(例如包含 "command"/"cmd" 字段),但工具名是 apply_patch。\n' +
|
|
126
|
+
'apply_patch 必须提供非空的 "changes" 数组;如果你需要执行命令请改用 exec_command(注意:禁止通过 shell 写文件)。');
|
|
127
|
+
}
|
|
128
|
+
// User-requested hint (directory deletion is not supported via delete_file).
|
|
129
|
+
// Heuristic: detect delete_file with a directory-like target (trailing slash).
|
|
130
|
+
const hintTarget = extractDeleteFileTarget(rawArgs);
|
|
131
|
+
if (!hintTarget) {
|
|
132
|
+
return base;
|
|
133
|
+
}
|
|
134
|
+
return (base +
|
|
135
|
+
'\n\n' +
|
|
136
|
+
`- {"changes":[{"kind":"delete_file","target":"${hintTarget}"}]} ❌ 仍会 invalid_file(因为是目录)\n\n` +
|
|
137
|
+
'如果你真要删目录:请用 exec_command(例如 rm -rf tmp web-container-manager),或者用 apply_patch 逐个删目录下的文件(更安全、可审计)。');
|
|
138
|
+
}
|
|
139
|
+
function extractDeleteFileTarget(rawArgs) {
|
|
140
|
+
if (!rawArgs || typeof rawArgs !== 'string') {
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
let parsed;
|
|
144
|
+
try {
|
|
145
|
+
parsed = JSON.parse(rawArgs);
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
const record = parsed;
|
|
154
|
+
const changes = Array.isArray(record.changes) ? record.changes : [];
|
|
155
|
+
for (const change of changes) {
|
|
156
|
+
if (!change || typeof change !== 'object' || Array.isArray(change))
|
|
157
|
+
continue;
|
|
158
|
+
const c = change;
|
|
159
|
+
const kind = typeof c.kind === 'string' ? c.kind.trim().toLowerCase() : '';
|
|
160
|
+
if (kind !== 'delete_file')
|
|
161
|
+
continue;
|
|
162
|
+
const target = typeof c.target === 'string' ? c.target.trim() : '';
|
|
163
|
+
if (!target)
|
|
164
|
+
continue;
|
|
165
|
+
if (target.endsWith('/')) {
|
|
166
|
+
return target;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
function extractLikelyExecCommandShape(rawArgs) {
|
|
172
|
+
if (!rawArgs || typeof rawArgs !== 'string') {
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
let parsed;
|
|
176
|
+
try {
|
|
177
|
+
parsed = JSON.parse(rawArgs);
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
const record = parsed;
|
|
186
|
+
const command = record.command;
|
|
187
|
+
const cmd = record.cmd;
|
|
188
|
+
if (typeof command === 'string' && command.trim()) {
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
191
|
+
if (typeof cmd === 'string' && cmd.trim()) {
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
function buildToolFollowupPayload(adapterContext, chatResponse, entryEndpoint) {
|
|
197
|
+
const captured = adapterContext && typeof adapterContext === 'object'
|
|
198
|
+
? adapterContext.capturedChatRequest
|
|
199
|
+
: undefined;
|
|
200
|
+
const seed = extractCapturedChatSeed(captured);
|
|
201
|
+
if (!seed) {
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
const assistantMessage = extractAssistantMessage(chatResponse);
|
|
205
|
+
if (!assistantMessage) {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
const toolMessages = buildToolMessages(chatResponse);
|
|
209
|
+
if (!toolMessages.length) {
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
const reconstructed = [...seed.messages, assistantMessage, ...toolMessages];
|
|
213
|
+
return buildEntryAwareFollowupPayload({
|
|
214
|
+
entryEndpoint,
|
|
215
|
+
model: seed.model,
|
|
216
|
+
messages: reconstructed,
|
|
217
|
+
...(seed.tools ? { tools: seed.tools } : {}),
|
|
218
|
+
...(seed.parameters ? { parameters: seed.parameters } : {})
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
function extractAssistantMessage(chatResponse) {
|
|
222
|
+
const choices = Array.isArray(chatResponse.choices)
|
|
223
|
+
? chatResponse.choices
|
|
224
|
+
: [];
|
|
225
|
+
if (!choices.length)
|
|
226
|
+
return null;
|
|
227
|
+
const first = choices[0];
|
|
228
|
+
if (!first || typeof first !== 'object' || Array.isArray(first))
|
|
229
|
+
return null;
|
|
230
|
+
const message = first.message;
|
|
231
|
+
if (!message || typeof message !== 'object' || Array.isArray(message))
|
|
232
|
+
return null;
|
|
233
|
+
return cloneJson(message);
|
|
234
|
+
}
|
|
235
|
+
function buildToolMessages(chatResponse) {
|
|
236
|
+
const toolOutputs = Array.isArray(chatResponse.tool_outputs)
|
|
237
|
+
? chatResponse.tool_outputs
|
|
238
|
+
: [];
|
|
239
|
+
const messages = [];
|
|
240
|
+
for (const entry of toolOutputs) {
|
|
241
|
+
if (!entry || typeof entry !== 'object' || Array.isArray(entry))
|
|
242
|
+
continue;
|
|
243
|
+
const record = entry;
|
|
244
|
+
const toolCallId = typeof record.tool_call_id === 'string' ? record.tool_call_id : undefined;
|
|
245
|
+
if (!toolCallId)
|
|
246
|
+
continue;
|
|
247
|
+
const name = typeof record.name === 'string' && record.name.trim() ? record.name.trim() : 'apply_patch';
|
|
248
|
+
const rawContent = record.content;
|
|
249
|
+
let contentText;
|
|
250
|
+
if (typeof rawContent === 'string') {
|
|
251
|
+
contentText = rawContent;
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
try {
|
|
255
|
+
contentText = JSON.stringify(rawContent ?? {});
|
|
256
|
+
}
|
|
257
|
+
catch {
|
|
258
|
+
contentText = String(rawContent ?? '');
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
messages.push({
|
|
262
|
+
role: 'tool',
|
|
263
|
+
tool_call_id: toolCallId,
|
|
264
|
+
name,
|
|
265
|
+
content: contentText
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
return messages;
|
|
269
|
+
}
|