flashclaw 1.0.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/LICENSE +21 -0
- package/README.md +305 -0
- package/config/plugins.json +23 -0
- package/dist/agent-runner.d.ts +103 -0
- package/dist/agent-runner.d.ts.map +1 -0
- package/dist/agent-runner.js +530 -0
- package/dist/agent-runner.js.map +1 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +497 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands.d.ts +68 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +252 -0
- package/dist/commands.js.map +1 -0
- package/dist/config-schema.d.ts +21 -0
- package/dist/config-schema.d.ts.map +1 -0
- package/dist/config-schema.js +26 -0
- package/dist/config-schema.js.map +1 -0
- package/dist/config.d.ts +11 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +36 -0
- package/dist/config.js.map +1 -0
- package/dist/core/api-client.d.ts +236 -0
- package/dist/core/api-client.d.ts.map +1 -0
- package/dist/core/api-client.js +369 -0
- package/dist/core/api-client.js.map +1 -0
- package/dist/core/memory.d.ts +291 -0
- package/dist/core/memory.d.ts.map +1 -0
- package/dist/core/memory.js +754 -0
- package/dist/core/memory.js.map +1 -0
- package/dist/core/model-capabilities.d.ts +45 -0
- package/dist/core/model-capabilities.d.ts.map +1 -0
- package/dist/core/model-capabilities.js +85 -0
- package/dist/core/model-capabilities.js.map +1 -0
- package/dist/db.d.ts +103 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +380 -0
- package/dist/db.js.map +1 -0
- package/dist/errors.d.ts +22 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +44 -0
- package/dist/errors.js.map +1 -0
- package/dist/health.d.ts +27 -0
- package/dist/health.d.ts.map +1 -0
- package/dist/health.js +55 -0
- package/dist/health.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1181 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +9 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +19 -0
- package/dist/logger.js.map +1 -0
- package/dist/message-queue.d.ts +69 -0
- package/dist/message-queue.d.ts.map +1 -0
- package/dist/message-queue.js +198 -0
- package/dist/message-queue.js.map +1 -0
- package/dist/metrics.d.ts +46 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +101 -0
- package/dist/metrics.js.map +1 -0
- package/dist/paths.d.ts +81 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +127 -0
- package/dist/paths.js.map +1 -0
- package/dist/plugins/index.d.ts +9 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +13 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/installer.d.ts +120 -0
- package/dist/plugins/installer.d.ts.map +1 -0
- package/dist/plugins/installer.js +1008 -0
- package/dist/plugins/installer.js.map +1 -0
- package/dist/plugins/loader.d.ts +37 -0
- package/dist/plugins/loader.d.ts.map +1 -0
- package/dist/plugins/loader.js +429 -0
- package/dist/plugins/loader.js.map +1 -0
- package/dist/plugins/manager.d.ts +72 -0
- package/dist/plugins/manager.d.ts.map +1 -0
- package/dist/plugins/manager.js +187 -0
- package/dist/plugins/manager.js.map +1 -0
- package/dist/plugins/types.d.ts +101 -0
- package/dist/plugins/types.d.ts.map +1 -0
- package/dist/plugins/types.js +12 -0
- package/dist/plugins/types.js.map +1 -0
- package/dist/session-tracker.d.ts +81 -0
- package/dist/session-tracker.d.ts.map +1 -0
- package/dist/session-tracker.js +228 -0
- package/dist/session-tracker.js.map +1 -0
- package/dist/task-scheduler.d.ts +47 -0
- package/dist/task-scheduler.d.ts.map +1 -0
- package/dist/task-scheduler.js +331 -0
- package/dist/task-scheduler.js.map +1 -0
- package/dist/types.d.ts +57 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/env-substitute.d.ts +63 -0
- package/dist/utils/env-substitute.d.ts.map +1 -0
- package/dist/utils/env-substitute.js +133 -0
- package/dist/utils/env-substitute.js.map +1 -0
- package/dist/utils/log-rotate.d.ts +19 -0
- package/dist/utils/log-rotate.d.ts.map +1 -0
- package/dist/utils/log-rotate.js +85 -0
- package/dist/utils/log-rotate.js.map +1 -0
- package/dist/utils/rate-limiter.d.ts +38 -0
- package/dist/utils/rate-limiter.d.ts.map +1 -0
- package/dist/utils/rate-limiter.js +79 -0
- package/dist/utils/rate-limiter.js.map +1 -0
- package/dist/utils/retry.d.ts +10 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +47 -0
- package/dist/utils/retry.js.map +1 -0
- package/dist/utils.d.ts +86 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +218 -0
- package/dist/utils.js.map +1 -0
- package/package.json +78 -0
- package/plugins/cancel-task/index.ts +161 -0
- package/plugins/cancel-task/plugin.json +9 -0
- package/plugins/feishu/index.ts +944 -0
- package/plugins/feishu/plugin.json +29 -0
- package/plugins/list-tasks/index.ts +150 -0
- package/plugins/list-tasks/plugin.json +9 -0
- package/plugins/memory/index.ts +190 -0
- package/plugins/memory/plugin.json +7 -0
- package/plugins/pause-task/index.ts +95 -0
- package/plugins/pause-task/plugin.json +8 -0
- package/plugins/register-group/index.ts +147 -0
- package/plugins/register-group/plugin.json +7 -0
- package/plugins/resume-task/index.ts +92 -0
- package/plugins/resume-task/plugin.json +8 -0
- package/plugins/schedule-task/index.ts +248 -0
- package/plugins/schedule-task/plugin.json +9 -0
- package/plugins/send-message/index.ts +75 -0
- package/plugins/send-message/plugin.json +9 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FlashClaw 插件管理器
|
|
3
|
+
* 负责插件的注册、卸载和查询
|
|
4
|
+
*/
|
|
5
|
+
import { isToolPlugin, isChannelPlugin, } from './types.js';
|
|
6
|
+
import { createLogger } from '../logger.js';
|
|
7
|
+
const logger = createLogger('PluginManager');
|
|
8
|
+
/**
|
|
9
|
+
* 插件管理器
|
|
10
|
+
* 管理所有已加载的插件
|
|
11
|
+
*/
|
|
12
|
+
export class PluginManager {
|
|
13
|
+
// 插件注册表:name -> PluginEntry
|
|
14
|
+
plugins = new Map();
|
|
15
|
+
/**
|
|
16
|
+
* 注册插件
|
|
17
|
+
* @param plugin 插件实例
|
|
18
|
+
* @returns 是否注册成功
|
|
19
|
+
*/
|
|
20
|
+
register(plugin) {
|
|
21
|
+
const name = plugin.name;
|
|
22
|
+
// 检查是否已存在
|
|
23
|
+
if (this.plugins.has(name)) {
|
|
24
|
+
logger.warn({ plugin: name }, '插件已存在,跳过注册');
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
// 确定插件类型
|
|
28
|
+
const type = isToolPlugin(plugin) ? 'tool' : 'channel';
|
|
29
|
+
// 注册
|
|
30
|
+
this.plugins.set(name, {
|
|
31
|
+
plugin,
|
|
32
|
+
type,
|
|
33
|
+
loadedAt: new Date(),
|
|
34
|
+
});
|
|
35
|
+
logger.info({ plugin: name, type, version: plugin.version }, '⚡ 已注册插件');
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* 卸载插件
|
|
40
|
+
* @param name 插件名称
|
|
41
|
+
* @returns 是否卸载成功
|
|
42
|
+
*/
|
|
43
|
+
async unregister(name) {
|
|
44
|
+
const entry = this.plugins.get(name);
|
|
45
|
+
if (!entry) {
|
|
46
|
+
logger.warn({ plugin: name }, '插件不存在');
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
// 如果是渠道插件,先停止
|
|
50
|
+
if (isChannelPlugin(entry.plugin)) {
|
|
51
|
+
try {
|
|
52
|
+
await entry.plugin.stop();
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
logger.error({ plugin: name, err }, '停止渠道插件失败');
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
this.plugins.delete(name);
|
|
59
|
+
logger.info({ plugin: name }, '⚡ 已卸载插件');
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* 获取所有工具的 Schema
|
|
64
|
+
* 用于传递给 AI Agent
|
|
65
|
+
*/
|
|
66
|
+
getActiveTools() {
|
|
67
|
+
const schemas = [];
|
|
68
|
+
for (const entry of this.plugins.values()) {
|
|
69
|
+
if (entry.type === 'tool' && isToolPlugin(entry.plugin)) {
|
|
70
|
+
// 支持多工具插件(tools 数组)
|
|
71
|
+
if (entry.plugin.tools && Array.isArray(entry.plugin.tools)) {
|
|
72
|
+
schemas.push(...entry.plugin.tools);
|
|
73
|
+
}
|
|
74
|
+
else if (entry.plugin.schema) {
|
|
75
|
+
// 单工具插件
|
|
76
|
+
schemas.push(entry.plugin.schema);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return schemas;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* 获取所有渠道插件
|
|
84
|
+
*/
|
|
85
|
+
getActiveChannels() {
|
|
86
|
+
const channels = [];
|
|
87
|
+
for (const entry of this.plugins.values()) {
|
|
88
|
+
if (entry.type === 'channel' && isChannelPlugin(entry.plugin)) {
|
|
89
|
+
channels.push(entry.plugin);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return channels;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* 获取指定工具插件
|
|
96
|
+
* @param toolName 工具名称
|
|
97
|
+
* @returns 插件和是否为多工具模式
|
|
98
|
+
*/
|
|
99
|
+
getTool(toolName) {
|
|
100
|
+
// 1. 先按插件名称查找(单工具模式:插件名 = 工具名)
|
|
101
|
+
const entry = this.plugins.get(toolName);
|
|
102
|
+
if (entry && entry.type === 'tool' && isToolPlugin(entry.plugin)) {
|
|
103
|
+
return { plugin: entry.plugin, isMultiTool: false };
|
|
104
|
+
}
|
|
105
|
+
// 2. 再在所有工具插件的 tools 数组中查找(多工具模式)
|
|
106
|
+
for (const pluginEntry of this.plugins.values()) {
|
|
107
|
+
if (pluginEntry.type === 'tool' && isToolPlugin(pluginEntry.plugin)) {
|
|
108
|
+
const plugin = pluginEntry.plugin;
|
|
109
|
+
if (plugin.tools && Array.isArray(plugin.tools)) {
|
|
110
|
+
const found = plugin.tools.some(t => t.name === toolName);
|
|
111
|
+
if (found) {
|
|
112
|
+
return { plugin, isMultiTool: true };
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* 获取指定渠道插件
|
|
121
|
+
* @param name 渠道名称
|
|
122
|
+
*/
|
|
123
|
+
getChannel(name) {
|
|
124
|
+
const entry = this.plugins.get(name);
|
|
125
|
+
if (entry && entry.type === 'channel' && isChannelPlugin(entry.plugin)) {
|
|
126
|
+
return entry.plugin;
|
|
127
|
+
}
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* 获取所有已注册的插件名称
|
|
132
|
+
*/
|
|
133
|
+
getPluginNames() {
|
|
134
|
+
return Array.from(this.plugins.keys());
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* 获取插件数量统计
|
|
138
|
+
*/
|
|
139
|
+
getStats() {
|
|
140
|
+
let tools = 0;
|
|
141
|
+
let channels = 0;
|
|
142
|
+
for (const entry of this.plugins.values()) {
|
|
143
|
+
if (entry.type === 'tool')
|
|
144
|
+
tools++;
|
|
145
|
+
else
|
|
146
|
+
channels++;
|
|
147
|
+
}
|
|
148
|
+
return { total: this.plugins.size, tools, channels };
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* 清空所有插件
|
|
152
|
+
*/
|
|
153
|
+
async clear() {
|
|
154
|
+
// 先停止所有渠道
|
|
155
|
+
for (const entry of this.plugins.values()) {
|
|
156
|
+
if (isChannelPlugin(entry.plugin)) {
|
|
157
|
+
await entry.plugin.stop().catch(() => { });
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
this.plugins.clear();
|
|
161
|
+
logger.info('⚡ 已清空所有插件');
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* 停止所有渠道插件(不清空注册)
|
|
165
|
+
*/
|
|
166
|
+
async stopAll() {
|
|
167
|
+
const promises = [];
|
|
168
|
+
for (const entry of this.plugins.values()) {
|
|
169
|
+
if (isChannelPlugin(entry.plugin)) {
|
|
170
|
+
promises.push(entry.plugin.stop().catch((err) => {
|
|
171
|
+
logger.warn({ plugin: entry.plugin.name, err }, '停止插件失败');
|
|
172
|
+
}));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
await Promise.all(promises);
|
|
176
|
+
logger.info('⚡ 所有渠道插件已停止');
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
function getPluginManager() {
|
|
180
|
+
if (!global.__flashclaw_plugin_manager) {
|
|
181
|
+
global.__flashclaw_plugin_manager = new PluginManager();
|
|
182
|
+
}
|
|
183
|
+
return global.__flashclaw_plugin_manager;
|
|
184
|
+
}
|
|
185
|
+
// 导出单例(通过全局变量)
|
|
186
|
+
export const pluginManager = getPluginManager();
|
|
187
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/plugins/manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FlashClaw 插件类型定义
|
|
3
|
+
* 乐高式架构 - 放进去就能用
|
|
4
|
+
*/
|
|
5
|
+
export interface PluginConfig {
|
|
6
|
+
[key: string]: unknown;
|
|
7
|
+
}
|
|
8
|
+
export interface ToolContext {
|
|
9
|
+
chatId: string;
|
|
10
|
+
groupId: string;
|
|
11
|
+
userId: string;
|
|
12
|
+
sendMessage: (content: string) => Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
export interface ToolResult {
|
|
15
|
+
success: boolean;
|
|
16
|
+
data?: unknown;
|
|
17
|
+
error?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface Attachment {
|
|
20
|
+
type: 'image' | 'video' | 'audio' | 'file';
|
|
21
|
+
content?: string;
|
|
22
|
+
mimeType?: string;
|
|
23
|
+
fileName?: string;
|
|
24
|
+
fileKey?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface Message {
|
|
27
|
+
id: string;
|
|
28
|
+
chatId: string;
|
|
29
|
+
senderId: string;
|
|
30
|
+
senderName: string;
|
|
31
|
+
content: string;
|
|
32
|
+
timestamp: string;
|
|
33
|
+
chatType: 'p2p' | 'group';
|
|
34
|
+
platform: string;
|
|
35
|
+
attachments?: Attachment[];
|
|
36
|
+
mentions?: string[];
|
|
37
|
+
replyToMessageId?: string;
|
|
38
|
+
}
|
|
39
|
+
export type MessageHandler = (message: Message) => Promise<void>;
|
|
40
|
+
export interface ToolSchema {
|
|
41
|
+
name: string;
|
|
42
|
+
description: string;
|
|
43
|
+
input_schema: {
|
|
44
|
+
type: 'object';
|
|
45
|
+
properties: Record<string, unknown>;
|
|
46
|
+
required?: string[];
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
export interface PluginManifest {
|
|
50
|
+
name: string;
|
|
51
|
+
version: string;
|
|
52
|
+
type: 'tool' | 'channel';
|
|
53
|
+
description: string;
|
|
54
|
+
author?: string;
|
|
55
|
+
main: string;
|
|
56
|
+
config?: Record<string, {
|
|
57
|
+
type: string;
|
|
58
|
+
required?: boolean;
|
|
59
|
+
env?: string;
|
|
60
|
+
default?: unknown;
|
|
61
|
+
}>;
|
|
62
|
+
dependencies?: string[];
|
|
63
|
+
}
|
|
64
|
+
export interface ToolPlugin {
|
|
65
|
+
name: string;
|
|
66
|
+
version: string;
|
|
67
|
+
description: string;
|
|
68
|
+
schema?: ToolSchema;
|
|
69
|
+
tools?: ToolSchema[];
|
|
70
|
+
init?(config: PluginConfig): Promise<void>;
|
|
71
|
+
execute(paramsOrToolName: unknown, contextOrParams?: ToolContext | unknown, context?: ToolContext): Promise<ToolResult>;
|
|
72
|
+
reload?(): Promise<void>;
|
|
73
|
+
cleanup?(): Promise<void>;
|
|
74
|
+
}
|
|
75
|
+
export interface SendMessageOptions {
|
|
76
|
+
placeholderMessageId?: string;
|
|
77
|
+
attachments?: Attachment[];
|
|
78
|
+
}
|
|
79
|
+
export interface SendMessageResult {
|
|
80
|
+
messageId?: string;
|
|
81
|
+
success: boolean;
|
|
82
|
+
error?: string;
|
|
83
|
+
}
|
|
84
|
+
export interface ChannelPlugin {
|
|
85
|
+
name: string;
|
|
86
|
+
version: string;
|
|
87
|
+
init(config: PluginConfig): Promise<void>;
|
|
88
|
+
start(): Promise<void>;
|
|
89
|
+
stop(): Promise<void>;
|
|
90
|
+
onMessage(handler: MessageHandler): void;
|
|
91
|
+
sendMessage(chatId: string, content: string, options?: SendMessageOptions): Promise<SendMessageResult>;
|
|
92
|
+
updateMessage?(messageId: string, content: string): Promise<void>;
|
|
93
|
+
deleteMessage?(messageId: string): Promise<void>;
|
|
94
|
+
sendImage?(chatId: string, imageData: string | Buffer, caption?: string): Promise<SendMessageResult>;
|
|
95
|
+
sendFile?(chatId: string, filePath: string, fileName?: string): Promise<SendMessageResult>;
|
|
96
|
+
reload?(): Promise<void>;
|
|
97
|
+
}
|
|
98
|
+
export type Plugin = ToolPlugin | ChannelPlugin;
|
|
99
|
+
export declare function isToolPlugin(plugin: Plugin): plugin is ToolPlugin;
|
|
100
|
+
export declare function isChannelPlugin(plugin: Plugin): plugin is ChannelPlugin;
|
|
101
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/plugins/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FlashClaw 插件类型定义
|
|
3
|
+
* 乐高式架构 - 放进去就能用
|
|
4
|
+
*/
|
|
5
|
+
// 类型守卫
|
|
6
|
+
export function isToolPlugin(plugin) {
|
|
7
|
+
return ('schema' in plugin || 'tools' in plugin) && 'execute' in plugin;
|
|
8
|
+
}
|
|
9
|
+
export function isChannelPlugin(plugin) {
|
|
10
|
+
return 'onMessage' in plugin && 'sendMessage' in plugin;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/plugins/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAwIH,OAAO;AACP,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,OAAO,CAAC,QAAQ,IAAI,MAAM,IAAI,OAAO,IAAI,MAAM,CAAC,IAAI,SAAS,IAAI,MAAM,CAAC;AAC1E,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,OAAO,WAAW,IAAI,MAAM,IAAI,aAAa,IAAI,MAAM,CAAC;AAC1D,CAAC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Tracker
|
|
3
|
+
*
|
|
4
|
+
* 追踪每个会话的 token 使用量和状态
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* 会话统计数据
|
|
8
|
+
*/
|
|
9
|
+
export interface SessionData {
|
|
10
|
+
/** 会话 ID (chatId) */
|
|
11
|
+
chatId: string;
|
|
12
|
+
/** 消息数量 */
|
|
13
|
+
messageCount: number;
|
|
14
|
+
/** 累计输入 token */
|
|
15
|
+
inputTokens: number;
|
|
16
|
+
/** 累计输出 token */
|
|
17
|
+
outputTokens: number;
|
|
18
|
+
/** 总 token 数 */
|
|
19
|
+
totalTokens: number;
|
|
20
|
+
/** 使用的模型 */
|
|
21
|
+
model: string;
|
|
22
|
+
/** 会话开始时间 */
|
|
23
|
+
startedAt: string;
|
|
24
|
+
/** 最后活动时间 */
|
|
25
|
+
lastActivityAt: string;
|
|
26
|
+
/** 是否已提示过压缩 */
|
|
27
|
+
compactSuggested: boolean;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Token 使用情况
|
|
31
|
+
*/
|
|
32
|
+
export interface TokenUsage {
|
|
33
|
+
inputTokens: number;
|
|
34
|
+
outputTokens: number;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 获取或创建会话数据
|
|
38
|
+
*/
|
|
39
|
+
export declare function getOrCreateSession(chatId: string, model?: string): SessionData;
|
|
40
|
+
/**
|
|
41
|
+
* 获取会话数据(不创建)
|
|
42
|
+
*/
|
|
43
|
+
export declare function getSession(chatId: string): SessionData | null;
|
|
44
|
+
/**
|
|
45
|
+
* 记录 token 使用
|
|
46
|
+
*/
|
|
47
|
+
export declare function recordTokenUsage(chatId: string, usage: TokenUsage, model?: string): SessionData;
|
|
48
|
+
/**
|
|
49
|
+
* 获取模型的上下文窗口大小
|
|
50
|
+
*/
|
|
51
|
+
export declare function getContextWindowSize(model?: string): number;
|
|
52
|
+
/**
|
|
53
|
+
* 检查是否需要提示压缩
|
|
54
|
+
*
|
|
55
|
+
* @returns 如果需要提示返回使用率百分比,否则返回 null
|
|
56
|
+
*/
|
|
57
|
+
export declare function checkCompactThreshold(chatId: string): number | null;
|
|
58
|
+
/**
|
|
59
|
+
* 重置会话
|
|
60
|
+
*/
|
|
61
|
+
export declare function resetSession(chatId: string): void;
|
|
62
|
+
/**
|
|
63
|
+
* 获取会话统计(用于 /status 命令)
|
|
64
|
+
*/
|
|
65
|
+
export declare function getSessionStats(chatId: string): {
|
|
66
|
+
messageCount: number;
|
|
67
|
+
tokenCount: number;
|
|
68
|
+
maxTokens: number;
|
|
69
|
+
model: string;
|
|
70
|
+
startedAt: string;
|
|
71
|
+
usagePercent: number;
|
|
72
|
+
} | null;
|
|
73
|
+
/**
|
|
74
|
+
* 获取所有活跃会话数量
|
|
75
|
+
*/
|
|
76
|
+
export declare function getActiveSessionCount(): number;
|
|
77
|
+
/**
|
|
78
|
+
* 清理过期会话(超过 24 小时无活动)
|
|
79
|
+
*/
|
|
80
|
+
export declare function cleanupStaleSessions(maxAgeMs?: number): number;
|
|
81
|
+
//# sourceMappingURL=session-tracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-tracker.d.ts","sourceRoot":"","sources":["../src/session-tracker.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAaH;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,qBAAqB;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,aAAa;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe;IACf,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB;AAyDD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,WAAW,CAqB9E;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAE7D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,WAAW,CA8B/F;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAsB3D;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAiBnE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAIjD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG;IAC/C,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,IAAI,CAiBP;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,GAAE,MAA4B,GAAG,MAAM,CAkBnF"}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Tracker
|
|
3
|
+
*
|
|
4
|
+
* 追踪每个会话的 token 使用量和状态
|
|
5
|
+
*/
|
|
6
|
+
import pino from 'pino';
|
|
7
|
+
import { existsSync, readFileSync, statSync } from 'fs';
|
|
8
|
+
import { promises as fs } from 'fs';
|
|
9
|
+
import { join } from 'path';
|
|
10
|
+
import { getFlashClawHome } from './paths.js';
|
|
11
|
+
const logger = pino({
|
|
12
|
+
level: process.env.LOG_LEVEL || 'info',
|
|
13
|
+
transport: { target: 'pino-pretty', options: { colorize: true } }
|
|
14
|
+
});
|
|
15
|
+
// 内存存储 - 按 chatId 存储会话数据
|
|
16
|
+
const sessions = new Map();
|
|
17
|
+
const SESSION_CACHE_PATH = join(getFlashClawHome(), 'cache', 'session-tracker.json');
|
|
18
|
+
const MAX_SESSION_CACHE_BYTES = 10 * 1024 * 1024;
|
|
19
|
+
let persistTimer = null;
|
|
20
|
+
function loadSessionsFromDisk() {
|
|
21
|
+
try {
|
|
22
|
+
if (!existsSync(SESSION_CACHE_PATH))
|
|
23
|
+
return;
|
|
24
|
+
const stat = statSync(SESSION_CACHE_PATH);
|
|
25
|
+
if (stat.size > MAX_SESSION_CACHE_BYTES) {
|
|
26
|
+
logger.warn({ size: stat.size }, '📊 会话追踪缓存文件过大,跳过加载');
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const content = readFileSync(SESSION_CACHE_PATH, 'utf-8');
|
|
30
|
+
const parsed = JSON.parse(content);
|
|
31
|
+
if (!Array.isArray(parsed))
|
|
32
|
+
return;
|
|
33
|
+
for (const item of parsed) {
|
|
34
|
+
if (item && typeof item.chatId === 'string') {
|
|
35
|
+
sessions.set(item.chatId, item);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
logger.debug({ count: sessions.size }, '📊 会话追踪缓存已加载');
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
logger.warn({ error }, '📊 加载会话追踪缓存失败');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async function persistSessions() {
|
|
45
|
+
try {
|
|
46
|
+
const cacheDir = join(getFlashClawHome(), 'cache');
|
|
47
|
+
await fs.mkdir(cacheDir, { recursive: true });
|
|
48
|
+
const payload = JSON.stringify(Array.from(sessions.values()), null, 2);
|
|
49
|
+
await fs.writeFile(SESSION_CACHE_PATH, payload, 'utf-8');
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
logger.warn({ error }, '📊 保存会话追踪缓存失败');
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function schedulePersist() {
|
|
56
|
+
if (persistTimer)
|
|
57
|
+
return;
|
|
58
|
+
persistTimer = setTimeout(() => {
|
|
59
|
+
persistTimer = null;
|
|
60
|
+
void persistSessions();
|
|
61
|
+
}, 1000);
|
|
62
|
+
persistTimer.unref?.();
|
|
63
|
+
}
|
|
64
|
+
// 默认上下文窗口大小(Claude 3.5 Sonnet = 200k)
|
|
65
|
+
const DEFAULT_CONTEXT_WINDOW = 200000;
|
|
66
|
+
// 压缩提示阈值(70%)
|
|
67
|
+
const COMPACT_THRESHOLD = 0.7;
|
|
68
|
+
/**
|
|
69
|
+
* 获取或创建会话数据
|
|
70
|
+
*/
|
|
71
|
+
export function getOrCreateSession(chatId, model) {
|
|
72
|
+
let session = sessions.get(chatId);
|
|
73
|
+
if (!session) {
|
|
74
|
+
const now = new Date().toISOString();
|
|
75
|
+
session = {
|
|
76
|
+
chatId,
|
|
77
|
+
messageCount: 0,
|
|
78
|
+
inputTokens: 0,
|
|
79
|
+
outputTokens: 0,
|
|
80
|
+
totalTokens: 0,
|
|
81
|
+
model: model || process.env.AI_MODEL || 'claude-4-5-sonnet-20250929',
|
|
82
|
+
startedAt: now,
|
|
83
|
+
lastActivityAt: now,
|
|
84
|
+
compactSuggested: false
|
|
85
|
+
};
|
|
86
|
+
sessions.set(chatId, session);
|
|
87
|
+
logger.debug({ chatId }, '📊 新建会话追踪');
|
|
88
|
+
}
|
|
89
|
+
return session;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* 获取会话数据(不创建)
|
|
93
|
+
*/
|
|
94
|
+
export function getSession(chatId) {
|
|
95
|
+
return sessions.get(chatId) || null;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* 记录 token 使用
|
|
99
|
+
*/
|
|
100
|
+
export function recordTokenUsage(chatId, usage, model) {
|
|
101
|
+
const session = getOrCreateSession(chatId, model);
|
|
102
|
+
const inputTokens = Number.isFinite(usage.inputTokens) && usage.inputTokens >= 0 ? usage.inputTokens : 0;
|
|
103
|
+
const outputTokens = Number.isFinite(usage.outputTokens) && usage.outputTokens >= 0 ? usage.outputTokens : 0;
|
|
104
|
+
if (inputTokens !== usage.inputTokens || outputTokens !== usage.outputTokens) {
|
|
105
|
+
logger.warn({ chatId, usage }, '📊 发现无效 token 数据,已忽略');
|
|
106
|
+
}
|
|
107
|
+
session.messageCount += 1;
|
|
108
|
+
session.inputTokens += inputTokens;
|
|
109
|
+
session.outputTokens += outputTokens;
|
|
110
|
+
session.totalTokens = session.inputTokens + session.outputTokens;
|
|
111
|
+
session.lastActivityAt = new Date().toISOString();
|
|
112
|
+
if (model) {
|
|
113
|
+
session.model = model;
|
|
114
|
+
}
|
|
115
|
+
logger.debug({
|
|
116
|
+
chatId,
|
|
117
|
+
inputTokens,
|
|
118
|
+
outputTokens,
|
|
119
|
+
totalTokens: session.totalTokens
|
|
120
|
+
}, '📊 Token 使用已记录');
|
|
121
|
+
schedulePersist();
|
|
122
|
+
return session;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* 获取模型的上下文窗口大小
|
|
126
|
+
*/
|
|
127
|
+
export function getContextWindowSize(model) {
|
|
128
|
+
// Claude 模型的上下文窗口
|
|
129
|
+
const contextWindows = {
|
|
130
|
+
'claude-4-5-sonnet-20250929': 200000,
|
|
131
|
+
'claude-3-5-sonnet-20241022': 200000,
|
|
132
|
+
'claude-3-opus-20240229': 200000,
|
|
133
|
+
'claude-3-sonnet-20240229': 200000,
|
|
134
|
+
'claude-3-haiku-20240307': 200000,
|
|
135
|
+
};
|
|
136
|
+
// 匹配模型名称(支持部分匹配)
|
|
137
|
+
if (!model) {
|
|
138
|
+
return DEFAULT_CONTEXT_WINDOW;
|
|
139
|
+
}
|
|
140
|
+
for (const [key, value] of Object.entries(contextWindows)) {
|
|
141
|
+
if (model.includes(key) || key.includes(model)) {
|
|
142
|
+
return value;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return DEFAULT_CONTEXT_WINDOW;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* 检查是否需要提示压缩
|
|
149
|
+
*
|
|
150
|
+
* @returns 如果需要提示返回使用率百分比,否则返回 null
|
|
151
|
+
*/
|
|
152
|
+
export function checkCompactThreshold(chatId) {
|
|
153
|
+
const session = sessions.get(chatId);
|
|
154
|
+
if (!session)
|
|
155
|
+
return null;
|
|
156
|
+
// 已经提示过了
|
|
157
|
+
if (session.compactSuggested)
|
|
158
|
+
return null;
|
|
159
|
+
const maxTokens = getContextWindowSize(session.model);
|
|
160
|
+
if (!Number.isFinite(maxTokens) || maxTokens <= 0)
|
|
161
|
+
return null;
|
|
162
|
+
const usageRate = session.totalTokens / maxTokens;
|
|
163
|
+
if (usageRate >= COMPACT_THRESHOLD) {
|
|
164
|
+
session.compactSuggested = true;
|
|
165
|
+
return Math.round(usageRate * 100);
|
|
166
|
+
}
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* 重置会话
|
|
171
|
+
*/
|
|
172
|
+
export function resetSession(chatId) {
|
|
173
|
+
sessions.delete(chatId);
|
|
174
|
+
schedulePersist();
|
|
175
|
+
logger.debug({ chatId }, '📊 会话追踪已重置');
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* 获取会话统计(用于 /status 命令)
|
|
179
|
+
*/
|
|
180
|
+
export function getSessionStats(chatId) {
|
|
181
|
+
const session = sessions.get(chatId);
|
|
182
|
+
if (!session)
|
|
183
|
+
return null;
|
|
184
|
+
const maxTokens = getContextWindowSize(session.model);
|
|
185
|
+
const usagePercent = maxTokens > 0
|
|
186
|
+
? Math.round((session.totalTokens / maxTokens) * 100)
|
|
187
|
+
: 0;
|
|
188
|
+
return {
|
|
189
|
+
messageCount: session.messageCount,
|
|
190
|
+
tokenCount: session.totalTokens,
|
|
191
|
+
maxTokens,
|
|
192
|
+
model: session.model,
|
|
193
|
+
startedAt: session.startedAt,
|
|
194
|
+
usagePercent
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* 获取所有活跃会话数量
|
|
199
|
+
*/
|
|
200
|
+
export function getActiveSessionCount() {
|
|
201
|
+
return sessions.size;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* 清理过期会话(超过 24 小时无活动)
|
|
205
|
+
*/
|
|
206
|
+
export function cleanupStaleSessions(maxAgeMs = 24 * 60 * 60 * 1000) {
|
|
207
|
+
const now = Date.now();
|
|
208
|
+
let cleaned = 0;
|
|
209
|
+
for (const [chatId, session] of sessions) {
|
|
210
|
+
const lastActivity = new Date(session.lastActivityAt).getTime();
|
|
211
|
+
if (now - lastActivity > maxAgeMs) {
|
|
212
|
+
sessions.delete(chatId);
|
|
213
|
+
cleaned++;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (cleaned > 0) {
|
|
217
|
+
logger.info({ cleaned }, '📊 清理过期会话');
|
|
218
|
+
schedulePersist();
|
|
219
|
+
}
|
|
220
|
+
return cleaned;
|
|
221
|
+
}
|
|
222
|
+
// 初始化:加载缓存并定期清理
|
|
223
|
+
loadSessionsFromDisk();
|
|
224
|
+
const cleanupTimer = setInterval(() => {
|
|
225
|
+
cleanupStaleSessions();
|
|
226
|
+
}, 60 * 60 * 1000);
|
|
227
|
+
cleanupTimer.unref?.();
|
|
228
|
+
//# sourceMappingURL=session-tracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-tracker.js","sourceRoot":"","sources":["../src/session-tracker.ts"],"names":[],"mappings":"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"}
|