@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 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,2 @@
1
+ import type { ProviderPlugin } from "openclaw/plugin-sdk/provider-models";
2
+ export declare const xiaoyiProvider: ProviderPlugin;
@@ -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)
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "id": "xiaoyi-channel",
3
3
  "channels": ["xiaoyi-channel"],
4
+ "providers": ["xiaoyiprovider"],
4
5
  "skills": [],
5
6
  "configSchema": {
6
7
  "type": "object",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ynhcj/xiaoyi-channel",
3
- "version": "0.0.45-next",
3
+ "version": "0.0.46-next",
4
4
  "description": "OpenClaw Xiaoyi Channel plugin - Xiaoyi A2A protocol integration",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",