Skip to content

feat(hack16): agentic search - #17544

Open
starsirius wants to merge 7 commits into
mainfrom
starsirius/agentic-commerce-poc
Open

feat(hack16): agentic search#17544
starsirius wants to merge 7 commits into
mainfrom
starsirius/agentic-commerce-poc

Conversation

@starsirius

@starsirius starsirius commented Aug 5, 2026

Copy link
Copy Markdown
Member

The type of this PR is: Feat

Description

This PR includes the agentic search experience from the hackathon (with the commerce portion removed).

  • The artwork search results return mocked data. We'll fill in with the right search algorithm.
  • It is guarded behind the emerald_agentic-search feature flag, and if we want to, it's safe to merge and iterate.
  • The code was quickly put together for hackathon demo purposes, and can definitely use refactoring/polish.
  • There is no test.

Agentic loop considerations

  • It occupies a web process for the length of an agentic loop which could be multiple seconds, which could be real performance implications. Long-lived (and streaming) requests might deserve a dedicated service.
  • The endpoint will need to live elsewhere to be consumed by Eigen and other clients.
  • Streaming can be considered for better responsiveness.

Migration

-[x] Set the ANTHROPIC_API_KEY secret

agentic-search

@starsirius starsirius self-assigned this Aug 5, 2026
@starsirius
starsirius requested a review from a team August 5, 2026 14:44
Comment on lines +172 to +176
{typeof artwork.priceUsd === "number" ? (
<Text variant="xs" color="mono100">
{formatPriceUsd(artwork.priceUsd)}
</Text>
) : null}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this can't be handled by the MP Money type?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Eventually it should. This demo simply mocks the artwork search results and does not really query MP for data.

Comment on lines +255 to +265
const response = await fetch("/api/advisor-agent/chat", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ messages: nextWire }),
})

if (!response.ok) {
throw new Error(`Request failed: ${response.status}`)
}

const payload = await response.json()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

so the force backend handles this rather than mp - do we have a library like swr that can give us an easy loading state?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It seems we are interested in building this on Eigen. If that's the case, the agentic loop will probably be moved elsewhere to be shared.

import { type NextFunction, Router } from "express"

const ANTHROPIC_API_URL = "https://api.anthropic.com/v1/messages"
const MODEL = "claude-opus-4-8"

@erikdstock erikdstock Aug 5, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

curious if sonnet can do this just as well - maybe good to make this configurable via the ENV.

@starsirius starsirius Aug 6, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

good idea! I probably won't add this to another env var, but it'd be helpful to evaluate.

@starsirius starsirius changed the title feat: agentic search feat(hack16): agentic search Aug 5, 2026
@starsirius
starsirius marked this pull request as draft August 6, 2026 06:40
@relativeci

relativeci Bot commented Aug 12, 2026

Copy link
Copy Markdown

#9574 Bundle Size — 9.03MiB (+0.06%).

df560be(current) vs b83648c main#9569(baseline)

Warning

Bundle contains 29 duplicate packages – View duplicate packages

Bundle metrics  Change 2 changes Regression 1 regression
                 Current
#9574
     Baseline
#9569
Regression  Initial JS 2.94MiB(+0.01%) 2.94MiB
No change  Initial CSS 0B 0B
No change  Cache Invalidation 97.48% 97.48%
No change  Chunks 111 111
No change  Assets 114 114
Change  Modules 5705(+0.02%) 5704
No change  Duplicate Modules 691 691
No change  Duplicate Code 5.05% 5.05%
No change  Packages 248 248
No change  Duplicate Packages 28 28
Bundle size by type  Change 1 change Regression 1 regression
                 Current
#9574
     Baseline
#9569
Regression  JS 8.8MiB (+0.06%) 8.8MiB
No change  Other 232.77KiB 232.77KiB

Bundle analysis reportBranch starsirius/agentic-commerce-pocProject dashboard


Generated by RelativeCIDocumentationReport issue

@leamotta
leamotta marked this pull request as ready for review August 12, 2026 12:31
Comment thread src/Components/AdvisorAgent/advisorAgentServerRoutes.ts
Comment thread src/Components/AdvisorAgent/advisorAgentServerRoutes.ts
Comment thread src/Components/AdvisorAgent/advisorAgentServerRoutes.ts
Comment thread src/Components/AdvisorAgent/AdvisorAgent.tsx
@leamotta
leamotta requested a review from rquartararo August 13, 2026 12:24
- Keep a turn inside the app's 29s production timeout: cap the agentic
  loop at 4 steps and run the model at medium effort.
- Require a signed-in user and bound the client-supplied transcript, so
  the endpoint isn't an open proxy to Artsy's Anthropic account.
- Raise max_tokens to 16000 (thinking shares the budget) and pass the
  stop reason through so truncated, refused, and step-exhausted replies
  say so instead of rendering as finished answers.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot deleted a comment from claude Bot Aug 13, 2026
Comment thread src/Components/AdvisorAgent/advisorArtworkCatalog.ts
Comment thread src/Components/AdvisorAgent/AdvisorAgent.tsx
The chat endpoint requires a signed-in user, but the UI only gated on the
feature flag — logged-out visitors could open the panel and type, and only
learn they needed an account once the request came back 403.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot deleted a comment from claude Bot Aug 14, 2026
return
}

const messages: AgentMessage[] = [...incomingMessages]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The client-supplied messages array is forwarded verbatim to Anthropic with no per-user or per-session rate limiting. Any signed-in user (once the flag is on) can supply arbitrary role/content blocks — including fabricated system-style instructions — and get a general-purpose Claude Opus proxy billed to Artsy's account. The per-request size bounds cap one turn, but nothing caps requests per user. Since the PR notes this "spends against Artsy's Anthropic account," consider a simple per-user rate limit before this graduates from the flag. Not blocking given it's flag-gated and login-gated.

@claude

claude Bot commented Aug 14, 2026

Copy link
Copy Markdown

Code Review

Summary

Adds a flag-gated (emerald_agentic-search) “Ask an art advisor” chat widget to the Collect route. A new Express endpoint runs a short agentic loop against Anthropic with a single mocked search_artworks tool backed by a hardcoded demo catalog. The author flags this as hackathon code: mocked data, no tests, staging links, safe to merge and iterate behind the flag.

Issues Found

Reviewed against the hackathon-behind-a-flag framing, so nothing here is blocking.

🟡 Important — no per-user rate limiting on a metered endpoint (advisorAgentServerRoutes.ts:158)
Client-supplied messages go to Anthropic verbatim with only per-request size caps. A signed-in user can send arbitrary role/content and effectively use Artsy's Anthropic key as a general LLM proxy, with no cap on request count. Flag- and login-gated, so fine for the demo, but worth a per-user limit before wider rollout. Left inline.

🟢 Suggestion — failed turn desyncs transcript from wire state (AdvisorAgent.tsx:283-293)
On a non-OK response the user's message stays in transcript and an error bubble is appended, but wireMessages is never updated with that user turn. The next send builds nextWire from wireMessages, so the earlier question is dropped from the model's context while still shown on screen. Likely intentional (retry-friendly), but the visible/actual history diverge.

🟢 Suggestion — substring title match produces false previews (AdvisorAgent.tsx:116-129)
findRecommendedArtworks attaches a preview when the normalized title is a substring of the normalized reply. Short titles like “Town” (→ town) or “4:04” (→ 404) will match unrelated words in prose. Minor for a demo; a word-boundary or exact-name check would tighten it.

🟢 Suggestion — demo catalog links/images point to staging (advisorArtworkCatalog.ts:26,36,…)
link values are https://staging.artsy.net/..., so “View on Artsy →” and thumbnails will break in production. Already called out in the file's ⚠️ comment; noting so it isn't forgotten when the mock is replaced.

Areas Reviewed

  • SSR safety: Clean. AdvisorAgent returns null before any browser-global access, and navigator.clipboard / window.setTimeout are only touched inside the handleCopy event handler. No module-scope or render-time globals. Server route lives under Server/server.ts.
  • Typographic quotes: Rendered copy uses curly quotes (AdvisorAgent.tsx:358,441); straight apostrophes only appear in comments, the system prompt, and tool descriptions (not user-facing UI).
  • Feature gating: Consistent — client gates on useFlag + isLoggedIn; server gates on server-side Unleash + req.user (403), and featureEnabled falls through to 404 when off.
  • Testing: None, acknowledged by the author. Given the flag, acceptable for now.

Questions for Author

  • The endpoint occupies a web process for the full agentic loop (up to 4 Anthropic calls) against the 29s request timeout. Under concurrent use, has worker saturation been considered, or is the flag expected to stay low-traffic until this moves to a dedicated service (as the description hints)?

@leamotta

Copy link
Copy Markdown
Contributor

@rquartararo do you think we can merge this as is, to play around on staging?

@rquartararo rquartararo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Excited to test this out!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants