@ynhcj/xiaoyi-channel 0.0.176-beta → 0.0.178-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.
package/dist/src/bot.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { updateSessionStoreEntry, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
|
|
1
|
+
import { updateSessionStoreEntry, updateSessionStore, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
|
|
2
2
|
import { getXYRuntime } from "./runtime.js";
|
|
3
3
|
import { createXYReplyDispatcher } from "./reply-dispatcher.js";
|
|
4
4
|
import { parseA2AMessage, extractTextFromParts, extractFileParts, extractPushId, extractDeviceType, extractModelName, extractTriggerData, extractRunCrossTaskContext } from "./parser.js";
|
|
@@ -33,7 +33,6 @@ export async function handleXYMessage(params) {
|
|
|
33
33
|
try {
|
|
34
34
|
// Check for special messages BEFORE parsing (these have different param structures)
|
|
35
35
|
const messageMethod = message.method;
|
|
36
|
-
logger.log(`[BOT] Received A2A message: ${JSON.stringify(message)}`);
|
|
37
36
|
// Handle clearContext messages (sessionId at top level, no params)
|
|
38
37
|
if (messageMethod === "clearContext" || messageMethod === "clear_context") {
|
|
39
38
|
const sessionId = message.sessionId ?? message.params?.sessionId;
|
|
@@ -179,16 +178,41 @@ export async function handleXYMessage(params) {
|
|
|
179
178
|
// configured default model instead of the A2A-specified one.
|
|
180
179
|
if (modelName && modelName.trim() !== "" && modelName.toLowerCase() !== "none") {
|
|
181
180
|
try {
|
|
182
|
-
|
|
183
|
-
|
|
181
|
+
const storePath = resolveStorePath();
|
|
182
|
+
const result = await updateSessionStoreEntry({
|
|
183
|
+
storePath,
|
|
184
184
|
sessionKey: route.sessionKey,
|
|
185
185
|
update: async () => ({
|
|
186
186
|
providerOverride: "xiaoyiprovider",
|
|
187
187
|
modelOverride: modelName,
|
|
188
188
|
modelOverrideSource: "user",
|
|
189
|
+
model: "",
|
|
190
|
+
modelProvider: "",
|
|
189
191
|
}),
|
|
190
192
|
});
|
|
191
|
-
|
|
193
|
+
if (!result) {
|
|
194
|
+
// Session entry doesn't exist yet (first message, xy_channel
|
|
195
|
+
// bypasses the standard turn kernel). Create a minimal entry
|
|
196
|
+
// with the override via updateSessionStore.
|
|
197
|
+
await updateSessionStore(storePath, (store) => {
|
|
198
|
+
if (!store[route.sessionKey]) {
|
|
199
|
+
store[route.sessionKey] = {
|
|
200
|
+
// sessionId must pass validateSessionId regex /^[a-z0-9][a-z0-9._-]{0,127}$/i
|
|
201
|
+
// route.sessionKey like "agent:main:direct:xxx" contains colons which are invalid.
|
|
202
|
+
// Use parsed.sessionId (raw UUID from A2A) which is always safe.
|
|
203
|
+
sessionId: parsed.sessionId,
|
|
204
|
+
updatedAt: Date.now(),
|
|
205
|
+
providerOverride: "xiaoyiprovider",
|
|
206
|
+
modelOverride: modelName,
|
|
207
|
+
modelOverrideSource: "user",
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
log.log(`[BOT] Created session entry with model override: xiaoyiprovider/${modelName}`);
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
log.log(`[BOT] Patched session store model override: xiaoyiprovider/${modelName}`);
|
|
215
|
+
}
|
|
192
216
|
}
|
|
193
217
|
catch (patchErr) {
|
|
194
218
|
log.error(`[BOT] Failed to patch session model override:`, patchErr);
|
package/dist/src/provider.js
CHANGED
|
@@ -417,6 +417,32 @@ export const xiaoyiProvider = {
|
|
|
417
417
|
docsPath: "/providers/models",
|
|
418
418
|
auth: [],
|
|
419
419
|
isCacheTtlEligible: () => true,
|
|
420
|
+
/**
|
|
421
|
+
* Dynamic model resolution for A2A-specified model names.
|
|
422
|
+
* A2A messages carry a dynamic modelName that isn't in any static catalog.
|
|
423
|
+
* This hook lets OpenClaw's resolveModelAsync accept any model ID under
|
|
424
|
+
* xiaoyiprovider as long as the provider has a configured baseUrl.
|
|
425
|
+
*/
|
|
426
|
+
resolveDynamicModel: (ctx) => {
|
|
427
|
+
const baseUrl = ctx.providerConfig?.baseUrl;
|
|
428
|
+
if (!baseUrl || typeof baseUrl !== "string")
|
|
429
|
+
return null;
|
|
430
|
+
return {
|
|
431
|
+
id: ctx.modelId,
|
|
432
|
+
name: ctx.modelId,
|
|
433
|
+
api: ctx.providerConfig?.api ?? "openai-completions",
|
|
434
|
+
provider: "xiaoyiprovider",
|
|
435
|
+
baseUrl,
|
|
436
|
+
reasoning: false,
|
|
437
|
+
input: ["text"],
|
|
438
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
439
|
+
contextWindow: 128_000,
|
|
440
|
+
maxTokens: 8192,
|
|
441
|
+
...(ctx.providerConfig?.headers && typeof ctx.providerConfig.headers === "object"
|
|
442
|
+
? { headers: ctx.providerConfig.headers }
|
|
443
|
+
: {}),
|
|
444
|
+
};
|
|
445
|
+
},
|
|
420
446
|
/**
|
|
421
447
|
* Store uid-based fallback prefix for lazy timestamp generation in wrapStreamFn.
|
|
422
448
|
* Session-level headers (traceId / sessionId / interactionId) are resolved
|
|
@@ -116,10 +116,6 @@ export function createXYReplyDispatcher(params) {
|
|
|
116
116
|
let hasSentResponse = false;
|
|
117
117
|
let finalSent = false;
|
|
118
118
|
let accumulatedText = "";
|
|
119
|
-
let accumulatedReasoningHistory = "";
|
|
120
|
-
let lastReasoningText = "";
|
|
121
|
-
let accumulatedReplyHistory = "";
|
|
122
|
-
let lastReplyText = "";
|
|
123
119
|
const initialRunCrossTaskContext = getCurrentSessionContext()?.runCrossTaskContext;
|
|
124
120
|
const getRunCrossTaskContext = () => {
|
|
125
121
|
return getCurrentSessionContext()?.runCrossTaskContext ?? initialRunCrossTaskContext;
|
|
@@ -408,26 +404,12 @@ export function createXYReplyDispatcher(params) {
|
|
|
408
404
|
}
|
|
409
405
|
try {
|
|
410
406
|
if (text.length > 0) {
|
|
411
|
-
// 🔑 检测是否是新一轮思考:当前text比上一次短,或不以上次内容开头
|
|
412
|
-
const isNewRound = lastReasoningText.length > 0 &&
|
|
413
|
-
text.length < lastReasoningText.length;
|
|
414
|
-
if (isNewRound) {
|
|
415
|
-
// 将上一轮思考追加到历史
|
|
416
|
-
accumulatedReasoningHistory += (accumulatedReasoningHistory ? "\n\n" : "") + lastReasoningText;
|
|
417
|
-
}
|
|
418
|
-
// 更新当前轮最后一次text
|
|
419
|
-
lastReasoningText = text;
|
|
420
|
-
// 🔑 拼接历史 + 当前轮内容
|
|
421
|
-
const fullText = accumulatedReasoningHistory
|
|
422
|
-
? accumulatedReasoningHistory + "\n\n" + text
|
|
423
|
-
: text;
|
|
424
|
-
// 🔑 将模型真实的thinking/reasoning内容通过reasoningText转发
|
|
425
407
|
await sendReasoningTextUpdate({
|
|
426
408
|
config,
|
|
427
409
|
sessionId,
|
|
428
410
|
taskId: currentTaskId,
|
|
429
411
|
messageId: currentMessageId,
|
|
430
|
-
text
|
|
412
|
+
text,
|
|
431
413
|
append: false,
|
|
432
414
|
});
|
|
433
415
|
}
|
|
@@ -443,31 +425,17 @@ export function createXYReplyDispatcher(params) {
|
|
|
443
425
|
}
|
|
444
426
|
const currentTaskId = getActiveTaskId();
|
|
445
427
|
const currentMessageId = getActiveMessageId();
|
|
446
|
-
|
|
428
|
+
const text = payload.text ?? "";
|
|
447
429
|
try {
|
|
448
430
|
if (text.length > 0) {
|
|
449
|
-
// 🔑 检测是否是新一轮回复:当前text比上一次短,或不以上次内容开头
|
|
450
|
-
const isNewRound = lastReplyText.length > 0 &&
|
|
451
|
-
(text.length < lastReplyText.length || !text.startsWith(lastReplyText));
|
|
452
|
-
if (isNewRound) {
|
|
453
|
-
// 将上一轮回复追加到历史
|
|
454
|
-
accumulatedReplyHistory += (accumulatedReplyHistory ? "\n\n" : "") + lastReplyText;
|
|
455
|
-
}
|
|
456
|
-
// 更新当前轮最后一次text
|
|
457
|
-
lastReplyText = text;
|
|
458
|
-
// 🔑 拼接历史 + 当前轮内容
|
|
459
|
-
const fullText = accumulatedReplyHistory
|
|
460
|
-
? accumulatedReplyHistory + "\n\n" + text
|
|
461
|
-
: text;
|
|
462
431
|
accumulatedText += text;
|
|
463
432
|
hasSentResponse = true;
|
|
464
|
-
// 🔑 流式文本通过 A2A text 通道发送(而非 reasoningText)
|
|
465
433
|
await sendA2AResponse({
|
|
466
434
|
config,
|
|
467
435
|
sessionId,
|
|
468
436
|
taskId: currentTaskId,
|
|
469
437
|
messageId: currentMessageId,
|
|
470
|
-
text
|
|
438
|
+
text,
|
|
471
439
|
append: false,
|
|
472
440
|
final: false,
|
|
473
441
|
log: false,
|
|
@@ -17,10 +17,6 @@ import { createGetCollectionToolSchemaTool } from "./get-collection-tool-schema.
|
|
|
17
17
|
// import { createGetEmailToolSchemaTool } from "./get-email-tool-schema.js";
|
|
18
18
|
import { createLoginTokenTool } from "./login-token-tool.js";
|
|
19
19
|
import { createAgentAsSkillTool } from "./agent-as-skill-tool.js";
|
|
20
|
-
import { createDiscoverCrossDevicesTool } from "./discover-cross-devices-tool.js";
|
|
21
|
-
import { createSendCrossDeviceTaskTool } from "./send-cross-device-task-tool.js";
|
|
22
|
-
import { createDisplayA2UICardTool } from "./display-a2ui-card-tool.js";
|
|
23
|
-
import { createCheckPluginPrivilegeTool } from "./check-plugin-privilege-tool.js";
|
|
24
20
|
import { logger } from "../utils/logger.js";
|
|
25
21
|
/**
|
|
26
22
|
* Create all XY channel tools for the given session context.
|
|
@@ -36,9 +32,9 @@ export function createAllTools(ctx) {
|
|
|
36
32
|
logger.log(`[CREATE-ALL-TOOLS] creating tools`);
|
|
37
33
|
return [
|
|
38
34
|
createLocationTool(ctx),
|
|
39
|
-
createDiscoverCrossDevicesTool(ctx),
|
|
40
|
-
createSendCrossDeviceTaskTool(ctx),
|
|
41
|
-
createDisplayA2UICardTool(ctx),
|
|
35
|
+
// createDiscoverCrossDevicesTool(ctx),
|
|
36
|
+
// createSendCrossDeviceTaskTool(ctx),
|
|
37
|
+
// createDisplayA2UICardTool(ctx),
|
|
42
38
|
createCallDeviceTool(ctx),
|
|
43
39
|
createGetNoteToolSchemaTool(ctx),
|
|
44
40
|
createGetCalendarToolSchemaTool(ctx),
|
|
@@ -57,6 +53,6 @@ export function createAllTools(ctx) {
|
|
|
57
53
|
createSaveSelfEvolutionSkillTool(ctx),
|
|
58
54
|
createLoginTokenTool(ctx),
|
|
59
55
|
createAgentAsSkillTool(ctx),
|
|
60
|
-
createCheckPluginPrivilegeTool(ctx),
|
|
56
|
+
// createCheckPluginPrivilegeTool(ctx),
|
|
61
57
|
];
|
|
62
58
|
}
|