Skip to content

feat(form): Error msges can now be overrided neatly#292

Merged
H-Weisner merged 2 commits into
mainfrom
feature/add-solution-for-custom-err-messages
Apr 13, 2026
Merged

feat(form): Error msges can now be overrided neatly#292
H-Weisner merged 2 commits into
mainfrom
feature/add-solution-for-custom-err-messages

Conversation

@H-Weisner

Copy link
Copy Markdown
Contributor

What's new?

This pull request introduces a new global and per-form validation message formatting system for Zod-based form validation, and adds direct support for OpenAI and Gemini API providers to the AI commit message suggestion CLI (cz-ai). It also includes improvements to error handling, configuration, and user interface for both form validation and the CLI tool.

Form Validation Enhancements:

  • Added a new ValidationMessageFormatter type and related context interface, allowing developers to globally or per-form customize how Zod validation messages are formatted and displayed. The global formatter can be set via ArmstrongConfigProvider and overridden per form using the formatValidationMessage option in useForm. [1] [2] [3]
  • Updated getMyZodErrors utility to accept an optional formatter callback, using it to generate validation messages and falling back to Zod's default messages if the formatter returns undefined or throws. [1] [2]
  • Modified useForm to utilize the new global and per-form validation message formatter, and added corresponding tests to ensure correct prioritization and fallback behavior. [1] [2] [3] [4] [5] [6] [7]

AI Commit CLI (cz-ai) Improvements:

  • Added support for direct OpenAI and Gemini API providers, including environment variable configuration, model selection, and robust error handling for API responses. [1] [2] [3]
  • Enhanced the CLI user interface by implementing a terminal-friendly box display for commit suggestions, with word wrapping, dynamic sizing, and clear controls. Also improved provider setup instructions and model picker grouping. [1] [2]
  • Updated model selection logic to differentiate between small and large models for OpenAI and Gemini direct APIs, based on diff size.

These changes provide more flexible and user-friendly validation error messaging for forms, expand AI provider support for commit message suggestions, and improve the usability and configurability of the CLI tool.

board

Checklist

  • does this work have all the relevant tests?
  • are your changes in Storybook?
  • does everything have jsdoc?
  • is everything exported from index.ts?

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces customizable Zod validation message formatting (global via ArmstrongConfigProvider and per-form via useForm), and expands the cz-ai commit message CLI with direct OpenAI/Gemini providers plus improved terminal UI output.

Changes:

  • Add ValidationMessageFormatter and wire it through useFormgetMyZodErrors with fallback-to-default behavior.
  • Extend Armstrong global config with defaultValidationMessageFormatter and add tests for formatter priority/fallback.
  • Enhance cz-ai with direct OpenAI/Gemini API support, model grouping, and boxed suggestion display.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
scripts/cz-ai/index.js Adds direct OpenAI/Gemini providers, model selection grouping, and boxed output UI.
module/src/form/utils/validation.ts Adds optional formatter callback support when mapping Zod issues to Armstrong validation errors.
module/src/form/utils/validation.spec.ts Adds tests for formatter usage and fallback behavior in getMyZodErrors.
module/src/form/types.ts Introduces formatter types and adds formatValidationMessage to IFormConfig.
module/src/form/hooks/useForm.ts Applies global/per-form formatter when generating field validation errors.
module/src/form/hooks/useForm.spec.ts Tests global default formatter and form-level override priority.
module/src/components/config/config.context.tsx Adds global defaultValidationMessageFormatter to Armstrong config context typing.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread scripts/cz-ai/index.js
Comment on lines +214 to +221
async function callOpenAiDirect(prompt, model) {
const apiKey = process.env.OPENAI_API_KEY;
const response = await fetch('https://api.openai.com/v1/responses', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${apiKey}`,
},

Copilot AI Apr 13, 2026

Copy link

Choose a reason for hiding this comment

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

callOpenAiDirect() uses OPENAI_API_KEY without verifying it’s set. In cases like skipModel=true or misconfigured settings, this sends Authorization: Bearer undefined and yields a confusing API error. Add an explicit check for a missing/empty key and throw a clear error before making the request.

Copilot uses AI. Check for mistakes.
Comment thread scripts/cz-ai/index.js
Comment on lines +249 to +256
async function callGeminiDirect(prompt, model) {
const apiKey = process.env.GEMINI_API_KEY;
const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${encodeURIComponent(model)}:generateContent`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-goog-api-key': apiKey,
},

Copilot AI Apr 13, 2026

Copy link

Choose a reason for hiding this comment

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

callGeminiDirect() uses GEMINI_API_KEY without validating it’s present. If the model is selected via settings (e.g. skipModel) without an env var, the request is sent with an empty key and fails with an unclear response. Add a guard that throws a helpful error when the key is missing.

Copilot uses AI. Check for mistakes.
Comment thread scripts/cz-ai/index.js
Comment on lines +672 to 678
const hasOpenRouterKey = !!process.env.OPENROUTER_API_KEY;
const hasOpenAiKey = !!process.env.OPENAI_API_KEY;
const hasGeminiKey = !!process.env.GEMINI_API_KEY;
const hasAnyApiKey = hasOpenRouterKey || hasOpenAiKey || hasGeminiKey;
const resolved = resolveSettings();
const settings = hasApiKey ? resolved : { ...resolved, model: CLAUDE_CLI, skipModel: false };
const settings = hasAnyApiKey ? resolved : { ...resolved, model: CLAUDE_CLI, skipModel: false };

Copilot AI Apr 13, 2026

Copy link

Choose a reason for hiding this comment

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

When skipModel is true, settings.model can still point at an OpenRouter model even if only OPENAI_API_KEY/GEMINI_API_KEY are set (or vice-versa). That leads to calling a provider without its corresponding key. Consider validating the selected model/provider against available keys up front and falling back to a working provider (e.g. Claude CLI) or prompting the user.

Copilot uses AI. Check for mistakes.
Comment thread scripts/cz-ai/index.js Outdated

words.forEach(word => {
if (/^\s+$/.test(word)) {
if (current && current.length < width) current += word;

Copilot AI Apr 13, 2026

Copy link

Choose a reason for hiding this comment

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

wrapLine() can append whitespace tokens even when they push current beyond width (e.g. multiple spaces when current.length < width). That can produce wrapped lines longer than maxContentWidth, causing the box borders to misalign. Consider normalizing whitespace to a single space and/or only appending whitespace when it fits within the remaining width.

Suggested change
if (current && current.length < width) current += word;
if (current && current.length + 1 <= width) current += ' ';

Copilot uses AI. Check for mistakes.
@H-Weisner H-Weisner merged commit 9fb97ee into main Apr 13, 2026
2 checks passed
@H-Weisner H-Weisner deleted the feature/add-solution-for-custom-err-messages branch April 13, 2026 12:46
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