Skip to content

feat: add wacli agent — JSON-RPC 2.0 mode for AI agents#49

Open
delltrak wants to merge 1 commit intosteipete:mainfrom
delltrak:main
Open

feat: add wacli agent — JSON-RPC 2.0 mode for AI agents#49
delltrak wants to merge 1 commit intosteipete:mainfrom
delltrak:main

Conversation

@delltrak
Copy link
Copy Markdown

Summary

  • Adds wacli agent subcommand: a long-lived JSON-RPC 2.0 server over NDJSON (stdin/stdout)
  • Solves the lock contention between sync --follow and send text — one process handles both directions
  • 9 RPC methods: send_text, send_file, mark_read, set_typing, set_presence, list_chats, list_messages, search, get_message
  • 6 notification types: message, receipt, presence, chat_presence, connection, agent.ready
  • Optional --auto-presence: simulates human-like behavior (online → typing → send → offline)
  • Read receipts are explicit only (mark_read method) — the consumer decides when to show blue ticks

Files changed

File Change
internal/wa/client.go 4 new wrapper methods (SendPresence, SendChatPresence, MarkRead, SetForceActiveDeliveryReceipts)
internal/app/app.go Extend WAClient interface
internal/app/jsonrpc.go New — JSON-RPC 2.0 types + mutex-protected writer
internal/app/agent.go New — Agent loop, dispatcher, 9 handlers, event notifications, typing simulation
internal/app/sync.go Refactor storeParsedMessage to return StreamMessage; add OnMessage callback
cmd/wacli/sync.go Add --stream flag
cmd/wacli/agent.go New — Cobra command
cmd/wacli/root.go Register agent command
internal/app/agent_test.go New — 9 tests
internal/app/fake_wa_test.go Stubs for new interface methods

Test plan

  • go test -tags sqlite_fts5 ./... — all pass
  • go test ./... (without FTS5) — all pass
  • go vet ./... — clean
  • gofmt -l . — clean
  • Build: go build -tags sqlite_fts5 -o ./dist/wacli ./cmd/wacli
  • Manual test: interactive session with real WhatsApp (send, receive, receipts)

Closes #48

🤖 Generated with Claude Code

Add a new `wacli agent` subcommand that runs as a long-lived JSON-RPC 2.0
server over NDJSON (stdin/stdout), enabling AI agents to receive and send
WhatsApp messages through a single process.

This solves the problem of `sync --follow` and `send text` competing for
the exclusive flock — the agent holds one connection and handles both
directions simultaneously.

Changes:
- internal/wa/client.go: add SendPresence, SendChatPresence, MarkRead,
  SetForceActiveDeliveryReceipts wrapper methods
- internal/app/app.go: extend WAClient interface with the 4 new methods
- internal/app/jsonrpc.go: JSON-RPC 2.0 protocol types and mutex writer
- internal/app/agent.go: agent loop, dispatcher, 9 RPC handlers
  (send_text, send_file, mark_read, set_typing, set_presence,
  list_chats, list_messages, search, get_message), event notifications
  (message, receipt, presence, chat_presence, connection), and
  optional auto-presence with typing simulation
- internal/app/sync.go: refactor storeParsedMessage to return
  StreamMessage; add OnMessage callback to SyncOptions
- cmd/wacli/sync.go: add --stream flag for NDJSON message output
- cmd/wacli/agent.go: cobra command with --auto-presence flag
- cmd/wacli/root.go: register agent command
- internal/app/agent_test.go: 9 tests covering the full RPC surface
- internal/app/fake_wa_test.go: stubs for the 4 new interface methods

Ref: steipete#48

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

fmt.Fprintf(os.Stdout, "Messages stored: %d\n", res.MessagesStored)

P2 Badge Preserve JSON stream when --stream is enabled

When --stream is set, messages are emitted as JSON lines on stdout, but this unconditional summary print appends a plain-text line (Messages stored: ...) to the same stdout stream. In --once mode this breaks NDJSON consumers that parse stdout as JSON-only message events, so the summary should be suppressed or redirected (e.g., stderr) while streaming.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread internal/app/agent.go
writer.respondError(req.ID, errCodeParse, "invalid jsonrpc version")
continue
}
a.dispatchRPC(ctx, writer, req, opts)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Skip replies for notification requests without id

JSON-RPC 2.0 notifications are requests that omit id and must not produce a response, but this loop dispatches every request and downstream handlers always call respond/respondError, which emits frames with "id":null. Clients that send fire-and-forget notifications (for example set_presence) will receive unexpected responses and may treat them as protocol violations or mis-correlate them with real request/response traffic.

Useful? React with 👍 / 👎.

Comment thread internal/app/agent.go
}
a.dispatchRPC(ctx, writer, req, opts)
}
return nil
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Propagate scanner errors from agent input loop

The input loop returns nil immediately after scanner.Scan() ends, without checking scanner.Err(). If stdin hits a read failure or a request line exceeds the configured 1 MiB scanner limit, the agent exits silently and drops subsequent requests, leaving callers without a detectable failure signal.

Useful? React with 👍 / 👎.

@steipete steipete requested a review from dinakars777 as a code owner April 21, 2026 03:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature proposal: wacli agent — JSON-RPC 2.0 mode for AI agent integration

1 participant