mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-19 21:21:10 +00:00
fix(agents): preserve acp and openai wrapper defaults
This commit is contained in:
@@ -519,7 +519,7 @@ describe("spawnAcpDirect", () => {
|
||||
agentTo: "room:!room:example",
|
||||
},
|
||||
);
|
||||
expect(result.status).toBe("accepted");
|
||||
expect(result.status, JSON.stringify(result)).toBe("accepted");
|
||||
expect(hoisted.sessionBindingBindMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
placement: "child",
|
||||
@@ -533,7 +533,7 @@ describe("spawnAcpDirect", () => {
|
||||
expectAgentGatewayCall({
|
||||
deliver: true,
|
||||
channel: "matrix",
|
||||
to: "room:!room:example",
|
||||
to: "channel:child-thread",
|
||||
threadId: "child-thread",
|
||||
});
|
||||
});
|
||||
@@ -576,7 +576,7 @@ describe("spawnAcpDirect", () => {
|
||||
},
|
||||
);
|
||||
|
||||
expect(result.status).toBe("accepted");
|
||||
expect(result.status, JSON.stringify(result)).toBe("accepted");
|
||||
expect(hoisted.sessionBindingBindMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
placement: "current",
|
||||
|
||||
@@ -19,7 +19,6 @@ import {
|
||||
import {
|
||||
formatThreadBindingDisabledError,
|
||||
formatThreadBindingSpawnDisabledError,
|
||||
requiresNativeThreadContextForThreadHere,
|
||||
resolveThreadBindingIdleTimeoutMsForChannel,
|
||||
resolveThreadBindingMaxAgeMsForChannel,
|
||||
resolveThreadBindingSpawnPolicy,
|
||||
@@ -172,6 +171,59 @@ type AcpSpawnBootstrapDeliveryPlan = {
|
||||
threadId?: string;
|
||||
};
|
||||
|
||||
function resolvePlacementWithoutChannelPlugin(params: {
|
||||
channel: string;
|
||||
capabilities: { placements: Array<"current" | "child"> };
|
||||
}): "current" | "child" {
|
||||
switch (params.channel) {
|
||||
case "discord":
|
||||
case "matrix":
|
||||
return params.capabilities.placements.includes("child") ? "child" : "current";
|
||||
case "line":
|
||||
case "telegram":
|
||||
return "current";
|
||||
}
|
||||
return params.capabilities.placements.includes("child") ? "child" : "current";
|
||||
}
|
||||
|
||||
function normalizeLineConversationIdFallback(value: string | undefined): string | undefined {
|
||||
const trimmed = value?.trim() ?? "";
|
||||
if (!trimmed) {
|
||||
return undefined;
|
||||
}
|
||||
const normalized = trimmed.match(/^line:(?:(?:user|group|room):)?(.+)$/i)?.[1]?.trim() ?? trimmed;
|
||||
return normalized ? normalized : undefined;
|
||||
}
|
||||
|
||||
function normalizeTelegramConversationIdFallback(params: {
|
||||
to?: string;
|
||||
threadId?: string | number;
|
||||
groupId?: string;
|
||||
}): string | undefined {
|
||||
const explicitGroupId = params.groupId?.trim();
|
||||
const explicitThreadId =
|
||||
params.threadId != null ? String(params.threadId).trim() || undefined : undefined;
|
||||
if (
|
||||
explicitGroupId &&
|
||||
explicitThreadId &&
|
||||
/^-?\d+$/.test(explicitGroupId) &&
|
||||
/^\d+$/.test(explicitThreadId)
|
||||
) {
|
||||
return `${explicitGroupId}:topic:${explicitThreadId}`;
|
||||
}
|
||||
|
||||
const trimmed = params.to?.trim() ?? "";
|
||||
if (!trimmed) {
|
||||
return undefined;
|
||||
}
|
||||
const normalized = trimmed.replace(/^telegram:(?:group:|channel:|direct:)?/i, "");
|
||||
const topicMatch = /^(-?\d+):topic:(\d+)$/i.exec(normalized);
|
||||
if (topicMatch?.[1] && topicMatch[2]) {
|
||||
return `${topicMatch[1]}:topic:${topicMatch[2]}`;
|
||||
}
|
||||
return /^-?\d+$/.test(normalized) ? normalized : undefined;
|
||||
}
|
||||
|
||||
function resolveSpawnMode(params: {
|
||||
requestedMode?: SpawnAcpMode;
|
||||
threadRequested: boolean;
|
||||
@@ -367,6 +419,7 @@ function resolveConversationIdForThreadBinding(params: {
|
||||
}): string | undefined {
|
||||
const channel = params.channel?.trim().toLowerCase();
|
||||
const normalizedChannelId = channel ? normalizeChannelId(channel) : null;
|
||||
const channelKey = normalizedChannelId ?? channel ?? null;
|
||||
const pluginResolvedConversationId = normalizedChannelId
|
||||
? getChannelPlugin(normalizedChannelId)?.messaging?.resolveInboundConversation?.({
|
||||
to: params.groupId ?? params.to,
|
||||
@@ -378,6 +431,18 @@ function resolveConversationIdForThreadBinding(params: {
|
||||
if (pluginResolvedConversationId?.trim()) {
|
||||
return pluginResolvedConversationId.trim();
|
||||
}
|
||||
if (channelKey === "line") {
|
||||
const lineConversationId = normalizeLineConversationIdFallback(params.groupId ?? params.to);
|
||||
if (lineConversationId) {
|
||||
return lineConversationId;
|
||||
}
|
||||
}
|
||||
if (channelKey === "telegram") {
|
||||
const telegramConversationId = normalizeTelegramConversationIdFallback(params);
|
||||
if (telegramConversationId) {
|
||||
return telegramConversationId;
|
||||
}
|
||||
}
|
||||
const genericConversationId = resolveConversationIdFromTargets({
|
||||
threadId: params.threadId,
|
||||
targets: [params.to],
|
||||
@@ -466,11 +531,18 @@ function prepareAcpThreadBinding(params: {
|
||||
error: `Thread bindings are unavailable for ${policy.channel}.`,
|
||||
};
|
||||
}
|
||||
const placement = requiresNativeThreadContextForThreadHere(policy.channel) ? "child" : "current";
|
||||
if (!capabilities.bindSupported || !capabilities.placements.includes(placement)) {
|
||||
const pluginPlacement = getChannelPlugin(policy.channel)?.conversationBindings
|
||||
?.defaultTopLevelPlacement;
|
||||
const placementToUse =
|
||||
pluginPlacement ??
|
||||
resolvePlacementWithoutChannelPlugin({
|
||||
channel: policy.channel,
|
||||
capabilities,
|
||||
});
|
||||
if (!capabilities.bindSupported || !capabilities.placements.includes(placementToUse)) {
|
||||
return {
|
||||
ok: false,
|
||||
error: `Thread bindings do not support ${placement} placement for ${policy.channel}.`,
|
||||
error: `Thread bindings do not support ${placementToUse} placement for ${policy.channel}.`,
|
||||
};
|
||||
}
|
||||
const conversationIdRaw = resolveConversationIdForThreadBinding({
|
||||
@@ -491,7 +563,7 @@ function prepareAcpThreadBinding(params: {
|
||||
binding: {
|
||||
channel: policy.channel,
|
||||
accountId: policy.accountId,
|
||||
placement,
|
||||
placement: placementToUse,
|
||||
conversationId: conversationIdRaw,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -80,8 +80,8 @@ function stripDisabledOpenAIReasoningPayload(payloadObj: Record<string, unknown>
|
||||
return;
|
||||
}
|
||||
|
||||
// GPT-5 models reject `reasoning.effort: "none"`. Treat the disabled effort
|
||||
// as "reasoning omitted" instead of forwarding an unsupported value.
|
||||
// Proxy/OpenAI-compat routes can reject `reasoning.effort: "none"`. Treat the
|
||||
// disabled effort as "reasoning omitted" instead of forwarding an unsupported value.
|
||||
const reasoningObj = reasoning as Record<string, unknown>;
|
||||
if (reasoningObj.effort === "none") {
|
||||
delete payloadObj.reasoning;
|
||||
|
||||
@@ -735,7 +735,9 @@ describe("applyExtraParamsToAgent", () => {
|
||||
|
||||
expect(payloads).toHaveLength(1);
|
||||
expect(payloads[0]).toEqual({
|
||||
context_management: [{ type: "compaction", compact_threshold: 80000 }],
|
||||
reasoning: { effort: "none", summary: "auto" },
|
||||
store: true,
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -416,7 +416,6 @@ export function applyExtraParamsToAgent(
|
||||
override,
|
||||
};
|
||||
|
||||
applyPrePluginStreamWrappers(wrapperContext);
|
||||
const providerStreamBase = agent.streamFn;
|
||||
const pluginWrappedStreamFn = providerRuntimeDeps.wrapProviderStreamFn({
|
||||
provider,
|
||||
@@ -432,6 +431,9 @@ export function applyExtraParamsToAgent(
|
||||
},
|
||||
});
|
||||
agent.streamFn = pluginWrappedStreamFn ?? providerStreamBase;
|
||||
// Apply caller/config extra params outside provider defaults so explicit values
|
||||
// like `openaiWsWarmup=false` can override provider-added defaults.
|
||||
applyPrePluginStreamWrappers(wrapperContext);
|
||||
const providerWrapperHandled =
|
||||
pluginWrappedStreamFn !== undefined && pluginWrappedStreamFn !== providerStreamBase;
|
||||
applyPostPluginStreamWrappers({
|
||||
|
||||
Reference in New Issue
Block a user