- Remove unused PluginRuntime import, consolidate import lines
- Bump @mariozechner/pi-ai from 0.55.3 to 0.58.0 to match root
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When a provider (e.g. anthropic, openai) is not explicitly configured in
openclaw.json, fall back to pi-ai's built-in model database to resolve
baseUrl and api type. This avoids requiring users to manually configure
well-known providers.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Bundled plugins must use scoped plugin-sdk imports (e.g. /core, /compat)
instead of the monolithic openclaw/plugin-sdk entry point.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Align with main's PluginRuntime interface: use `modelAuth` (not `models`)
for API key resolution. Remove dependency on `resolveProviderInfo` (not
available on main) — provider info is now resolved from config at
registration time via `resolveModelFromConfig`.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The rebase left stale versions of src/plugin-sdk/index.ts,
src/agents/model-auth.ts, src/plugins/runtime/*, and
src/cli/daemon-cli/lifecycle.test.ts. These are not guardian changes —
restore them to match origin/main exactly.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove the LLM-based standingInstructions and availableSkills extraction
pipeline. Instead, cache the main agent's full system prompt on the first
llm_input and pass it as-is to the guardian as "Agent context".
This eliminates two async LLM calls per session, simplifies the codebase
(~340 lines removed), and gives the guardian MORE context (the complete
system prompt including tool definitions, memory, and skills) rather than
a lossy LLM-extracted summary.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Recommend instruction-following models (sonnet, haiku, gpt-4o-mini) and
warn against coding-specific models that tend to ignore the strict
ALLOW/BLOCK output format.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Heartbeat prompts may arrive via historyMessages (as the last user message)
rather than via currentPrompt, depending on the agent loop stage. Check both
sources for system trigger detection so heartbeat tool calls are consistently
skipped regardless of how the prompt is delivered.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
During a heartbeat cycle, llm_input fires multiple times: first with the
heartbeat prompt (isSystemTrigger=true), then without a prompt as the agent
loop continues after tool results. Previously the flag was unconditionally
rewritten on each llm_input, resetting to false when currentPrompt was
undefined — causing heartbeat tool calls to reach the guardian LLM
unnecessarily.
Now preserves the existing isSystemTrigger value when currentPrompt is
empty/undefined, and only resets it when a real user message arrives.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Require a delimiter (colon, space, or end of line) after ALLOW/BLOCK keywords.
Previously `startsWith("ALLOW")` would match words like "ALLOWING" or
"ALLOWANCE", potentially causing a false ALLOW verdict if the model's
response started with such a word.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace Enable/Config sections with Quick start (bundled plugin, no npm install)
- Show all default values in config example
- Add "When a tool call is blocked" section explaining user flow
- Remove Model selection section
- Fix dead anchor link
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add rolling conversation summary generation to provide long-term context without token waste
- Extract standing instructions and available skills from system prompt for better decision context
- Support thinking block extraction for reasoning model responses (e.g. kimi-coding)
- Add config options for context tools, recent turns, and tool result length
- Implement lazy context extraction with live message array reference
- Skip guardian review for system triggers (heartbeat, cron)
- Improve error handling for abort race conditions and timeout scenarios
- Normalize headers in model-auth to handle secret inputs consistently
- Update documentation with comprehensive usage guide and security model
When the main model is iterating autonomously (tool call → response →
tool call → ...) without new user input, assistant messages after the
last user message were being discarded. The guardian couldn't see what
the model had been doing, leading to potential misjudgments.
Now trailing assistant messages are appended to the last conversation
turn, giving the guardian full visibility into the model's recent
actions and reasoning during autonomous iteration.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace 3 raw fetch() API call functions (OpenAI, Anthropic, Google)
with a single pi-ai completeSimple() call, ensuring consistent HTTP
behavior (User-Agent, auth, retry) with the main model
- Remove authMode field — pi-ai auto-detects OAuth from API key prefix
- Rewrite system prompt for strict single-line output format, add
"Do NOT change your mind" and "Do NOT output reasoning" constraints
- Move decision guidelines to system prompt, add multi-step workflow
awareness (intermediate read steps should be ALLOWed)
- Simplify user prompt — remove inline examples and criteria
- Use forward scanning in parseGuardianResponse for security (model's
verdict appears first, attacker-injected text appears after)
- Add prominent BLOCK logging via logger.error with full conversation
context dump (████ banner, all turns, tool arguments)
- Remove 800-char assistant message truncation limit
- Increase default max_user_messages from 3 to 10
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Guardian intercepts tool calls via before_tool_call hook and sends them
to a separate LLM for review — blocks actions the user never requested,
defending against prompt injection attacks.
Key design decisions:
- Conversation turns (user + assistant pairs) give guardian context to
understand confirmations like "yes" / "go ahead"
- Assistant replies are explicitly marked as untrusted in the prompt to
prevent poisoning attacks from propagating
- Provider resolution uses SDK (not hardcoded list) with 3-layer
fallback: explicit config → models.json → pi-ai built-in database
- Lazy resolution pattern for async provider/auth lookup in sync register()
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The revert of #43478 (commit 39b4185d0b) was silently undone by
3704293e6f which was based on a branch that included the original
change. This removes the auth.mode=none skipPairing condition again.
The blanket skip was too broad - it disabled pairing for ALL websocket
clients, not just Control UI behind reverse proxies.
Reuses the cron isolated session pattern (resolveCronSession with forceNew)
to give each heartbeat a fresh session with no prior conversation history.
Reduces per-heartbeat token cost from ~100K to ~2-5K tokens.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(feishu): fetch thread context so AI can see bot replies in topic threads
When a user replies in a Feishu topic thread, the AI previously could only
see the quoted parent message but not the bot's own prior replies in the
thread. This made multi-turn conversations in threads feel broken.
- Add `threadId` (omt_xxx) to `FeishuMessageInfo` and `getMessageFeishu`
- Add `listFeishuThreadMessages()` using `container_id_type=thread` API
to fetch all messages in a thread including bot replies
- In `handleFeishuMessage`, fetch ThreadStarterBody and ThreadHistoryBody
for topic session modes and pass them to the AI context
- Reuse quoted message result when rootId === parentId to avoid redundant
API calls; exclude root message from thread history to prevent duplication
- Fall back to inbound ctx.threadId when rootId is absent or API fails
- Fetch newest messages first (ByCreateTimeDesc + reverse) so long threads
keep the most recent turns instead of the oldest
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(feishu): skip redundant thread context injection on subsequent turns
Only inject ThreadHistoryBody on the first turn of a thread session.
On subsequent turns the session already contains prior context, so
re-injecting thread history (and starter) would waste tokens.
The heuristic checks whether the current user has already sent a
non-root message in the thread — if so, the session has prior turns
and thread context injection is skipped entirely.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(feishu): handle thread_id-only events in prior-turn detection
When ctx.rootId is undefined (thread_id-only events), the starter
message exclusion check `msg.messageId !== ctx.rootId` was always
true, causing the first follow-up to be misclassified as a prior
turn. Fall back to the first message in the chronologically-sorted
thread history as the starter.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(feishu): bootstrap topic thread context via session state
* test(memory): pin remote embedding hostnames in offline suites
* fix(feishu): use plugin-safe session runtime for thread bootstrap
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>