@ynhcj/xiaoyi-channel 0.0.29-beta → 0.0.31-beta
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.
|
@@ -2,6 +2,18 @@ import { getXYWebSocketManager } from "../client.js";
|
|
|
2
2
|
import { sendCommand } from "../formatter.js";
|
|
3
3
|
import { getCurrentSessionContext } from "./session-manager.js";
|
|
4
4
|
import { logger } from "../utils/logger.js";
|
|
5
|
+
/**
|
|
6
|
+
* Duck-typed ToolInputError: openclaw 按 .name 字段匹配,不用 instanceof。
|
|
7
|
+
* 抛出此错误会让 openclaw 返回 HTTP 400 而非 500,
|
|
8
|
+
* LLM 会将其识别为参数错误而非瞬时故障,不会触发重试。
|
|
9
|
+
*/
|
|
10
|
+
class ToolInputError extends Error {
|
|
11
|
+
status = 400;
|
|
12
|
+
constructor(message) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.name = "ToolInputError";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
5
17
|
/**
|
|
6
18
|
* XY note tool - creates a note on user's device.
|
|
7
19
|
* Requires title and content parameters.
|
|
@@ -9,26 +21,35 @@ import { logger } from "../utils/logger.js";
|
|
|
9
21
|
export const noteTool = {
|
|
10
22
|
name: "create_note",
|
|
11
23
|
label: "Create Note",
|
|
12
|
-
description:
|
|
24
|
+
description: `在用户设备上创建备忘录。需要提供备忘录标题和内容。
|
|
25
|
+
注意:
|
|
26
|
+
a. 操作超时时间为60秒,请勿重复调用此工具
|
|
27
|
+
b. 如果遇到各类调用失败场景,最多只能重试一次,不可以重复调用多次。
|
|
28
|
+
c. 调用工具前需认真检查调用参数是否满足工具要求
|
|
29
|
+
`,
|
|
13
30
|
parameters: {
|
|
14
31
|
type: "object",
|
|
15
32
|
properties: {
|
|
16
33
|
title: {
|
|
17
34
|
type: "string",
|
|
18
|
-
description: "
|
|
35
|
+
description: "备忘录标题,必填",
|
|
19
36
|
},
|
|
20
37
|
content: {
|
|
21
38
|
type: "string",
|
|
22
|
-
description: "
|
|
39
|
+
description: "备忘录内容,必填",
|
|
23
40
|
},
|
|
24
41
|
},
|
|
25
42
|
required: ["title", "content"],
|
|
26
43
|
},
|
|
27
44
|
async execute(toolCallId, params) {
|
|
28
45
|
logger.debug("Executing note tool, toolCallId:", toolCallId);
|
|
29
|
-
// Validate parameters
|
|
30
|
-
|
|
31
|
-
|
|
46
|
+
// Validate parameters — 抛 ToolInputError 而非普通 Error,
|
|
47
|
+
// 让 openclaw 返回 400 而非 500,明确告知 LLM 这是参数错误,不应重试。
|
|
48
|
+
if (typeof params.title !== "string" || !params.title) {
|
|
49
|
+
throw new ToolInputError("缺少必填参数 title(备忘录标题)");
|
|
50
|
+
}
|
|
51
|
+
if (typeof params.content !== "string" || !params.content) {
|
|
52
|
+
throw new ToolInputError("缺少必填参数 content(备忘录内容)");
|
|
32
53
|
}
|
|
33
54
|
// Get session context
|
|
34
55
|
const sessionContext = getCurrentSessionContext();
|
|
@@ -37,5 +37,8 @@ export declare function runWithSessionContext<T>(context: SessionContext, callba
|
|
|
37
37
|
* Get the current session context from AsyncLocalStorage.
|
|
38
38
|
* This is the recommended way to access session context in tools.
|
|
39
39
|
* Returns null if not running within a session context.
|
|
40
|
+
*
|
|
41
|
+
* Enhanced version: Automatically fetches the latest taskId from task-manager
|
|
42
|
+
* to support interruption scenarios where a new message updates the taskId.
|
|
40
43
|
*/
|
|
41
44
|
export declare function getCurrentSessionContext(): SessionContext | null;
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { AsyncLocalStorage } from "async_hooks";
|
|
4
4
|
import { logger } from "../utils/logger.js";
|
|
5
5
|
import { configManager } from "../utils/config-manager.js";
|
|
6
|
+
import { getCurrentTaskId, getCurrentMessageId } from "../task-manager.js";
|
|
6
7
|
// Map of sessionKey -> SessionContextWithRef
|
|
7
8
|
const activeSessions = new Map();
|
|
8
9
|
// AsyncLocalStorage for thread-safe session context isolation
|
|
@@ -116,16 +117,39 @@ export function runWithSessionContext(context, callback) {
|
|
|
116
117
|
* Get the current session context from AsyncLocalStorage.
|
|
117
118
|
* This is the recommended way to access session context in tools.
|
|
118
119
|
* Returns null if not running within a session context.
|
|
120
|
+
*
|
|
121
|
+
* Enhanced version: Automatically fetches the latest taskId from task-manager
|
|
122
|
+
* to support interruption scenarios where a new message updates the taskId.
|
|
119
123
|
*/
|
|
120
124
|
export function getCurrentSessionContext() {
|
|
125
|
+
// 1. Get base context from AsyncLocalStorage
|
|
121
126
|
const context = asyncLocalStorage.getStore() ?? null;
|
|
122
|
-
if (context) {
|
|
123
|
-
logger.log(`[SESSION_MANAGER] ✅ Got current session context from AsyncLocalStorage`);
|
|
124
|
-
logger.log(`[SESSION_MANAGER] - sessionId: ${context.sessionId}`);
|
|
125
|
-
logger.log(`[SESSION_MANAGER] - taskId: ${context.taskId}`);
|
|
126
|
-
}
|
|
127
|
-
else {
|
|
127
|
+
if (!context) {
|
|
128
128
|
logger.warn(`[SESSION_MANAGER] ⚠️ No session context in AsyncLocalStorage`);
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
// 2. Get latest taskId and messageId from task-manager
|
|
132
|
+
const latestTaskId = getCurrentTaskId(context.sessionId);
|
|
133
|
+
const latestMessageId = getCurrentMessageId(context.sessionId);
|
|
134
|
+
// 3. If task-manager has a newer taskId, use the latest value
|
|
135
|
+
if (latestTaskId && latestTaskId !== context.taskId) {
|
|
136
|
+
logger.log(`[SESSION_MANAGER] 🔄 TaskId updated (interruption detected)`);
|
|
137
|
+
logger.log(`[SESSION_MANAGER] - sessionId: ${context.sessionId}`);
|
|
138
|
+
logger.log(`[SESSION_MANAGER] - Old taskId: ${context.taskId}`);
|
|
139
|
+
logger.log(`[SESSION_MANAGER] - New taskId: ${latestTaskId}`);
|
|
140
|
+
logger.log(`[SESSION_MANAGER] - Old messageId: ${context.messageId}`);
|
|
141
|
+
logger.log(`[SESSION_MANAGER] - New messageId: ${latestMessageId ?? context.messageId}`);
|
|
142
|
+
// Return updated context (create new object, don't modify original)
|
|
143
|
+
return {
|
|
144
|
+
...context,
|
|
145
|
+
taskId: latestTaskId,
|
|
146
|
+
messageId: latestMessageId ?? context.messageId,
|
|
147
|
+
};
|
|
129
148
|
}
|
|
149
|
+
// 4. No update needed, return original context
|
|
150
|
+
logger.log(`[SESSION_MANAGER] ✅ Got current session context from AsyncLocalStorage`);
|
|
151
|
+
logger.log(`[SESSION_MANAGER] - sessionId: ${context.sessionId}`);
|
|
152
|
+
logger.log(`[SESSION_MANAGER] - taskId: ${context.taskId}`);
|
|
153
|
+
logger.log(`[SESSION_MANAGER] - messageId: ${context.messageId}`);
|
|
130
154
|
return context;
|
|
131
155
|
}
|