@zihanw/pi-forge 0.3.2 → 0.4.0-beta.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.
Files changed (244) hide show
  1. package/CHANGELOG.md +160 -0
  2. package/PUBLIC_API.md +28 -0
  3. package/README.md +137 -11
  4. package/README.zh-CN.md +137 -11
  5. package/SUBAGENT_ADAPTER_CONTRACT.md +199 -0
  6. package/dist/agent-profile.d.ts +71 -0
  7. package/dist/agent-profile.d.ts.map +1 -0
  8. package/dist/agent-profile.js +303 -0
  9. package/dist/agent-profile.js.map +1 -0
  10. package/dist/forge-config.d.ts +8 -0
  11. package/dist/forge-config.d.ts.map +1 -0
  12. package/dist/forge-config.js +40 -0
  13. package/dist/forge-config.js.map +1 -0
  14. package/dist/forge-extensions.d.ts.map +1 -1
  15. package/dist/forge-extensions.js +19 -3
  16. package/dist/forge-extensions.js.map +1 -1
  17. package/dist/index.d.ts +7 -0
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +75 -361
  20. package/dist/index.js.map +1 -1
  21. package/dist/lifecycle.d.ts +11 -3
  22. package/dist/lifecycle.d.ts.map +1 -1
  23. package/dist/lifecycle.js +90 -4
  24. package/dist/lifecycle.js.map +1 -1
  25. package/dist/loader.d.ts.map +1 -1
  26. package/dist/loader.js +116 -5
  27. package/dist/loader.js.map +1 -1
  28. package/dist/payload-capture.d.ts.map +1 -1
  29. package/dist/payload-capture.js +27 -0
  30. package/dist/payload-capture.js.map +1 -1
  31. package/dist/payload-command.d.ts +3 -3
  32. package/dist/payload-command.d.ts.map +1 -1
  33. package/dist/payload-command.js.map +1 -1
  34. package/dist/preview.d.ts +2 -2
  35. package/dist/preview.d.ts.map +1 -1
  36. package/dist/preview.js +2 -3
  37. package/dist/preview.js.map +1 -1
  38. package/dist/profile-command.d.ts +12 -0
  39. package/dist/profile-command.d.ts.map +1 -0
  40. package/dist/profile-command.js +291 -0
  41. package/dist/profile-command.js.map +1 -0
  42. package/dist/profile-service.d.ts +103 -0
  43. package/dist/profile-service.d.ts.map +1 -0
  44. package/dist/profile-service.js +215 -0
  45. package/dist/profile-service.js.map +1 -0
  46. package/dist/runtime/profile-runtime.d.ts +13 -0
  47. package/dist/runtime/profile-runtime.d.ts.map +1 -0
  48. package/dist/runtime/profile-runtime.js +47 -0
  49. package/dist/runtime/profile-runtime.js.map +1 -0
  50. package/dist/runtime/prompt-stack-runtime.d.ts +22 -0
  51. package/dist/runtime/prompt-stack-runtime.d.ts.map +1 -0
  52. package/dist/runtime/prompt-stack-runtime.js +104 -0
  53. package/dist/runtime/prompt-stack-runtime.js.map +1 -0
  54. package/dist/runtime/subagent-runtime.d.ts +30 -0
  55. package/dist/runtime/subagent-runtime.d.ts.map +1 -0
  56. package/dist/runtime/subagent-runtime.js +114 -0
  57. package/dist/runtime/subagent-runtime.js.map +1 -0
  58. package/dist/runtime/tool-policy-runtime.d.ts +15 -0
  59. package/dist/runtime/tool-policy-runtime.d.ts.map +1 -0
  60. package/dist/runtime/tool-policy-runtime.js +170 -0
  61. package/dist/runtime/tool-policy-runtime.js.map +1 -0
  62. package/dist/runtime/web-editor-runtime.d.ts +9 -0
  63. package/dist/runtime/web-editor-runtime.d.ts.map +1 -0
  64. package/dist/runtime/web-editor-runtime.js +131 -0
  65. package/dist/runtime/web-editor-runtime.js.map +1 -0
  66. package/dist/runtime-state.d.ts +4 -0
  67. package/dist/runtime-state.d.ts.map +1 -1
  68. package/dist/runtime-state.js +2 -0
  69. package/dist/runtime-state.js.map +1 -1
  70. package/dist/storage.d.ts +3 -0
  71. package/dist/storage.d.ts.map +1 -1
  72. package/dist/storage.js +9 -0
  73. package/dist/storage.js.map +1 -1
  74. package/dist/subagent/backend-registry.d.ts +75 -0
  75. package/dist/subagent/backend-registry.d.ts.map +1 -0
  76. package/dist/subagent/backend-registry.js +463 -0
  77. package/dist/subagent/backend-registry.js.map +1 -0
  78. package/dist/subagent/canonical.d.ts +10 -0
  79. package/dist/subagent/canonical.d.ts.map +1 -0
  80. package/dist/subagent/canonical.js +52 -0
  81. package/dist/subagent/canonical.js.map +1 -0
  82. package/dist/subagent/context.d.ts +8 -0
  83. package/dist/subagent/context.d.ts.map +1 -0
  84. package/dist/subagent/context.js +125 -0
  85. package/dist/subagent/context.js.map +1 -0
  86. package/dist/subagent/contract.d.ts +11 -0
  87. package/dist/subagent/contract.d.ts.map +1 -0
  88. package/dist/subagent/contract.js +11 -0
  89. package/dist/subagent/contract.js.map +1 -0
  90. package/dist/subagent/diagnostics.d.ts +3 -0
  91. package/dist/subagent/diagnostics.d.ts.map +1 -0
  92. package/dist/subagent/diagnostics.js +5 -0
  93. package/dist/subagent/diagnostics.js.map +1 -0
  94. package/dist/subagent/index.d.ts +13 -0
  95. package/dist/subagent/index.d.ts.map +1 -0
  96. package/dist/subagent/index.js +13 -0
  97. package/dist/subagent/index.js.map +1 -0
  98. package/dist/subagent/pi-model-runtime.d.ts +8 -0
  99. package/dist/subagent/pi-model-runtime.d.ts.map +1 -0
  100. package/dist/subagent/pi-model-runtime.js +22 -0
  101. package/dist/subagent/pi-model-runtime.js.map +1 -0
  102. package/dist/subagent/pi-sdk-backend.d.ts +23 -0
  103. package/dist/subagent/pi-sdk-backend.d.ts.map +1 -0
  104. package/dist/subagent/pi-sdk-backend.js +383 -0
  105. package/dist/subagent/pi-sdk-backend.js.map +1 -0
  106. package/dist/subagent/pi-subprocess-backend.d.ts +72 -0
  107. package/dist/subagent/pi-subprocess-backend.d.ts.map +1 -0
  108. package/dist/subagent/pi-subprocess-backend.js +756 -0
  109. package/dist/subagent/pi-subprocess-backend.js.map +1 -0
  110. package/dist/subagent/plan.d.ts +14 -0
  111. package/dist/subagent/plan.d.ts.map +1 -0
  112. package/dist/subagent/plan.js +160 -0
  113. package/dist/subagent/plan.js.map +1 -0
  114. package/dist/subagent/preflight.d.ts +4 -0
  115. package/dist/subagent/preflight.d.ts.map +1 -0
  116. package/dist/subagent/preflight.js +108 -0
  117. package/dist/subagent/preflight.js.map +1 -0
  118. package/dist/subagent/request.d.ts +4 -0
  119. package/dist/subagent/request.d.ts.map +1 -0
  120. package/dist/subagent/request.js +122 -0
  121. package/dist/subagent/request.js.map +1 -0
  122. package/dist/subagent/response.d.ts +8 -0
  123. package/dist/subagent/response.d.ts.map +1 -0
  124. package/dist/subagent/response.js +155 -0
  125. package/dist/subagent/response.js.map +1 -0
  126. package/dist/subagent/subprocess-bridge.d.ts +21 -0
  127. package/dist/subagent/subprocess-bridge.d.ts.map +1 -0
  128. package/dist/subagent/subprocess-bridge.js +87 -0
  129. package/dist/subagent/subprocess-bridge.js.map +1 -0
  130. package/dist/subagent/subprocess-report.d.ts +4 -0
  131. package/dist/subagent/subprocess-report.d.ts.map +1 -0
  132. package/dist/subagent/subprocess-report.js +55 -0
  133. package/dist/subagent/subprocess-report.js.map +1 -0
  134. package/dist/subagent/tools.d.ts +4 -0
  135. package/dist/subagent/tools.d.ts.map +1 -0
  136. package/dist/subagent/tools.js +42 -0
  137. package/dist/subagent/tools.js.map +1 -0
  138. package/dist/subagent/types.d.ts +384 -0
  139. package/dist/subagent/types.d.ts.map +1 -0
  140. package/dist/subagent/types.js +3 -0
  141. package/dist/subagent/types.js.map +1 -0
  142. package/dist/subagent/validation.d.ts +35 -0
  143. package/dist/subagent/validation.d.ts.map +1 -0
  144. package/dist/subagent/validation.js +500 -0
  145. package/dist/subagent/validation.js.map +1 -0
  146. package/dist/subagent-command.d.ts +4 -0
  147. package/dist/subagent-command.d.ts.map +1 -0
  148. package/dist/subagent-command.js +153 -0
  149. package/dist/subagent-command.js.map +1 -0
  150. package/dist/subagent-contract.d.ts +8 -0
  151. package/dist/subagent-contract.d.ts.map +1 -0
  152. package/dist/subagent-contract.js +8 -0
  153. package/dist/subagent-contract.js.map +1 -0
  154. package/dist/subagent-host.d.ts +44 -0
  155. package/dist/subagent-host.d.ts.map +1 -0
  156. package/dist/subagent-host.js +291 -0
  157. package/dist/subagent-host.js.map +1 -0
  158. package/dist/subagent-profile-tool.d.ts +26 -0
  159. package/dist/subagent-profile-tool.d.ts.map +1 -0
  160. package/dist/subagent-profile-tool.js +93 -0
  161. package/dist/subagent-profile-tool.js.map +1 -0
  162. package/dist/subagent-tool.d.ts +50 -0
  163. package/dist/subagent-tool.d.ts.map +1 -0
  164. package/dist/subagent-tool.js +385 -0
  165. package/dist/subagent-tool.js.map +1 -0
  166. package/dist/web-editor/client/api.d.ts +9 -0
  167. package/dist/web-editor/client/api.d.ts.map +1 -0
  168. package/dist/web-editor/client/api.js +26 -0
  169. package/dist/web-editor/client/api.js.map +1 -0
  170. package/dist/web-editor/client/dom.d.ts +13 -0
  171. package/dist/web-editor/client/dom.d.ts.map +1 -0
  172. package/dist/web-editor/client/dom.js +30 -0
  173. package/dist/web-editor/client/dom.js.map +1 -0
  174. package/dist/web-editor/client/inspector.d.ts +22 -0
  175. package/dist/web-editor/client/inspector.d.ts.map +1 -0
  176. package/dist/web-editor/client/inspector.js +226 -0
  177. package/dist/web-editor/client/inspector.js.map +1 -0
  178. package/dist/web-editor/client/main.d.ts +2 -0
  179. package/dist/web-editor/client/main.d.ts.map +1 -0
  180. package/dist/web-editor/client/main.js +1468 -0
  181. package/dist/web-editor/client/main.js.map +1 -0
  182. package/dist/web-editor/client/policy-editor.d.ts +16 -0
  183. package/dist/web-editor/client/policy-editor.d.ts.map +1 -0
  184. package/dist/web-editor/client/policy-editor.js +330 -0
  185. package/dist/web-editor/client/policy-editor.js.map +1 -0
  186. package/dist/web-editor/client/regex-editor.d.ts +19 -0
  187. package/dist/web-editor/client/regex-editor.d.ts.map +1 -0
  188. package/dist/web-editor/client/regex-editor.js +281 -0
  189. package/dist/web-editor/client/regex-editor.js.map +1 -0
  190. package/dist/web-editor/client/types.d.ts +60 -0
  191. package/dist/web-editor/client/types.d.ts.map +1 -0
  192. package/dist/web-editor/client/types.js +2 -0
  193. package/dist/web-editor/client/types.js.map +1 -0
  194. package/dist/web-editor/client-script.d.ts +2 -0
  195. package/dist/web-editor/client-script.d.ts.map +1 -0
  196. package/dist/web-editor/client-script.generated.d.ts +2 -0
  197. package/dist/web-editor/client-script.generated.d.ts.map +1 -0
  198. package/dist/web-editor/client-script.generated.js +3 -0
  199. package/dist/web-editor/client-script.generated.js.map +1 -0
  200. package/dist/web-editor/client-script.js +2 -0
  201. package/dist/web-editor/client-script.js.map +1 -0
  202. package/dist/web-editor/page.d.ts.map +1 -1
  203. package/dist/web-editor/page.js +6 -3249
  204. package/dist/web-editor/page.js.map +1 -1
  205. package/dist/web-editor/styles.d.ts +2 -0
  206. package/dist/web-editor/styles.d.ts.map +1 -0
  207. package/dist/web-editor/styles.js +996 -0
  208. package/dist/web-editor/styles.js.map +1 -0
  209. package/dist/web-host.d.ts +3 -3
  210. package/dist/web-host.d.ts.map +1 -1
  211. package/dist/web-host.js +6 -0
  212. package/dist/web-host.js.map +1 -1
  213. package/package.json +42 -14
  214. package/src/compiler.ts +0 -578
  215. package/src/extension-registry.ts +0 -33
  216. package/src/forge-extensions.ts +0 -223
  217. package/src/index.ts +0 -445
  218. package/src/lifecycle.ts +0 -171
  219. package/src/loader.ts +0 -394
  220. package/src/macro-engine.ts +0 -358
  221. package/src/payload-capture.ts +0 -85
  222. package/src/payload-command.ts +0 -138
  223. package/src/policy.ts +0 -42
  224. package/src/preset-command.ts +0 -280
  225. package/src/preview.ts +0 -226
  226. package/src/regex.ts +0 -500
  227. package/src/render-helpers.ts +0 -169
  228. package/src/runtime-state.ts +0 -40
  229. package/src/sillytavern-importer/items.ts +0 -98
  230. package/src/sillytavern-importer/macros.ts +0 -159
  231. package/src/sillytavern-importer/prompt-order.ts +0 -54
  232. package/src/sillytavern-importer/regex.ts +0 -270
  233. package/src/sillytavern-importer/report.ts +0 -202
  234. package/src/sillytavern-importer/types.ts +0 -120
  235. package/src/sillytavern-importer.ts +0 -152
  236. package/src/slot-renderers.ts +0 -414
  237. package/src/stack-migration.ts +0 -159
  238. package/src/storage.ts +0 -45
  239. package/src/types.ts +0 -209
  240. package/src/web-editor/index.ts +0 -2
  241. package/src/web-editor/page.ts +0 -3330
  242. package/src/web-editor/server.ts +0 -294
  243. package/src/web-editor/types.ts +0 -98
  244. package/src/web-host.ts +0 -232
package/src/compiler.ts DELETED
@@ -1,578 +0,0 @@
1
- import type { AgentMessage } from "@earendil-works/pi-agent-core";
2
- import type {
3
- CompileMessageSource,
4
- CompileMessagesResult,
5
- CompileSystemPromptResult,
6
- PromptRuntime,
7
- PromptStack,
8
- PromptStackDiagnostic,
9
- PromptStackItem,
10
- PromptStackRole,
11
- PromptStackSlotItem,
12
- PromptVariableValue,
13
- PromptVariableStore,
14
- } from "./types.ts";
15
- import { applyRegexRulesToMessages, applyRegexRulesToString } from "./regex.ts";
16
- import { expandMacros } from "./macro-engine.ts";
17
- import { renderSlotText } from "./slot-renderers.ts";
18
-
19
- const ZERO_USAGE = {
20
- input: 0,
21
- output: 0,
22
- cacheRead: 0,
23
- cacheWrite: 0,
24
- totalTokens: 0,
25
- cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
26
- };
27
-
28
- const SUMMARY_ROLES = new Set(["branchSummary", "compactionSummary"]);
29
-
30
- export function createPromptVariableStore(sessionVariables: Record<string, PromptVariableValue> = {}): PromptVariableStore {
31
- return { turn: {}, session: { ...sessionVariables }, sessionDirty: false };
32
- }
33
-
34
- export function resetTurnVariables(store: PromptVariableStore): void {
35
- store.turn = {};
36
- store.sessionDirty = false;
37
- }
38
-
39
- export function markSessionVariablesClean(store: PromptVariableStore): void {
40
- store.sessionDirty = false;
41
- }
42
-
43
- export function compileSystemPrompt(
44
- stack: PromptStack,
45
- runtime: PromptRuntime,
46
- baseSystemPrompt: string,
47
- ): CompileSystemPromptResult {
48
- const diagnostics: PromptStackDiagnostic[] = [];
49
- const parts: string[] = [];
50
-
51
- for (const item of enabledItems(stack)) {
52
- if (item.role !== "system") continue;
53
-
54
- if (item.kind === "block") {
55
- const text = expandMacros(item.content, stack, runtime, diagnostics, item.id).trim();
56
- if (text) parts.push(text);
57
- continue;
58
- }
59
-
60
- if (item.slot === "chat-history") {
61
- diagnostics.push({ level: "warning", message: "chat-history slot cannot be placed in the system prompt.", itemId: item.id });
62
- continue;
63
- }
64
-
65
- const rendered = renderSlotText(item, stack, runtime, diagnostics).trim();
66
- if (rendered) parts.push(rendered);
67
- }
68
-
69
- const compiled = parts.join("\n\n");
70
- const mode = stack.mode ?? "replace";
71
-
72
- let systemPrompt: string;
73
- if (!compiled) {
74
- diagnostics.push({ level: "warning", message: "Compiled system prompt is empty; preserving base system prompt." });
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;
82
- }
83
-
84
- systemPrompt = applyRegexRulesToString(stack, systemPrompt, "compiled", "system", diagnostics);
85
- return { systemPrompt, diagnostics };
86
- }
87
-
88
- export function compileMessages(
89
- stack: PromptStack,
90
- runtime: PromptRuntime,
91
- originalMessages: AgentMessage[],
92
- ): CompileMessagesResult {
93
- const diagnostics: PromptStackDiagnostic[] = [];
94
- let messages: AgentMessage[] = [];
95
- let messageSources: CompileMessageSource[] = [];
96
- let insertedHistory = false;
97
-
98
- for (const item of enabledItems(stack)) {
99
- if (item.kind === "slot" && item.slot === "chat-history") {
100
- if (insertedHistory && !stack.context?.allowDuplicateChatHistory) {
101
- diagnostics.push({
102
- level: "warning",
103
- message: "Skipped duplicate chat-history slot.",
104
- itemId: item.id,
105
- });
106
- continue;
107
- }
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));
112
- insertedHistory = true;
113
- continue;
114
- }
115
-
116
- if (!item.role || item.role === "system") continue;
117
-
118
- const content = item.kind === "block"
119
- ? expandMacros(item.content, stack, runtime, diagnostics, item.id)
120
- : renderSlotText(item, stack, runtime, diagnostics);
121
-
122
- if (!content.trim()) continue;
123
- const message = createSyntheticMessage(item.role, content, stack, runtime);
124
- messages.push(message);
125
- messageSources.push(stackItemMessageSource(message, item));
126
- }
127
-
128
- if (!insertedHistory) {
129
- messages.push(...originalMessages);
130
- messageSources.push(...implicitHistoryMessageSources(originalMessages));
131
- }
132
-
133
- messages = applyRegexRulesToMessages(stack, messages, "compiled", diagnostics);
134
- return { messages, messageSources, diagnostics };
135
- }
136
-
137
- export function getLatestUserMessage(messages: AgentMessage[]): string | undefined {
138
- for (let i = messages.length - 1; i >= 0; i--) {
139
- const message = messages[i];
140
- if (message.role === "user") {
141
- const text = contentToText((message as { content?: unknown }).content);
142
- if (text.trim()) return text;
143
- }
144
- }
145
- return undefined;
146
- }
147
-
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 ?? ""}`;
154
- }
155
- if (role === "branchSummary" || role === "compactionSummary") {
156
- text += (message as { summary?: string }).summary ?? "";
157
- }
158
- return text;
159
- }
160
-
161
- function getChatHistoryMessages(
162
- messages: AgentMessage[],
163
- item: PromptStackSlotItem,
164
- diagnostics: PromptStackDiagnostic[],
165
- ): AgentMessage[] {
166
- let result = messages;
167
- const options = item.options ?? {};
168
- let shouldRepairToolPairs = false;
169
-
170
- if (options.includeLastUserMessage === false) {
171
- const lastUserIndex = findLastUserMessageIndex(result);
172
- if (lastUserIndex !== -1) result = result.filter((_message, index) => index !== lastUserIndex);
173
- }
174
-
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;
179
- }
180
-
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
- }
188
-
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 });
193
- }
194
-
195
- if (options.stripAssistantThinking === true) {
196
- result = stripAssistantThinkingFromHistory(result, diagnostics, item.id);
197
- }
198
-
199
- const limited = limitChatHistory(result, options, diagnostics, item.id);
200
- if (limited !== result) {
201
- result = limited;
202
- shouldRepairToolPairs = true;
203
- }
204
-
205
- if (shouldRepairToolPairs && options.toolMode !== "drop") {
206
- result = repairToolHistory(result, diagnostics, item.id);
207
- }
208
-
209
- return result;
210
- }
211
-
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;
217
- }
218
-
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);
228
-
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
- }
238
-
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
- }
249
- }
250
-
251
- return result;
252
- }
253
-
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;
263
- }
264
- return selected.reverse();
265
- }
266
-
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
- });
280
- }
281
-
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[] = [];
292
-
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);
307
- }
308
-
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);
330
- }
331
-
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;
348
- }
349
-
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;
356
- }
357
- result.push(stripped.message);
358
- }
359
-
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 };
382
- }
383
-
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
- }
391
-
392
- function isToolCallContent(value: unknown): boolean {
393
- return isPlainObject(value) && value.type === "toolCall";
394
- }
395
-
396
- function toolCallPartId(value: unknown): string | undefined {
397
- if (!isPlainObject(value)) return undefined;
398
- return firstString(value.id, value.toolCallId, value.callId);
399
- }
400
-
401
- function isToolResultMessage(message: AgentMessage): boolean {
402
- return messageRole(message) === "toolResult";
403
- }
404
-
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);
409
- }
410
-
411
- function isSummaryMessage(message: AgentMessage): boolean {
412
- return SUMMARY_ROLES.has(messageRole(message));
413
- }
414
-
415
- function messageRole(message: AgentMessage): string {
416
- return String((message as { role?: unknown }).role ?? "");
417
- }
418
-
419
- function positiveIntegerOption(value: unknown): number | undefined {
420
- return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : undefined;
421
- }
422
-
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;
428
- }
429
-
430
- function isStringArray(value: unknown): value is string[] {
431
- return Array.isArray(value) && value.every((item) => typeof item === "string");
432
- }
433
-
434
- function isPlainObject(value: unknown): value is Record<string, unknown> {
435
- return !!value && typeof value === "object" && !Array.isArray(value);
436
- }
437
-
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
- }));
448
- }
449
-
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
- }));
459
- }
460
-
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[],
472
- diagnostics: PromptStackDiagnostic[],
473
- itemId: string,
474
- ): AgentMessage[] {
475
- let strippedBlocks = 0;
476
- let changedMessages = 0;
477
- let droppedMessages = 0;
478
- let changed = false;
479
- const result: AgentMessage[] = [];
480
-
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++;
487
- }
488
- if (!stripped.message) {
489
- droppedMessages++;
490
- continue;
491
- }
492
- result.push(stripped.message);
493
- }
494
-
495
- if (!changed) return messages;
496
-
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,
502
- });
503
- return result;
504
- }
505
-
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 };
510
-
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 };
516
- }
517
-
518
- function isThinkingContent(value: unknown): boolean {
519
- return !!value && typeof value === "object" && !Array.isArray(value) && (value as { type?: unknown }).type === "thinking";
520
- }
521
-
522
- function enabledItems(stack: PromptStack): PromptStackItem[] {
523
- return stack.items.filter((item) => item.enabled !== false);
524
- }
525
-
526
- function createSyntheticMessage(role: Exclude<PromptStackRole, "system">, content: string, stack: PromptStack, runtime: PromptRuntime): AgentMessage {
527
- const timestamp = runtime.now.getTime();
528
- const visible = stack.defaults?.syntheticMessagesVisible ?? false;
529
-
530
- if (role === "custom") {
531
- return {
532
- role: "custom",
533
- customType: "pi-forge",
534
- content: [{ type: "text", text: content }],
535
- display: visible,
536
- details: { stackId: stack.id },
537
- timestamp,
538
- } as AgentMessage;
539
- }
540
-
541
- if (role === "assistant") {
542
- const model = runtime.ctx?.model;
543
- return {
544
- role: "assistant",
545
- content: [{ type: "text", text: content }],
546
- api: model?.api ?? "unknown",
547
- provider: model?.provider ?? "unknown",
548
- model: model?.id ?? "unknown",
549
- usage: ZERO_USAGE,
550
- stopReason: "stop",
551
- timestamp,
552
- } as AgentMessage;
553
- }
554
-
555
- return {
556
- role: "user",
557
- content: [{ type: "text", text: content }],
558
- timestamp,
559
- } as AgentMessage;
560
- }
561
-
562
- function contentToText(content: unknown): string {
563
- if (typeof content === "string") return content;
564
- if (!Array.isArray(content)) return "";
565
-
566
- return content
567
- .map((part) => {
568
- if (!part || typeof part !== "object") return "";
569
- const obj = part as Record<string, unknown>;
570
- if (obj.type === "text" && typeof obj.text === "string") return obj.text;
571
- if (obj.type === "thinking" && typeof obj.thinking === "string") return `<thinking>\n${obj.thinking}\n</thinking>`;
572
- if (obj.type === "toolCall") return `[toolCall: ${String(obj.name ?? "unknown")}]`;
573
- if (obj.type === "image") return "[image]";
574
- return "";
575
- })
576
- .filter(Boolean)
577
- .join("\n");
578
- }
@@ -1,33 +0,0 @@
1
- export type PromptExtensionOptionType = "boolean" | "string" | "number" | "enum" | "stringArray";
2
-
3
- export interface PromptExtensionOptionDefinition {
4
- type: PromptExtensionOptionType;
5
- description?: string;
6
- default?: string | number | boolean | readonly string[];
7
- values?: readonly string[];
8
- min?: number;
9
- max?: number;
10
- integer?: boolean;
11
- }
12
-
13
- export type PromptExtensionOptionsSchema = Record<string, PromptExtensionOptionDefinition>;
14
-
15
- export interface PromptExtensionArgumentDefinition {
16
- name: string;
17
- description?: string;
18
- required?: boolean;
19
- variadic?: boolean;
20
- expansion?: "eager" | "lazy";
21
- }
22
-
23
- export interface PromptRegistryEntry {
24
- name: string;
25
- description?: string;
26
- source?: string;
27
- }
28
-
29
- export function assertRegistryName(kind: string, name: string): void {
30
- if (!/^[A-Za-z][A-Za-z0-9_.-]*$/.test(name)) {
31
- throw new Error(`${kind} name must start with a letter and contain only letters, numbers, underscore, dot, or hyphen: ${name}`);
32
- }
33
- }