60 Commits

Author SHA1 Message Date
Cameron
8143af47ee fix: Windows TTY crash and LETTA_HOME shell expansion
#47: Skip /dev/tty entirely on Windows — it resolves to C:\dev\tty
which doesn't exist. The .on('error') handler from v2.1.1 catches the
async error on Linux, but on Windows we shouldn't even attempt it.

#48: Expand common shell syntax ($HOME, ${HOME}, ~) in LETTA_HOME.
When set via Claude Code settings.json, env vars aren't shell-expanded,
so "$HOME" becomes a literal directory name. expandPath() now resolves
these to os.homedir(). Fixes both getDurableStateDir() call sites and
the splash screen display.

Fixes #47, fixes #48.

Written by Cameron ◯ Letta Code

"Defensive programming is the art of expecting the unexpected." - Unknown
2026-04-15 17:13:09 -07:00
Cameron
382a2832e5 feat: add letta/auto and minimax/MiniMax-M2.7 to model fallback list
Written by Cameron ◯ Letta Code

"Variety is the spice of life." - William Cowper
2026-03-30 18:11:14 -07:00
Cameron
7c57b13683 fix: three bugs — silent worker resolution, TTY crash, plugin root fallback
#42: spawnSilentWorker on macOS/Linux now uses the plugin's local tsx
CLI (node_modules/tsx/dist/cli.mjs) instead of npx, which resolves to
a global cache that can't find @letta-ai/letta-code-sdk. Same pattern
Windows already used.

#41: Add error handler on /dev/tty WriteStream in session_start.ts.
createWriteStream returns synchronously but ENXIO fires async — without
a handler, Node crashes the process.

#34: Partial workaround for CLAUDE_PLUGIN_ROOT being empty on Linux.
hooks.json now uses ${CLAUDE_PLUGIN_ROOT:-.} fallback. silent-npx.cjs
re-resolves broken script paths via __dirname when the original path
doesn't exist. Note: this is primarily a Claude Code framework bug.

Fixes #42, fixes #41, partially addresses #34.

Written by Cameron ◯ Letta Code

"First, do no harm." - Hippocrates
2026-03-30 13:43:11 -07:00
cpacker
9d5a7e9c27 fix: tag Subconscious agents with origin marker
Ensure imported and existing Subconscious agents always include origin:claude-subconcious for tracking, and keep git-memory-enabled tagging in the same idempotent path.

👾 Generated with [Letta Code](https://letta.com)

Co-Authored-By: Letta Code <noreply@letta.com>
2026-03-23 22:38:49 -07:00
Cameron
fc2e50fc9d feat: migrate Subconscious to memfs (git-backed memory filesystem)
- Enable memfs on import: adds `git-memory-enabled` tag after importing
  the bundled agent, which triggers the server to create a git-backed
  memory repo and sync blocks as files
- Update system prompt: "memory blocks" → "files in a git-backed
  filesystem (memfs)"
- Update self_improvement: reference memfs conventions, file management
  instead of raw block management
- Update core_directives: "memory files" instead of "memory blocks"

Existing users' agents will get memfs when Letta Code enables it on
their cloud agent. New users get it automatically on import.

Closes #32

Written by Cameron ◯ Letta Code

"Simplicity is the ultimate sophistication." - Leonardo da Vinci
2026-03-18 04:33:15 -07:00
Cameron
04c342327e fix(api): normalize Letta URLs and avoid self-hosted conversations redirect (#31)
Use a shared URL builder across scripts and update createConversation to call /v1/conversations/ with query params to avoid HTTPS->HTTP redirect failures behind reverse proxies. This also deduplicates LETTA_API_BASE handling and adds regression tests for trailing-slash behavior.

👾 Generated with [Letta Code](https://letta.com)

Co-authored-by: Letta Code <noreply@letta.com>
2026-03-17 10:21:03 -07:00
Cameron
a14635dbc8 chore: remove dead countTranscriptLines function
Written by Cameron ◯ Letta Code

"Dead code is a liability, not an asset." - Ward Cunningham
2026-03-13 18:39:36 -07:00
Cameron
ab7b3432c7 feat: tell both Sub and Claude about SDK tools mode at init
- Session start message to Sub now includes sdk_tools_mode and
  describes what tools are available (read-only, full, or off)
- letta_context header to Claude describes Sub's capabilities
  ("can read files, search your codebase" vs "listen-only mode")
- Updated core_directives in bundled agent to reflect tool access
- Updated system prompt and description to "Subconscious" framing

Written by Cameron ◯ Letta Code

"Know thyself." - Socrates
2026-03-13 18:37:49 -07:00
Cameron
4193d25d40 fix: replace checkpoint mode with SDK tools in startup splash
Written by Cameron ◯ Letta Code

"Clean code always looks like it was written by someone who cares." - Robert C. Martin
2026-03-13 18:22:52 -07:00
Cameron
792cd99f52 feat: restore LETTA_SDK_TOOLS=off as listen-only mode
off now means "no client-side tools" — Sub still receives transcripts
via the SDK transport but can only use memory operations. Useful for
listen-only agents that observe without filesystem access.

Written by Cameron ◯ Letta Code

"Listening is an art that requires attention over talent." - Dean Jackson
2026-03-13 18:19:47 -07:00
Cameron
8329de34a2 chore: clean up for v2.0.0 — README, logging, version bump
- Remove checkpoint docs, legacy `off` mode, and stale log file refs from README
- Clean up verbose per-message stream logging in SDK worker (keep tool calls + errors)
- Bump version to 2.0.0 in package.json and plugin.json

Written by Cameron ◯ Letta Code

"Less is more." - Ludwig Mies van der Rohe
2026-03-13 18:16:39 -07:00
Cameron
9e0602a4fc feat!: remove legacy API path, require Letta Code SDK
BREAKING CHANGE: The `LETTA_SDK_TOOLS=off` option is removed. All
message delivery to Sub now goes through the Letta Code SDK. Users
who need the old behavior should pin to a pre-SDK tag.

Deleted:
- scripts/send_worker.ts (legacy raw API worker)
- scripts/plan_checkpoint.ts (was no-op in SDK mode)

Removed:
- Legacy branch in send_messages_to_letta.ts
- Early prompt notification in sync_letta_memory.ts
- sendMessageToConversation from conversation_utils.ts
- Checkpoint hook from hooks.json

Written by Cameron ◯ Letta Code

"Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away." - Antoine de Saint-Exupéry
2026-03-13 17:23:22 -07:00
Cameron
732e39599c fix: prevent conversation conflicts between SDK and legacy paths
In SDK mode, sync_letta_memory.ts and plan_checkpoint.ts were still
spawning legacy send_worker.ts — racing the SDK worker on the same
conversation and causing 409 CONFLICT errors (0 chars response).

- sync_letta_memory: skip early prompt notification in SDK mode
- plan_checkpoint: skip entirely in SDK mode (Stop hook handles it)

Written by Cameron ◯ Letta Code

"Two threads enter, one thread leaves." - Mad Max, concurrent edition
2026-03-13 16:41:12 -07:00
Cameron
3acd22f9d9 fix: restore conversationId + add verbose stream logging
Revert to resumeSession(conversationId) and log every stream message
type to diagnose why the session returns 0 chars.

Written by Cameron ◯ Letta Code

"Debugging is twice as hard as writing the code." - Brian Kernighan
2026-03-13 16:35:52 -07:00
Cameron
e71fc2f976 fix: revert to resumeSession(agentId) — API conversations incompatible with SDK
resumeSession(conversationId) silently fails (0 chars response) when the
conversation was created via the raw Letta API. The SDK needs to manage
its own conversation. Revert to agentId for now.

Written by Cameron ◯ Letta Code

"Move fast and fix things." - Unknown
2026-03-13 16:34:49 -07:00
Cameron
4c3c457f7a fix: use conversationId in SDK worker so messages appear in same thread
resumeSession(conversationId) instead of resumeSession(agentId) so that
SDK-routed messages show up in the same conversation on app.letta.com.

Written by Cameron ◯ Letta Code

"All problems in computer science can be solved by another level of indirection." - David Wheeler
2026-03-13 16:29:19 -07:00
Cameron
13b454bf00 feat: add Letta Code SDK transport for client-side tool access (#19)
Give the Subconscious agent client-side tool access (Read, Grep, Glob,
web_search) via the Letta Code SDK. Instead of being limited to memory
operations, Sub can now read files and search the web while processing
transcripts.

Architecture:
- New send_worker_sdk.ts uses resumeSession() from @letta-ai/letta-code-sdk
- send_messages_to_letta.ts routes to SDK or legacy worker based on
  LETTA_SDK_TOOLS env var (read-only | full | off)
- Stop hook is now async (won't block Claude Code)
- Legacy raw API path preserved for LETTA_SDK_TOOLS=off

New env var: LETTA_SDK_TOOLS
- read-only (default): Read, Grep, Glob, web_search, fetch_webpage
- full: all tools
- off: legacy memory-only behavior

Closes #19

Written by Cameron ◯ Letta Code

"The best interface is no interface." - Golden Krishna
2026-03-13 16:07:42 -07:00
Cameron
98a5dbdf0b fix: improve splash screen mascot and link display order
- Simplified spider mascot with red eyes
- Print Discord/agent links before blocking network call
- Ensures links display even if session message times out
2026-03-04 13:17:41 -08:00
Cameron
890872368c feat: add checkpoint hooks and startup splash screen
- Add PreToolUse hooks for AskUserQuestion and ExitPlanMode to send
  transcripts to Letta at natural pause points (plan_checkpoint.ts)
- Extract shared transcript utilities into transcript_utils.ts
- Add LETTA_CHECKPOINT_MODE env var (blocking/async/off)
- Add startup splash screen with agent info, settings, and links
- Write to /dev/tty to show splash in terminal (bypasses Claude capture)
- Update README with checkpoint hooks documentation
2026-03-04 12:36:01 -08:00
Cameron
f8cae38805 fix: use per-user temp dir to avoid EACCES on shared machines (#25)
The hardcoded /tmp/letta-claude-sync/ path caused EACCES errors when
multiple OS users shared the same machine — the first user to create
the directory owned it, blocking all others.

Now uses os.tmpdir() with a UID suffix (e.g. /tmp/letta-claude-sync-501/)
so each user gets their own log/payload directory.

Fixes #25

Written by Cameron ◯ Letta Code

"Sharing is caring, except for /tmp directories." - Unknown
2026-02-26 14:32:35 -08:00
Cameron
141194716f Merge pull request #22 from scrossle/fix/windows-pseudoconsole
fix(windows): eliminate console window flashes using PseudoConsole
2026-02-24 10:12:56 -08:00
Basit Mustafa
a794a66dda fix: use llm_config PATCH to preserve context_window during model updates
The top-level `{ model: "..." }` PATCH on the Letta API resets
context_window to a server-side default (32K), even when both fields
are sent in the same request. This means every LETTA_MODEL override
silently drops the agent's context_window back to 32K.

Switch updateAgentModel() to use `{ llm_config: {...} }` PATCH format
which preserves context_window and other settings. Add buildLlmConfig()
helper that constructs the full config from available model metadata and
the agent's current settings.

Also adds LETTA_CONTEXT_WINDOW environment variable so users can
explicitly set their desired context window size.

Changes:
- Extract findModel() from isModelAvailable() for reuse
- Add LlmConfig interface with full llm_config fields
- Add buildLlmConfig() to construct config from model handle + metadata
- Update updateAgentModel() to PATCH via llm_config instead of model
- Add LETTA_CONTEXT_WINDOW env var support
- Document LETTA_CONTEXT_WINDOW in README
- Add 13 tests for findModel() and buildLlmConfig()
2026-02-19 09:18:04 -08:00
scrossle
36898f1318 fix(windows): add Win10 compat and deduplicate worker spawn logic
- Add dual P/Invoke for UpdateProcThreadAttribute (Win11 26300+) vs
  UpdateProcThreadAttributeList (Win10/older) with EntryPointNotFoundException
  fallback in SilentLauncher.cs
- Extract shared spawnSilentWorker() utility into conversation_utils.ts,
  replacing ~50 duplicated lines in send_messages_to_letta.ts and
  sync_letta_memory.ts
- Add build.ps1 for reproducible silent-launcher.exe builds
- Rebuild silent-launcher.exe with updated source

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 21:28:23 -08:00
scrossle
8adae7cdbb fix(windows): eliminate console window flashes using PseudoConsole
On Windows 11 / Windows Terminal, hook execution caused visible console
window popups. This replaces the simple npx wrapper (silent-npx.js) with
a PseudoConsole (ConPTY) + CREATE_NO_WINDOW approach that runs scripts
in a headless console session.

New files:
- SilentLauncher.cs: C# launcher creating a PseudoConsole with
  CREATE_NO_WINDOW, stdin/stdout via temp files, and --import tsx/esm
  for single-process execution
- silent-launcher.exe: Compiled as AnyCPU winexe (works on x64 and ARM64)
- stdio-preload.cjs: Node.js --require script for temp file I/O
- silent-npx.cjs: Cross-platform shim that delegates to
  silent-launcher.exe on Windows, runs tsx directly elsewhere

Also fixes:
- Letta API message sync: bumped limit from 50 to 300 and added date
  sorting (API does not guarantee newest-first ordering)
- Background workers on Windows: spawn through silent-launcher.exe with
  detached:true so workers survive PseudoConsole closure

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 21:16:02 -08:00
letta-code
e96e8cdc30 fix: clean global ~/.claude/CLAUDE.md during session start cleanup
The cleanLettaFromClaudeMd() function only targeted the project-level
.claude/CLAUDE.md. Users with pre-v1.3.0 installations could have
bloated <letta> sections in their global ~/.claude/CLAUDE.md that
were never cleaned up, causing Claude Code to warn about large files.

Now session_start also cleans the global CLAUDE.md, with a guard to
avoid double-cleaning if cwd happens to be the home directory.

Fixes #16

Written by Cameron ◯ Letta Code

"The details are not the details. They make the design." - Charles Eames

Co-authored-by: Cameron <cpfiffer@users.noreply.github.com>
2026-02-07 01:06:10 +00:00
Cameron
50aafdd695 Differentiate whisper (messages only) from full (blocks + messages)
- whisper (default): Only inject Sub's messages
- full: Full memory blocks on first prompt, diffs + messages after
- off: Disable all hooks

No mode writes to CLAUDE.md.

Written by Cameron ◯ Letta Code

"Know the difference between detail and clutter." - Unknown
2026-02-05 16:54:09 -08:00
Cameron
ecd2ec1b63 Implement LETTA_MODE: never write to CLAUDE.md (fixes #14)
Subconscious never writes to CLAUDE.md in any mode. All memory is
injected via stdout into prompt context. Two modes:

- whisper (default): Full blocks on first prompt, diffs + messages after
- off: Disable all hooks

Existing <letta> sections in CLAUDE.md are cleaned up automatically.
If CLAUDE.md was entirely created by us, it gets deleted.
If user had their own content, only the <letta> section is stripped.

Written by Cameron ◯ Letta Code

"Less is more." - Mies van der Rohe
2026-02-05 16:46:21 -08:00
scrossle
170a8264d5 Replace LETTA_CLAUDE_MD_PATH with LETTA_HOME and LETTA_PROJECT
- LETTA_HOME: Base directory for .letta/ state files (conversations, sessions)
- LETTA_PROJECT: Base directory for .claude/CLAUDE.md memory blocks

Both default to current behavior but can be set to $HOME to consolidate
all plugin output in one location, preventing file proliferation.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 14:20:04 -08:00
scrossle
b747f670af Add LETTA_CLAUDE_MD_PATH environment variable support
Allows users to override the default CLAUDE.md location to prevent
file proliferation when the plugin is globally enabled.

When set (e.g., to $HOME/.claude/CLAUDE.md), the plugin writes to
that single location regardless of the current working directory.

This solves the duplication issue where Claude Code's recursive
discovery finds multiple CLAUDE.md files in parent and child
directories, injecting duplicate memory blocks into context.

Changes:
- scripts/conversation_utils.ts: Check LETTA_CLAUDE_MD_PATH env var
- README.md: Document the new optional environment variable

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-01 07:32:34 -08:00
scrossle
2639f3660c Normalize line endings (CRLF → LF for WSL)
All files converted to Unix line endings (LF) for consistent
cross-platform development in WSL environment.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-01 07:30:30 -08:00
Cameron
e4327e4789 Update preferred models list for quality over cost
- Claude Sonnet 4.5 first (recommended for agents by Anthropic)
- GPT-4.1-mini second (good balance, cheap)
- Claude Haiku 4.5 third (fast Claude option)
- Flagship models as fallback only
- Updated model examples in README to current versions
2026-01-29 13:06:54 -08:00
Cameron
8177437d5c Merge pull request #9 from letta-ai/letta/issue-8-20260128-2308
fix: add Windows compatibility for detached process spawning
2026-01-28 16:59:45 -08:00
letta-code
9b8ee3aaa3 Merge origin/main into feature branch
Resolve conflicts from divergent histories:
- Keep LETTA_MODEL env var and auto-detection features from this PR
- Merge agent ID validation from main
- Update to version 1.1.0
- Include Windows compatibility fixes (NPX_CMD)
- Restore pretool_sync.ts, tests, and CHANGELOG

Written by Cameron ◯ Letta Code

"Simple things should be simple, complex things should be possible." - Alan Kay

Co-authored-by: Cameron <cpfiffer@users.noreply.github.com>
2026-01-28 23:37:49 +00:00
letta-code
09972bfd71 fix: add Windows compatibility for detached process spawning
On Windows, spawning detached child processes with `spawn()` requires
`shell: true` to work properly, otherwise Node.js throws EINVAL error.

This adds the `shell: true` and `windowsHide: true` options when running
on Windows platform to fix the "spawn EINVAL" error reported in issue #8.

Fixes #8

Written by Cameron ◯ Letta Code

"The only way to make sense out of change is to plunge into it, move with it, and join the dance." - Alan Watts

Co-authored-by: Cameron <cpfiffer@users.noreply.github.com>
2026-01-28 23:10:46 +00:00
Cameron Pfiffer
8ac7feacb7 Add instruction to acknowledge Sub messages at prompt time
Same as PreToolUse - inject instruction dynamically so Claude
surfaces Sub messages to the user. Not in CLAUDE.md which gets
forgotten as context grows.

Written by Cameron ◯ Letta Code

"Context is everything." - Unknown
2026-01-28 14:46:58 -08:00
Cameron Pfiffer
2833b5c299 Instruct Claude to surface Sub messages mid-workflow
Add instruction in additionalContext telling Claude to briefly
acknowledge what Subconscious said, so users see it inline.

Written by Cameron ◯ Letta Code

"Show, don't tell." - Chekhov
2026-01-28 14:42:59 -08:00
Cameron Pfiffer
b612f9bd9b Show Subconscious messages during workflow
Add systemMessage to PreToolUse output so users can see when Sub has
something to say mid-workflow. Shows a preview of the message with 💭.

Written by Cameron ◯ Letta Code

"Make the invisible visible." - Edward Tufte
2026-01-28 14:34:52 -08:00
Cameron
69eb402332 Merge pull request #6 from letta-ai/letta/issue-5-20260128-1759
fix: validate LETTA_AGENT_ID format with helpful error message
2026-01-28 11:43:20 -08:00
Cameron Pfiffer
2a216f0655 Add PreToolUse hook for mid-workflow context injection
New lightweight hook that checks for Letta agent updates before each
tool use, addressing "workflow drift" in long workflows. Injects new
messages and memory block diffs via additionalContext if changes found,
silent no-op otherwise.

Written by Cameron ◯ Letta Code

"The only way to do great work is to love what you do." - Steve Jobs
2026-01-28 11:33:44 -08:00
Cameron Pfiffer
1ca82cb8f2 Sync CLAUDE.md at session start for fresh agent/conversation IDs
SessionStart now writes CLAUDE.md immediately after creating or
resuming a conversation. This ensures Claude sees current IDs from
the start rather than stale data from a previous session.

- Extract shared sync functions to conversation_utils.ts
- Add IS_HOSTED flag: show app URLs for hosted, raw IDs for self-hosted
- Remove duplicate code from sync_letta_memory.ts
2026-01-28 11:30:42 -08:00
letta-code
1e502682ca test: add tests for LETTA_AGENT_ID validation
Adds comprehensive test suite using vitest:
- Valid agent ID formats (lowercase, uppercase, mixed case)
- Invalid friendly names (e.g., "Memo", "My Agent")
- Missing "agent-" prefix
- Malformed UUIDs (truncated, extra chars, wrong segments)
- Edge cases (empty string, whitespace, newlines)

Co-authored-by: Cameron <cpfiffer@users.noreply.github.com>

Written by Cameron ◯ Letta Code

"A program that has not been tested does not work." - Bjarne Stroustrup
2026-01-28 18:13:21 +00:00
letta-code
61a758f433 feat: auto-detect available models and select fallback
Instead of requiring users to manually set LETTA_MODEL, the plugin now:
1. Queries available models from the Letta server
2. Checks if the agent's current model is available
3. Auto-selects a fallback if not (preferring openai/gpt-4o-mini)
4. Informs user via console output about model changes

LETTA_MODEL can still be used for manual override.

Fixes #2

Written by Cameron ◯ Letta Code

"Make it work, make it right, make it fast." - Kent Beck
2026-01-28 18:05:15 +00:00
letta-code
9068ba1e00 fix: validate LETTA_AGENT_ID format with helpful error message
Users were getting confusing SQL foreign key constraint errors when using
a friendly agent name (e.g., "Memo") instead of the proper UUID format.
This adds validation that:

- Checks the agent ID matches the expected format (agent-UUID)
- Provides a clear error message explaining the correct format
- Lists common mistakes like using the friendly name
- Includes instructions on how to find the correct agent ID

For saved configs with invalid IDs, we gracefully fall back to importing
the default agent instead of crashing.

Fixes #5

Co-authored-by: Cameron <cpfiffer@users.noreply.github.com>

Written by Cameron ◯ Letta Code

"The details are not the details. They make the design." - Charles Eames
2026-01-28 18:01:36 +00:00
letta-code
c3c72bde89 feat: add LETTA_MODEL environment variable for model configuration
When using self-hosted Letta with providers other than z.ai, users can now
set LETTA_MODEL to override the default model (e.g., "openai/gpt-4o-mini").

The model is applied:
- After auto-importing the default agent
- When the saved config has a different model
- When using LETTA_AGENT_ID env var

Fixes #2

Written by Cameron ◯ Letta Code

"Simplicity is the ultimate sophistication." - Leonardo da Vinci
2026-01-28 16:44:58 +00:00
letta-code
546f09b11c Fix Windows npx spawn ENOENT error
Use npx.cmd instead of npx on Windows platforms to fix spawn ENOENT errors.

Fixes #1

Written by Cameron ◯ Letta Code

"The only way to do great work is to love what you do." - Steve Jobs

Co-authored-by: Cameron <cpfiffer@users.noreply.github.com>
2026-01-28 16:41:12 +00:00
Cameron Pfiffer
f313d89669 Add LETTA_BASE_URL support for self-hosted servers 2026-01-26 15:08:29 -08:00
Cameron Pfiffer
9f9d6c1b3a Release prep cleanup
- Simplify install instructions (remove build step - tsx runs TS directly)
- Update .gitignore with tool configs, local state dirs, evals, skills
- Remove BLOG_SHORT.md (internal draft)
- Refactor send_messages_to_letta.ts to use conversation_utils
2026-01-26 12:36:37 -08:00
Cameron Pfiffer
03f18272c5 Fix message sync ordering and add conversationId fallback
- Fix message ordering: API returns newest-first, sync was iterating
  wrong direction. Now iterates from 0 to lastSeenIndex for new messages.
- Add lookupConversation() to recover conversationId from conversations.json
  when session state is missing it (handles state corruption/reset).
- Extract shared utilities to conversation_utils.ts
- Add LETTA_DEBUG=1 env var for debug logging to stderr
2026-01-22 17:19:57 -08:00
Cameron Pfiffer
87c3da8664 Update hooks format and prioritize conversation URL
- Add matcher: "*" to hooks for Claude Code compatibility
- Use conversation URL (with ?conversation=id) as primary link
- Update first message instruction to point users directly to their conversation

Written by Cameron ◯ Letta Code

"The best way to predict the future is to invent it." - Alan Kay
2026-01-18 17:52:11 -08:00
Cameron Pfiffer
24ebbca2ae Fix conversation message fetching in sync script
Change fetchLastAssistantMessage to use conversation-specific endpoint
(/conversations/{id}/messages) instead of agent-wide endpoint
(/agents/{id}/messages). Prevents mixing messages from multiple
conversations and ensures we fetch responses from the correct session.
2026-01-18 17:46:14 -08:00