@zihanw/pi-forge 0.2.0 → 0.3.1
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/README.md +233 -105
- package/README.zh-CN.md +215 -104
- package/dist/compiler.d.ts +10 -0
- package/dist/compiler.d.ts.map +1 -0
- package/dist/compiler.js +490 -0
- package/dist/compiler.js.map +1 -0
- package/dist/extension-registry.d.ts +25 -0
- package/dist/extension-registry.d.ts.map +1 -0
- package/dist/extension-registry.js +6 -0
- package/dist/extension-registry.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +364 -0
- package/dist/index.js.map +1 -0
- package/dist/lifecycle.d.ts +14 -0
- package/dist/lifecycle.d.ts.map +1 -0
- package/dist/lifecycle.js +139 -0
- package/dist/lifecycle.js.map +1 -0
- package/dist/loader.d.ts +8 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +345 -0
- package/dist/loader.js.map +1 -0
- package/dist/macro-engine.d.ts +23 -0
- package/dist/macro-engine.d.ts.map +1 -0
- package/dist/macro-engine.js +262 -0
- package/dist/macro-engine.js.map +1 -0
- package/dist/payload-capture.d.ts +15 -0
- package/dist/payload-capture.d.ts.map +1 -0
- package/dist/payload-capture.js +86 -0
- package/dist/payload-capture.js.map +1 -0
- package/dist/payload-command.d.ts +10 -0
- package/dist/payload-command.d.ts.map +1 -0
- package/dist/payload-command.js +112 -0
- package/dist/payload-command.js.map +1 -0
- package/dist/policy.d.ts +6 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +38 -0
- package/dist/policy.js.map +1 -0
- package/dist/preset-command.d.ts +14 -0
- package/dist/preset-command.d.ts.map +1 -0
- package/dist/preset-command.js +223 -0
- package/dist/preset-command.js.map +1 -0
- package/dist/preview.d.ts +12 -0
- package/dist/preview.d.ts.map +1 -0
- package/dist/preview.js +179 -0
- package/dist/preview.js.map +1 -0
- package/dist/regex.d.ts +7 -0
- package/dist/regex.d.ts.map +1 -0
- package/dist/regex.js +432 -0
- package/dist/regex.js.map +1 -0
- package/dist/render-helpers.d.ts +44 -0
- package/dist/render-helpers.d.ts.map +1 -0
- package/dist/render-helpers.js +128 -0
- package/dist/render-helpers.js.map +1 -0
- package/dist/runtime-state.d.ts +24 -0
- package/dist/runtime-state.d.ts.map +1 -0
- package/dist/runtime-state.js +13 -0
- package/dist/runtime-state.js.map +1 -0
- package/dist/sillytavern-importer/items.d.ts +3 -0
- package/dist/sillytavern-importer/items.d.ts.map +1 -0
- package/dist/sillytavern-importer/items.js +88 -0
- package/dist/sillytavern-importer/items.js.map +1 -0
- package/dist/sillytavern-importer/macros.d.ts +15 -0
- package/dist/sillytavern-importer/macros.d.ts.map +1 -0
- package/dist/sillytavern-importer/macros.js +141 -0
- package/dist/sillytavern-importer/macros.js.map +1 -0
- package/dist/sillytavern-importer/prompt-order.d.ts +6 -0
- package/dist/sillytavern-importer/prompt-order.d.ts.map +1 -0
- package/dist/sillytavern-importer/prompt-order.js +38 -0
- package/dist/sillytavern-importer/prompt-order.js.map +1 -0
- package/dist/sillytavern-importer/regex.d.ts +3 -0
- package/dist/sillytavern-importer/regex.d.ts.map +1 -0
- package/dist/sillytavern-importer/regex.js +275 -0
- package/dist/sillytavern-importer/regex.js.map +1 -0
- package/dist/sillytavern-importer/report.d.ts +21 -0
- package/dist/sillytavern-importer/report.d.ts.map +1 -0
- package/dist/sillytavern-importer/report.js +166 -0
- package/dist/sillytavern-importer/report.js.map +1 -0
- package/dist/sillytavern-importer/types.d.ts +106 -0
- package/dist/sillytavern-importer/types.d.ts.map +1 -0
- package/dist/sillytavern-importer/types.js +2 -0
- package/dist/sillytavern-importer/types.js.map +1 -0
- package/dist/sillytavern-importer.d.ts +5 -0
- package/dist/sillytavern-importer.d.ts.map +1 -0
- package/dist/sillytavern-importer.js +117 -0
- package/dist/sillytavern-importer.js.map +1 -0
- package/dist/slot-renderers.d.ts +25 -0
- package/dist/slot-renderers.d.ts.map +1 -0
- package/dist/slot-renderers.js +334 -0
- package/dist/slot-renderers.js.map +1 -0
- package/dist/stack-migration.d.ts +29 -0
- package/dist/stack-migration.d.ts.map +1 -0
- package/dist/stack-migration.js +126 -0
- package/dist/stack-migration.js.map +1 -0
- package/dist/storage.d.ts +6 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +23 -0
- package/dist/storage.js.map +1 -0
- package/dist/types.d.ts +173 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/web-editor/index.d.ts +3 -0
- package/dist/web-editor/index.d.ts.map +1 -0
- package/dist/web-editor/index.js +2 -0
- package/dist/web-editor/index.js.map +1 -0
- package/dist/web-editor/page.d.ts +2 -0
- package/dist/web-editor/page.d.ts.map +1 -0
- package/dist/web-editor/page.js +3331 -0
- package/dist/web-editor/page.js.map +1 -0
- package/dist/web-editor/server.d.ts +4 -0
- package/dist/web-editor/server.d.ts.map +1 -0
- package/dist/web-editor/server.js +263 -0
- package/dist/web-editor/server.js.map +1 -0
- package/dist/web-editor/types.d.ts +125 -0
- package/dist/web-editor/types.d.ts.map +1 -0
- package/dist/web-editor/types.js +2 -0
- package/dist/web-editor/types.js.map +1 -0
- package/dist/web-host.d.ts +29 -0
- package/dist/web-host.d.ts.map +1 -0
- package/dist/web-host.js +174 -0
- package/dist/web-host.js.map +1 -0
- package/examples/custom-system-status-extension/README.md +78 -0
- package/examples/custom-system-status-extension/index.ts +176 -0
- package/examples/custom-system-status-extension/prompt-stack.json +39 -0
- package/examples/default-prompt-stack.json +52 -93
- package/examples/image-reader-prompt-stack.json +124 -0
- package/examples/reviewer-prompt-stack.json +115 -0
- package/examples/sillytavern-dm-writer-prompt-stack.json +190 -0
- package/package.json +30 -9
- package/src/compiler.ts +321 -420
- package/src/extension-registry.ts +33 -0
- package/src/index.ts +310 -1110
- package/src/lifecycle.ts +171 -0
- package/src/loader.ts +141 -56
- package/src/macro-engine.ts +358 -0
- package/src/payload-capture.ts +85 -0
- package/src/payload-command.ts +138 -0
- package/src/policy.ts +42 -0
- package/src/preset-command.ts +271 -0
- package/src/preview.ts +226 -0
- package/src/regex.ts +500 -0
- package/src/render-helpers.ts +169 -0
- package/src/runtime-state.ts +36 -0
- package/src/sillytavern-importer/items.ts +98 -0
- package/src/sillytavern-importer/macros.ts +159 -0
- package/src/sillytavern-importer/prompt-order.ts +54 -0
- package/src/sillytavern-importer/regex.ts +270 -0
- package/src/sillytavern-importer/report.ts +202 -0
- package/src/sillytavern-importer/types.ts +120 -0
- package/src/sillytavern-importer.ts +57 -482
- package/src/slot-renderers.ts +414 -0
- package/src/stack-migration.ts +159 -0
- package/src/storage.ts +28 -0
- package/src/types.ts +83 -52
- package/src/web-editor/index.ts +2 -0
- package/src/web-editor/page.ts +3330 -0
- package/src/web-editor/server.ts +294 -0
- package/src/web-editor/types.ts +98 -0
- package/src/web-host.ts +232 -0
- package/src/web-editor.ts +0 -1491
package/src/compiler.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AgentMessage } from "@earendil-works/pi-agent-core";
|
|
2
2
|
import type {
|
|
3
|
+
CompileMessageSource,
|
|
3
4
|
CompileMessagesResult,
|
|
4
5
|
CompileSystemPromptResult,
|
|
5
6
|
PromptRuntime,
|
|
@@ -8,11 +9,12 @@ import type {
|
|
|
8
9
|
PromptStackItem,
|
|
9
10
|
PromptStackRole,
|
|
10
11
|
PromptStackSlotItem,
|
|
11
|
-
|
|
12
|
-
PromptStateValue,
|
|
12
|
+
PromptVariableValue,
|
|
13
13
|
PromptVariableStore,
|
|
14
14
|
} from "./types.ts";
|
|
15
|
-
import {
|
|
15
|
+
import { applyRegexRulesToMessages, applyRegexRulesToString } from "./regex.ts";
|
|
16
|
+
import { expandMacros } from "./macro-engine.ts";
|
|
17
|
+
import { renderSlotText } from "./slot-renderers.ts";
|
|
16
18
|
|
|
17
19
|
const ZERO_USAGE = {
|
|
18
20
|
input: 0,
|
|
@@ -23,7 +25,9 @@ const ZERO_USAGE = {
|
|
|
23
25
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
24
26
|
};
|
|
25
27
|
|
|
26
|
-
|
|
28
|
+
const SUMMARY_ROLES = new Set(["branchSummary", "compactionSummary"]);
|
|
29
|
+
|
|
30
|
+
export function createPromptVariableStore(sessionVariables: Record<string, PromptVariableValue> = {}): PromptVariableStore {
|
|
27
31
|
return { turn: {}, session: { ...sessionVariables }, sessionDirty: false };
|
|
28
32
|
}
|
|
29
33
|
|
|
@@ -65,20 +69,20 @@ export function compileSystemPrompt(
|
|
|
65
69
|
const compiled = parts.join("\n\n");
|
|
66
70
|
const mode = stack.mode ?? "replace";
|
|
67
71
|
|
|
72
|
+
let systemPrompt: string;
|
|
68
73
|
if (!compiled) {
|
|
69
74
|
diagnostics.push({ level: "warning", message: "Compiled system prompt is empty; preserving base system prompt." });
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (mode === "
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (mode === "prepend") {
|
|
78
|
-
return { systemPrompt: compiled ? `${compiled}\n\n${baseSystemPrompt}` : baseSystemPrompt, diagnostics };
|
|
75
|
+
systemPrompt = baseSystemPrompt;
|
|
76
|
+
} else if (mode === "append") {
|
|
77
|
+
systemPrompt = compiled ? `${baseSystemPrompt}\n\n${compiled}` : baseSystemPrompt;
|
|
78
|
+
} else if (mode === "prepend") {
|
|
79
|
+
systemPrompt = compiled ? `${compiled}\n\n${baseSystemPrompt}` : baseSystemPrompt;
|
|
80
|
+
} else {
|
|
81
|
+
systemPrompt = compiled;
|
|
79
82
|
}
|
|
80
83
|
|
|
81
|
-
|
|
84
|
+
systemPrompt = applyRegexRulesToString(stack, systemPrompt, "compiled", "system", diagnostics);
|
|
85
|
+
return { systemPrompt, diagnostics };
|
|
82
86
|
}
|
|
83
87
|
|
|
84
88
|
export function compileMessages(
|
|
@@ -87,7 +91,8 @@ export function compileMessages(
|
|
|
87
91
|
originalMessages: AgentMessage[],
|
|
88
92
|
): CompileMessagesResult {
|
|
89
93
|
const diagnostics: PromptStackDiagnostic[] = [];
|
|
90
|
-
|
|
94
|
+
let messages: AgentMessage[] = [];
|
|
95
|
+
let messageSources: CompileMessageSource[] = [];
|
|
91
96
|
let insertedHistory = false;
|
|
92
97
|
|
|
93
98
|
for (const item of enabledItems(stack)) {
|
|
@@ -100,7 +105,10 @@ export function compileMessages(
|
|
|
100
105
|
});
|
|
101
106
|
continue;
|
|
102
107
|
}
|
|
103
|
-
|
|
108
|
+
const historyMessages = getChatHistoryMessages(originalMessages, item, diagnostics);
|
|
109
|
+
const transformedHistory = applyRegexRulesToMessages(stack, historyMessages, "history", diagnostics);
|
|
110
|
+
messages.push(...transformedHistory);
|
|
111
|
+
messageSources.push(...chatHistoryMessageSources(transformedHistory, item));
|
|
104
112
|
insertedHistory = true;
|
|
105
113
|
continue;
|
|
106
114
|
}
|
|
@@ -112,14 +120,18 @@ export function compileMessages(
|
|
|
112
120
|
: renderSlotText(item, stack, runtime, diagnostics);
|
|
113
121
|
|
|
114
122
|
if (!content.trim()) continue;
|
|
115
|
-
|
|
123
|
+
const message = createSyntheticMessage(item.role, content, stack, runtime);
|
|
124
|
+
messages.push(message);
|
|
125
|
+
messageSources.push(stackItemMessageSource(message, item));
|
|
116
126
|
}
|
|
117
127
|
|
|
118
128
|
if (!insertedHistory) {
|
|
119
129
|
messages.push(...originalMessages);
|
|
130
|
+
messageSources.push(...implicitHistoryMessageSources(originalMessages));
|
|
120
131
|
}
|
|
121
132
|
|
|
122
|
-
|
|
133
|
+
messages = applyRegexRulesToMessages(stack, messages, "compiled", diagnostics);
|
|
134
|
+
return { messages, messageSources, diagnostics };
|
|
123
135
|
}
|
|
124
136
|
|
|
125
137
|
export function getLatestUserMessage(messages: AgentMessage[]): string | undefined {
|
|
@@ -133,470 +145,382 @@ export function getLatestUserMessage(messages: AgentMessage[]): string | undefin
|
|
|
133
145
|
return undefined;
|
|
134
146
|
}
|
|
135
147
|
|
|
136
|
-
export function
|
|
137
|
-
let text =
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
text +=
|
|
142
|
-
if (role === "bashExecution") {
|
|
143
|
-
const bash = message as { command?: string; output?: string };
|
|
144
|
-
text += `Ran ${bash.command ?? ""}\n${bash.output ?? ""}`;
|
|
145
|
-
}
|
|
146
|
-
if (role === "branchSummary" || role === "compactionSummary") {
|
|
147
|
-
text += (message as { summary?: string }).summary ?? "";
|
|
148
|
-
}
|
|
149
|
-
text += "\n";
|
|
150
|
-
if (text.length > maxChars) return `${text.slice(0, maxChars)}\n\n[preview truncated]`;
|
|
148
|
+
export function agentMessageToPreviewText(message: AgentMessage): string {
|
|
149
|
+
let text = contentToText((message as { content?: unknown; summary?: string; command?: string; output?: string }).content);
|
|
150
|
+
const role = message.role;
|
|
151
|
+
if (role === "bashExecution") {
|
|
152
|
+
const bash = message as { command?: string; output?: string };
|
|
153
|
+
text += `Ran ${bash.command ?? ""}\n${bash.output ?? ""}`;
|
|
151
154
|
}
|
|
152
|
-
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
function getChatHistoryMessages(messages: AgentMessage[], item: PromptStackSlotItem): AgentMessage[] {
|
|
156
|
-
if (item.options?.includeLastUserMessage !== false) return messages;
|
|
157
|
-
|
|
158
|
-
const lastUserIndex = findLastUserMessageIndex(messages);
|
|
159
|
-
if (lastUserIndex === -1) return messages;
|
|
160
|
-
|
|
161
|
-
return messages.filter((_message, index) => index !== lastUserIndex);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
function findLastUserMessageIndex(messages: AgentMessage[]): number {
|
|
165
|
-
for (let i = messages.length - 1; i >= 0; i--) {
|
|
166
|
-
if (messages[i].role === "user") return i;
|
|
155
|
+
if (role === "branchSummary" || role === "compactionSummary") {
|
|
156
|
+
text += (message as { summary?: string }).summary ?? "";
|
|
167
157
|
}
|
|
168
|
-
return
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
function enabledItems(stack: PromptStack): PromptStackItem[] {
|
|
172
|
-
return stack.items.filter((item) => item.enabled !== false);
|
|
158
|
+
return text;
|
|
173
159
|
}
|
|
174
160
|
|
|
175
|
-
function
|
|
161
|
+
function getChatHistoryMessages(
|
|
162
|
+
messages: AgentMessage[],
|
|
176
163
|
item: PromptStackSlotItem,
|
|
177
|
-
stack: PromptStack,
|
|
178
|
-
runtime: PromptRuntime,
|
|
179
164
|
diagnostics: PromptStackDiagnostic[],
|
|
180
|
-
):
|
|
181
|
-
|
|
165
|
+
): AgentMessage[] {
|
|
166
|
+
let result = messages;
|
|
167
|
+
const options = item.options ?? {};
|
|
168
|
+
let shouldRepairToolPairs = false;
|
|
182
169
|
|
|
183
|
-
if (
|
|
184
|
-
|
|
185
|
-
|
|
170
|
+
if (options.includeLastUserMessage === false) {
|
|
171
|
+
const lastUserIndex = findLastUserMessageIndex(result);
|
|
172
|
+
if (lastUserIndex !== -1) result = result.filter((_message, index) => index !== lastUserIndex);
|
|
186
173
|
}
|
|
187
174
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
return renderToolGuidelines(runtime);
|
|
193
|
-
case "skills":
|
|
194
|
-
return renderSkills(runtime);
|
|
195
|
-
case "project-context":
|
|
196
|
-
return renderProjectContext(runtime);
|
|
197
|
-
case "append-system-prompt":
|
|
198
|
-
return runtime.options.appendSystemPrompt ?? "";
|
|
199
|
-
case "date":
|
|
200
|
-
return `Current date: ${formatDate(runtime.now)}`;
|
|
201
|
-
case "cwd":
|
|
202
|
-
return `Current working directory: ${runtime.options.cwd.replace(/\\/g, "/")}`;
|
|
203
|
-
case "date-cwd":
|
|
204
|
-
return [`Current date: ${formatDate(runtime.now)}`, `Current working directory: ${runtime.options.cwd.replace(/\\/g, "/")}`].join("\n");
|
|
205
|
-
case "active-model": {
|
|
206
|
-
const model = runtime.ctx?.model;
|
|
207
|
-
return model ? `Current model: ${model.provider}/${model.id}` : "Current model: (none)";
|
|
208
|
-
}
|
|
209
|
-
case "pi-docs":
|
|
210
|
-
return renderPiDocsGuidance();
|
|
211
|
-
case "variables":
|
|
212
|
-
return renderVariables(item, stack, runtime);
|
|
213
|
-
case "chat-history":
|
|
214
|
-
return "";
|
|
215
|
-
default:
|
|
216
|
-
return "";
|
|
175
|
+
if (options.includeSummaries === false) {
|
|
176
|
+
const next = result.filter((message) => !isSummaryMessage(message));
|
|
177
|
+
addHistoryFilterDiagnostic(diagnostics, item.id, "summary", result.length, next.length);
|
|
178
|
+
result = next;
|
|
217
179
|
}
|
|
218
|
-
}
|
|
219
180
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
181
|
+
if (isStringArray(options.roles) && options.roles.length > 0) {
|
|
182
|
+
const allowedRoles = new Set(options.roles);
|
|
183
|
+
const next = result.filter((message) => allowedRoles.has(messageRole(message)));
|
|
184
|
+
addHistoryFilterDiagnostic(diagnostics, item.id, "role", result.length, next.length);
|
|
185
|
+
result = next;
|
|
186
|
+
shouldRepairToolPairs = true;
|
|
187
|
+
}
|
|
224
188
|
|
|
225
|
-
if (
|
|
226
|
-
|
|
227
|
-
} else {
|
|
228
|
-
|
|
229
|
-
const snippet = snippets[name] ?? "No prompt snippet provided.";
|
|
230
|
-
lines.push(` <tool name=\"${escapeXml(name)}\">${escapeXml(snippet)}</tool>`);
|
|
231
|
-
}
|
|
189
|
+
if (options.toolMode === "drop") {
|
|
190
|
+
result = dropToolHistory(result, diagnostics, item.id);
|
|
191
|
+
} else if (options.toolMode !== undefined && options.toolMode !== "keep") {
|
|
192
|
+
diagnostics.push({ level: "warning", message: `Unsupported chat-history toolMode: ${String(options.toolMode)}.`, itemId: item.id });
|
|
232
193
|
}
|
|
233
194
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
}
|
|
195
|
+
if (options.stripAssistantThinking === true) {
|
|
196
|
+
result = stripAssistantThinkingFromHistory(result, diagnostics, item.id);
|
|
197
|
+
}
|
|
237
198
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
const normalized = line.trim();
|
|
244
|
-
if (!normalized || seen.has(normalized)) return;
|
|
245
|
-
seen.add(normalized);
|
|
246
|
-
guidelines.push(normalized);
|
|
247
|
-
};
|
|
199
|
+
const limited = limitChatHistory(result, options, diagnostics, item.id);
|
|
200
|
+
if (limited !== result) {
|
|
201
|
+
result = limited;
|
|
202
|
+
shouldRepairToolPairs = true;
|
|
203
|
+
}
|
|
248
204
|
|
|
249
|
-
if (
|
|
250
|
-
|
|
205
|
+
if (shouldRepairToolPairs && options.toolMode !== "drop") {
|
|
206
|
+
result = repairToolHistory(result, diagnostics, item.id);
|
|
251
207
|
}
|
|
252
208
|
|
|
253
|
-
|
|
209
|
+
return result;
|
|
210
|
+
}
|
|
254
211
|
|
|
255
|
-
|
|
256
|
-
|
|
212
|
+
function findLastUserMessageIndex(messages: AgentMessage[]): number {
|
|
213
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
214
|
+
if (messages[i].role === "user") return i;
|
|
215
|
+
}
|
|
216
|
+
return -1;
|
|
257
217
|
}
|
|
258
218
|
|
|
259
|
-
function
|
|
260
|
-
|
|
261
|
-
|
|
219
|
+
function limitChatHistory(
|
|
220
|
+
messages: AgentMessage[],
|
|
221
|
+
options: NonNullable<PromptStackSlotItem["options"]>,
|
|
222
|
+
diagnostics: PromptStackDiagnostic[],
|
|
223
|
+
itemId: string,
|
|
224
|
+
): AgentMessage[] {
|
|
225
|
+
let result = messages;
|
|
226
|
+
const maxMessages = positiveIntegerOption(options.maxMessages);
|
|
227
|
+
const maxChars = positiveIntegerOption(options.maxChars);
|
|
262
228
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
229
|
+
if (maxMessages !== undefined && result.length > maxMessages) {
|
|
230
|
+
const next = result.slice(-maxMessages);
|
|
231
|
+
diagnostics.push({
|
|
232
|
+
level: "info",
|
|
233
|
+
message: `Trimmed chat history from ${result.length} to ${next.length} message(s) by maxMessages.`,
|
|
234
|
+
itemId,
|
|
235
|
+
});
|
|
236
|
+
result = next;
|
|
237
|
+
}
|
|
270
238
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
239
|
+
if (maxChars !== undefined) {
|
|
240
|
+
const next = takeRecentMessagesWithinChars(result, maxChars);
|
|
241
|
+
if (next.length < result.length) {
|
|
242
|
+
diagnostics.push({
|
|
243
|
+
level: "info",
|
|
244
|
+
message: `Trimmed chat history from ${result.length} to ${next.length} message(s) by maxChars.`,
|
|
245
|
+
itemId,
|
|
246
|
+
});
|
|
247
|
+
result = next;
|
|
248
|
+
}
|
|
277
249
|
}
|
|
278
250
|
|
|
279
|
-
|
|
280
|
-
return lines.join("\n");
|
|
251
|
+
return result;
|
|
281
252
|
}
|
|
282
253
|
|
|
283
|
-
function
|
|
284
|
-
const
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
254
|
+
function takeRecentMessagesWithinChars(messages: AgentMessage[], maxChars: number): AgentMessage[] {
|
|
255
|
+
const selected: AgentMessage[] = [];
|
|
256
|
+
let chars = 0;
|
|
257
|
+
for (let index = messages.length - 1; index >= 0; index--) {
|
|
258
|
+
const message = messages[index];
|
|
259
|
+
const messageChars = agentMessageToPreviewText(message).length;
|
|
260
|
+
if (selected.length > 0 && chars + messageChars > maxChars) break;
|
|
261
|
+
selected.push(message);
|
|
262
|
+
chars += messageChars;
|
|
292
263
|
}
|
|
293
|
-
|
|
294
|
-
return lines.join("\n");
|
|
264
|
+
return selected.reverse();
|
|
295
265
|
}
|
|
296
266
|
|
|
297
|
-
function
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
267
|
+
function addHistoryFilterDiagnostic(
|
|
268
|
+
diagnostics: PromptStackDiagnostic[],
|
|
269
|
+
itemId: string,
|
|
270
|
+
filter: string,
|
|
271
|
+
before: number,
|
|
272
|
+
after: number,
|
|
273
|
+
): void {
|
|
274
|
+
if (before === after) return;
|
|
275
|
+
diagnostics.push({
|
|
276
|
+
level: "info",
|
|
277
|
+
message: `Filtered ${before - after} chat-history message(s) by ${filter}.`,
|
|
278
|
+
itemId,
|
|
279
|
+
});
|
|
303
280
|
}
|
|
304
281
|
|
|
305
|
-
function
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
):
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
const
|
|
315
|
-
const excludeNamespaces = normalizeStringArray(options.excludeNamespaces);
|
|
316
|
-
const maxValueChars = typeof options.maxValueChars === "number" && Number.isFinite(options.maxValueChars) && options.maxValueChars > 0
|
|
317
|
-
? Math.floor(options.maxValueChars)
|
|
318
|
-
: undefined;
|
|
319
|
-
const store = runtime.variables;
|
|
320
|
-
const grouped: Record<PromptStateScope, Record<string, PromptStateValue>> = {
|
|
321
|
-
static: {},
|
|
322
|
-
session: {},
|
|
323
|
-
turn: {},
|
|
324
|
-
};
|
|
282
|
+
function dropToolHistory(
|
|
283
|
+
messages: AgentMessage[],
|
|
284
|
+
diagnostics: PromptStackDiagnostic[],
|
|
285
|
+
itemId: string,
|
|
286
|
+
): AgentMessage[] {
|
|
287
|
+
let removedToolCalls = 0;
|
|
288
|
+
let droppedToolResults = 0;
|
|
289
|
+
let droppedEmptyMessages = 0;
|
|
290
|
+
let changed = false;
|
|
291
|
+
const result: AgentMessage[] = [];
|
|
325
292
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
293
|
+
for (const message of messages) {
|
|
294
|
+
if (isToolResultMessage(message)) {
|
|
295
|
+
droppedToolResults++;
|
|
296
|
+
changed = true;
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
const stripped = stripToolCallParts(message, () => false);
|
|
300
|
+
removedToolCalls += stripped.removedCalls;
|
|
301
|
+
if (stripped.message !== message) changed = true;
|
|
302
|
+
if (!stripped.message) {
|
|
303
|
+
droppedEmptyMessages++;
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
result.push(stripped.message);
|
|
334
307
|
}
|
|
335
308
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
)
|
|
309
|
+
if (!changed) return messages;
|
|
310
|
+
diagnostics.push({
|
|
311
|
+
level: "info",
|
|
312
|
+
message: `Dropped tool history from chat-history: removed ${removedToolCalls} tool call(s), dropped ${droppedToolResults} tool result message(s)` +
|
|
313
|
+
(droppedEmptyMessages > 0 ? `, and dropped ${droppedEmptyMessages} empty message(s).` : "."),
|
|
314
|
+
itemId,
|
|
315
|
+
});
|
|
316
|
+
return result;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function repairToolHistory(
|
|
320
|
+
messages: AgentMessage[],
|
|
321
|
+
diagnostics: PromptStackDiagnostic[],
|
|
322
|
+
itemId: string,
|
|
323
|
+
): AgentMessage[] {
|
|
324
|
+
const includedCallIds = new Set<string>();
|
|
325
|
+
const includedResultIds = new Set<string>();
|
|
326
|
+
for (const message of messages) {
|
|
327
|
+
for (const id of toolCallIdsForMessage(message)) includedCallIds.add(id);
|
|
328
|
+
const resultId = toolResultMessageId(message);
|
|
329
|
+
if (resultId) includedResultIds.add(resultId);
|
|
340
330
|
}
|
|
341
331
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
332
|
+
let removedToolCalls = 0;
|
|
333
|
+
let droppedToolResults = 0;
|
|
334
|
+
let droppedEmptyMessages = 0;
|
|
335
|
+
let changed = false;
|
|
336
|
+
const result: AgentMessage[] = [];
|
|
337
|
+
|
|
338
|
+
for (const message of messages) {
|
|
339
|
+
if (isToolResultMessage(message)) {
|
|
340
|
+
const resultId = toolResultMessageId(message);
|
|
341
|
+
if (!resultId || !includedCallIds.has(resultId)) {
|
|
342
|
+
droppedToolResults++;
|
|
343
|
+
changed = true;
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
346
|
+
result.push(message);
|
|
347
|
+
continue;
|
|
357
348
|
}
|
|
358
|
-
return `<prompt_state format=\"json\">\n${escapeXml(JSON.stringify(payload, null, 2))}\n</prompt_state>`;
|
|
359
|
-
}
|
|
360
349
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
for (const [name, value] of entries) {
|
|
368
|
-
const metadata = includeMetadata ? metadataForVariable(stack, name) : {};
|
|
369
|
-
const attrs = [
|
|
370
|
-
`name=\"${escapeXml(name)}\"`,
|
|
371
|
-
`type=\"${escapeXml(metadata.type ?? inferStateValueType(value))}\"`,
|
|
372
|
-
];
|
|
373
|
-
if (metadata.description) attrs.push(`description=\"${escapeXml(metadata.description)}\"`);
|
|
374
|
-
if (metadata.agentWritable !== undefined) attrs.push(`agentWritable=\"${metadata.agentWritable ? "true" : "false"}\"`);
|
|
375
|
-
if (metadata.userWritable !== undefined) attrs.push(`userWritable=\"${metadata.userWritable ? "true" : "false"}\"`);
|
|
376
|
-
parts.push(` <var ${attrs.join(" ")}>${escapeXml(truncateValue(stateValueToPromptText(value), maxValueChars))}</var>`);
|
|
350
|
+
const stripped = stripToolCallParts(message, (id) => !!id && includedResultIds.has(id));
|
|
351
|
+
removedToolCalls += stripped.removedCalls;
|
|
352
|
+
if (stripped.message !== message) changed = true;
|
|
353
|
+
if (!stripped.message) {
|
|
354
|
+
droppedEmptyMessages++;
|
|
355
|
+
continue;
|
|
377
356
|
}
|
|
378
|
-
|
|
357
|
+
result.push(stripped.message);
|
|
379
358
|
}
|
|
380
359
|
|
|
381
|
-
|
|
382
|
-
|
|
360
|
+
if (!changed) return messages;
|
|
361
|
+
diagnostics.push({
|
|
362
|
+
level: "info",
|
|
363
|
+
message: `Repaired tool history after chat-history filtering: removed ${removedToolCalls} dangling tool call(s), dropped ${droppedToolResults} dangling tool result message(s)` +
|
|
364
|
+
(droppedEmptyMessages > 0 ? `, and dropped ${droppedEmptyMessages} empty message(s).` : "."),
|
|
365
|
+
itemId,
|
|
366
|
+
});
|
|
367
|
+
return result;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
function stripToolCallParts(
|
|
371
|
+
message: AgentMessage,
|
|
372
|
+
keep: (id: string | undefined) => boolean,
|
|
373
|
+
): { message?: AgentMessage; removedCalls: number } {
|
|
374
|
+
const content = (message as { content?: unknown }).content;
|
|
375
|
+
if (!Array.isArray(content)) return { message, removedCalls: 0 };
|
|
376
|
+
|
|
377
|
+
const nextContent = content.filter((part) => !isToolCallContent(part) || keep(toolCallPartId(part)));
|
|
378
|
+
const removedCalls = content.length - nextContent.length;
|
|
379
|
+
if (removedCalls === 0) return { message, removedCalls: 0 };
|
|
380
|
+
if (nextContent.length === 0) return { removedCalls };
|
|
381
|
+
return { message: { ...message, content: nextContent } as AgentMessage, removedCalls };
|
|
383
382
|
}
|
|
384
383
|
|
|
385
|
-
function
|
|
386
|
-
const
|
|
387
|
-
if (
|
|
384
|
+
function toolCallIdsForMessage(message: AgentMessage): string[] {
|
|
385
|
+
const content = (message as { content?: unknown }).content;
|
|
386
|
+
if (!Array.isArray(content)) return [];
|
|
387
|
+
return content
|
|
388
|
+
.map((part) => toolCallPartId(part))
|
|
389
|
+
.filter((id): id is string => !!id);
|
|
390
|
+
}
|
|
388
391
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
if (options.includeSession !== false) scopes.add("session");
|
|
392
|
-
if (options.includeTurn !== false) scopes.add("turn");
|
|
393
|
-
return scopes;
|
|
392
|
+
function isToolCallContent(value: unknown): boolean {
|
|
393
|
+
return isPlainObject(value) && value.type === "toolCall";
|
|
394
394
|
}
|
|
395
395
|
|
|
396
|
-
function
|
|
397
|
-
return
|
|
398
|
-
|
|
399
|
-
...(stack.variables ?? {}),
|
|
400
|
-
};
|
|
396
|
+
function toolCallPartId(value: unknown): string | undefined {
|
|
397
|
+
if (!isPlainObject(value)) return undefined;
|
|
398
|
+
return firstString(value.id, value.toolCallId, value.callId);
|
|
401
399
|
}
|
|
402
400
|
|
|
403
|
-
function
|
|
404
|
-
|
|
405
|
-
for (const [name, definition] of Object.entries(stack.state?.definitions ?? {})) {
|
|
406
|
-
if ((definition.scope ?? "session") !== scope) continue;
|
|
407
|
-
if (definition.default !== undefined) values[name] = definition.default;
|
|
408
|
-
}
|
|
409
|
-
return values;
|
|
401
|
+
function isToolResultMessage(message: AgentMessage): boolean {
|
|
402
|
+
return messageRole(message) === "toolResult";
|
|
410
403
|
}
|
|
411
404
|
|
|
412
|
-
function
|
|
413
|
-
if (
|
|
414
|
-
|
|
415
|
-
return
|
|
405
|
+
function toolResultMessageId(message: AgentMessage): string | undefined {
|
|
406
|
+
if (!isToolResultMessage(message)) return undefined;
|
|
407
|
+
const raw = message as unknown as Record<string, unknown>;
|
|
408
|
+
return firstString(raw.toolCallId, raw.id, raw.callId);
|
|
416
409
|
}
|
|
417
410
|
|
|
418
|
-
function
|
|
419
|
-
|
|
420
|
-
if (pattern.endsWith("*")) return name.startsWith(pattern.slice(0, -1));
|
|
421
|
-
return name === pattern;
|
|
411
|
+
function isSummaryMessage(message: AgentMessage): boolean {
|
|
412
|
+
return SUMMARY_ROLES.has(messageRole(message));
|
|
422
413
|
}
|
|
423
414
|
|
|
424
|
-
function
|
|
425
|
-
|
|
426
|
-
description?: string;
|
|
427
|
-
agentWritable?: boolean;
|
|
428
|
-
userWritable?: boolean;
|
|
429
|
-
} {
|
|
430
|
-
const definition = stack.state?.definitions?.[name];
|
|
431
|
-
if (!definition) return {};
|
|
432
|
-
return {
|
|
433
|
-
type: definition.type,
|
|
434
|
-
description: definition.description,
|
|
435
|
-
agentWritable: definition.agentWritable,
|
|
436
|
-
userWritable: definition.userWritable,
|
|
437
|
-
};
|
|
415
|
+
function messageRole(message: AgentMessage): string {
|
|
416
|
+
return String((message as { role?: unknown }).role ?? "");
|
|
438
417
|
}
|
|
439
418
|
|
|
440
|
-
function
|
|
441
|
-
return
|
|
419
|
+
function positiveIntegerOption(value: unknown): number | undefined {
|
|
420
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : undefined;
|
|
442
421
|
}
|
|
443
422
|
|
|
444
|
-
function
|
|
445
|
-
|
|
423
|
+
function firstString(...values: unknown[]): string | undefined {
|
|
424
|
+
for (const value of values) {
|
|
425
|
+
if (typeof value === "string" && value) return value;
|
|
426
|
+
}
|
|
427
|
+
return undefined;
|
|
446
428
|
}
|
|
447
429
|
|
|
448
|
-
function
|
|
449
|
-
|
|
450
|
-
if (Array.isArray(value)) return "array";
|
|
451
|
-
return typeof value;
|
|
430
|
+
function isStringArray(value: unknown): value is string[] {
|
|
431
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
452
432
|
}
|
|
453
433
|
|
|
454
|
-
function
|
|
455
|
-
|
|
456
|
-
return `${value.slice(0, maxChars)}\n[truncated]`;
|
|
434
|
+
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
435
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
457
436
|
}
|
|
458
437
|
|
|
459
|
-
function
|
|
460
|
-
|
|
461
|
-
|
|
438
|
+
function chatHistoryMessageSources(messages: AgentMessage[], item: PromptStackSlotItem): CompileMessageSource[] {
|
|
439
|
+
return messages.map((message, index) => ({
|
|
440
|
+
kind: "chat-history",
|
|
441
|
+
itemId: item.id,
|
|
442
|
+
itemName: item.name,
|
|
443
|
+
slot: item.slot,
|
|
444
|
+
historyIndex: index + 1,
|
|
445
|
+
historyCount: messages.length,
|
|
446
|
+
role: String((message as { role?: unknown }).role ?? ""),
|
|
447
|
+
}));
|
|
462
448
|
}
|
|
463
449
|
|
|
464
|
-
function
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
450
|
+
function implicitHistoryMessageSources(messages: AgentMessage[]): CompileMessageSource[] {
|
|
451
|
+
return messages.map((message, index) => ({
|
|
452
|
+
kind: "implicit-history",
|
|
453
|
+
itemName: "Conversation history",
|
|
454
|
+
slot: "chat-history",
|
|
455
|
+
historyIndex: index + 1,
|
|
456
|
+
historyCount: messages.length,
|
|
457
|
+
role: String((message as { role?: unknown }).role ?? ""),
|
|
458
|
+
}));
|
|
468
459
|
}
|
|
469
460
|
|
|
470
|
-
function
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
461
|
+
function stackItemMessageSource(message: AgentMessage, item: PromptStackItem): CompileMessageSource {
|
|
462
|
+
return {
|
|
463
|
+
kind: "stack-item",
|
|
464
|
+
itemId: item.id,
|
|
465
|
+
itemName: item.name,
|
|
466
|
+
role: String((message as { role?: unknown }).role ?? ""),
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
function stripAssistantThinkingFromHistory(
|
|
471
|
+
messages: AgentMessage[],
|
|
474
472
|
diagnostics: PromptStackDiagnostic[],
|
|
475
473
|
itemId: string,
|
|
476
|
-
):
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
const parts = expression.split("::");
|
|
483
|
-
const command = parts[0]?.trim();
|
|
484
|
-
|
|
485
|
-
if (!command) return full;
|
|
486
|
-
|
|
487
|
-
// SillyTavern-style mutable variables. By default, setvar is turn-scoped and returns empty text.
|
|
488
|
-
if (command === "setvar" || command === "setturnvar" || command === "setsessionvar") {
|
|
489
|
-
const scoped = command === "setvar" && (parts[1] === "turn" || parts[1] === "session");
|
|
490
|
-
const scope = command === "setsessionvar" || (scoped && parts[1] === "session") ? "session" : "turn";
|
|
491
|
-
const nameIndex = scoped ? 2 : 1;
|
|
492
|
-
const valueIndex = nameIndex + 1;
|
|
493
|
-
const name = parts[nameIndex]?.trim();
|
|
494
|
-
const value = parts.slice(valueIndex).join("::");
|
|
495
|
-
if (!name) {
|
|
496
|
-
unknown.add(expression);
|
|
497
|
-
return full;
|
|
498
|
-
}
|
|
499
|
-
setRuntimeVariable(runtime, scope, name, value);
|
|
500
|
-
return "";
|
|
501
|
-
}
|
|
474
|
+
): AgentMessage[] {
|
|
475
|
+
let strippedBlocks = 0;
|
|
476
|
+
let changedMessages = 0;
|
|
477
|
+
let droppedMessages = 0;
|
|
478
|
+
let changed = false;
|
|
479
|
+
const result: AgentMessage[] = [];
|
|
502
480
|
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
if (command === "getturnvar") return stateValueToMacroText(runtime.variables?.turn[name]);
|
|
510
|
-
if (command === "getsessionvar") return stateValueToMacroText(runtime.variables?.session[name]);
|
|
511
|
-
return stateValueToMacroText(getRuntimeVariable(runtime, stack, name));
|
|
481
|
+
for (const message of messages) {
|
|
482
|
+
const stripped = stripAssistantThinkingFromMessage(message);
|
|
483
|
+
if (stripped.message !== message) {
|
|
484
|
+
changed = true;
|
|
485
|
+
strippedBlocks += stripped.removedBlocks;
|
|
486
|
+
changedMessages++;
|
|
512
487
|
}
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
const scope = command === "clearsessionvar" || (scoped && parts[1] === "session") ? "session" : "turn";
|
|
517
|
-
const name = parts[scoped ? 2 : 1]?.trim();
|
|
518
|
-
if (!name) {
|
|
519
|
-
unknown.add(expression);
|
|
520
|
-
return full;
|
|
521
|
-
}
|
|
522
|
-
clearRuntimeVariable(runtime, scope, name);
|
|
523
|
-
return "";
|
|
488
|
+
if (!stripped.message) {
|
|
489
|
+
droppedMessages++;
|
|
490
|
+
continue;
|
|
524
491
|
}
|
|
492
|
+
result.push(stripped.message);
|
|
493
|
+
}
|
|
525
494
|
|
|
526
|
-
|
|
527
|
-
if (dynamicValue !== undefined) return dynamicValue;
|
|
528
|
-
|
|
529
|
-
const variableValue = getRuntimeVariable(runtime, stack, command);
|
|
530
|
-
if (variableValue !== undefined) return stateValueToMacroText(variableValue);
|
|
495
|
+
if (!changed) return messages;
|
|
531
496
|
|
|
532
|
-
|
|
533
|
-
|
|
497
|
+
diagnostics.push({
|
|
498
|
+
level: "info",
|
|
499
|
+
message: `Stripped ${strippedBlocks} assistant thinking block(s) from ${changedMessages} chat-history message(s)` +
|
|
500
|
+
(droppedMessages > 0 ? ` and dropped ${droppedMessages} empty assistant message(s).` : "."),
|
|
501
|
+
itemId,
|
|
534
502
|
});
|
|
535
|
-
|
|
536
|
-
for (const name of unknown) {
|
|
537
|
-
if (policy === "keep") continue;
|
|
538
|
-
diagnostics.push({
|
|
539
|
-
level: policy === "error" ? "error" : "warning",
|
|
540
|
-
message: `Unresolved macro: {{${name}}}`,
|
|
541
|
-
itemId,
|
|
542
|
-
});
|
|
543
|
-
}
|
|
544
|
-
|
|
545
503
|
return result;
|
|
546
504
|
}
|
|
547
505
|
|
|
548
|
-
function
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
case "date":
|
|
553
|
-
return formatDate(runtime.now);
|
|
554
|
-
case "time":
|
|
555
|
-
return formatTime(runtime.now);
|
|
556
|
-
case "lastUserMessage":
|
|
557
|
-
return runtime.latestUserMessage ?? "";
|
|
558
|
-
case "selectedTools":
|
|
559
|
-
case "tools":
|
|
560
|
-
return (runtime.options.selectedTools ?? []).join(", ");
|
|
561
|
-
case "activeModel": {
|
|
562
|
-
const model = runtime.ctx?.model;
|
|
563
|
-
return model ? `${model.provider}/${model.id}` : "";
|
|
564
|
-
}
|
|
565
|
-
default:
|
|
566
|
-
return undefined;
|
|
567
|
-
}
|
|
568
|
-
}
|
|
506
|
+
function stripAssistantThinkingFromMessage(message: AgentMessage): { message?: AgentMessage; removedBlocks: number } {
|
|
507
|
+
if (message.role !== "assistant") return { message, removedBlocks: 0 };
|
|
508
|
+
const content = (message as { content?: unknown }).content;
|
|
509
|
+
if (!Array.isArray(content)) return { message, removedBlocks: 0 };
|
|
569
510
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
if (
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
return undefined;
|
|
511
|
+
const nextContent = content.filter((part) => !isThinkingContent(part));
|
|
512
|
+
const removedBlocks = content.length - nextContent.length;
|
|
513
|
+
if (removedBlocks === 0) return { message, removedBlocks: 0 };
|
|
514
|
+
if (nextContent.length === 0) return { removedBlocks };
|
|
515
|
+
return { message: { ...message, content: nextContent } as AgentMessage, removedBlocks };
|
|
576
516
|
}
|
|
577
517
|
|
|
578
|
-
function
|
|
579
|
-
|
|
580
|
-
if (scope === "session") {
|
|
581
|
-
if (runtime.variables.session[name] !== value) {
|
|
582
|
-
runtime.variables.session[name] = value;
|
|
583
|
-
runtime.variables.sessionDirty = true;
|
|
584
|
-
}
|
|
585
|
-
return;
|
|
586
|
-
}
|
|
587
|
-
runtime.variables.turn[name] = value;
|
|
518
|
+
function isThinkingContent(value: unknown): boolean {
|
|
519
|
+
return !!value && typeof value === "object" && !Array.isArray(value) && (value as { type?: unknown }).type === "thinking";
|
|
588
520
|
}
|
|
589
521
|
|
|
590
|
-
function
|
|
591
|
-
|
|
592
|
-
if (scope === "session") {
|
|
593
|
-
if (Object.prototype.hasOwnProperty.call(runtime.variables.session, name)) {
|
|
594
|
-
delete runtime.variables.session[name];
|
|
595
|
-
runtime.variables.sessionDirty = true;
|
|
596
|
-
}
|
|
597
|
-
return;
|
|
598
|
-
}
|
|
599
|
-
delete runtime.variables.turn[name];
|
|
522
|
+
function enabledItems(stack: PromptStack): PromptStackItem[] {
|
|
523
|
+
return stack.items.filter((item) => item.enabled !== false);
|
|
600
524
|
}
|
|
601
525
|
|
|
602
526
|
function createSyntheticMessage(role: Exclude<PromptStackRole, "system">, content: string, stack: PromptStack, runtime: PromptRuntime): AgentMessage {
|
|
@@ -652,26 +576,3 @@ function contentToText(content: unknown): string {
|
|
|
652
576
|
.filter(Boolean)
|
|
653
577
|
.join("\n");
|
|
654
578
|
}
|
|
655
|
-
|
|
656
|
-
function formatDate(now: Date): string {
|
|
657
|
-
const year = now.getFullYear();
|
|
658
|
-
const month = String(now.getMonth() + 1).padStart(2, "0");
|
|
659
|
-
const day = String(now.getDate()).padStart(2, "0");
|
|
660
|
-
return `${year}-${month}-${day}`;
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
function formatTime(now: Date): string {
|
|
664
|
-
const hours = String(now.getHours()).padStart(2, "0");
|
|
665
|
-
const minutes = String(now.getMinutes()).padStart(2, "0");
|
|
666
|
-
const seconds = String(now.getSeconds()).padStart(2, "0");
|
|
667
|
-
return `${hours}:${minutes}:${seconds}`;
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
function escapeXml(value: string): string {
|
|
671
|
-
return value
|
|
672
|
-
.replace(/&/g, "&")
|
|
673
|
-
.replace(/</g, "<")
|
|
674
|
-
.replace(/>/g, ">")
|
|
675
|
-
.replace(/\"/g, """)
|
|
676
|
-
.replace(/'/g, "'");
|
|
677
|
-
}
|