Commit Graph

7106 Commits

Author SHA1 Message Date
Peter Steinberger dee0134269 style: reformat dedupe-touched files 2026-02-17 00:32:34 +00:00
Peter Steinberger 817b5812e1 refactor(agents): share queued JSONL file writer 2026-02-17 00:32:34 +00:00
Peter Steinberger 80c7d04ad2 refactor(cron): reuse shared run outcome telemetry types 2026-02-17 00:32:34 +00:00
Peter Steinberger a6466f2576 refactor(web-tools): share URL allowlist resolver 2026-02-17 00:32:34 +00:00
Peter Steinberger 64fc82844e refactor(channels): share prefixed target parsing 2026-02-17 00:32:34 +00:00
Peter Steinberger 10b060dbd3 refactor(agent-tools): reuse gateway option parsing 2026-02-17 00:32:34 +00:00
Peter Steinberger 37c97964af refactor(media): centralize input file limit resolution 2026-02-17 00:32:34 +00:00
Peter Steinberger ed74f48bd5 refactor(status): share update channel display + one-liner 2026-02-17 00:32:34 +00:00
cpojer 1dc9bb8d62
chore: Fix more type issues. 2026-02-17 09:29:47 +09:00
cpojer 90ef2d6bdf
chore: Update formatting. 2026-02-17 09:18:40 +09:00
Peter Steinberger 5cbdd3a9c1 test(auto-reply): dedupe command spawn test harness 2026-02-17 00:11:02 +00:00
Peter Steinberger b9aed3a07c refactor(infra): reuse device auth scope normalization 2026-02-17 00:11:02 +00:00
Peter Steinberger fbd3786e7a refactor(channels): share target parsing helpers 2026-02-17 00:11:02 +00:00
Peter Steinberger 9bfd3ca195 refactor(memory): consolidate embeddings and batch helpers 2026-02-17 00:11:02 +00:00
Peter Steinberger 423b7a0f28 refactor(auto-reply): reuse embedded run context helpers 2026-02-17 00:11:02 +00:00
Peter Steinberger 246bb7f30f refactor(agents): share model auth label resolution 2026-02-17 00:11:02 +00:00
Peter Steinberger 4088c0b89d refactor(core): dedupe schema and command parsing helpers 2026-02-16 23:48:43 +00:00
Peter Steinberger c55e017c19 refactor(daemon): dedupe user bin path assembly helpers 2026-02-16 23:48:43 +00:00
Peter Steinberger 3451159174 refactor(channels): share draft stream loop across slack and telegram 2026-02-16 23:48:43 +00:00
Peter Steinberger f6111622e6 refactor(commands): share system prompt bundle for context and export 2026-02-16 23:48:43 +00:00
Peter Steinberger 32e2c369d7 refactor(agents): extract shared session dir resolver 2026-02-16 23:48:43 +00:00
Peter Steinberger b3d0e0cb45 fix(cron): preserve overrides and harden next-run calculation 2026-02-16 23:48:26 +00:00
Peter Steinberger 968bba5c18 refactor(telegram): remove duplicate poll dispatch branch 2026-02-16 23:47:57 +00:00
Peter Steinberger 0a188ee49a test(ci): stabilize update and discord process tests 2026-02-16 23:47:57 +00:00
Peter Steinberger a186ce2158 fix(ci): preserve whatsapp send API compatibility 2026-02-16 23:47:57 +00:00
Peter Steinberger 7632e60d70 refactor(onboarding): reuse allowFrom merge helper in extensions 2026-02-16 23:47:57 +00:00
Peter Steinberger 12a947223b fix(ci): restore main checks after bulk merges 2026-02-16 23:47:27 +00:00
Peter Steinberger 83a8b78a42 fix(ci): guard loop detection integer parsing 2026-02-16 23:27:35 +00:00
Peter Steinberger eaa2f7a7bf fix(ci): restore main lint/typecheck after direct merges 2026-02-16 23:26:11 +00:00
Peter Steinberger 076df941a3 feat: add configurable tool loop detection 2026-02-17 00:17:01 +01:00
Rain dacffd7ac8 fix(sandbox): parse Windows bind mounts in fs-path mapping 2026-02-17 00:02:12 +01:00
尹凯 3f617e33b7 style(discord): format provider after proxy fetch changes 2026-02-17 00:02:09 +01:00
尹凯 e997545d4b fix(discord): apply proxy to app-id and allowlist REST lookups 2026-02-17 00:02:09 +01:00
ikari 84383b5e0f fix(tts): show all provider errors instead of only the last one
When TTS conversion fails, the error message now includes failures
from every provider in the fallback chain instead of only the last
one tried. Previously, a timeout on the primary provider (e.g.
ElevenLabs) would be masked by the final fallback's error (e.g.
"edge: disabled"), making it impossible to diagnose the real issue.

Before: "TTS conversion failed: edge: disabled"
After:  "TTS conversion failed: elevenlabs: timeout (30004ms); openai: no API key; edge: disabled"
2026-02-17 00:01:56 +01:00
Operative-001 de6cc05e7e fix(cron): prevent spin loop when job completes within firing second (#17821)
When a cron job fires at 13:00:00.014 and completes at 13:00:00.021,
computeNextRunAtMs was flooring nowMs to 13:00:00.000 and asking croner
for the next occurrence from that exact boundary. Croner could return
13:00:00.000 (same second) since it uses >= semantics, causing the job
to be immediately re-triggered hundreds of times.

Fix: Ask croner for the next occurrence starting from the NEXT second
(e.g., 13:00:01.000). This ensures we always skip the current/elapsed
second and correctly return the next day's occurrence.

This also correctly handles the before-match case: if nowMs is
11:59:59.500, we ask from 12:00:00.000, and croner returns today's
12:00:00.000 match.

Added regression tests for the spin loop scenario.
2026-02-17 00:01:53 +01:00
Operative-001 16ddbbc628 fix(sessions): skip cache when initializing session state
Fixes #17971

When initSessionState() reads the session store, use skipCache: true
to ensure fresh data from disk. The session store cache is process-local
and uses mtime-based invalidation, which can fail in these scenarios:

1. Multiple gateway processes (each has separate in-memory cache)
2. Windows file system where mtime granularity may miss rapid writes
3. Race conditions between messages 6-8 seconds apart

Symptoms: 134+ orphaned .jsonl transcript files, each with only 1
exchange. Session rotates on every incoming message even when
sessionKey is stable.

Root cause: loadSessionStore() returns stale cache → entry not found
for sessionKey → new sessionId generated → new transcript file.

The fix ensures session identity (sessionId) is always resolved from
the latest on-disk state, not potentially-stale cache.
2026-02-17 00:01:37 +01:00
Elie Habib 5b3873add4 fix(skills): guard against skills prompt bloat 2026-02-17 00:01:34 +01:00
artale b4a90bb743 fix(telegram): suppress message_thread_id for private chat sends (#17242)
Private chats (positive numeric chat IDs) never support forum topics.
Sending message_thread_id to a private chat causes Telegram to reject
the request with '400: Bad Request: message thread not found', silently
dropping the message.

Guard all three send functions (sendMessageTelegram, sendStickerTelegram,
sendPollTelegram) to omit thread-related parameters when the target is a
private chat.

Root cause: the auto-reply pipeline can set messageThreadId from a
previous forum-group context, then reuse it when sending a DM.

Tests: add private-chat suppression assertions; update existing thread-
retry tests to use group chat IDs so the retry path is still exercised.
2026-02-17 00:01:26 +01:00
simonemacario 2ed43fd7b4 fix(cron): resolve accountId from agent bindings in isolated sessions
When an isolated cron session has no lastAccountId (e.g. first-run or
fresh session), the message tool receives an undefined accountId which
defaults to "default". In multi-account setups where accounts are named
(e.g. "willy", "betty"), this causes resolveTelegramToken() to fail
because accounts["default"] doesn't exist.

This change adds a fallback in resolveDeliveryTarget(): when the
session-derived accountId is undefined, look up the agent's bound
account from the bindings config using buildChannelAccountBindings().
This mirrors the same binding resolution used for inbound routing,
closing the gap between inbound and outbound account resolution.

Session-derived accountId still takes precedence when present.

Fixes #17889
Related: #12628, #16259

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 00:01:22 +01:00
Operative-001 e9f2e6a829 fix(heartbeat): prune transcript for HEARTBEAT_OK turns
When a heartbeat run results in HEARTBEAT_OK (or empty/duplicate), the user+assistant
turns are now pruned from the session transcript. This prevents context window
pollution from zero-information exchanges.

Implementation:
- captureTranscriptState(): records transcript file path and size before heartbeat
- pruneHeartbeatTranscript(): truncates file back to pre-heartbeat size
- Called in ok-empty, ok-token, and duplicate cases (same places as restoreHeartbeatUpdatedAt)

This extends the existing pattern where delivery is suppressed and updatedAt is restored
for HEARTBEAT_OK responses - now the transcript is also cleaned up.

Fixes #17804
2026-02-17 00:01:15 +01:00
artale 7bb9a7dcfc fix(telegram): wire sendPollTelegram into channel action handler (#16977)
The Telegram channel adapter listed no 'poll' action, so agents could
not create polls via the unified action interface. The underlying
sendPollTelegram function was already implemented but unreachable.

Changes:
- telegram.ts: add 'poll' to listActions (enabled by default via gate),
  add handleAction branch that reads pollQuestion/pollOption params and
  delegates to handleTelegramAction with action 'sendPoll'.
- telegram-actions.ts: add 'sendPoll' handler that validates question,
  options (≥2), and forwards to sendPollTelegram with threading, silent,
  and anonymous options.
- actions.test.ts: add test verifying poll action routes correctly.

Fixes #16977
2026-02-17 00:01:07 +01:00
amabito 068b9c9749 feat: wrap compaction generateSummary in retryAsync
Integrate retry logic with abort-classifier for /compact endpoint:
- Wrap generateSummary calls in retryAsync with exponential backoff
- Auto-skip retry on user cancellation and gateway restart (AbortError)
- Config: 3 attempts, 500ms-5s delay, 20% jitter
- Add comprehensive Vitest tests (5/5 passed)

Related: #16809, #5744, #17143
2026-02-17 00:01:03 +01:00
boris f82a3d3e2b fix: use resolveUserPath utility for tilde expansion 2026-02-17 00:00:57 +01:00
boris f70b3a2e68 refactor: bundle export-html templates instead of reading from node_modules
- Copy templates from pi-coding-agent into src/auto-reply/reply/export-html/
- Add build script to copy templates to dist/
- Remove fragile node_modules path traversal
- Templates are now self-contained (~250KB total)
2026-02-17 00:00:57 +01:00
boris 1eb1a33f37 chore: remove --open option (not useful for remote sessions) 2026-02-17 00:00:57 +01:00
boris ffe700bf94 fix: use proper pi-mono dark theme colors for export HTML 2026-02-17 00:00:57 +01:00
boris add3afb743 feat: add /export-session command
Export current session to HTML file with full system prompt included.
Uses pi-coding-agent templates for consistent rendering.

Features:
- Exports session entries + full system prompt + tools
- Saves to workspace by default, or custom path
- Optional --open flag to open in browser
- Reuses pi-mono export-html templates

Usage:
  /export-session           # Export to workspace
  /export-session ~/export  # Export to custom path
  /export-session --open    # Export and open in browser
2026-02-17 00:00:57 +01:00
Xinhua Gu 3c3a39d165 fix(test): use path.resolve for cross-platform Windows compatibility 2026-02-17 00:00:54 +01:00
Xinhua Gu 90774c098a fix(sessions): allow cross-agent session file paths in multi-agent setups
When OPENCLAW_STATE_DIR changes between session creation and resolution
(e.g., after reinstall or config change), absolute session file paths
pointing to other agents' sessions directories were rejected even though
they structurally match the valid .../agents/<agentId>/sessions/... pattern.

The existing fallback logic in resolvePathWithinSessionsDir extracts the
agent ID from the path and tries to resolve it via the current env's
state directory. When those directories differ, the containment check
fails. Now, if the path structurally matches the agent sessions pattern
(validated by extractAgentIdFromAbsoluteSessionPath), we accept it
directly as a final fallback.

Fixes #15410, Fixes #15565, Fixes #15468
2026-02-17 00:00:54 +01:00
8BlT e20b87f1ba fix: handle forum/topics in Telegram DM thread routing (#17980)
resolveTelegramThreadSpec now checks isForum in the non-group path.
DMs with forum/topics enabled return scope 'forum' so each topic
gets its own session, while plain DM threads keep scope 'dm'.
2026-02-17 00:00:51 +01:00