Skip to content

feat(pinning): add user-scoped /api/pinning/unpin action#4

Open
humanoidrobot-glitch wants to merge 347 commits intonirholas:mainfrom
humanoidrobot-glitch:feat/pinning-unpin-action
Open

feat(pinning): add user-scoped /api/pinning/unpin action#4
humanoidrobot-glitch wants to merge 347 commits intonirholas:mainfrom
humanoidrobot-glitch:feat/pinning-unpin-action

Conversation

@humanoidrobot-glitch
Copy link
Copy Markdown

Summary

The pinning dispatcher (api/pinning/[action].js) exposes pin and status actions but had no way to remove a pin. Pinata's unpin HTTP endpoint was reachable from the client-side src/pinning/pinata.js library but had no caller, and the backend had no equivalent surface, so users had no way to release pinned manifests / GLBs they no longer cared about. CIDs accumulate on the Pinata account indefinitely.

What's added

A new unpin action mirroring the existing pin shape:

POST /api/pinning?action=unpin   { cid }
  • Auth: session or bearer (same as pin).
  • Rate limit: reuses the existing limits.pinUser preset (30/h).
  • Scope: looks up the pin in the pins table scoped to the caller's user_id so users can only unpin their own pins.
  • Provider routing:
    • provider = 'pinata' → calls Pinata DELETE /pinning/unpin/:cid. Treats Pinata 404 as idempotent success (pin already gone).
    • provider = 'web3.storage' → drops the local row only. web3.storage has no first-class unpin endpoint; pins age out via their own lifecycle.
    • Anything else → 400 validation_error.
  • On success, deletes the row from pins and returns { ok: true, cid, provider }.

Why not auto-unpin on agent delete

The original audit suggestion was "call unpin() on agent deletion." That requires linking pins to agents, but the current pins table has only user_id — no agent_id column. Adding that column is a schema change flagged as must-ask-first in api/CLAUDE.md.

This PR ships the missing API capability without speculation. A follow-up can wire it into the agent-delete flow or a UI control once the linkage design is decided.

Test plan

  • node --check api/pinning/[action].js passes.
  • POST /api/pinning?action=unpin with { cid: "<owned cid>" } → 200, row deleted from pins, Pinata DELETE called.
  • Same call but the cid belongs to a different user → 404.
  • Pinata returns 404 on a stale cid → still 200 (idempotent).
  • cid missing or non-alphanumeric → 400 validation_error.
  • Unauthenticated → 401.
  • Rate-limit: 31 calls in an hour → 429 on the 31st.
  • No PINATA_JWT env set + provider=pinata row → 503 pinning_unconfigured.

nirholas and others added 30 commits April 20, 2026 10:23
- Removed cheerio from dependencies in package.json.
- Updated actions.html and sessions.html to manage body visibility during authentication.
- Refactored dashboard.js for improved readability and consistency.
- Minor formatting adjustments in storage.html and validator-report.jsx for better code style.
- Cleaned up test files for consistency and readability.
- Removed unused dependencies from yarn.lock to streamline package management.
This commit introduces a comprehensive guide on replacing default hero images with custom artwork. The documentation covers image format selection, dimension requirements, transparency rules, depth value strategy, scene composition principles, and the mechanics of integrating new images into the theme. It aims to empower users to confidently swap layered images in the parallax hero.
feat: add home.html entry to appConfig in vite.config.js
Removed HTML files from PWA precache and set navigateFallback to null. The
prior config precached every .html and used Workbox's default navigation
fallback to /index.html, which caused failed-or-uncached route navigations
to silently render the homepage instead of the actual page. Users on any
broken route saw the home hero rather than a 404 or the correct page.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
public/agent/index.html references /style.css and raw /src/*.js paths that
404 in the built deploy because vite only rewrites imports for HTML files
listed in rollupOptions.input. The root-level agent-home.html is in that
list and gets its assets hashed and bundled into /assets/*. Pointing the
route there gives the working page instead of a stylesheet/script-less stub.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
After avatar creation, redirect the creator to /app?agent=<id> (the editor)
instead of /agent/<id> (the public profile). Matches the conventional split:
creators get an interactive workspace, the public URL is for visitors.

agent-home.html now mounts a <model-viewer> showing the agent's actual GLB
plus two CTAs — "Open in editor" (signed-in only) and "Copy share link".
The page is no longer a sparse identity card with no body.

app.html nav gains a "Public profile" link that surfaces only when an agent
is loaded via ?agent=, so creators can grab the canonical share URL.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
DeployButton on the agent profile now exposes a chain dropdown next to the
"Deploy on-chain" CTA, grouped into Mainnets / Testnets via optgroups.
Selecting a chain triggers wallet_switchEthereumChain (with auto-add fallback
already wired in chain-meta.switchChain), so the user lands on the right
network before signing. If switch is rejected, we still update the local
target so the existing mismatch-error UI surfaces a manual switch button.

DEFAULT_CHAIN_ID flipped from BSC Testnet (97) to Base mainnet (8453) so
new users land on a production chain by default. The /deploy page dropdown
also lists mainnets first.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
agent-home.html:
- Dynamic model-viewer alt text using the agent's name
- aria-busy on the stage section flips false once load resolves
- Empty state shown when an agent has no avatar attached
- "Copied" button feedback now also announced via role=status aria-live
- focus-visible outline on stage CTAs, descriptive aria-label on edit link

deploy-button.js / .css:
- Detect missing wallet up front and surface "Install MetaMask" instead of
  a cryptic provider error
- Progress region wrapped with role=status aria-live so screen readers hear
  each step (estimating gas → sign → confirming → done)
- Visually-hidden utility class for SR-only step text
- Fixed broken Base Sepolia faucet URL (was pointing to dead Goerli faucet)

app.html:
- Public-profile button gains explicit aria-label clarifying it opens in a
  new tab; svg marked focusable=false to keep tab order clean

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ion banner

The /app?agent=<id> editor was mounting the AgentHome sidebar twice — once
from the bootstrap _initAgentSystem at the end of init(), and once from
_loadAgentForEdit's own _initAgentSystem call after the GLB resolved. The
container ended up with two stacked identity / skills / permissions cards,
which is what made the post-create UI look so noisy.

Two fixes:
- Early-return after _loadAgentForEdit so the bootstrap doesn't double-fire.
- Make the AgentHome render in _initAgentSystem idempotent: tear down any
  existing instance and clear the container before mounting a fresh one.

On top of that, freshly arrived users now get a one-time orientation
banner ("Your agent is ready") with two CTAs — Deploy on-chain and View
public profile. Dismiss persists per-agent in localStorage so it never
nags returning users.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous early-return refactor changed the order in which
_loadAgentForEdit and _initAgentSystem ran, which left the loaded GLB in a
state where it briefly rendered then disappeared. Restoring the original
fire-both-in-parallel pattern makes the model stick again.

The duplicate AgentHome sidebar — the bug the early-return was originally
trying to address — is still suppressed by the idempotent render in
_initAgentSystem (destroy + clear before mount), so we don't regress that.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The animation panel was auto-playing manifest[0] ("idle") as soon as all
external Mixamo-rigged FBX clips finished downloading. RPM / Avaturn avatars
use a different bone naming convention than Mixamo, so the retarget partially
fails and the rig collapses — which is what users were seeing as the avatar
"loading for a second then disappearing" right after creation. The model was
loading fine; an off-rig idle clip was warping it out of frame.

Removing the auto-play keeps the avatar in its authored standing pose. The
animation strip still works on click for the cases where retargeting does
succeed (and in the cases it doesn't, the failure is now opt-in rather than
the default first impression).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…s + per-agent prefs

Five small, high-impact UX wins on /app?agent=:

- Spacebar toggles play/pause on the active animation, or starts the first
  loaded one if nothing is playing yet.
- Double-click on the canvas (or pressing F) frames the model with a smooth
  600ms cubic ease-out camera tween.
- First-load camera reveal: the avatar starts ~40% wider and slightly higher,
  then eases into the framed pose over 1.5s. Skipped in kiosk/embed modes
  and on subsequent loads in the same session.
- New attachScenePrefs(agentId) on the viewer persists background,
  transparency, bgColor, autoRotate, exposure, and environment per agent in
  localStorage and auto-restores them next visit. Wired from app.js after
  _loadAgentForEdit resolves so each user's studio remembers itself.
- Shared _tweenCamera helper drives both the reveal and the dblclick frame
  with the same easing, so they feel consistent.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…iting

Two more compressions on the post-create flow:

1) /app header now surfaces a state-aware "Deploy on-chain" CTA right next
   to "Public profile". On load it reads the agent record and either:
     • shows "Deploy on-chain →" linking to /deploy?avatar=<id>
       (avatar pre-fills the wizard), or
     • flips to a green "Deployed ✓ <ChainName>" chip linking to the block
       explorer once the agent has erc8004_agent_id + chain_id.
   Owners no longer have to leave the editor to publish.

2) Agent sidebar identity card has inline-editable name and description.
   contenteditable + Enter-to-blur / Escape-to-revert, debounced PUT to
   /api/agents/:id with optimistic update and rollback if the backend
   rejects (e.g. unauthenticated viewer hits 401). Visual states for
   editing / saving / saved / error via lightweight ring outlines, plus an
   empty-state placeholder ("Add a description…") when description is blank.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
feat: add share panel builders for generating embed snippets

refactor: simplify SharePanel by utilizing share panel builders

style: update CSS for discover page and related components

test: add unit tests for share panel builders and embed functionality

fix: update vercel routing for discover page
…tURI

Two real bugs that meant on-chain deploys "succeeded" but produced nothing
useful:

1) The deploy chip in agent-home was POSTing to /api/agents/:id/onchain
   after the tx confirmed — that endpoint never existed. Every successful
   mint silently failed to persist, so a page reload showed "not deployed"
   even though gas had been spent. The chip is now wired through the
   existing canonical pipeline: register-prep → sign → register-confirm.
   Same flow used by /deploy, with proper IPFS pinning of the manifest and
   server-side verification of the on-chain receipt against the prep record.

2) The on-chain agentURI was being set to https://3dagent.vercel.app/api/
   agents/:id/manifest — also a non-existent endpoint. Any consumer
   resolving the registered tokenURI got a 404. Added the missing
   GET /api/agents/:id/manifest serving canonical agent-manifest/0.1 JSON
   with body uri, skills, registrations, and homeUrl. Routed in vercel.json
   and cached as public, max-age=60, s-maxage=300.

Plus:
- Idempotency: prep records are cached in localStorage keyed per-agent so
  retries on flaky networks reuse the same IPFS pin instead of re-pinning.
  Cache expires 50m before the server-side prep TTL.
- EIP-1193 error classification: user rejection (4001 / ACTION_REJECTED),
  insufficient funds (INSUFFICIENT_FUNDS / -32000), and replacement-
  underpriced get distinct UI affordances (faucet link, cancel-pending hint,
  retry) instead of one generic regex on error message.
- Pre-flight: refuse to deploy if the agent has no avatar_id attached and
  surface a clear "open editor" CTA instead of failing mid-flight.
- agent-home-orphans now passes avatarId, description, and skills through
  to DeployButton so the pinned manifest is complete.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ency and Clarity

- Renamed classes and IDs in index.html and my-agents.css to use `my-agents-*` prefix for better clarity.
- Updated styles in my-agents.css to reflect new class names and improve responsiveness.
- Modified my-agents.js to align with new class names and IDs, ensuring functionality remains intact.
- Enhanced avatar naming logic in account.js to derive names from source metadata.
- Updated agent-home-orphans.js to pass additional data when mounting agents.
- Added optional name plate overlay in element.js for agent display.
- Implemented emotion expression functionality in element.js for agent interactions.
- Created validate-agent-cards.yml GitHub Action for validating agent card schemas on PRs and pushes.
- Introduced demo widget fixtures in _demo-fixtures.js for testing without a live database.
- Developed features.js to handle lazy loading of agent components and dynamic content on the features page.
- Added validate-agent-cards.mjs script for schema validation of agent cards.
…e preview

- Updated renderEmbed function to include a new handshake verification feature.
- Added bindEmbedHandshake function to manage communication with the embedded agent and display capabilities.
- Improved user feedback during the handshake process with detailed status messages.

refactor: optimize animation serialization for reduced payload size

- Modified serializeClip function to round float values to 5 decimal places, halving payload size while maintaining visual fidelity.

test: update features page tests for navigation consistency

- Adjusted test descriptions and expectations to reflect changes in navigation links.
- Enhanced emotion chip click test to accommodate dataset variations.

feat: add billing summary API endpoint for user plan and usage details

- Implemented GET /api/billing/summary to provide current user's plan, quotas, and usage statistics.
- Integrated database queries to fetch avatar and agent counts, as well as usage events for billing insights.
…ency

- Updated SKILL.md to fix formatting issues in the requested scope table.
- Improved CSS transitions in skill.css for better readability.
- Cleaned up JavaScript code in skill.js for consistency in formatting and style.
- Modified index.html to remove unnecessary stylesheet link.
- Enhanced studio.css with self-contained styles and improved layout.
- Adjusted studio.js to correct embed URL structure.
- Changed navigation link from "Explore" to "Discover" in validation index.html.
- Updated wallet-connect-demo.html for better formatting and readability.
- Refined wallet-connect.css for improved transition effects and consistency.
- Enhanced connect-button.js for better readability and consistency in method formatting.
- Updated state.js to improve readability and maintainability of state management.
- Improved gallery.js to correct widget URL structure and enhance readability.
- Added billing summary API endpoint to dashboard.js.
- Enhanced avatar card rendering in dashboard.js for better user experience.
- Implemented new API endpoint for resolving ERC-8004 agents with CAIP support.
nirholas and others added 26 commits April 30, 2026 07:27
- Introduced `SolanaAgent` class for managing wallet interactions and transactions.
- Implemented actions for transferring SOL and SPL tokens.
- Added Jupiter integration for token swaps, including fetching quotes and executing swaps.
- Created utility functions for managing associated token accounts.
- Developed x402 "exact" scheme client and facilitator for SPL TransferChecked payments.
- Included types and constants for payment requirements and network identifiers.
…SPL tokens, swapping, and balance retrieval

- Implemented actions for transferring native SOL and SPL tokens, swapping tokens using Jupiter, and retrieving wallet balances.
- Created a plugin interface for easy integration with SolanaAgent.
- Added type definitions for actions and plugin methods to enhance type safety and developer experience.
…ication

- Implemented tests for the agent runtime tool loop to ensure proper functionality.
- Added tests for the MCP server to cover critical external-facing API endpoints.
- Extended auth flow tests to cover gaps in email/password, SIWE, and OAuth 2.1.
- Created tests for the memory system to validate runtime and backend API behavior.
- Developed tests for the skills registry to ensure proper installation and execution of skills.
- Modularized the MCP server for better maintainability and testability.
- Eliminated the 15-minute delay in ERC-8004 registration by adding immediate confirmation handling.
- Integrated voice chat functionality into the main agent widget for enhanced user experience.
- Implemented multi-device memory sync to ensure consistent agent memory across devices.
- Enabled agent-to-agent communication via skills for task delegation.
- Introduced new types and interfaces for Solana agent actions and transactions.
- Implemented build and send functionality for transactions, including fee estimation.
- Added utility functions for formatting and memo handling.
- Created a voice client for streaming audio to a voice server.
- Developed comprehensive tests for the MCP API, covering authentication, tool execution, and payment flows.
- Implemented a new tool `call_agent` that allows agents to send messages to each other and receive responses.
- Introduced input schema validation for agent ID and message.
- Integrated with the Anthropic API to handle message processing and response retrieval.
- Added rate limiting to prevent abuse of the tool.

feat(talking-head): update subproject commit to dirty state

fix(tests): update OAuth test imports to use dynamic action routing

fix(jest): restrict test matches to wallet tests only

feat(agent-memory): enhance memory management with pull method

- Added a `pull` method to synchronize agent memory entries from the backend.
- Implemented conflict resolution based on the `updatedAt` timestamp.
- Ensured idempotency and best-effort handling of network issues.

feat(agent-skills): add call context for agent delegation

- Introduced a `call` method in the agent context to facilitate delegation to other agents.
- Implemented fetch logic to handle agent-to-agent communication.

test(auth): add comprehensive tests for email/password authentication

- Created tests for login, logout, and registration endpoints.
- Mocked dependencies to simulate database interactions and session management.

test(auth-helpers): add unit tests for JWT and CSRF token helpers

- Implemented tests for minting and verifying JWTs.
- Added tests for CSRF token generation and verification.

feat(payments): implement X402 error handling in payments module

- Created a new `sendX402Error` function to handle X402 errors consistently.

feat(avatars): add tools for avatar management and rendering

- Implemented tools for listing, retrieving, searching, rendering, and deleting avatars.
- Added safety checks for avatar policies and rendering parameters.
…igation; update ResourcePage for docSlug handling
…ction approval modal

- Add a reactive Svelte store to track the connected wallet's type, address, and chainId.
- Create a transaction approval modal component to handle user confirmations for wallet transactions.
- Enhance Toolcall component to display transaction results in a user-friendly format.
- Develop backend API for building Solana transactions and integrate with frontend tools for executing transfers and swaps.
- Introduce frontend tools for Solana and EVM transactions, including transfer and swap functionalities.
- Bundle wallet tools into a new curated tool pack for easy access in the chat UI.
- Implemented `showPaymentGateModal` function to display a modal for user payment confirmation before executing a priced skill.
- The modal includes skill details, payment amount, and action buttons for canceling or proceeding with payment.

test: add monetization tests for agent pricing and revenue

- Created comprehensive tests for pricing CRUD operations, x402 manifest, revenue attribution, and withdrawals.
- Included scenarios for authenticated and unauthenticated users, as well as rate limiting checks.
- Mocked necessary dependencies and state for accurate testing of agent monetization features.
… agents

- New CSS file for three.ws integration
- Created documentation for three.ws's listing in the MCP Registry
- Explained features of three.ws platform, including 3D model uploads, LLM integration, and on-chain identity
- Detailed how to connect to three.ws via MCP for both users and developers
- Highlighted the significance of persistent identity and the convergence of AI and crypto
The pinning dispatcher exposed `pin` and `status` actions but no way to
remove a pin. Pinata's `unpin` HTTP endpoint was reachable from the
client-side `src/pinning/pinata.js` library but had no caller, and the
backend had no equivalent surface, so users had no way to release
pinned manifests / GLBs they no longer cared about and CIDs accumulated
on the org's Pinata account indefinitely.

Add an `unpin` action mirroring the existing `pin` shape:

  POST /api/pinning?action=unpin   { cid }

- Auth: session or bearer (same as `pin`)
- Rate-limited via the existing `limits.pinUser` preset (30/h)
- Looks up the pin in the `pins` table scoped to the caller's user_id
  so users can only unpin their own pins
- Calls Pinata DELETE /pinning/unpin/:cid for `provider = 'pinata'`
- Treats Pinata 404 as idempotent success (pin already gone)
- For `provider = 'web3.storage'`, drops the local row only —
  web3.storage has no first-class unpin endpoint
- On success, deletes the row from `pins`

Scope note: the audit recommendation was "call unpin() on agent
deletion." That requires linking pins to agents (the `pins` table
currently has only `user_id`, no `agent_id`), which is a schema change
flagged as must-ask-first in api/CLAUDE.md. This change ships the
missing API capability so a future PR can wire it into the agent
delete path or a UI control without needing schema work first.

Verified with `node --check api/pinning/[action].js`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@nirholas nirholas force-pushed the main branch 4 times, most recently from 0585807 to 87d01c2 Compare May 4, 2026 19:39
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.

2 participants