mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-26 09:15:16 +00:00
@@ -15,6 +15,7 @@ Docs: https://docs.openclaw.ai
|
||||
- CLI/plugins: have `openclaw plugins doctor` warn when a configured runtime needs a missing owner plugin, sharing the same install mapping as `openclaw doctor --fix`. Fixes #81326. (#81674) Thanks @Zavianx.
|
||||
- Agents/Codex: route OpenAI runs that resolve to `openai-codex` through the Codex provider and bootstrap OpenClaw's stored OAuth profile into the Codex harness when the harness owns transport, so `openai/*` model refs no longer fail with `No API key found for openai-codex` despite an existing Codex OAuth profile. (#82864) Thanks @ragesaq.
|
||||
- Agents/ACP: distinguish prompt-submitted and runtime-active child stalls from true interactive waits, including redacted proxy-env diagnostics for Codex ACP no-output runs. Fixes #44810.
|
||||
- Agents/memory: explain that memory-triggered compaction exposes only `read` and append-only `write` when configured core tools are unavailable in `tools.allow` warnings. Fixes #82941. Thanks @galiniliev.
|
||||
- Agents/skills: apply the full effective tool policy pipeline to inline `command-dispatch: tool` skill dispatch before owner-only filtering, preserving configured allow, deny, sandbox, sender, group, and subagent restrictions. (#78525)
|
||||
- Channel accounts: keep top-level default channel accounts visible when named accounts are added alongside default credential material, so mixed legacy/new account configs keep resolving `default` instead of silently dropping it.
|
||||
- Codex/Telegram: synthesize native Codex tool progress from final turn snapshots so Telegram `/verbose` stays visible when command events arrive only at completion.
|
||||
|
||||
@@ -990,6 +990,10 @@ export function createOpenClawCodingTools(options?: {
|
||||
toolsForMemoryFlush.push(tool);
|
||||
}
|
||||
}
|
||||
const unavailableCoreToolReason =
|
||||
isMemoryFlushRun && memoryFlushWritePath
|
||||
? "memory-triggered compaction runs expose only read and append-only write"
|
||||
: undefined;
|
||||
const toolsForMessageProvider = filterToolsByMessageProvider(
|
||||
toolsForMemoryFlush,
|
||||
options?.messageProvider,
|
||||
@@ -1031,10 +1035,19 @@ export function createOpenClawCodingTools(options?: {
|
||||
groupPolicy: groupPolicyWithToolSearchControls,
|
||||
senderPolicy: senderPolicyWithToolSearchControls,
|
||||
agentId,
|
||||
unavailableCoreToolReason,
|
||||
}),
|
||||
{ policy: sandboxToolPolicyWithToolSearchControls, label: "sandbox tools.allow" },
|
||||
{ policy: subagentPolicyWithToolSearchControls, label: "subagent tools.allow" },
|
||||
{ policy: inheritedToolPolicy, label: "inherited tools" },
|
||||
{
|
||||
policy: sandboxToolPolicyWithToolSearchControls,
|
||||
label: "sandbox tools.allow",
|
||||
unavailableCoreToolReason,
|
||||
},
|
||||
{
|
||||
policy: subagentPolicyWithToolSearchControls,
|
||||
label: "subagent tools.allow",
|
||||
unavailableCoreToolReason,
|
||||
},
|
||||
{ policy: inheritedToolPolicy, label: "inherited tools", unavailableCoreToolReason },
|
||||
],
|
||||
});
|
||||
if (shouldInheritEffectiveToolAllowlist) {
|
||||
|
||||
@@ -13,6 +13,7 @@ function runAllowlistWarningStep(params: {
|
||||
label: string;
|
||||
suppressUnavailableCoreToolWarning?: boolean;
|
||||
suppressUnavailableCoreToolWarningAllowlist?: string[];
|
||||
unavailableCoreToolReason?: string;
|
||||
}) {
|
||||
const warnings: string[] = [];
|
||||
const tools = [{ name: "exec" }] as unknown as DummyTool[];
|
||||
@@ -28,6 +29,7 @@ function runAllowlistWarningStep(params: {
|
||||
suppressUnavailableCoreToolWarning: params.suppressUnavailableCoreToolWarning,
|
||||
suppressUnavailableCoreToolWarningAllowlist:
|
||||
params.suppressUnavailableCoreToolWarningAllowlist,
|
||||
unavailableCoreToolReason: params.unavailableCoreToolReason,
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -107,6 +109,18 @@ describe("tool-policy-pipeline", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
test("includes the active reason for unavailable core tool warnings", () => {
|
||||
const warnings = runAllowlistWarningStep({
|
||||
allow: ["apply_patch", "wat"],
|
||||
label: "tools.allow",
|
||||
unavailableCoreToolReason:
|
||||
"memory-triggered compaction runs expose only read and append-only write",
|
||||
});
|
||||
expect(warnings).toEqual([
|
||||
"tools: tools.allow allowlist contains unknown entries (apply_patch, wat). Some entries are shipped core tools but unavailable here: memory-triggered compaction runs expose only read and append-only write; other entries won't match any tool unless the plugin is enabled.",
|
||||
]);
|
||||
});
|
||||
|
||||
test("default profile steps suppress unavailable baseline profile entries", () => {
|
||||
const warnings: string[] = [];
|
||||
const profilePolicy = resolveToolProfilePolicy("coding");
|
||||
|
||||
@@ -34,6 +34,7 @@ export type ToolPolicyPipelineStep = {
|
||||
stripPluginOnlyAllowlist?: boolean;
|
||||
suppressUnavailableCoreToolWarning?: boolean;
|
||||
suppressUnavailableCoreToolWarningAllowlist?: string[];
|
||||
unavailableCoreToolReason?: string;
|
||||
};
|
||||
|
||||
export function buildDefaultToolPolicyPipelineSteps(params: {
|
||||
@@ -50,16 +51,19 @@ export function buildDefaultToolPolicyPipelineSteps(params: {
|
||||
groupPolicy?: ToolPolicyLike;
|
||||
senderPolicy?: ToolPolicyLike;
|
||||
agentId?: string;
|
||||
unavailableCoreToolReason?: string;
|
||||
}): ToolPolicyPipelineStep[] {
|
||||
const agentId = params.agentId?.trim();
|
||||
const profile = params.profile?.trim();
|
||||
const providerProfile = params.providerProfile?.trim();
|
||||
const unavailableCoreToolReason = params.unavailableCoreToolReason?.trim();
|
||||
return [
|
||||
{
|
||||
policy: params.profilePolicy,
|
||||
label: profile ? `tools.profile (${profile})` : "tools.profile",
|
||||
stripPluginOnlyAllowlist: true,
|
||||
suppressUnavailableCoreToolWarningAllowlist: params.profileUnavailableCoreWarningAllowlist,
|
||||
unavailableCoreToolReason,
|
||||
},
|
||||
{
|
||||
policy: params.providerProfilePolicy,
|
||||
@@ -69,25 +73,44 @@ export function buildDefaultToolPolicyPipelineSteps(params: {
|
||||
stripPluginOnlyAllowlist: true,
|
||||
suppressUnavailableCoreToolWarningAllowlist:
|
||||
params.providerProfileUnavailableCoreWarningAllowlist,
|
||||
unavailableCoreToolReason,
|
||||
},
|
||||
{
|
||||
policy: params.globalPolicy,
|
||||
label: "tools.allow",
|
||||
stripPluginOnlyAllowlist: true,
|
||||
unavailableCoreToolReason,
|
||||
},
|
||||
{ policy: params.globalPolicy, label: "tools.allow", stripPluginOnlyAllowlist: true },
|
||||
{
|
||||
policy: params.globalProviderPolicy,
|
||||
label: "tools.byProvider.allow",
|
||||
stripPluginOnlyAllowlist: true,
|
||||
unavailableCoreToolReason,
|
||||
},
|
||||
{
|
||||
policy: params.agentPolicy,
|
||||
label: agentId ? `agents.${agentId}.tools.allow` : "agent tools.allow",
|
||||
stripPluginOnlyAllowlist: true,
|
||||
unavailableCoreToolReason,
|
||||
},
|
||||
{
|
||||
policy: params.agentProviderPolicy,
|
||||
label: agentId ? `agents.${agentId}.tools.byProvider.allow` : "agent tools.byProvider.allow",
|
||||
stripPluginOnlyAllowlist: true,
|
||||
unavailableCoreToolReason,
|
||||
},
|
||||
{
|
||||
policy: params.groupPolicy,
|
||||
label: "group tools.allow",
|
||||
stripPluginOnlyAllowlist: true,
|
||||
unavailableCoreToolReason,
|
||||
},
|
||||
{
|
||||
policy: params.senderPolicy,
|
||||
label: "tools.toolsBySender",
|
||||
stripPluginOnlyAllowlist: true,
|
||||
unavailableCoreToolReason,
|
||||
},
|
||||
{ policy: params.groupPolicy, label: "group tools.allow", stripPluginOnlyAllowlist: true },
|
||||
{ policy: params.senderPolicy, label: "tools.toolsBySender", stripPluginOnlyAllowlist: true },
|
||||
];
|
||||
}
|
||||
|
||||
@@ -145,6 +168,7 @@ export function applyToolPolicyPipeline(params: {
|
||||
pluginOnlyAllowlist: resolved.pluginOnlyAllowlist,
|
||||
hasGatedCoreEntries: warnableGatedCoreEntries.length > 0,
|
||||
hasOtherEntries: otherEntries.length > 0,
|
||||
unavailableCoreToolReason: step.unavailableCoreToolReason,
|
||||
});
|
||||
const warning = `tools: ${step.label} allowlist contains unknown entries (${entries}). ${suffix}`;
|
||||
if (rememberToolPolicyWarning(warning)) {
|
||||
@@ -172,15 +196,23 @@ function describeUnknownAllowlistSuffix(params: {
|
||||
pluginOnlyAllowlist: boolean;
|
||||
hasGatedCoreEntries: boolean;
|
||||
hasOtherEntries: boolean;
|
||||
unavailableCoreToolReason?: string;
|
||||
}): string {
|
||||
const preface = params.pluginOnlyAllowlist
|
||||
? "Allowlist contains only plugin entries; core tools will not be available."
|
||||
: "";
|
||||
const unavailableCoreToolReason = params.unavailableCoreToolReason?.trim();
|
||||
const unavailableCoreDetail = unavailableCoreToolReason
|
||||
? `These entries are shipped core tools but unavailable here: ${unavailableCoreToolReason}.`
|
||||
: "These entries are shipped core tools but unavailable in the current runtime/provider/model/config.";
|
||||
const mixedUnavailableCoreDetail = unavailableCoreToolReason
|
||||
? `Some entries are shipped core tools but unavailable here: ${unavailableCoreToolReason}; other entries won't match any tool unless the plugin is enabled.`
|
||||
: "Some entries are shipped core tools but unavailable in the current runtime/provider/model/config; other entries won't match any tool unless the plugin is enabled.";
|
||||
const detail =
|
||||
params.hasGatedCoreEntries && params.hasOtherEntries
|
||||
? "Some entries are shipped core tools but unavailable in the current runtime/provider/model/config; other entries won't match any tool unless the plugin is enabled."
|
||||
? mixedUnavailableCoreDetail
|
||||
: params.hasGatedCoreEntries
|
||||
? "These entries are shipped core tools but unavailable in the current runtime/provider/model/config."
|
||||
? unavailableCoreDetail
|
||||
: "These entries won't match any tool unless the plugin is enabled.";
|
||||
return preface ? `${preface} ${detail}` : detail;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user