Commit Graph
902 Commits
Author SHA1 Message Date
Duc Nguyen 983f6184d9 fix(ui): dynamic searchable timezone picker with validation (#614)
Replace hardcoded 20-entry IANA_TIMEZONES with getAllIanaTimezones()
using Intl.supportedValuesOf (~400 zones). Switch Select dropdowns
to searchable Combobox in cron, heartbeat, and system config.

Add defense-in-depth timezone validation:
- Backend: validate in heartbeat.set handler and SetDefaultTimezone()
- Frontend: isValidIanaTimezone() guard before save in all 3 dialogs

Closes #614
2026-04-01 11:12:35 +07:00
viettranx 9c2b4cbf0f fix(agent): improve memory recall accuracy and flush safety
- Add "low confidence" instruction to memory_search tool description
  to prevent models from fabricating memories when no results found
- Add dedicated ## Memory Recall section in system prompt (supplements
  recency reminder) with clear instructions for memory_search/memory_get
- Update flush prompts: replace YYYY-MM-DD with actual date at runtime,
  cleaner append-only wording
- Update AGENTS.md memory privacy section for multi-tenant: remove
  implementation details (per-user scoping), keep group chat output
  guardrails that work for both shared and isolated memory configs
2026-04-01 09:16:16 +07:00
viettranx 5b66d64545 fix(ui): decouple Edit with AI from SummoningModal, improve agent create UX
- RegenerateDialog now handles its own progress via WS events instead of
  opening SummoningModal (inline spinner + auto-close on completion)
- Clean up SummoningModal: remove mode/isRegenerate prop, summon-only
- Agent create: default to Predefined, collapse Open type behind toggle
  with warning banner explaining per-user context trade-off
- Add 4 new agent presets: Coder, Support, Writer, Translator (en/vi/zh)
- Remove 15 dead summoning.regenerate* i18n keys
2026-04-01 09:06:41 +07:00
viettranx 2092c50a04 fix(agent): use DB provider_type for SOUL echo and strict mode detection
- Add providerTypeOf() to extract provider_type via type assertion
  (e.g. "chatgpt_oauth") instead of config name (user-set "openai")
- Exclude "compat" providers (openai_compat → OpenRouter/DeepSeek/Groq)
  from strict mode and SOUL echo — they proxy to non-OpenAI models
- Fix isOpenAIStrict matching openai_compat incorrectly
2026-03-31 23:38:48 +07:00
viettranx 2a9400949b fix(agent): SOUL echo in recency zone for OpenAI/Codex providers
GPT models have strong recency bias and lose persona in long prompts.
Extract Style/Vibe sections from SOUL.md and echo them at the end of
the system prompt (~200 chars each) so GPT sees personality traits right
before generating. Only applies to OpenAI/Codex — Claude respects early
system prompt instructions well and doesn't need this.
2026-03-31 23:32:21 +07:00
viettranx ff4d370d27 fix(mcp): require 3 consecutive ping failures before marking server disconnected
Single transient errors (e.g. 504 from upstream proxy) no longer
instantly disconnect MCP servers. Requires healthFailThreshold (3)
consecutive failures before setting connected=false and triggering
reconnect. Applies to both Manager.healthLoop and poolHealthLoop.
2026-03-31 23:15:59 +07:00
viettranx e48ba1df7f fix(mcp): prevent LLM hallucination of optional tool parameters
3-layer defense against GPT-5.4 filling all optional MCP tool params
with fabricated values (e.g. api_key:"optional", proxyUrl:"http://example.com"):

Layer 1 — bridge_tool.go: expand placeholder detection to catch "optional",
"skip", example URLs; type-aware empty string handling (keep for string-typed,
strip for non-string); add propertyType() helper.

Layer 2 — schema_strict.go: OpenAI strict mode transform — optional props
become nullable unions, all props required, additionalProperties:false.
Constrained decoding prevents invalid output. Only enabled for first-party
OpenAI/Codex providers.

Layer 3 — systemprompt_sections.go: concrete WRONG/RIGHT examples in MCP
optional param instruction.
2026-03-31 23:15:59 +07:00
Tai Nguyen 06de8b41cf fix(cmd): sanitize followup reminder UTF-8 truncation (#609)
Prevent invalid UTF-8 from being persisted when auto-setting followups by sanitizing message content and truncating by rune count. Add regression tests for emoji truncation and malformed byte sequences.
2026-03-31 23:14:39 +07:00
viettranx f623ef9d55 feat(mcp): hybrid search mode — keep first 40 tools inline, defer rest
Instead of all-or-nothing when MCP tool count exceeds threshold,
keep first 40 tools registered inline and only defer the excess
to BM25 search via mcp_tool_search. System prompt now shows both
inline descriptions and search guidance in hybrid mode.

Also raises skill inline count from 40 to 60 (token limit is the
real bottleneck for skills).
2026-03-31 23:14:12 +07:00
viettranx aaa56ff004 fix(ui): summoning modal mode, dialog widths, and MCP refresh animation
- Add mode prop to SummoningModal (summon vs regenerate) so Edit with AI
  shows appropriate text instead of summoning language
- Fix memory document and KG entity detail dialogs using sm:max-w-* to
  properly override base sm:max-w-lg from DialogContent
- Expose isFetching from useMCP hook so refresh button animation works
2026-03-31 23:07:15 +07:00
viettranx ef0de0d760 fix(kg): merge recursive CTE branches and widen detail dialog
Combine forward+reverse traversal into single recursive branch using
CASE to fix SQLSTATE 42P19 (PostgreSQL parses triple UNION ALL as
left-associative, putting recursive ref in non-recursive term).

Also widen entity detail dialog from max-w-5xl to max-w-7xl.
2026-03-31 19:33:01 +07:00
viettranx 1d39626a88 fix(agent): use forward-scan replaceFirstMediaTag for correct multi-ref ordering
Replace replaceLastMediaTag with replaceFirstMediaTag across all 5 media
enrichment functions. Forward iteration + first-match produces natural
positional pairing, fixing reversed tag alignment when multiple media
refs exist in one message.

Also fixes same latent bug in enrichDocumentPaths, enrichAudioIDs, and
enrichVideoIDs. Supersedes #608.
2026-03-31 19:26:40 +07:00
viettranx 49f51da81c fix(kg): raise extraction temperature from 0.0 to 0.2
Zero temperature was too rigid, causing LLM to miss implied entities
and relations. 0.2 allows picking up contextual connections while
staying deterministic for structured JSON output.
2026-03-31 19:06:38 +07:00
viettranx c49952a1e5 feat(kg): expand entity types and improve extraction prompt
Add 3 new entity types: technology, product, document — reducing
concept catch-all bucket. Add 4 new relation types: authored,
references, provides, requires. Improve prompt with disambiguation
guide between similar types, stricter related_to usage, and varied
confidence examples. Update graph view colors and mass for new types.
2026-03-31 19:03:43 +07:00
viettranx 09a7823498 feat(providers): add tool schema normalization for MCP tools
Port TypeScript schema normalization pipeline to Go. MCP tools with
complex JSON Schemas ($ref, anyOf/oneOf, const, constraints) were
being rejected by OpenAI, Gemini, Codex, and xAI providers.

Pipeline per provider:
- Anthropic: resolve $ref → strip ref keys
- OpenAI/Codex/default: resolve $ref → flatten unions → inject type
- Gemini: resolve $ref → strip nulls → flatten → const→enum → strip 20+ keys
- xAI: resolve $ref → flatten → inject type → strip constraints

Key fixes:
- $ref resolution with circular detection (was: stripped → empty schema)
- anyOf/oneOf flattening into merged objects (was: raw → provider reject)
- type:"object" injection for OpenAI/Codex (was: 400 error)
- Codex now runs normalization (was: zero cleaning)
- Gemini strips 20+ constraint keywords (was: 5)
- xAI constraint keyword stripping (was: no profile)
- Builtin web_search/web_fetch minimum/maximum now stripped for Gemini/xAI
- DB provider type detection via schemaProviderName() for reliable Gemini matching
- Recursion depth guard (maxSchemaDepth=64) prevents DoS from malicious schemas
- Type inference from const values when explicit type is omitted
2026-03-31 17:56:24 +07:00
viettranx 37058918a0 feat(kg): enlarge entity detail dialog with table/graph tabs
Enlarge dialog max-w-3xl→5xl. Split relations into Table and Graph
tabs — graph tab renders traversal results as ReactFlow visualization.
Auto-traverse on open, bump depth 2→3 hops. Update i18n (en/vi/zh).
2026-03-31 17:55:35 +07:00
viettranx b99f119e37 feat(kg): bidirectional multi-hop traversal
Add reverse-edge UNION ALL to recursive CTE so traversal follows both
source→target and target→source edges. Reverse edges prefixed with ~
in via field (e.g. ~manages). Tool output shows directional arrows.
2026-03-31 17:55:27 +07:00
Plateau Nguyenandviettranx 9ad4a879d5 fix(discord): preserve attachment source URL in media tags (#606)
* fix(discord): preserve attachment source URL in media tags (#602)

- Add SourceURL field to MediaInfo struct
- Populate SourceURL from Discord attachment URL in resolveMedia()
- Emit <media:image url="..."> in BuildMediaTags() when SourceURL is set
- Refactor enrichImageIDs/enrichImagePaths with helper functions
- Add comprehensive unit tests for media URL handling

* fix: update system prompt for url attribute + add enrichment regression tests

- System prompt now documents the url attribute in <media:image> tags
- Add TestEnrichImageIDs_BareTag for non-Discord channel enrichment
- Add TestEnrichImageIDs_SkipsAlreadyEnriched for double-enrichment safety
- Add TestEnrichImagePaths_NoDoubleEnrich for historical message safety
- Add TestEnrichImagePaths_AttributeOrderIndependence for url-before-id tags

---------

Co-authored-by: viettranx <viettranx@gmail.com>
2026-03-31 17:16:45 +07:00
viettranx 8372298fba fix(providers): xAI generation models bypass chat verification
grok-imagine-video and grok-2-image were not in the isNonChatModel()
allowlist, causing verify to call Chat API which fails with malformed
error. Also fix friendlyVerifyError() fallback splitting inside JSON
values via LastIndex.
2026-03-31 14:35:57 +07:00
viettranx a565ad8402 fix: preserve FinishReason on truncated tool calls + ParseError propagation (#605)
Three layered bugs caused OpenAI-compatible providers to silently
produce empty tool call arguments when max_tokens was hit mid-JSON:

1. FinishReason override: all providers unconditionally overwrote
   "length" → "tool_calls" when tool calls existed, preventing the
   agent loop's truncation guard from firing.

2. Silent parse failure: JSON unmarshal errors were logged but args
   stayed as empty map with no signal to the caller.

3. No fallback for unreliable providers: some proxies don't emit
   finish_reason:"length" at all, leaving no detection path.

Fixes:
- Add ParseError field to ToolCall struct for explicit error signal
- Guard FinishReason override with `!= "length"` in OpenAI, Codex
- Set ParseError in all provider parsers (OpenAI, Anthropic, Codex)
- Add hasParseErrors() fallback guard in agent loop for EC-5 scenario
- Cap consecutive truncation retries (maxTruncationRetries=3) to
  prevent burning all iterations when max_tokens is persistently low

Closes #605
2026-03-31 14:33:33 +07:00
viettranx 4e9ce0e0e1 fix(contacts): consistent sender_id format and show contact_type in UI
- Use senderID (id|username) instead of userID in group no-mention path,
  preventing duplicate contacts for the same Telegram user
- Use full name (FirstName + LastName) in both contact insert paths
- Show contact_type (User/Group) instead of peer_kind (Direct/Group) in
  contacts table TYPE column and filter dropdown
- Add contact_type filter support in HTTP handler, PG and SQLite stores
2026-03-31 14:18:09 +07:00
viettranx 36b43ed7f1 feat(workspace): leader dual workspace with auto-copy to team on delegate
- Revert leader workspace override: leader keeps personal workspace as
  default, team workspace accessible via ToolTeamWorkspaceFromCtx
- Auto-copy: when leader creates team_tasks, scan subject+description
  for file paths → copy from personal to team workspace so members can
  access them
- Safety: Lstat (reject symlinks), 10MB size cap, .env excluded from
  allowed extensions, path traversal blocked
- Prompt hint: clarify members can only access team workspace files,
  referenced files are auto-copied
2026-03-31 12:10:55 +07:00
viettranx 8193d10fe9 docs: update architecture and changelog for subagent enhancement (#600) 2026-03-31 11:54:00 +07:00
viettranx 63878b16ca feat(telegram): /subagents commands + functional options refactor (#600)
- New /subagents and /subagent <id> commands for viewing subagent tasks
  from the persistent DB table
- Inline keyboard with sa: callback prefix for detail view
- Refactor telegram.New() to functional options pattern (WithAgentStore,
  WithTeamStore, WithSubagentTaskStore, WithPendingMessageStore)
- Wire SubagentTaskStore via WithSubagentTaskStore option
2026-03-31 11:45:25 +07:00
viettranx 2c1ef25392 feat(subagent): token tracking, edition limits, waitAll, auto-retry, producer-consumer announce (#600)
- Token cost tracking: accumulate input/output tokens per subagent,
  include in announce messages and persist to DB
- Per-edition rate limits: MaxSubagentConcurrent/Depth on Edition struct,
  tenant-scoped concurrency enforcement in Spawn/RunSync
- WaitAll action: spawn(action=wait, timeout=N) blocks until all
  children complete, returns merged summary
- Auto-retry: configurable MaxRetries (default 2) with linear backoff
  for transient LLM failures
- Producer-consumer announce queue: merges staggered subagent results
  into single LLM run (same pattern as team task announces)
- Raw metadata in bus messages to prevent double-formatting
- Fire-and-forget DB persistence with detached context + tenant scope
- Split oversized files for <200 line compliance
2026-03-31 11:45:16 +07:00
viettranx d8fc97ec63 feat(store): persist subagent tasks to PostgreSQL (#600)
- Migration 000034: subagent_tasks table with tenant scope, JSONB
  metadata + GIN index, partial index for archival candidates
- SubagentTaskStore interface with Create/Get/UpdateStatus/List/Archive
- PG implementation with parameterized queries and tenant isolation
- SQLite schema v3→4 migration + no-op stub for Lite edition
- Wire into store.Stores and factories
2026-03-31 11:45:03 +07:00
viettranx 7d35ee53c7 fix(agent): smart delegation prompt + compaction pending state + block team tools in subagents
- Leader prompt: replace blanket "prefer delegation" with conditional —
  delegate complex work, handle simple requests directly
- Compaction prompt: explicitly preserve pending subagent/team task state
  and "waiting for" expectations across summarization
- Add team_tasks to SubagentDenyAlways — subagents must not use team
  orchestration tools

Closes partially #600
2026-03-31 11:44:54 +07:00
viettranx 0f6cebc783 feat: structured compaction summary with identifier preservation
Compaction summaries were too generic ("provide a concise summary"),
causing loss of task progress, decisions, and identifier corruption
after summarization.

Port from OpenClaw TS (compaction.ts):
- Structured MUST PRESERVE sections: active tasks, progress, last
  request, decisions, TODOs, commitments
- Identifier preservation: preserve UUIDs, hashes, URLs, file names
  exactly as written (no shortening/reconstruction)
- Prioritize recent context over older history
- Shared prompt constant used by both mid-loop and background
  compaction paths
2026-03-31 09:32:38 +07:00
viettranx ab5bad11ff feat: cap tool output at source + improve context pruning pipeline
Problem: Agent sessions accumulated 71K+ input tokens (83% history)
because read_file and exec had no output limits. SOUL personality
drowned by massive context.

Changes:
- read_file: add offset/limit params + 50K char output cap with
  pagination hints (model can re-read with offset)
- exec/shell: cap output at 30K chars with smart head+tail truncation
  (preserves errors/summaries at tail)
- pruning: add per-result 30% context guard, tune softTrimRatio
  0.3→0.25 and softTrimMaxChars 4K→3K, add tail-aware soft trim
- mid-loop: allow pruning to re-trigger each iteration (was one-shot)

Design: cap at source, preserve full data in session, prune at
consumption time. read_file offset/limit enables recovery of
truncated content.
2026-03-31 08:35:06 +07:00
viettranx fe163eca30 fix(claude-cli): preserve CLAUDE_CODE_OAUTH_TOKEN in env filter
filterCLIEnv was stripping all CLAUDE* env vars including the OAuth
token needed for CLI subprocess authentication.

Closes #541
2026-03-31 08:19:58 +07:00
Plateau Nguyen dbc93aae8e fix(discord): stop typing after successful delivery (#589) 2026-03-31 08:14:52 +07:00
Kai (Tam Nhu) Tran 343b530480 fix: cap tool call IDs to 40 chars via hash-based uniquification (#590)
Closes #532

- Replace prefix truncation with SHA-256 hash-based shortening for oversized tool call IDs (40-char OpenAI/Azure limit)
- Normalize provider-prefixed model IDs (e.g. openai/o3-mini) before capability checks for temperature and max_completion_tokens
- Add regression tests for ID collision, correlation, and prefixed model routing
2026-03-31 08:10:01 +07:00
Kai (Tam Nhu) Tranandviettranx 3ca3bb2062 feat: add capability-aware reasoning effort controls (#593)
* feat(reasoning): add capability-aware effort resolution

- resolve requested reasoning levels against exact model capabilities

- persist requested effort on agents and expose effective effort in traces

- add backend tests for provider models, agent store, and resolution logic

Refs #591

* feat(ui): gate reasoning controls by model capabilities

- only show supported reasoning levels when provider model metadata is available

- preserve expert reasoning selections during async model loading

- surface effective reasoning details in trace dialogs and localized copy

Refs #591

* docs(api): document capability-aware reasoning controls

- describe exact-match capability lookup and downgrade behavior

- update provider model metadata and trace response documentation

- refresh the generated OpenAPI spec for the new reasoning fields

Refs #591

* feat: add provider-first reasoning controls

* docs: refresh PR 593 UI evidence callouts

* refactor: deduplicate reasoning normalize functions and remove PR evidence

- Export NormalizeReasoningEffort/NormalizeReasoningFallback from providers
  package; store package now delegates instead of duplicating
- Store reasoning fallback constants alias providers canonical definitions
- Export deriveLegacyThinkingLevel from types/provider.ts; remove local
  copies from agent-advanced-dialog and provider-overview
- Remove unused _providerType param from useProviderModels hook
- Fix reasoning debug log to fire for all cases with a reason (not just
  non-off efforts)
- Remove docs/pr-593-evidence/ binary screenshots from repo

---------

Co-authored-by: viettranx <viettranx@gmail.com>
2026-03-31 07:56:01 +07:00
viettranx 1dee22aeb7 fix(telegram): add human-like writing instructions for group chats
Port missing group chat style guidance from OpenClaw TS:
- "Write like a human" — prevents robotic/formal GPT responses
- "Avoid Markdown tables" — GPT tends to spam tables in groups
- "Use real line breaks sparingly"

These instructions exist in OpenClaw TS (groups.ts buildGroupIntro)
but were missing in GoClaw's group prompt.
2026-03-31 07:27:57 +07:00
viettranx a47d7f9f4f fix(providers): use developer role for native OpenAI endpoints (GPT-4o+)
GPT-4o+ models prioritize "developer" messages over "system" for
instruction adherence. GoClaw was sending "system" for all providers,
causing GPT models to poorly follow SOUL/system prompts.

Map "system" → "developer" only for native OpenAI endpoints
(api.openai.com). Non-OpenAI backends keep "system" role unchanged.

Ported from OpenClaw TS: model-compat.ts → isOpenAINativeEndpoint()
2026-03-30 23:56:51 +07:00
viettranx 7fd31c34aa fix(telegram): retry 429 rate limit errors and preserve stream messages
429 (Too Many Requests) was not recognized as retryable, causing:
1. editMessage fails with 429 → no retry
2. Stream message deleted as fallback
3. Fresh sendMessage also 429 → message lost entirely

Changes:
- Add 429 to isRetryableNetworkErr (matching OpenClaw TS TELEGRAM_RETRY_RE)
- Honor Telegram retry_after parameter for backoff delay
- Don't delete stream message on retryable errors (keep valid content)
2026-03-30 23:04:26 +07:00
viettranx 33f975edf0 fix: use agent_key instead of UUID for session tool authorization (#573)
Session tools (sessions_list, session_status, sessions_history, sessions_send)
were using resolveAgentIDString(ctx) which returns the agent UUID, but session
keys are built using agent_key. This caused all session tool operations to fail
silently or return "access denied" for every channel.

Replace resolveAgentIDString() with ToolAgentKeyFromCtx() in all four session
tools. Add fail-closed guard for empty agent key.
2026-03-30 22:28:00 +07:00
dale bb5647aaa8 fix sending image via lark (#587) 2026-03-30 22:15:34 +07:00
Kai (Tam Nhu) Tranandviettranx 287946bb9a fix(ui): restore provider-owned Codex pool inherit state (#585)
* fix(ui): restore provider-owned codex pool inherit state

* docs(pr): add before-after UI evidence

* refactor: remove dead hasProviderDefaults param and harden pool rendering

- Remove unused _hasProviderDefaults parameter from buildDraftRouting
  and routingDraftSignature, clean up all call sites and useMemo deps
- Filter deleted providers from selectedPoolProviderNames to prevent
  ghost entries when a saved pool member no longer exists
- Add symmetric backend test for inherit + non-nil provider defaults

---------

Co-authored-by: viettranx <viettranx@gmail.com>
2026-03-30 22:04:23 +07:00
Kai (Tam Nhu) Tran 3fe0633d35 fix: auto-install deps on skill upload before archiving (#559)
Upload handler previously archived skills immediately when deps were
missing. Now calls InstallDeps() first (owner/master tenant only) and
falls back to archive on failure.

Changes:
- Auto-install missing deps during skill upload (same flow as seeder)
- Atomic DB persist: deps state written with CreateSkillManaged in one call
- Per-slug upload mutex prevents concurrent race conditions
- Frontend: warning state (amber triangle) instead of throwing error
- Non-cancellable context for DB write after dep install
- SQLite StoreMissingDeps now works for custom skills (not just system)
- Comprehensive unit + integration tests

Closes #468
2026-03-30 21:58:29 +07:00
Kai (Tam Nhu) Tran 4c60dd021e fix: clarify container-scoped runtime warnings for minimal images (#395)
* fix(ui): clarify container-scoped runtime warnings

* docs(runtime): clarify docker image variant expectations

* test(tools): align media path expectations with workspace policy

* docs(tests): narrow message media path contract wording
2026-03-30 21:44:53 +07:00
Kai (Tam Nhu) Tran 65d0d62acf fix(memory): guard provider embedding dimensions to 1536 schema (#563)
- Reject incompatible explicit provider embedding dimensions on create/update
- Ignore previously saved incompatible dimensions at runtime, fall back to 1536
- Share RequiredMemoryEmbeddingDimensions constant from store package
- Remove dimensions input from provider UI (always 1536 per pgvector schema)
- Add HTTP, runtime, and validation unit tests

Closes #548
Supersedes #410
2026-03-30 21:36:09 +07:00
viettranx 53932cf532 fix(channels): include display name in [From:] annotation for Telegram and WhatsApp
Telegram: senderLabel now includes full name alongside username, e.g.
[From: @nguyennlt (Nguyễn Trần)] instead of just [From: @nguyennlt].
Also uses FirstName + LastName when no username is set.

WhatsApp: add missing [From:] annotation — was the only channel not
annotating sender identity for the LLM.
2026-03-30 21:24:39 +07:00
teexiii b38a078e70 fix(tools): delivered media tracker prevents duplicate file delivery (#579)
Replace naive HasPrefix("MEDIA:") self-send bypass with context-based
DeliveredMedia tracker (PendingTeamDispatch pattern).

write_file(deliver=true) marks paths → message self-send guard checks:
- Already delivered → blocked (no duplicate)
- Not delivered → allowed (fixes runaway retry loop)

Adds 8 test cases for self-send guard + tracker.
2026-03-30 21:13:27 +07:00
teexiii 88a5793030 fix(agents): sync IDENTITY.md Name field on agent rename (#582)
## Summary

- Agent rename now updates Name field in IDENTITY.md (agent-level + per-user copies for open agents) via both HTTP and WS paths
- Fixes lossy identity rebuild: previous logic reconstructed IDENTITY.md from only Name/Emoji/Avatar, silently dropping LLM-written fields (Creature, Purpose, Vibe, etc.)
- Uses targeted field replacement (bootstrap.UpdateIdentityField) preserving original formatting
- Adds ListUserContextFilesByName to AgentContextStore (PG + SQLite)
- Fixes LastIndex bug in UpdateIdentityField where values containing colons (e.g. Avatar URLs) would break field replacement
- Removes ~335 lines of dead config.json fallback code (agentStore is always set)
- Adds 9 unit tests for UpdateIdentityField covering plain/markdown formats, URLs, edge cases
2026-03-30 20:56:49 +07:00
Plateau Nguyenandviettranx 0e2db21345 fix(cron+providers): Run Now stuck fix, type safety, and claude-cli image format (#577, #568) (#580)
* fix(cron): Run Now executes correctly and reset stale running status (#568)

- PG store RunJob now sets next_run_at = NULL before executeOneJob so
  loadClaimedJob (which requires next_run_at IS NULL) succeeds instead
  of silently skipping the forced run
- recomputeStaleJobs on startup resets last_status 'running' → 'interrupted'
  for jobs that were mid-execution when the server crashed
- UI: add typed CronJobPatch interface matching backend store.CronJobPatch
  (deliverChannel/deliverTo/stateless) — replaces Record<string, unknown>
  on updateJob and onUpdate props across cron detail components
- UI: fix enabled/disabled label in overview tab to reflect local state
  instead of stale job prop

* fix(cron): add error handling for ExecContext calls per code review

- RunJob: return error if claiming job (next_run_at = NULL update) fails
  instead of silently proceeding to executeOneJob which would then skip
- recomputeStaleJobs: log warning on failure, log count of reset jobs
- Add log/slog import to cron_exec.go

* fix(providers): claude-cli ChatSync image format mismatch (#577)

When images are present, Chat() now uses stream-json output format to
match the stream-json input format required by Claude CLI >= v2.1.87.

Also adds concurrent execution guard to RunJob() preventing
double-execution when Run Now is clicked rapidly.

---------

Co-authored-by: viettranx <viettranx@gmail.com>
2026-03-30 20:37:49 +07:00
therichardngai-code 0ef30ad060 fix(ui): reduce KG graph INP from 808ms to <100ms (#581)
- Defer dialog open via setTimeout(0) on node click — decouples edge
  restyle from dialog mount (808ms → <100ms INP)
- Memoize relations table with React.memo + limit initial render to 50
  rows with "Show all" button (792ms table cell INP → <100ms)
- Added i18n key kg.entity.showAll for en/vi/zh

Based on upstream review fixes (989e4f3).
2026-03-30 20:21:48 +07:00
viettranx 989e4f3123 fix(ui): KG graph review fixes — edge colors, fetch limit, double fitView
- Fix hardcoded dark edge color on deselect — use neutral #64748b
- Reduce graph fetch limit 200→50 to match component render cap
- Fix O(n*m) node lookup on theme change — use Map for O(1)
- Remove double fitView (prop + manual call)
2026-03-30 16:53:14 +07:00
viettranx 88f4fa264a fix(ui): KG graph perf + theme support + entity limit
- Limit graph to 50 entities for smooth DOM-based rendering
- Dual-theme node colors (light: solid bg/dark text, dark: translucent/light)
- Follow user theme via colorMode (no hardcoded dark)
- Theme change updates node colors without re-layout or fitView
- Remove MiniMap, backdrop-filter blur, translateZ GPU layers
- Thicker edges (strokeWidth 2, opacity 0.6) for visibility
- Simplified footer: entity/relation counts + limit note
- memo EntityNode to prevent re-render during pan/zoom
- i18n: add limitNote/limitHint keys (en/vi/zh)
2026-03-30 16:46:25 +07:00
viettranx 1cb7d3cb70 perf(ui): optimize KG graph view for large graphs
- Add KGEdgeData interface replacing `as any` casts for type safety
- Use entityMap (useMemo Map) for O(1) entity lookup instead of O(n) find
- Pre-compute EDGE_STYLE_DEFAULT/FADED constants to reduce GC pressure
- Skip edge object recreation when style unchanged during selection
- Wrap EntityNode in memo() with memoized container style
- Cap force simulation ticks at 200 for graphs with 100+ nodes
2026-03-30 15:54:34 +07:00