wave-agent-sdk 0.14.1 → 0.14.2
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/builtin/skills/settings/HOOKS.md +69 -0
- package/builtin/skills/settings/PLUGINS.md +171 -0
- package/builtin/skills/settings/SKILL.md +8 -3
- package/dist/agent.d.ts +2 -2
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +12 -3
- package/dist/managers/aiManager.d.ts +6 -6
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +122 -59
- package/dist/managers/backgroundTaskManager.d.ts.map +1 -1
- package/dist/managers/backgroundTaskManager.js +28 -18
- package/dist/managers/hookManager.d.ts +16 -1
- package/dist/managers/hookManager.d.ts.map +1 -1
- package/dist/managers/hookManager.js +97 -8
- package/dist/managers/messageManager.d.ts +19 -4
- package/dist/managers/messageManager.d.ts.map +1 -1
- package/dist/managers/messageManager.js +63 -18
- package/dist/prompts/index.d.ts +1 -1
- package/dist/prompts/index.d.ts.map +1 -1
- package/dist/prompts/index.js +1 -1
- package/dist/services/MarketplaceService.d.ts +0 -11
- package/dist/services/MarketplaceService.d.ts.map +1 -1
- package/dist/services/MarketplaceService.js +21 -89
- package/dist/services/aiService.d.ts +3 -3
- package/dist/services/aiService.d.ts.map +1 -1
- package/dist/services/aiService.js +7 -7
- package/dist/services/hook.d.ts.map +1 -1
- package/dist/services/hook.js +15 -0
- package/dist/services/initializationService.d.ts.map +1 -1
- package/dist/services/initializationService.js +24 -1
- package/dist/services/interactionService.js +1 -1
- package/dist/services/pluginLoader.d.ts +0 -6
- package/dist/services/pluginLoader.d.ts.map +1 -1
- package/dist/services/pluginLoader.js +14 -53
- package/dist/services/session.d.ts +1 -1
- package/dist/services/session.js +7 -7
- package/dist/services/taskManager.d.ts +1 -1
- package/dist/services/taskManager.js +1 -1
- package/dist/types/core.d.ts +1 -1
- package/dist/types/core.d.ts.map +1 -1
- package/dist/types/hooks.d.ts +9 -1
- package/dist/types/hooks.d.ts.map +1 -1
- package/dist/types/hooks.js +2 -0
- package/dist/types/marketplace.d.ts +1 -26
- package/dist/types/marketplace.d.ts.map +1 -1
- package/dist/types/messaging.d.ts +3 -3
- package/dist/types/messaging.d.ts.map +1 -1
- package/dist/types/plugins.d.ts +1 -13
- package/dist/types/plugins.d.ts.map +1 -1
- package/dist/utils/convertMessagesForAPI.d.ts +1 -1
- package/dist/utils/convertMessagesForAPI.js +7 -7
- package/dist/utils/groupMessagesByApiRound.d.ts +1 -1
- package/dist/utils/groupMessagesByApiRound.js +6 -6
- package/dist/utils/messageOperations.d.ts.map +1 -1
- package/dist/utils/messageOperations.js +3 -3
- package/package.json +1 -1
- package/src/agent.ts +16 -3
- package/src/managers/aiManager.ts +142 -63
- package/src/managers/backgroundTaskManager.ts +32 -22
- package/src/managers/hookManager.ts +125 -10
- package/src/managers/messageManager.ts +76 -22
- package/src/prompts/index.ts +1 -1
- package/src/services/MarketplaceService.ts +26 -127
- package/src/services/aiService.ts +11 -11
- package/src/services/hook.ts +17 -0
- package/src/services/initializationService.ts +33 -1
- package/src/services/interactionService.ts +1 -1
- package/src/services/pluginLoader.ts +14 -67
- package/src/services/session.ts +7 -7
- package/src/services/taskManager.ts +1 -1
- package/src/types/core.ts +1 -1
- package/src/types/hooks.ts +16 -2
- package/src/types/marketplace.ts +1 -24
- package/src/types/messaging.ts +3 -3
- package/src/types/plugins.ts +1 -13
- package/src/utils/convertMessagesForAPI.ts +8 -8
- package/src/utils/groupMessagesByApiRound.ts +6 -6
- package/src/utils/messageOperations.ts +3 -5
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import * as fs from "fs/promises";
|
|
2
|
-
import * as fsSync from "fs";
|
|
3
2
|
import * as path from "path";
|
|
4
3
|
import {
|
|
5
4
|
PluginManifest,
|
|
@@ -14,79 +13,21 @@ import { parseSkillFile } from "../utils/skillParser.js";
|
|
|
14
13
|
import { resolveMcpConfig } from "../managers/mcpManager.js";
|
|
15
14
|
|
|
16
15
|
export class PluginLoader {
|
|
17
|
-
/**
|
|
18
|
-
* Finds the first existing plugin manifest path.
|
|
19
|
-
* Prefers .wave-plugin/ for backward compatibility, falls back to .claude-plugin/.
|
|
20
|
-
* Returns null if neither exists.
|
|
21
|
-
*/
|
|
22
|
-
private static findPluginManifestPath(pluginPath: string): string | null {
|
|
23
|
-
const waveManifestPath = path.join(
|
|
24
|
-
pluginPath,
|
|
25
|
-
".wave-plugin",
|
|
26
|
-
"plugin.json",
|
|
27
|
-
);
|
|
28
|
-
const claudeManifestPath = path.join(
|
|
29
|
-
pluginPath,
|
|
30
|
-
".claude-plugin",
|
|
31
|
-
"plugin.json",
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
// Check .wave-plugin first for backward compatibility
|
|
35
|
-
try {
|
|
36
|
-
const waveStat = fsSync.statSync(waveManifestPath);
|
|
37
|
-
if (waveStat.isFile()) {
|
|
38
|
-
return waveManifestPath;
|
|
39
|
-
}
|
|
40
|
-
} catch {
|
|
41
|
-
// .wave-plugin/plugin.json doesn't exist
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
try {
|
|
45
|
-
const claudeStat = fsSync.statSync(claudeManifestPath);
|
|
46
|
-
if (claudeStat.isFile()) {
|
|
47
|
-
return claudeManifestPath;
|
|
48
|
-
}
|
|
49
|
-
} catch {
|
|
50
|
-
// .claude-plugin/plugin.json doesn't exist
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return null;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
16
|
/**
|
|
57
17
|
* Load and validate a plugin manifest from a directory
|
|
58
18
|
* @param pluginPath Absolute path to the plugin directory
|
|
59
19
|
*/
|
|
60
20
|
static async loadManifest(pluginPath: string): Promise<PluginManifest> {
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
throw new Error(
|
|
64
|
-
`Plugin manifest not found at ${pluginPath}. Neither .wave-plugin/plugin.json nor .claude-plugin/plugin.json exists.`,
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Determine which directory is being used for validation
|
|
69
|
-
const pluginDirName = manifestPath.includes(".claude-plugin")
|
|
70
|
-
? ".claude-plugin"
|
|
71
|
-
: ".wave-plugin";
|
|
72
|
-
const pluginDirPath = path.join(pluginPath, pluginDirName);
|
|
21
|
+
const dotWavePluginPath = path.join(pluginPath, ".wave-plugin");
|
|
22
|
+
const manifestPath = path.join(dotWavePluginPath, "plugin.json");
|
|
73
23
|
|
|
74
|
-
// T018: Ensure plugin.json is the only file in
|
|
75
|
-
// For .claude-plugin/, marketplace.json is also allowed (Claude Code convention)
|
|
24
|
+
// T018: Ensure plugin.json is the only file in .wave-plugin/
|
|
76
25
|
try {
|
|
77
|
-
const entries = await fs.readdir(
|
|
78
|
-
const
|
|
79
|
-
if (pluginDirName === ".claude-plugin") {
|
|
80
|
-
allowedFiles.push("marketplace.json");
|
|
81
|
-
}
|
|
82
|
-
const misplaced = entries.filter((e) => !allowedFiles.includes(e));
|
|
26
|
+
const entries = await fs.readdir(dotWavePluginPath);
|
|
27
|
+
const misplaced = entries.filter((e) => e !== "plugin.json");
|
|
83
28
|
if (misplaced.length > 0) {
|
|
84
|
-
const allowedMsg =
|
|
85
|
-
pluginDirName === ".claude-plugin"
|
|
86
|
-
? "Only plugin.json and marketplace.json should be in this directory."
|
|
87
|
-
: "Only plugin.json should be in this directory.";
|
|
88
29
|
throw new Error(
|
|
89
|
-
`Misplaced files/directories in
|
|
30
|
+
`Misplaced files/directories in .wave-plugin/: ${misplaced.join(", ")}. Only plugin.json should be in this directory.`,
|
|
90
31
|
);
|
|
91
32
|
}
|
|
92
33
|
} catch (error) {
|
|
@@ -95,7 +36,7 @@ export class PluginLoader {
|
|
|
95
36
|
(error as { code?: string }).code === "ENOENT"
|
|
96
37
|
) {
|
|
97
38
|
throw new Error(
|
|
98
|
-
`Plugin manifest directory not found at ${
|
|
39
|
+
`Plugin manifest directory not found at ${dotWavePluginPath}`,
|
|
99
40
|
);
|
|
100
41
|
}
|
|
101
42
|
throw error;
|
|
@@ -212,7 +153,13 @@ export class PluginLoader {
|
|
|
212
153
|
const hooksPath = path.join(pluginPath, "hooks", "hooks.json");
|
|
213
154
|
try {
|
|
214
155
|
const content = await fs.readFile(hooksPath, "utf-8");
|
|
215
|
-
|
|
156
|
+
const parsed = JSON.parse(content);
|
|
157
|
+
// Claude Code wrapper format: { "hooks": { "SessionStart": [...] } }
|
|
158
|
+
// (optional "description" sibling key)
|
|
159
|
+
if (parsed && typeof parsed === "object" && "hooks" in parsed) {
|
|
160
|
+
return parsed.hooks as PartialHookConfiguration;
|
|
161
|
+
}
|
|
162
|
+
return undefined;
|
|
216
163
|
} catch {
|
|
217
164
|
return undefined;
|
|
218
165
|
}
|
package/src/services/session.ts
CHANGED
|
@@ -816,7 +816,7 @@ export async function sessionExistsInJsonl(
|
|
|
816
816
|
/**
|
|
817
817
|
* Get the content of the first message in a session
|
|
818
818
|
* For user role: get text block content
|
|
819
|
-
* For assistant role: get
|
|
819
|
+
* For assistant role: get compact block content
|
|
820
820
|
* @param sessionId - Session ID to get first message from
|
|
821
821
|
* @param workdir - Working directory for session operations
|
|
822
822
|
* @returns Promise that resolves to the first message content or null if not found
|
|
@@ -996,18 +996,18 @@ export async function loadFullMessageThread(
|
|
|
996
996
|
|
|
997
997
|
sessionIds.unshift(currentId);
|
|
998
998
|
// Add messages from this session to the beginning of the list
|
|
999
|
-
// But skip the "
|
|
999
|
+
// But skip the "compact" block if it's not the first session in our traversal (which is the latest)
|
|
1000
1000
|
// Actually, we should probably keep all messages and let the UI/logic handle it.
|
|
1001
|
-
// But wait, if we are concatenating, the "
|
|
1002
|
-
// So if we have session N-1 and session N, we should probably skip the
|
|
1001
|
+
// But wait, if we are concatenating, the "compact" block in session N summarizes session N-1.
|
|
1002
|
+
// So if we have session N-1 and session N, we should probably skip the compact block in session N.
|
|
1003
1003
|
|
|
1004
1004
|
const messages = sessionData.messages;
|
|
1005
1005
|
if (allMessages.length > 0) {
|
|
1006
1006
|
// If we already have messages (from "later" sessions),
|
|
1007
1007
|
// we are now adding messages from an "earlier" session.
|
|
1008
|
-
// The later session's first message might be a "
|
|
1009
|
-
if (allMessages[0].blocks.some((b) => b.type === "
|
|
1010
|
-
// Remove the
|
|
1008
|
+
// The later session's first message might be a "compact" block.
|
|
1009
|
+
if (allMessages[0].blocks.some((b) => b.type === "compact")) {
|
|
1010
|
+
// Remove the compact block from the later session's messages
|
|
1011
1011
|
// because we are now providing the actual messages it summarized.
|
|
1012
1012
|
allMessages.shift();
|
|
1013
1013
|
}
|
|
@@ -30,7 +30,7 @@ export class TaskManager extends EventEmitter {
|
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
32
|
* Syncs the task list ID with the current session's root session ID.
|
|
33
|
-
* This is typically called when the session is cleared or
|
|
33
|
+
* This is typically called when the session is cleared or compacted.
|
|
34
34
|
*/
|
|
35
35
|
public async syncWithSession(): Promise<void> {
|
|
36
36
|
const messageManager = this.container.get<MessageManager>("MessageManager");
|
package/src/types/core.ts
CHANGED
|
@@ -25,7 +25,7 @@ export interface Usage {
|
|
|
25
25
|
completion_tokens: number; // Tokens generated in completions
|
|
26
26
|
total_tokens: number; // Sum of prompt + completion tokens
|
|
27
27
|
model?: string; // Model used for the operation (e.g., "gpt-4", "gpt-3.5-turbo")
|
|
28
|
-
operation_type?: "agent" | "
|
|
28
|
+
operation_type?: "agent" | "compact"; // Type of operation that generated usage
|
|
29
29
|
|
|
30
30
|
// Cache-related tokens (Claude models only)
|
|
31
31
|
cache_read_input_tokens?: number; // Tokens read from cache
|
package/src/types/hooks.ts
CHANGED
|
@@ -21,7 +21,9 @@ export type HookEvent =
|
|
|
21
21
|
| "SubagentStop"
|
|
22
22
|
| "PermissionRequest"
|
|
23
23
|
| "WorktreeCreate"
|
|
24
|
-
| "CwdChanged"
|
|
24
|
+
| "CwdChanged"
|
|
25
|
+
| "SessionStart"
|
|
26
|
+
| "SessionEnd";
|
|
25
27
|
|
|
26
28
|
// Individual hook command configuration
|
|
27
29
|
export interface HookCommand {
|
|
@@ -94,6 +96,10 @@ export class HookConfigurationError extends Error {
|
|
|
94
96
|
}
|
|
95
97
|
}
|
|
96
98
|
|
|
99
|
+
export type SessionStartSource = "startup" | "resume" | "compact";
|
|
100
|
+
|
|
101
|
+
export type SessionEndSource = "exit" | "stop" | "compact";
|
|
102
|
+
|
|
97
103
|
// Type guards for runtime validation
|
|
98
104
|
export function isValidHookEvent(event: string): event is HookEvent {
|
|
99
105
|
return [
|
|
@@ -105,6 +111,8 @@ export function isValidHookEvent(event: string): event is HookEvent {
|
|
|
105
111
|
"PermissionRequest",
|
|
106
112
|
"WorktreeCreate",
|
|
107
113
|
"CwdChanged",
|
|
114
|
+
"SessionStart",
|
|
115
|
+
"SessionEnd",
|
|
108
116
|
].includes(event);
|
|
109
117
|
}
|
|
110
118
|
|
|
@@ -161,7 +169,7 @@ export interface HookJsonInput {
|
|
|
161
169
|
session_id: string; // Format: "wave_session_{uuid}_{shortId}"
|
|
162
170
|
transcript_path: string; // Format: "~/.wave/sessions/session_{shortId}.json"
|
|
163
171
|
cwd: string; // Absolute path to current working directory
|
|
164
|
-
hook_event_name: HookEvent; // "PreToolUse" | "PostToolUse" | "UserPromptSubmit" | "Stop" | "SubagentStop" | "PermissionRequest" | "WorktreeCreate" | "CwdChanged"
|
|
172
|
+
hook_event_name: HookEvent; // "PreToolUse" | "PostToolUse" | "UserPromptSubmit" | "Stop" | "SubagentStop" | "PermissionRequest" | "WorktreeCreate" | "CwdChanged" | "SessionStart"
|
|
165
173
|
|
|
166
174
|
// Optional fields based on event type
|
|
167
175
|
tool_name?: string; // Present for PreToolUse, PostToolUse, PermissionRequest
|
|
@@ -172,6 +180,9 @@ export interface HookJsonInput {
|
|
|
172
180
|
name?: string; // Present for WorktreeCreate events
|
|
173
181
|
old_cwd?: string; // Present for CwdChanged events
|
|
174
182
|
new_cwd?: string; // Present for CwdChanged events
|
|
183
|
+
source?: SessionStartSource; // Present for SessionStart events
|
|
184
|
+
agent_type?: string; // Present for SessionStart events
|
|
185
|
+
end_source?: SessionEndSource; // Present for SessionEnd events
|
|
175
186
|
}
|
|
176
187
|
|
|
177
188
|
// Extended context interface for passing additional data to hook executor
|
|
@@ -187,6 +198,9 @@ export interface ExtendedHookExecutionContext extends HookExecutionContext {
|
|
|
187
198
|
worktreeName?: string; // Worktree name (WorktreeCreate only)
|
|
188
199
|
oldCwd?: string; // Previous working directory (CwdChanged only)
|
|
189
200
|
newCwd?: string; // New working directory (CwdChanged only)
|
|
201
|
+
source?: SessionStartSource; // Session start source (SessionStart only)
|
|
202
|
+
agentType?: string; // Agent type identifier (SessionStart only)
|
|
203
|
+
endSource?: SessionEndSource; // Session end source (SessionEnd only)
|
|
190
204
|
}
|
|
191
205
|
|
|
192
206
|
// Environment variables injected into hook processes
|
package/src/types/marketplace.ts
CHANGED
|
@@ -7,24 +7,8 @@ export interface MarketplaceOwner {
|
|
|
7
7
|
|
|
8
8
|
export interface MarketplacePluginEntry {
|
|
9
9
|
name: string;
|
|
10
|
-
source: string
|
|
10
|
+
source: string;
|
|
11
11
|
description: string;
|
|
12
|
-
/** Claude Code compatibility: plugin category */
|
|
13
|
-
category?: string;
|
|
14
|
-
/** Claude Code compatibility: plugin tags */
|
|
15
|
-
tags?: string[];
|
|
16
|
-
/** Claude Code compatibility: when false, plugin.json is optional */
|
|
17
|
-
strict?: boolean;
|
|
18
|
-
/** Claude Code compatibility: inline manifest fields */
|
|
19
|
-
version?: string;
|
|
20
|
-
author?: { name: string; url?: string };
|
|
21
|
-
homepage?: string;
|
|
22
|
-
repository?: string;
|
|
23
|
-
license?: string;
|
|
24
|
-
keywords?: string[];
|
|
25
|
-
commands?: string;
|
|
26
|
-
skills?: string;
|
|
27
|
-
agents?: string;
|
|
28
12
|
}
|
|
29
13
|
|
|
30
14
|
export interface MarketplacePluginStatus extends MarketplacePluginEntry {
|
|
@@ -40,8 +24,6 @@ export interface MarketplaceManifest {
|
|
|
40
24
|
name: string;
|
|
41
25
|
owner: MarketplaceOwner;
|
|
42
26
|
plugins: MarketplacePluginEntry[];
|
|
43
|
-
/** Claude Code compatibility: additional metadata */
|
|
44
|
-
metadata?: Record<string, unknown>;
|
|
45
27
|
}
|
|
46
28
|
|
|
47
29
|
export type MarketplaceSource =
|
|
@@ -58,11 +40,6 @@ export type MarketplaceSource =
|
|
|
58
40
|
source: "git";
|
|
59
41
|
url: string;
|
|
60
42
|
ref?: string;
|
|
61
|
-
}
|
|
62
|
-
| {
|
|
63
|
-
source: "url";
|
|
64
|
-
url: string;
|
|
65
|
-
ref?: string;
|
|
66
43
|
};
|
|
67
44
|
|
|
68
45
|
export interface KnownMarketplace {
|
package/src/types/messaging.ts
CHANGED
|
@@ -25,7 +25,7 @@ export type MessageBlock =
|
|
|
25
25
|
| ToolBlock
|
|
26
26
|
| ImageBlock
|
|
27
27
|
| BangBlock
|
|
28
|
-
|
|
|
28
|
+
| CompactBlock
|
|
29
29
|
| ReasoningBlock
|
|
30
30
|
| FileHistoryBlock
|
|
31
31
|
| TaskNotificationBlock;
|
|
@@ -85,8 +85,8 @@ export interface BangBlock {
|
|
|
85
85
|
exitCode: number | null;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
export interface
|
|
89
|
-
type: "
|
|
88
|
+
export interface CompactBlock {
|
|
89
|
+
type: "compact";
|
|
90
90
|
content: string;
|
|
91
91
|
sessionId: string;
|
|
92
92
|
}
|
package/src/types/plugins.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { McpConfig } from "./mcp.js";
|
|
|
5
5
|
import { PartialHookConfiguration } from "./configuration.js";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* Plugin manifest structure (.wave-plugin/plugin.json
|
|
8
|
+
* Plugin manifest structure (.wave-plugin/plugin.json)
|
|
9
9
|
*/
|
|
10
10
|
export interface PluginManifest {
|
|
11
11
|
name: string;
|
|
@@ -14,18 +14,6 @@ export interface PluginManifest {
|
|
|
14
14
|
author?: {
|
|
15
15
|
name: string;
|
|
16
16
|
};
|
|
17
|
-
/** Claude Code compatibility: plugin keywords */
|
|
18
|
-
keywords?: string[];
|
|
19
|
-
/** Claude Code compatibility: plugin homepage URL */
|
|
20
|
-
homepage?: string;
|
|
21
|
-
/** Claude Code compatibility: repository info */
|
|
22
|
-
repository?: string;
|
|
23
|
-
/** Claude Code compatibility: license info */
|
|
24
|
-
license?: string;
|
|
25
|
-
/** Claude Code compatibility: plugin dependencies */
|
|
26
|
-
dependencies?: Record<string, string>;
|
|
27
|
-
/** Claude Code compatibility: user configuration schema */
|
|
28
|
-
userConfig?: Record<string, unknown>;
|
|
29
17
|
}
|
|
30
18
|
|
|
31
19
|
/**
|
|
@@ -33,7 +33,7 @@ function safeToolArguments(args: string): string {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
|
-
* Convert message format to API call format, stopping when a
|
|
36
|
+
* Convert message format to API call format, stopping when a compacted message is encountered.
|
|
37
37
|
* Messages with no meaningful content or tool calls are filtered out.
|
|
38
38
|
* @param messages Message list
|
|
39
39
|
* @returns Converted API message format list
|
|
@@ -47,19 +47,19 @@ export function convertMessagesForAPI(
|
|
|
47
47
|
for (let i = startIndex; i >= 0; i--) {
|
|
48
48
|
const message = messages[i];
|
|
49
49
|
|
|
50
|
-
// Check if a
|
|
50
|
+
// Check if a compaction block is encountered, if so, stop iteration
|
|
51
51
|
if (
|
|
52
52
|
message.role === "assistant" &&
|
|
53
|
-
message.blocks.some((block) => block.type === "
|
|
53
|
+
message.blocks.some((block) => block.type === "compact")
|
|
54
54
|
) {
|
|
55
|
-
// Add the content of the
|
|
56
|
-
const
|
|
57
|
-
(block) => block.type === "
|
|
55
|
+
// Add the content of the compaction block as an assistant message to the history
|
|
56
|
+
const compactBlock = message.blocks.find(
|
|
57
|
+
(block) => block.type === "compact",
|
|
58
58
|
);
|
|
59
|
-
if (
|
|
59
|
+
if (compactBlock && compactBlock.type === "compact") {
|
|
60
60
|
recentMessages.unshift({
|
|
61
61
|
role: "user",
|
|
62
|
-
content:
|
|
62
|
+
content: compactBlock.content,
|
|
63
63
|
});
|
|
64
64
|
}
|
|
65
65
|
break;
|
|
@@ -14,7 +14,7 @@ export interface ApiRound {
|
|
|
14
14
|
* Boundaries:
|
|
15
15
|
* - A new `role: "user"` message starts a new round.
|
|
16
16
|
* - A new `role: "assistant"` message with a different `id` starts a new round.
|
|
17
|
-
* - A message with a `
|
|
17
|
+
* - A message with a `compact` block is pushed as its own round and starts a
|
|
18
18
|
* new round after it.
|
|
19
19
|
*/
|
|
20
20
|
export function groupMessagesByApiRound(messages: Message[]): ApiRound[] {
|
|
@@ -28,9 +28,9 @@ export function groupMessagesByApiRound(messages: Message[]): ApiRound[] {
|
|
|
28
28
|
if (msg.role === "user") {
|
|
29
29
|
startNewRound = true;
|
|
30
30
|
} else if (msg.role === "assistant") {
|
|
31
|
-
//
|
|
32
|
-
const
|
|
33
|
-
if (
|
|
31
|
+
// Compact block is always its own round
|
|
32
|
+
const hasCompact = msg.blocks.some((b) => b.type === "compact");
|
|
33
|
+
if (hasCompact) {
|
|
34
34
|
startNewRound = true;
|
|
35
35
|
} else if (msg.id !== lastAssistantId) {
|
|
36
36
|
// New assistant id starts a new round.
|
|
@@ -58,10 +58,10 @@ export function groupMessagesByApiRound(messages: Message[]): ApiRound[] {
|
|
|
58
58
|
|
|
59
59
|
currentRound.push(msg);
|
|
60
60
|
|
|
61
|
-
// After pushing a
|
|
61
|
+
// After pushing a compact message as its own round, flush immediately
|
|
62
62
|
if (
|
|
63
63
|
msg.role === "assistant" &&
|
|
64
|
-
msg.blocks.some((b) => b.type === "
|
|
64
|
+
msg.blocks.some((b) => b.type === "compact")
|
|
65
65
|
) {
|
|
66
66
|
rounds.push({
|
|
67
67
|
messages: currentRound,
|
|
@@ -582,11 +582,9 @@ export function getMessageContent(message: Message): string {
|
|
|
582
582
|
return `!${bangBlock.command}`;
|
|
583
583
|
}
|
|
584
584
|
|
|
585
|
-
const
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
if (compressBlock && "content" in compressBlock) {
|
|
589
|
-
return compressBlock.content;
|
|
585
|
+
const compactBlock = message.blocks.find((block) => block.type === "compact");
|
|
586
|
+
if (compactBlock && "content" in compactBlock) {
|
|
587
|
+
return compactBlock.content;
|
|
590
588
|
}
|
|
591
589
|
|
|
592
590
|
return "";
|