@ynhcj/xiaoyi-channel 0.0.45-next → 0.0.46-next
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/dist/index.js +2 -0
- package/dist/src/provider.d.ts +2 -0
- package/dist/src/provider.js +80 -0
- package/dist/src/tools/device-tool-map.js +0 -2
- package/openclaw.plugin.json +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
|
2
2
|
import { xyPlugin } from "./src/channel.js";
|
|
3
|
+
import { xiaoyiProvider } from "./src/provider.js";
|
|
3
4
|
import { setXYRuntime } from "./src/runtime.js";
|
|
4
5
|
import { tryInjectSteer } from "./src/steer-injector.js";
|
|
5
6
|
import { callCsplApi } from "./src/cspl/call-api.js";
|
|
@@ -18,6 +19,7 @@ const plugin = {
|
|
|
18
19
|
register(api) {
|
|
19
20
|
setXYRuntime(api.runtime);
|
|
20
21
|
api.registerChannel({ plugin: xyPlugin });
|
|
22
|
+
api.registerProvider(xiaoyiProvider);
|
|
21
23
|
// CSPL after_tool_call hook: 监听工具结果,发送至 CSPL API 进行安全检测
|
|
22
24
|
// 如果响应为 REJECT,注入 steer 消息中止当前对话
|
|
23
25
|
api.on("after_tool_call", async (event, ctx) => {
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { getCurrentSessionContext } from "./tools/session-manager.js";
|
|
2
|
+
/**
|
|
3
|
+
* Dynamic header keys injected via extraParams and forwarded to the HTTP request.
|
|
4
|
+
* Correspond to the three fields written to .xiaoyiruntime:
|
|
5
|
+
* TASK_ID, SESSION_ID, CONVERSATION_ID
|
|
6
|
+
*/
|
|
7
|
+
const HEADER_TASK_ID = "x-task-id";
|
|
8
|
+
const HEADER_SESSION_ID = "x-session-id";
|
|
9
|
+
const HEADER_CONVERSATION_ID = "x-conversation-id";
|
|
10
|
+
const EXTRA_PARAM_TASK_ID = "x-task-id";
|
|
11
|
+
const EXTRA_PARAM_SESSION_ID = "x-session-id";
|
|
12
|
+
const EXTRA_PARAM_CONVERSATION_ID = "x-conversation-id";
|
|
13
|
+
export const xiaoyiProvider = {
|
|
14
|
+
id: "xiaoyiprovider",
|
|
15
|
+
label: "Xiaoyi Provider",
|
|
16
|
+
docsPath: "/providers/models",
|
|
17
|
+
auth: [],
|
|
18
|
+
/**
|
|
19
|
+
* Inject dynamic session params into extraParams so they flow
|
|
20
|
+
* through to wrapStreamFn's ctx.extraParams.
|
|
21
|
+
*
|
|
22
|
+
* Reads from AsyncLocalStorage (set by bot.ts runWithSessionContext)
|
|
23
|
+
* which automatically fetches the latest taskId from task-manager
|
|
24
|
+
* (handles steer mode taskId switching).
|
|
25
|
+
*/
|
|
26
|
+
prepareExtraParams: (ctx) => {
|
|
27
|
+
const sessionCtx = getCurrentSessionContext();
|
|
28
|
+
if (!sessionCtx)
|
|
29
|
+
return undefined;
|
|
30
|
+
return {
|
|
31
|
+
...ctx.extraParams,
|
|
32
|
+
[EXTRA_PARAM_TASK_ID]: sessionCtx.taskId,
|
|
33
|
+
[EXTRA_PARAM_SESSION_ID]: sessionCtx.sessionId,
|
|
34
|
+
[EXTRA_PARAM_CONVERSATION_ID]: sessionCtx.messageId,
|
|
35
|
+
};
|
|
36
|
+
},
|
|
37
|
+
/**
|
|
38
|
+
* Wrap the stream function to inject dynamic headers into every
|
|
39
|
+
* HTTP request to the model provider.
|
|
40
|
+
*
|
|
41
|
+
* Reads the values injected by prepareExtraParams and adds them
|
|
42
|
+
* as HTTP headers on the outgoing request.
|
|
43
|
+
*/
|
|
44
|
+
wrapStreamFn: (ctx) => {
|
|
45
|
+
const underlying = ctx.streamFn;
|
|
46
|
+
if (!underlying)
|
|
47
|
+
return underlying;
|
|
48
|
+
const dynamicHeaders = {};
|
|
49
|
+
if (ctx.extraParams) {
|
|
50
|
+
const taskId = ctx.extraParams[EXTRA_PARAM_TASK_ID];
|
|
51
|
+
const sessionId = ctx.extraParams[EXTRA_PARAM_SESSION_ID];
|
|
52
|
+
const conversationId = ctx.extraParams[EXTRA_PARAM_CONVERSATION_ID];
|
|
53
|
+
if (typeof taskId === "string")
|
|
54
|
+
dynamicHeaders[HEADER_TASK_ID] = taskId;
|
|
55
|
+
if (typeof sessionId === "string")
|
|
56
|
+
dynamicHeaders[HEADER_SESSION_ID] = sessionId;
|
|
57
|
+
if (typeof conversationId === "string")
|
|
58
|
+
dynamicHeaders[HEADER_CONVERSATION_ID] = conversationId;
|
|
59
|
+
}
|
|
60
|
+
if (Object.keys(dynamicHeaders).length === 0)
|
|
61
|
+
return underlying;
|
|
62
|
+
return async (model, context, options) => {
|
|
63
|
+
// 记录输入
|
|
64
|
+
console.log(`[xiaoyiprovider] input messages: ${JSON.stringify(context.messages)}`);
|
|
65
|
+
if (context.systemPrompt) {
|
|
66
|
+
console.log(`[xiaoyiprovider] system prompt: ${context.systemPrompt}`);
|
|
67
|
+
}
|
|
68
|
+
const stream = await underlying(model, context, {
|
|
69
|
+
...options,
|
|
70
|
+
headers: {
|
|
71
|
+
...options?.headers,
|
|
72
|
+
...dynamicHeaders,
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
// 异步监听输出(不阻塞 stream 返回)
|
|
76
|
+
stream.result().then((msg) => console.log(`[xiaoyiprovider] output: ${JSON.stringify(msg)}`), (err) => console.log(`[xiaoyiprovider] error: ${err}`));
|
|
77
|
+
return stream;
|
|
78
|
+
};
|
|
79
|
+
},
|
|
80
|
+
};
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
/** Known device type enum. */
|
|
7
7
|
export const DEVICE_TYPES = ["car", "pc", "phone"];
|
|
8
8
|
const DEVICE_TOOL_POLICY = {
|
|
9
|
-
car: { allowlist: true, tools: ["send_command_to_car"] },
|
|
10
9
|
pc: {
|
|
11
10
|
allowlist: false,
|
|
12
11
|
tools: [
|
|
@@ -16,7 +15,6 @@ const DEVICE_TOOL_POLICY = {
|
|
|
16
15
|
"search_contact",
|
|
17
16
|
],
|
|
18
17
|
},
|
|
19
|
-
phone: { allowlist: true, tools: ["get_user_location"] },
|
|
20
18
|
};
|
|
21
19
|
export function filterToolsByDevice(tools, deviceType) {
|
|
22
20
|
if (!deviceType)
|
package/openclaw.plugin.json
CHANGED