@zihanw/pi-forge 0.3.2 → 0.4.0
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/CHANGELOG.md +196 -0
- package/PUBLIC_API.md +5 -0
- package/README.md +93 -478
- package/README.zh-CN.md +88 -461
- package/SUBAGENT_ADAPTER_CONTRACT.md +5 -0
- package/dist/agent-profile.d.ts +71 -0
- package/dist/agent-profile.d.ts.map +1 -0
- package/dist/agent-profile.js +303 -0
- package/dist/agent-profile.js.map +1 -0
- package/dist/forge-config.d.ts +88 -0
- package/dist/forge-config.d.ts.map +1 -0
- package/dist/forge-config.js +290 -0
- package/dist/forge-config.js.map +1 -0
- package/dist/forge-extensions.d.ts.map +1 -1
- package/dist/forge-extensions.js +19 -3
- package/dist/forge-extensions.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +97 -358
- package/dist/index.js.map +1 -1
- package/dist/lifecycle.d.ts +11 -3
- package/dist/lifecycle.d.ts.map +1 -1
- package/dist/lifecycle.js +90 -4
- package/dist/lifecycle.js.map +1 -1
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +116 -5
- package/dist/loader.js.map +1 -1
- package/dist/payload-capture.d.ts.map +1 -1
- package/dist/payload-capture.js +27 -0
- package/dist/payload-capture.js.map +1 -1
- package/dist/payload-command.d.ts +3 -3
- package/dist/payload-command.d.ts.map +1 -1
- package/dist/payload-command.js.map +1 -1
- package/dist/preview.d.ts +2 -2
- package/dist/preview.d.ts.map +1 -1
- package/dist/preview.js +2 -3
- package/dist/preview.js.map +1 -1
- package/dist/profile-command.d.ts +12 -0
- package/dist/profile-command.d.ts.map +1 -0
- package/dist/profile-command.js +291 -0
- package/dist/profile-command.js.map +1 -0
- package/dist/profile-service.d.ts +103 -0
- package/dist/profile-service.d.ts.map +1 -0
- package/dist/profile-service.js +220 -0
- package/dist/profile-service.js.map +1 -0
- package/dist/runtime/profile-runtime.d.ts +13 -0
- package/dist/runtime/profile-runtime.d.ts.map +1 -0
- package/dist/runtime/profile-runtime.js +47 -0
- package/dist/runtime/profile-runtime.js.map +1 -0
- package/dist/runtime/prompt-stack-runtime.d.ts +22 -0
- package/dist/runtime/prompt-stack-runtime.d.ts.map +1 -0
- package/dist/runtime/prompt-stack-runtime.js +104 -0
- package/dist/runtime/prompt-stack-runtime.js.map +1 -0
- package/dist/runtime/subagent-runtime.d.ts +45 -0
- package/dist/runtime/subagent-runtime.d.ts.map +1 -0
- package/dist/runtime/subagent-runtime.js +335 -0
- package/dist/runtime/subagent-runtime.js.map +1 -0
- package/dist/runtime/tool-policy-runtime.d.ts +15 -0
- package/dist/runtime/tool-policy-runtime.d.ts.map +1 -0
- package/dist/runtime/tool-policy-runtime.js +170 -0
- package/dist/runtime/tool-policy-runtime.js.map +1 -0
- package/dist/runtime/web-editor-runtime.d.ts +9 -0
- package/dist/runtime/web-editor-runtime.d.ts.map +1 -0
- package/dist/runtime/web-editor-runtime.js +131 -0
- package/dist/runtime/web-editor-runtime.js.map +1 -0
- package/dist/runtime-state.d.ts +4 -0
- package/dist/runtime-state.d.ts.map +1 -1
- package/dist/runtime-state.js +2 -0
- package/dist/runtime-state.js.map +1 -1
- package/dist/storage.d.ts +4 -0
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +24 -1
- package/dist/storage.js.map +1 -1
- package/dist/subagent/canonical.d.ts +22 -0
- package/dist/subagent/canonical.d.ts.map +1 -0
- package/dist/subagent/canonical.js +24 -0
- package/dist/subagent/canonical.js.map +1 -0
- package/dist/subagent/context.d.ts +8 -0
- package/dist/subagent/context.d.ts.map +1 -0
- package/dist/subagent/context.js +125 -0
- package/dist/subagent/context.js.map +1 -0
- package/dist/subagent/contract.d.ts +10 -0
- package/dist/subagent/contract.d.ts.map +1 -0
- package/dist/subagent/contract.js +10 -0
- package/dist/subagent/contract.js.map +1 -0
- package/dist/subagent/index.d.ts +14 -0
- package/dist/subagent/index.d.ts.map +1 -0
- package/dist/subagent/index.js +14 -0
- package/dist/subagent/index.js.map +1 -0
- package/dist/subagent/plan.d.ts +18 -0
- package/dist/subagent/plan.d.ts.map +1 -0
- package/dist/subagent/plan.js +157 -0
- package/dist/subagent/plan.js.map +1 -0
- package/dist/subagent/preflight.d.ts +4 -0
- package/dist/subagent/preflight.d.ts.map +1 -0
- package/dist/subagent/preflight.js +108 -0
- package/dist/subagent/preflight.js.map +1 -0
- package/dist/subagent/request.d.ts +4 -0
- package/dist/subagent/request.d.ts.map +1 -0
- package/dist/subagent/request.js +122 -0
- package/dist/subagent/request.js.map +1 -0
- package/dist/subagent/response.d.ts +8 -0
- package/dist/subagent/response.d.ts.map +1 -0
- package/dist/subagent/response.js +155 -0
- package/dist/subagent/response.js.map +1 -0
- package/dist/subagent/tools.d.ts +4 -0
- package/dist/subagent/tools.d.ts.map +1 -0
- package/dist/subagent/tools.js +42 -0
- package/dist/subagent/tools.js.map +1 -0
- package/dist/subagent/types.d.ts +268 -0
- package/dist/subagent/types.d.ts.map +1 -0
- package/dist/subagent/types.js +3 -0
- package/dist/subagent/types.js.map +1 -0
- package/dist/subagent/validation.d.ts +35 -0
- package/dist/subagent/validation.d.ts.map +1 -0
- package/dist/subagent/validation.js +314 -0
- package/dist/subagent/validation.js.map +1 -0
- package/dist/subagent-command.d.ts +4 -0
- package/dist/subagent-command.d.ts.map +1 -0
- package/dist/subagent-command.js +246 -0
- package/dist/subagent-command.js.map +1 -0
- package/dist/subagent-host.d.ts +44 -0
- package/dist/subagent-host.d.ts.map +1 -0
- package/dist/subagent-host.js +292 -0
- package/dist/subagent-host.js.map +1 -0
- package/dist/subagent-profile-tool.d.ts +49 -0
- package/dist/subagent-profile-tool.d.ts.map +1 -0
- package/dist/subagent-profile-tool.js +124 -0
- package/dist/subagent-profile-tool.js.map +1 -0
- package/dist/subagent-tool.d.ts +53 -0
- package/dist/subagent-tool.d.ts.map +1 -0
- package/dist/subagent-tool.js +456 -0
- package/dist/subagent-tool.js.map +1 -0
- package/dist/web-editor/client-script.d.ts +2 -0
- package/dist/web-editor/client-script.d.ts.map +1 -0
- package/dist/web-editor/client-script.generated.d.ts +2 -0
- package/dist/web-editor/client-script.generated.d.ts.map +1 -0
- package/dist/web-editor/client-script.generated.js +3 -0
- package/dist/web-editor/client-script.generated.js.map +1 -0
- package/dist/web-editor/client-script.js +2 -0
- package/dist/web-editor/client-script.js.map +1 -0
- package/dist/web-editor/client-styles.d.ts +2 -0
- package/dist/web-editor/client-styles.d.ts.map +1 -0
- package/dist/web-editor/client-styles.generated.d.ts +2 -0
- package/dist/web-editor/client-styles.generated.d.ts.map +1 -0
- package/dist/web-editor/client-styles.generated.js +3 -0
- package/dist/web-editor/client-styles.generated.js.map +1 -0
- package/dist/web-editor/client-styles.js +2 -0
- package/dist/web-editor/client-styles.js.map +1 -0
- package/dist/web-editor/page.d.ts +2 -0
- package/dist/web-editor/page.d.ts.map +1 -1
- package/dist/web-editor/page.js +14 -3319
- package/dist/web-editor/page.js.map +1 -1
- package/dist/web-editor/server.d.ts.map +1 -1
- package/dist/web-editor/server.js +148 -0
- package/dist/web-editor/server.js.map +1 -1
- package/dist/web-editor/styles.d.ts +2 -0
- package/dist/web-editor/styles.d.ts.map +1 -0
- package/dist/web-editor/styles.js +1053 -0
- package/dist/web-editor/styles.js.map +1 -0
- package/dist/web-editor/types.d.ts +79 -0
- package/dist/web-editor/types.d.ts.map +1 -1
- package/dist/web-host.d.ts +16 -5
- package/dist/web-host.d.ts.map +1 -1
- package/dist/web-host.js +307 -0
- package/dist/web-host.js.map +1 -1
- package/docs/README.md +41 -0
- package/docs/concepts/agent-profiles.md +60 -0
- package/docs/concepts/prompt-stacks.md +90 -0
- package/docs/design/README.md +17 -0
- package/docs/design/roadmap-0.4-archive.md +216 -0
- package/docs/design/subagents/design-review.md +220 -0
- package/docs/design/subagents/interface-design.md +274 -0
- package/docs/design/subagents/sdk-spike-findings.md +117 -0
- package/docs/development/complexity-review.md +86 -0
- package/docs/development/release.md +31 -0
- package/docs/development/roadmap.md +42 -0
- package/docs/development/setup.md +75 -0
- package/docs/getting-started.md +93 -0
- package/docs/guides/custom-macros-and-slots.md +68 -0
- package/docs/guides/debugging.md +39 -0
- package/docs/guides/delegation.md +99 -0
- package/docs/guides/sillytavern-import.md +47 -0
- package/docs/guides/use-cases.md +65 -0
- package/docs/guides/web-editor.md +75 -0
- package/docs/reference/commands.md +60 -0
- package/docs/reference/configuration.md +64 -0
- package/docs/reference/features.md +279 -0
- package/docs/reference/macros-and-slots.md +82 -0
- package/docs/reference/public-api.md +28 -0
- package/docs/reference/stack-schema.md +167 -0
- package/docs/reference/subagent-adapter.md +204 -0
- package/docs/zh-CN/README.md +37 -0
- package/docs/zh-CN/concepts/agent-profiles.md +44 -0
- package/docs/zh-CN/concepts/prompt-stacks.md +40 -0
- package/docs/zh-CN/getting-started.md +79 -0
- package/docs/zh-CN/guides/delegation.md +66 -0
- package/docs/zh-CN/guides/web-editor.md +45 -0
- package/docs/zh-CN/reference/commands.md +58 -0
- package/package.json +55 -13
- package/src/compiler.ts +0 -578
- package/src/extension-registry.ts +0 -33
- package/src/forge-extensions.ts +0 -223
- package/src/index.ts +0 -445
- package/src/lifecycle.ts +0 -171
- package/src/loader.ts +0 -394
- package/src/macro-engine.ts +0 -358
- package/src/payload-capture.ts +0 -85
- package/src/payload-command.ts +0 -138
- package/src/policy.ts +0 -42
- package/src/preset-command.ts +0 -280
- package/src/preview.ts +0 -226
- package/src/regex.ts +0 -500
- package/src/render-helpers.ts +0 -169
- package/src/runtime-state.ts +0 -40
- package/src/sillytavern-importer/items.ts +0 -98
- package/src/sillytavern-importer/macros.ts +0 -159
- package/src/sillytavern-importer/prompt-order.ts +0 -54
- package/src/sillytavern-importer/regex.ts +0 -270
- package/src/sillytavern-importer/report.ts +0 -202
- package/src/sillytavern-importer/types.ts +0 -120
- package/src/sillytavern-importer.ts +0 -152
- package/src/slot-renderers.ts +0 -414
- package/src/stack-migration.ts +0 -159
- package/src/storage.ts +0 -45
- package/src/types.ts +0 -209
- package/src/web-editor/index.ts +0 -2
- package/src/web-editor/page.ts +0 -3330
- package/src/web-editor/server.ts +0 -294
- package/src/web-editor/types.ts +0 -98
- package/src/web-host.ts +0 -232
package/package.json
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zihanw/pi-forge",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Pi extension for prompt
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Pi extension for prompt stacks, one-shot agent profiles, policy, import, and debugging.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/MacroSony/pi-forge.git"
|
|
8
|
+
},
|
|
5
9
|
"type": "module",
|
|
6
10
|
"exports": {
|
|
7
11
|
".": {
|
|
@@ -9,6 +13,11 @@
|
|
|
9
13
|
"import": "./dist/index.js",
|
|
10
14
|
"default": "./dist/index.js"
|
|
11
15
|
},
|
|
16
|
+
"./subagent": {
|
|
17
|
+
"types": "./dist/subagent/index.d.ts",
|
|
18
|
+
"import": "./dist/subagent/index.js",
|
|
19
|
+
"default": "./dist/subagent/index.js"
|
|
20
|
+
},
|
|
12
21
|
"./src/*.ts": {
|
|
13
22
|
"types": "./dist/*.d.ts",
|
|
14
23
|
"import": "./dist/*.js",
|
|
@@ -24,14 +33,19 @@
|
|
|
24
33
|
"import": "./dist/*.js",
|
|
25
34
|
"default": "./dist/*.js"
|
|
26
35
|
},
|
|
36
|
+
"./src/web-editor/client/*": null,
|
|
27
37
|
"./examples/*": "./examples/*"
|
|
28
38
|
},
|
|
29
39
|
"keywords": [
|
|
30
40
|
"pi-package",
|
|
31
41
|
"pi-extension",
|
|
32
|
-
"prompt-stack"
|
|
42
|
+
"prompt-stack",
|
|
43
|
+
"agent-profile"
|
|
33
44
|
],
|
|
34
45
|
"license": "MIT",
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=22.19.0"
|
|
48
|
+
},
|
|
35
49
|
"pi": {
|
|
36
50
|
"extensions": [
|
|
37
51
|
"./dist/index.js"
|
|
@@ -40,7 +54,9 @@
|
|
|
40
54
|
"peerDependencies": {
|
|
41
55
|
"@earendil-works/pi-agent-core": "*",
|
|
42
56
|
"@earendil-works/pi-ai": "*",
|
|
43
|
-
"@earendil-works/pi-coding-agent": "*"
|
|
57
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
58
|
+
"@earendil-works/pi-tui": "*",
|
|
59
|
+
"typebox": "*"
|
|
44
60
|
},
|
|
45
61
|
"peerDependenciesMeta": {
|
|
46
62
|
"@earendil-works/pi-agent-core": {
|
|
@@ -51,27 +67,53 @@
|
|
|
51
67
|
},
|
|
52
68
|
"@earendil-works/pi-coding-agent": {
|
|
53
69
|
"optional": true
|
|
70
|
+
},
|
|
71
|
+
"@earendil-works/pi-tui": {
|
|
72
|
+
"optional": true
|
|
73
|
+
},
|
|
74
|
+
"typebox": {
|
|
75
|
+
"optional": true
|
|
54
76
|
}
|
|
55
77
|
},
|
|
78
|
+
"dependencies": {
|
|
79
|
+
"@zihanw/pi-subagent-runtime": "0.1.0-beta.2"
|
|
80
|
+
},
|
|
56
81
|
"devDependencies": {
|
|
57
|
-
"@earendil-works/pi-agent-core": "
|
|
58
|
-
"@earendil-works/pi-ai": "
|
|
59
|
-
"@earendil-works/pi-coding-agent": "
|
|
60
|
-
"@
|
|
61
|
-
"
|
|
82
|
+
"@earendil-works/pi-agent-core": "0.83.0",
|
|
83
|
+
"@earendil-works/pi-ai": "0.83.0",
|
|
84
|
+
"@earendil-works/pi-coding-agent": "0.83.0",
|
|
85
|
+
"@earendil-works/pi-tui": "0.83.0",
|
|
86
|
+
"@types/node": "22.20.1",
|
|
87
|
+
"@vitejs/plugin-vue": "6.0.8",
|
|
88
|
+
"playwright-core": "1.61.1",
|
|
89
|
+
"typebox": "1.3.7",
|
|
90
|
+
"typescript": "6.0.3",
|
|
91
|
+
"vite": "8.1.5",
|
|
92
|
+
"vue": "3.5.40",
|
|
93
|
+
"vue-tsc": "3.3.8"
|
|
62
94
|
},
|
|
63
95
|
"scripts": {
|
|
64
|
-
"build": "tsc -p tsconfig.build.json",
|
|
96
|
+
"build": "npm run build:client && tsc -p tsconfig.build.json",
|
|
97
|
+
"build:client": "node scripts/build-web-client.mjs",
|
|
98
|
+
"check:client": "node scripts/build-web-client.mjs --check",
|
|
99
|
+
"check:docs": "node scripts/check-docs.mjs",
|
|
100
|
+
"check:dist": "node scripts/check-dist.mjs",
|
|
101
|
+
"check:package": "node scripts/check-package.mjs",
|
|
65
102
|
"prepack": "npm run build",
|
|
66
|
-
"typecheck": "tsc --noEmit",
|
|
67
|
-
"test": "node --test tests/*.test.ts"
|
|
103
|
+
"typecheck": "tsc --noEmit && vue-tsc --noEmit -p tsconfig.web.json",
|
|
104
|
+
"test": "node --test tests/*.test.ts",
|
|
105
|
+
"test:browser": "node --test tests-browser/*.test.ts",
|
|
106
|
+
"verify": "npm test && npm run test:browser && npm run typecheck && npm run check:client && npm run check:docs && npm run check:dist && npm run check:package"
|
|
68
107
|
},
|
|
69
108
|
"files": [
|
|
70
109
|
"dist/",
|
|
71
|
-
"
|
|
110
|
+
"docs/",
|
|
72
111
|
"examples/",
|
|
73
112
|
"README.md",
|
|
74
113
|
"README.zh-CN.md",
|
|
114
|
+
"CHANGELOG.md",
|
|
115
|
+
"SUBAGENT_ADAPTER_CONTRACT.md",
|
|
116
|
+
"PUBLIC_API.md",
|
|
75
117
|
"LICENSE*"
|
|
76
118
|
],
|
|
77
119
|
"publishConfig": {
|
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
|
-
}
|