Commit graph

144 commits

Author SHA1 Message Date
d3845671b4 ollama: fix EmbedTexts signature, add model config, use clustering package
- ollama/client.go: EmbedTexts accepts []clustering.Item, returns [][]float64
- backends.go: ollamaBackend interface uses clustering.Item
- utils/styleProfiles.go: remove duplicate KMeans, normalize, cosineSimilarity
- clustering/: new package with Item, Result types and KMeans
- config.go: add EmbeddingModel, StyleModel env vars
- main.go: pass model config to ollama.New()
- go.mod: add github.com/ethereum/go-ethereum for test client
2026-09-01 23:40:21 +02:00
027a4ee5e9 test: add auto-funding to test client and fix CI workflow
- testClient: add ensureFundedWallet() with USDC/ETH balance checks and faucet requests
- fund-wallet.sh: update faucet format for Coinbase CDP API
- start-test-server.sh: use Coinbase facilitator URL, add payment endpoint verification
- test-endpoints.yaml: fund test wallet before server, pass RPC/Faucet URLs to test client
2026-09-01 23:39:14 +02:00
e54d17736b Complete Matrix webhook integration and interface{}→any migration
- Add MATRIX_WEBHOOK_URL and MATRIX_SERVER_ID config fields (optional, defaults to hostname)
- Create internal/server/webhook.go: WebhookSender with exponential backoff retry (5 attempts),
  first/last attempt logging, non-blocking goroutine integration
- Wire webhook into OnAfterSettle callback in server.go (goroutine, fire-and-forget)
- Migrate all persistent interface{} to any (Go 1.25.4 convention):
  db.go: ...any in DBTX interface
  models.go: Embedding any
  FindSimilarUsers.sql.go: QueryEmbedding any, Embedding any
  UpsertStyleProfiles.sql.go: Embedding any
- Migrate server.go map[string]interface{} to map[string]any in webhook payload
- Add TestStoreSaveTransaction integration test (skipped without TEST_DATABASE_URL)
- Add TestSettleHook unit test for param mapping
2026-08-31 01:02:55 +02:00
114574b331 Complete transaction save test suite
- TestSettleHook (internal/server/mcp_test.go): verifies SaveTransactionParams field mapping
  - Tests all 6 params: X402TransactionHash, Amount, Asset, Network, Recipient, Sender
  - Ensures params are settable without panic, critical for legal compliance of x402 flow

- TestStoreSaveTransaction (internal/store/integration_test.go): integration test against real Postgres
  - Exercised SaveTransaction query end-to-end with full param mapping
  - Skipped without TEST_DATABASE_URL (same pattern as TestStoreRoundTrip)
  - Verifies: insert returns ID and CreatedAt, ID is positive, CreatedAt is valid
  - Uses unique transaction hash per test run via time.Now().Unix()

Both tests ensure the critical transaction-saving mechanism is verified at both unit and integration levels, providing regression protection for the legal-compliance x402 payment flow.
2026-08-31 00:01:29 +02:00
fbd1f5af6c Add SaveTransaction SQL and params tests
- TestSaveTransactionSQL: verifies the sqlc-generated SaveTransaction query constant matches the source SQL file
- TestSaveTransactionParams: verifies SaveTransactionParams struct can be constructed with valid and edge-case values (empty hash, empty amount)

Both tests are pure-unit tests that don't require a database connection. They ensure the critical transaction-saving SQL query and its parameter mapping remain consistent, which is important for legal compliance of the x402 payment flow.
2026-08-30 23:56:40 +02:00
9918134fd0 Add ModelVersion/SchemaVersion/AlgorithmVersion fields to UserStyleProfile and update db.go version
- Add missing ModelVersion, SchemaVersion, AlgorithmVersion fields to UserStyleProfile struct
- Update sqlc version from v1.30.0 to v1.31.1 in db.go and models.go
- Fix any/interface{} type consistency in db.go
2026-08-30 22:42:47 +02:00
d7bece250f Use named parameters in SQL queries to avoid ColumnN naming in sqlc generated structs
- Rewrite GetStyleProfile, FindSimilarUsers, UpsertStyleProfiles SQL queries
  to use @named parameters instead of  positional placeholders
- Regenerate sqlc Go files with meaningful parameter names
- Update server.go and integration test to use new parameter field names
- Fix Similarity int32→float64 type conversion
2026-08-30 22:41:53 +02:00
71797cfc4f x402: implement dynamic pricing for Twitter getStyleProfile
- Add upto scheme support for dynamic pricing on getStyleProfile
- computeTwitterStyleProfileCost: calculates actual charge based on posts fetched + user lookup
  - User read: /bin/bash.01 (if not cached)
  - Posts read: /bin/bash.005 per post, max 50 posts = /bin/bash.25
  - Minimum: /bin/bash.10
  - Maximum: /bin/bash.26
- handleRESTCall: apply settlement override for upto scheme on getStyleProfile
- GetStyleProfileResponse: local schema type for cost calculation
2026-08-30 18:20:17 +02:00
d085d9e3ae twitter: policy compliance and per-post pricing
- Change base URI from api.twitter.com to api.x.com/2
- Rate limit: honor x-rate-limit-remaining and x-rate-limit-reset headers
- Remove GetActor/SearchActors from Twitter client (policy: prohibits reselling user/profile data)
- Block Twitter from getActor, searchActors, getPost, getLatestPosts, getPostsInTime, getFeed in MCP server
- Allow Twitter for getStyleProfile with exact /bin/bash.10 pricing (minimum across all platforms)
- Remove GetActor/SearchActors from twitterBackend interface
- Update tests for new Twitter restrictions
- Add upto EVM scheme support for future dynamic pricing
2026-08-30 17:44:30 +02:00
bd707cf2ca refactor: replace interface{} with any
- convert remaining interface{} usages to any in store, utils, bluesky
- consolidate pgvector extension drop into 002 migration
2026-08-30 16:03:03 +02:00
3c024d668e Add observability, post caching, dedup, Bluesky refresh, Twitter backoff, MCP tests
- Per-tool Prometheus-style metrics via /metrics and error logging on failures
- In-memory TTL post cache for getPost/getLatestPosts/getPostsInTime/getFeed
- searchActors dedupes cross-platform duplicates by normalized handle
- Bluesky client refreshes session on auth/expired-token errors (retry once)
- Twitter client backs off on HTTP 429 honoring Retry-After
- MCP tests with fake platform backends (dispatch, caching, dedup, partial/full failure)

Co-Authored-By: Claude (AI assistant) <noreply@anthropic.com>
2026-08-29 02:46:17 +02:00
cab911ea6f fix: searchActors errors only when all platforms fail
Return merged results whenever at least one platform succeeds (even if others errored or
returned empty). Only surface an error when every platform failed, so a caller is never
billed for a search that produced nothing while still getting partial results when available.

Co-Authored-By: Claude (AI assistant) <noreply@anthropic.com>
2026-08-29 02:28:14 +02:00
ec27416cb1 fix: payable tools fail fast on server errors instead of degrading
The x402 layer only settles payment when a tool handler succeeds (server.go:604-605
creates a cancellation dispatcher, not a settlement, on handler error / non-2xx). So
returning a real error is what prevents billing a caller for a deliverable they didn't
ask for.

- Revert the Ollama-down graceful degradation in buildStyleProfile: getStyleProfile and
  findSimilarUsers now return an error when embedding/summary generation fails, instead of a
  successful zero-embedding profile.
- searchActors now fails fast: if any platform client errors, the error is surfaced rather
  than silently returning a partial (other-platforms-only) result.

Co-Authored-By: Claude (AI assistant) <noreply@anthropic.com>
2026-08-29 02:24:08 +02:00
4ac15ff6c2 test: cover getActor/searchActors clients and migrations
Runnable (HTTP-mocked) unit tests:
- activitypub: GetActor (accounts/lookup) plus id-lookup fallback, and SearchActors
  (accounts/search).
- twitter: GetActor (/users/by/username) and SearchActors (/users/search).
- nostr: SearchActors best-effort path (non-resolvable query returns empty, no network).
- store: extractUpSQL parsing helper.

Store integration test (TestStoreRoundTrip) is gated behind TEST_DATABASE_URL and skipped
when no Postgres+pgvector is available; it runs Migrate and exercises the Upsert/Get/
FindSimilarUsers round-trip against a real database.

Co-Authored-By: Claude (AI assistant) <noreply@anthropic.com>
2026-08-29 02:16:39 +02:00
1d97ca1164 feat: add getActor and searchActors tools across platforms
Introduce a shared actor.Profile type (internal/actor) so every platform client can return a
common shape without importing the server package (which would be an import cycle).

- Bluesky: GetActor (app.bsky.actor.getProfile) and SearchActors (app.bsky.actor.searchActors) via XRPC.
- ActivityPub: GetActor (accounts/lookup, falling back to accounts/{id}) and SearchActors
  (accounts/search).
- Nostr: GetActor subscribes to kind:0 metadata; SearchActors is best-effort (resolves a
  pubkey/npub query to a single profile; Nostr has no global actor search).
- Twitter: GetActor (/users/by/username) and SearchActors (/users/search).

server: register getActor and searchActors as payable tools; searchActors fans the query out
to all four platforms and merges results, skipping any platform that errors.

Schema fixes: document that getPost.collection is Bluesky-only, and that getFeed.uri is a feed
URI for Bluesky but an author handle for other platforms.

Co-Authored-By: Claude (AI assistant) <noreply@anthropic.com>
2026-08-29 02:14:29 +02:00
8cfb1291aa ops: migrator, enrichment backpressure, ollama fallback, readiness
- Add dependency-free in-process schema migrator (internal/store/migrate.go) that applies
  sql/schema/*.sql in order, tracking versions in schema_migrations. Gated by MIGRATE_ON_START
  and MIGRATIONS_DIR (default sql/schema).
- Fix migration ordering: 002 now creates the 'vector' extension before defining the
  user_style_profiles table (previously the extension was only created later in 003).
- Bound concurrent background enrichment with a 4-slot semaphore so bursts of live
  getStyleProfile calls cannot overwhelm Ollama.
- buildStyleProfile degrades gracefully when Ollama is down: stores a zero embedding and a
  keyword-based fallback summary instead of failing the whole request.
- Add a /readyz side server (READYZ_PORT, default 9090) that checks DB connectivity and
  Ollama availability.

Co-Authored-By: Claude (AI assistant) <noreply@anthropic.com>
2026-08-29 02:09:50 +02:00
533ecede00 test: cover new cross-platform client methods
Add runnable (HTTP-mocked) unit tests for the client methods added when extending the
post tools to all platforms:

- twitter: GetPost (single-tweet object response + author expansion + public_metrics) and
  GetPostsInTimeframe (start_time/end_time query params + metrics)
- activitypub: GetPostsInTimeframe (paginated Mastodon statuses within a window)
- nostr: resolvePubkey/resolveEventID resolution helpers via real npub/note encoding

Also fix a latent bug in internal/nostr: resolvePubkey/resolveEventID wrapped the wrong
error variable (the nip19 error instead of the hex-decode error) when the 64-hex fallback
failed, producing misleading messages.

Co-Authored-By: Claude (AI assistant) <noreply@anthropic.com>
2026-08-29 01:44:39 +02:00
4d11cea6cd feat: extend post tools (getPost, getLatestPosts, getPostsInTime, getFeed) to all platforms
Previously these tools were Bluesky-only. They now dispatch by platform:

- getPost: Bluesky uses actor+collection+rkey; ActivityPub uses GetPost(statusID);
  Nostr uses GetPost(noteID); Twitter uses GetPost(tweetID)
- getLatestPosts / getPostsInTime: delegate to each platform client
- getFeed: Bluesky uses GetFeed; other platforms treat the URI as an author handle and
  return their latest posts (no custom-feed concept elsewhere)

Client additions:
- twitter: GetPost, GetPostsInTimeframe; Post now carries like/repost/quote/reply
  counts from public_metrics (populated in GetLatestNPosts and GetPostsInTimeframe)
- nostr: GetPost, GetPostsInTimeframe (relay queries with Since/Until); resolveEventID
  helper mirroring resolvePubkey

Server gains normalized mapping/dispatch helpers (bskyPostViewToResponse,
apPostToResponse, nostrPostToResponse, twitterPostToResponse, fetchSinglePost,
fetchLatestPosts, fetchPostsInTime, fetchFeed) that return a uniform
GetPostResponsePost, mapping missing engagement counts to 0.

Co-Authored-By: Claude (AI assistant) <noreply@anthropic.com>
2026-08-29 01:41:14 +02:00
e31a4313f4 test: add unit tests for pure helpers and HTTP clients
Add runnable unit tests (no external services required):

- internal/utils: FormatVector/ParseEmbedding (all type branches + round-trip),
  AverageVector, TopWords (min-length + stopword filtering + ranking)
- internal/config: getEnvBool, splitComma, Load defaults/override
- internal/server: determinePlatform (did/npub/@-handle/64-hex/dotted) and
  platformFromString
- internal/twitter: mocked Twitter API v2 (empty-token error, fetch+parse,
  max_results clamping, non-200 error)
- internal/activitypub: mocked Mastodon API (constructor validation,
  GetLatestNPosts, GetPost, non-200 error)

Not covered (require live services / heavy mocking): store sqlc queries +
pgvector migrations (need Postgres), nostr client (needs a relay), ollama
client (wraps the ollama/go API over HTTP), and server orchestration
(requestStyleProfile, enrichCrossPlatform, fetchProfilePosts, getSimilarProfiles
need a DB + platform clients).

Co-Authored-By: Claude (AI assistant) <noreply@anthropic.com>
2026-08-29 01:33:42 +02:00
e8a37831cb add: findSimilarUsers payable tool (pgvector similarity search)
- register findSimilarUsers (price 0.05) which reuses requestStyleProfile to get the source
  persona embedding, encodes it with utils.FormatVector, and queries the existing (previously
  unused) FindSimilarUsers pgvector query for ranked cross-platform matches; self excluded
- add FindSimilarUsersRequest/Response/SimilarUser types and an OutputSchema for the tool
- fix generated store: FindSimilarUsersRow.Similarity int32 -> float64 (SQL returns
  1 - (embedding <=> $1::vector), a float8; scanning into int32 would error)
2026-08-29 01:26:41 +02:00
bc168e1bca add: background cross-platform enrichment on profile request
- refactor requestStyleProfile into a shared requestStyleProfileForced core (resolve -> cache
  check -> build) so a specific platform can be targeted regardless of identifier format
- on a live getStyleProfile request, fire-and-forget enrichCrossPlatform: bounded fan-out
  (<=3 goroutines) tries the same identifier on every other platform, logs/skips mismatches,
  and still obeys the 1-week update gate; uses a detached context (context.WithoutCancel +
  5m timeout) so it outlives the request
- trigger only on live tool calls (not the prewarmer) and gated by ENRICH_CROSS_PLATFORM
  (default true)
- add platformFromString helper
2026-08-29 01:26:08 +02:00
e5168e33f3 add: multi-platform getStyleProfile with slow, discovery-based prewarmer
- Nostr client (fiatjaf.com/nostr) fetching kind:1 notes from relays
- Twitter client using raw Twitter API v2 (no external X library), optional (no token = lazy error)
- getStyleProfile dispatches by platform; a profile is updated only when a request is
  made and the cached profile is older than a week (served from cache otherwise)
- shared requestStyleProfile path used by both the tool and the prewarmer
- StartPrewarm discovers interesting authors (from a feed URI or seed list) and
  pre-fetches at most one profile per minute; fresh profiles are never re-embedded
2026-08-29 01:07:47 +02:00
12bf3e8311 add: make getStyleProfile work (embeddings, platform gating, pgvector extension) 2026-08-29 00:32:50 +02:00
b8b39af276 fix: long standing typo 2026-08-03 13:23:52 +00:00
dbf0e2591b add: supported network config option
update: align testClient with x402-v2
2026-08-03 12:40:04 +00:00
4af4d79940 add: global logging 2026-08-03 11:08:53 +00:00
33f07ea75a revert label 2026-08-02 00:53:31 +00:00
bd62f05b5d update runner label 2026-08-02 00:49:54 +00:00
641bf66dbb Merge pull request 'task/migrate-x402-v2' (#1) from task/migrate-x402-v2 into main
Reviewed-on: #1
2026-07-30 08:13:05 +00:00
9f59a7d9d6 add x402 unit test
add test workflow
2026-07-30 06:45:26 +00:00
5c89b8077a critical: fix infinite recursion 2026-07-29 22:09:32 +00:00
8b27ecacfa Remove obsolete types 2026-07-29 22:09:31 +00:00
b655faca4a rewrite wrapper
migrate server from v1 to v2
2026-07-29 22:09:27 +00:00
f7c75e05f0 Migrate internal x402 wrapper 2026-07-29 22:09:12 +00:00
f144cf8868 migrate middlewares 2026-07-29 22:09:01 +00:00
fed1a8d294 feat: add activitypub 2026-07-18 22:42:44 +00:00
9f116d82d2 refactor: module name 2026-02-04 00:16:15 +00:00
262c54b827 add: healthz endpoint 2026-01-15 00:23:02 +00:00
5ca7f55ddf fix: log client ip 2025-12-21 01:53:10 +00:00
2b4980edab Major changes 2025-12-19 00:05:45 +00:00
6843964c59 cleanup 2025-12-02 19:33:03 +00:00
b87910d1c4 Major changes 2025-12-02 19:33:03 +00:00
5b409678ad First release build 2025-12-02 19:32:47 +00:00
af58fdeeab initial commit 2025-10-25 01:06:02 +00:00