feat(stock-watchlist-agent-js): accept image inputs and annotate them on spans - #91
Open
cdfox wants to merge 1 commit into
Open
feat(stock-watchlist-agent-js): accept image inputs and annotate them on spans#91cdfox wants to merge 1 commit into
cdfox wants to merge 1 commit into
Conversation
… on spans
Adds an image input path to the JS stock watchlist demo. Arguments that look
like images (by extension, http(s) URL, or data: URL) are translated to ticker
symbols by an LLM before research begins, and the image bytes are attached to
the resulting llm span via imageParts.
- vision.js: identify_ticker is an llm-kind span annotated with
imageParts: [{mimeType, content}]; images are always materialized as base64
(URLs downloaded) so the same bytes go to OpenAI and onto the span
- orchestrator: image resolution runs inside the root analyze_portfolio span
so vision and research share one trace
- main.js: mixed ticker/image args, --image override, resolution summary
- logos/: three small wordmark images so the image path is runnable as-is
- default model for all call sites is now gpt-5.4-nano
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds an image input path to the JS stock watchlist demo, and attaches the input image to the LLM Observability span that consumes it.
Inputs can now be ticker symbols, images, or a mix of both:
When images are given, a vision step runs first: one LLM call per image identifies the public company shown and returns its ticker symbol. Resolved tickers are merged with any tickers passed directly, deduped, and handed to the existing orchestrator. Images that match no public company come back as
UNKNOWNand are skipped.Changes
src/agents/vision.js(new) —resolveTickersFromImages()fans out oneidentify_tickerspan per image. That span iskind: 'llm'and is annotated with a user message carryingimageParts: [{ mimeType, content }], so the image renders on the span. Images are always materialized as base64 (http(s) URLs are downloaded first) so the same bytes are sent to OpenAI and attached to the trace.src/agents/orchestrator.js— image resolution happens inside the rootanalyze_portfolioagent span, so image translation and research share a single trace rather than producing two.src/main.js— argument parsing accepts images by extension /http(s):///data:image/..., plus an explicit--image <path|url>override. Prints what each image resolved to. Evaluations run against the resolved ticker list.src/models.js—tickerFromImageSchema+validateTickerFromImage.logos/— three small wordmark PNGs (Apple, Google, NVIDIA; ~900 bytes each, 12K total) so the image path is runnable without supplying your own files.gpt-5.4-nano, matching the direction of Unpin openai, trim requirements, and update notebooks to gpt-5.4-nano #78. All remain overridable viaOPENAI_MODEL,OPENAI_VISION_MODEL,OPENAI_SEARCH_MODEL,OPENAI_EVAL_MODEL.Trace shape
Testing
Tested against @joizddog's dd-trace-js branch for image support, dd-trace-js#9684 (
jose/mlob-7916-llmobs-image-parts), installed as a local file dependency:The Apple wordmark renders on the
identify_tickerspan in the LLM Observability trace view, alongside the user message and the assistant's structured{ticker: "AAPL", ...}output.Two findings from that testing shaped this implementation:
OpenAI.createResponsechild span carries no image. The image has to be annotated by hand.imagePartsis only honored onllm-kind spans. Insdk.js, onlyspanKind === 'llm'routes totagLLMIO→tagMessages, which is the sole reader ofimageParts. Ontask/workflow/agentspans the input goes throughtagTextIOand the whole message array is stringified into an opaque value —imagePartspasses through as inert text with no warning.identify_tickerwas originally ataskspan, which is why no image appeared at first.Also verified end to end:
npm start -- AAPL GOOGL NVDA— unchanged text-only pathnpm start -- logos/apple.png logos/google.png NVDA— mixed path; resolves AAPL + GOOGL, analyzes three tickers, evals submittedtrace_idNote on dd-trace version
package.jsonstill points atdd-trace: latest; the local-checkout dependency swap used for testing is deliberately not committed. Until image-part support ships in a release, the app runs normally on the publisheddd-trace— theimagePartsfield is simply ignored and no image appears on the span. Everything else in this PR is version-independent.🤖 Generated with Claude Code