Skip to content

feat(image): forward --model and --aspect-ratio; bump @atxp/client 0.10.5 → 0.11.7#61

Merged
badjer merged 2 commits intomainfrom
feat/image-command-model-aspect-ratio-and-sdk-bump
Apr 27, 2026
Merged

feat(image): forward --model and --aspect-ratio; bump @atxp/client 0.10.5 → 0.11.7#61
badjer merged 2 commits intomainfrom
feat/image-command-model-aspect-ratio-and-sdk-bump

Conversation

@badjer
Copy link
Copy Markdown
Contributor

@badjer badjer commented Apr 27, 2026

Summary

The atxp image command was silently dropping any model or aspect-ratio the user might want — imageCommand(prompt) only forwarded the prompt itself to image_create_image_async. For direct MCP callers (i.e. anyone not going through the atxp-pics wrapper, which pins IMAGE_MODEL=gpt-image-2), this means the server default decides, which during last week's incident silently routed to gpt-4o-mini via the Responses API and produced unfaithful outputs. Surfacing these flags lets CLI/agent users pin the model and aspect ratio explicitly.

This PR also bumps @atxp/client from ^0.10.5 to ^0.11.7 to align with what the MCP servers (image, music, videogen) are running. The 0.10.x series predates the middleware-settlement work and several payment-protocol fixes in 0.11.x; the API surface used here (atxpClient, ATXPAccount) is unchanged.

Code shape

// commands/image.ts
export interface ImageOptions {
  model?: string;
  aspectRatio?: string;
}

export async function imageCommand(prompt: string, options: ImageOptions = {}) {
  // ...
  const args: Record<string, string> = { prompt: prompt.trim() };
  if (options.model) args.model = options.model;
  if (options.aspectRatio) args.aspectRatio = options.aspectRatio;
  await client.callTool({ name: 'image_create_image_async', arguments: args });
}

index.ts parses --model and --aspect-ratio (also accepts --aspectRatio for parity with the underlying tool parameter name). Empty/unset options are not added to args, so server defaults still apply when nothing is specified.

Local test plan

# clone branch
gh pr checkout <this-pr-number>
cd packages/atxp
npm install
npm run build

# verify build
npm run typecheck      # tsc --noEmit, clean
npm test               # 302 tests passing

# smoke against prod (or a local image MCP server) — requires you to be logged in already
node dist/index.js image "wizard typing at a computer" --model gpt-image-2 --aspect-ratio 16:9
node dist/index.js image "test"                                    # no flags — server default
node dist/index.js image "test" --model gpt-image-2                # only model
node dist/index.js image "test" --aspect-ratio 1:1                 # only aspect ratio

Verify in each case the tool args going to image_create_image_async reflect what was passed (or omit the field cleanly when not supplied). The image MCP server logs Inferred creator '...' from model '...' when a model is forwarded — easy way to confirm from the server side.

🤖 Generated with Claude Code

…ver; bump @atxp/client to ^0.11.7

The `atxp image` command was dropping any model/aspect-ratio the user wanted
to pin — `imageCommand(prompt)` only forwarded the prompt to
`image_create_image_async`. That left the server-side default in charge
which, for direct MCP callers (no atxp-pics wrapping), recently caused a
production incident where the default `gpt-4o-mini` path produced unfaithful
outputs until the env var was switched to `gpt-image-2`.

This adds:
- `--model <model>` — forwarded as the tool's `model` arg (gpt-image-2,
  gpt-4o, dall-e-3, gemini-3-pro-image-preview, etc.)
- `--aspect-ratio <ratio>` (also accepts `--aspectRatio` for parity with the
  underlying tool parameter name) — forwarded as `aspectRatio`

Empty/unset options are not added to the args object so server defaults
still kick in when nothing is specified.

Also bumps `@atxp/client` from `^0.10.5` to `^0.11.7` to match what
production MCP servers (image, music) are running. The 0.10.x series
predates the middleware-settlement work and several payment-protocol
fixes that landed in 0.11.x; the API surface used here (`atxpClient`,
`ATXPAccount`) is unchanged. `npm install` regenerated `package-lock.json`.

Help text + README usage examples updated.

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

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

AI Code Review

Recommendation: APPROVE

Summary

This PR surfaces --model and --aspect-ratio flags for the atxp image command, passing them through to image_create_image_async, and bumps @atxp/client from 0.10.5 to 0.11.7 (resolved to 0.11.8) to align with the MCP server releases.

Actionable Feedback (2 items)
  • packages/atxp/src/index.ts:300-307imageOptions (including the --model parse) is evaluated unconditionally for every command. Currently harmless because imageOptions is only consumed in the image case, but if any future command adds its own --model flag it would silently conflict. Consider scoping imageOptions parsing inside the image branch of main(), or add a comment noting the global parse is intentional.
  • General: The @atxp/client 0.11.x bump pulls in a substantial new transitive dependency tree — viem (2.48.4), @x402/core, @x402/evm, and a suite of @noble/*/@scure/* cryptographic primitives — adding several hundred kB to the install footprint. The PR description explains why (payment-protocol fixes, middleware-settlement work), but it's worth ensuring downstream consumers are aware of the size increase, particularly in size-sensitive CI environments.
Detailed Review

Code Quality

The implementation is clean and minimal. The ImageOptions interface is well-typed, the conditional args construction is idiomatic and correct (only appends optional fields when non-empty, so server defaults are preserved), and the getArgValue('--model', '') || undefined pattern correctly converts empty strings to undefined. Accepting both --aspect-ratio and --aspectRatio is a nice ergonomic touch. The change is fully backward-compatible: the options parameter defaults to {} so all existing callers are unaffected.

The pattern exactly mirrors how musicOptions/MusicOptions is handled, keeping the codebase consistent.

Security

No injection risk — options are passed as JSON object properties to an MCP tool call, not interpolated into a shell command. The new cryptographic transitive dependencies (@noble/*, @scure/*) are well-audited libraries widely used in the web3 ecosystem. No credentials or sensitive values are introduced.

Suggestions

The usage string in the error path now correctly reflects the new flags. The help text and example additions in help.ts are clear and match the actual CLI surface.

Positive Notes

  • Minimal, focused diff — exactly the surface area needed and no more.
  • Consistent with existing option-passing patterns (musicOptions).
  • The args object approach (only set fields when provided) is the right way to avoid accidentally overriding server defaults with empty strings.
  • Lock file cleanup (removing nested chalk/qrcode-terminal from create-atxp) is a welcome housekeeping item.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

AI Code Review

Recommendation: APPROVE

Summary

This PR surfaces --model and --aspect-ratio flags on the atxp image command, forwarding them as tool arguments to image_create_image_async, and bumps @atxp/client from ^0.10.5 to ^0.11.8 to align with the MCP server versions.

Actionable Feedback (3 items)
  • packages/atxp/src/index.ts:306--model is a very generic flag name parsed from the full process.argv regardless of active command. If any future command also registers --model, it will bleed into imageOptions. Consider namespacing it (e.g. --image-model) or scoping arg parsing to the active command.
  • packages/atxp/src/index.ts:152getArgValue('--aspect-ratio', '') passes an empty string as shortFlag. It works (no real argv element is ""), but it's misleading. The function signature implies a real short flag; passing '' as a sentinel for "no short flag" suggests the function could use an optional second argument (shortFlag?: string).
  • General: The dependency bump introduces substantial new transitive packages — viem (~2MB EVM library), @x402/core, @x402/evm, and the @noble/@scure cryptography suite. For a CLI tool, this is a meaningful bundle-size and attack-surface increase. Worth confirming with the team that the payment-protocol middleware in @atxp/client@0.11.x is intentionally a hard dependency rather than a lazy-loaded or optional one.
Detailed Review

Code Quality

The command-layer change in commands/image.ts is clean and idiomatic: the ImageOptions interface is well-typed, the default-omission guard (if (options.model) args.model = ...) correctly prevents empty-string overrides of server defaults, and the updated usage string is accurate. The index.ts wiring follows the exact same pattern as the existing musicOptions block, making it easy to read and consistent with the codebase.

The || undefined idiom (getArgValue('--model', '') || undefined) is correct: getArgValue returns undefined when the flag is absent, and the || undefined coerces an empty string (flag present but no value) to undefined. No crash path here.

Security

No credential handling or injection vectors introduced. The model/aspect-ratio values are passed as-is to an MCP tool call; input validation is delegated to the server, which is the right boundary for this CLI. The new @x402/evm payment-protocol dependency introduces EVM/blockchain crypto code — not a concern for this feature, but worth a supply-chain audit pass given the breadth of new packages.

Suggestions

  • The --aspectRatio camelCase alias is a nice UX touch for parity with the tool parameter name. Consider documenting it in the help text as well (currently only --aspect-ratio appears there).
  • No automated tests cover the new flag parsing. The existing index.test.ts suite would be a natural home for a couple of cases: flag forwarded when set, flag absent when not set, and the camelCase alias resolving correctly.

Positive Notes

  • The args object approach (only populating optional fields when non-empty) is exactly right and avoids subtle bugs where "" vs undefined behaves differently server-side.
  • The PR description is thorough: it explains the incident that motivated the change, the version gap being closed, and provides a concrete smoke-test plan.
  • The lockfile cleanup (removing hoisted chalk/qrcode-terminal overrides from create-atxp) is a nice bonus tidy-up.

@badjer badjer merged commit f3c1024 into main Apr 27, 2026
2 checks passed
@badjer badjer deleted the feat/image-command-model-aspect-ratio-and-sdk-bump branch April 27, 2026 22:31
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.

1 participant