Skip to content

chore: fix workflow generations#399

Merged
ElasticBottle merged 3 commits intomainfrom
winston/hot-fixes
Feb 23, 2026
Merged

chore: fix workflow generations#399
ElasticBottle merged 3 commits intomainfrom
winston/hot-fixes

Conversation

@ElasticBottle
Copy link
Collaborator

No description provided.

Copilot AI review requested due to automatic review settings February 23, 2026 11:52
@gemini-code-assist
Copy link

Summary of Changes

Hello @ElasticBottle, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances internal tooling by providing a dedicated admin interface and API endpoints to trigger AI-driven workflows for project onboarding and strategy generation. It also refactors the underlying schema conversion logic for AI models, improving the robustness and compatibility of schema definitions across various AI-powered features. These changes streamline the management and execution of key AI processes within the application.

Highlights

  • Admin UI and API for Workflow Triggers: A new admin page and corresponding API routes have been introduced, allowing internal users to manually trigger onboarding and strategy suggestion AI workflows for specific projects. Access is restricted to 'fluidposts.com' email addresses.
  • ArkType to AI JSON Schema Transformation Utility: A new utility function, arktypeToAiJsonSchema, was added to convert ArkType schemas into a format compatible with the 'ai' library's JSON Schema. This includes handling additionalProperties: false for objects and converting string enums to anyOf.
  • Integration of New Schema Transformer in AI Workflows: Existing AI workflows (onboarding, planner, strategy generation, strategy suggestions, writer) and AI tools (Google Search Console, settings) have been updated to utilize the new arktypeToAiJsonSchema utility for their input and output schemas, ensuring consistent and correct schema generation.
  • Schema Definition Update: The description field within the strategySuggestionSchema has been updated from an optional string to a nullable string, reflecting a change in its expected data type.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • apps/seo/src/routeTree.gen.ts
    • Added AuthedAdminRouteRoute to the generated route tree.
  • apps/seo/src/routes/_authed/admin/route.tsx
    • Added a new React component for the admin page, providing forms to trigger onboarding and strategy suggestion workflows.
    • Implemented client-side logic for triggering mutations and displaying toast notifications for success or error.
  • packages/api-seo/src/lib/ai/arktype-json-schema.ts
    • Added arktypeToAiJsonSchema function to convert ArkType schemas to ai library's JSONSchema7 format.
    • Included logic to set additionalProperties: false for objects and transform string enum types to anyOf.
  • packages/api-seo/src/lib/ai/tools/google-search-console-tool.ts
    • Updated the inputSchema for createGscToolWithMetadata to use the new arktypeToAiJsonSchema utility.
  • packages/api-seo/src/lib/ai/tools/settings-tools.ts
    • Integrated arktypeToAiJsonSchema for output schemas in generateText calls within createSettingsToolsWithMetadata for business background, image, writing, and publishing settings.
  • packages/api-seo/src/routes/admin.ts
    • Added new ORPC routes triggerOnboardingTask and triggerStrategySuggestionsTask under an /admin prefix.
    • Implemented authorization checks to restrict access to users with 'fluidposts.com' email addresses.
    • Defined logic to find projects, create tasks, and update project records in the database.
  • packages/api-seo/src/routes/index.ts
    • Added a lazy import for the new admin API routes to the main API router.
  • packages/api-seo/src/workflows/onboarding-workflow.ts
    • Imported arktypeToAiJsonSchema.
    • Updated generateText output schemas for extracting project name, business background, and brand voice to use arktypeToAiJsonSchema.
  • packages/api-seo/src/workflows/planner-workflow.ts
    • Imported arktypeToAiJsonSchema.
    • Updated generateText output schemas for strategy generation and content outline generation to use arktypeToAiJsonSchema.
  • packages/api-seo/src/workflows/strategy-phase-generation-workflow.ts
    • Imported arktypeToAiJsonSchema.
    • Updated generateText output schema for strategy phase suggestions to use arktypeToAiJsonSchema.
  • packages/api-seo/src/workflows/strategy-suggestions-workflow.ts
    • Imported arktypeToAiJsonSchema.
    • Wrapped the main workflow logic in a try-catch block for improved error handling.
    • Updated generateText output schema for strategy suggestions to use arktypeToAiJsonSchema.
  • packages/api-seo/src/workflows/writer-workflow.ts
    • Imported arktypeToAiJsonSchema.
    • Updated generateText output schemas for inferring article type, generating article content, and reviewing articles to use arktypeToAiJsonSchema.
  • packages/core/src/schema/arktype-json-schema-transformer.ts
    • Added a new file containing arkTypeJsonSchemaTransformer and replaceStringEnumWithAnyOf functions.
    • Implemented recursive logic to traverse JSON Schema and apply transformations, including setting additionalProperties: false and converting string enum to anyOf.
  • packages/core/src/schemas/strategy-parsers.ts
    • Changed the description field in strategySuggestionSchema from optional (description?) to nullable (description: 'string|null').
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Feb 23, 2026

Open in StackBlitz

pnpm add https://pkg.pr.new/rectangular-labs/monorepo/@rectangular-labs/emails@399
pnpm add https://pkg.pr.new/rectangular-labs/monorepo/@rectangular-labs/loro-file-system@399
pnpm add https://pkg.pr.new/rectangular-labs/monorepo/@rectangular-labs/result@399

commit: a2bf7cb

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new admin page for triggering workflows and refactors how ArkType schemas are converted to JSON schemas for AI tool use. The refactoring to a centralized arktypeToAiJsonSchema utility is a good improvement for consistency and maintainability. However, I've identified a couple of issues. The new admin page has a bug where form inputs share state, which could lead to incorrect workflow triggers. Additionally, there's a potential issue in the new schema transformation logic that could generate invalid JSON schemas for certain union types. My review includes suggestions to fix these problems.

Copy link

Copilot AI left a comment

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 fixes workflow generation issues by introducing proper ArkType-to-AI-JSON-Schema transformation and adds admin endpoints for manual workflow triggering. The core issue being addressed is that ArkType schemas weren't being correctly converted to JSON Schema format compatible with the AI SDK's structured output requirements.

Changes:

  • Introduced arktypeToAiJsonSchema helper to properly transform ArkType schemas to AI SDK compatible JSON schemas
  • Changed description field in strategySuggestionSchema from optional (description?) to explicitly nullable (string|null)
  • Added admin API routes and frontend UI for triggering onboarding and strategy suggestion workflows

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
packages/core/src/schemas/strategy-parsers.ts Changed description field from optional to nullable for explicit schema handling
packages/core/src/schema/arktype-json-schema-transformer.ts New utility to transform enum fields to anyOf format in JSON schemas
packages/api-seo/src/lib/ai/arktype-json-schema.ts Main transformer combining enum conversion with additionalProperties enforcement
packages/api-seo/src/workflows/writer-workflow.ts Applied arktypeToAiJsonSchema wrapper to all Output.object schemas
packages/api-seo/src/workflows/strategy-suggestions-workflow.ts Applied schema wrapper and added try-catch for error logging
packages/api-seo/src/workflows/strategy-phase-generation-workflow.ts Applied schema wrapper to phase suggestion output
packages/api-seo/src/workflows/planner-workflow.ts Applied schema wrapper to planning workflow outputs
packages/api-seo/src/workflows/onboarding-workflow.ts Applied schema wrapper to onboarding workflow outputs
packages/api-seo/src/lib/ai/tools/settings-tools.ts Applied schema wrapper to settings modification outputs
packages/api-seo/src/lib/ai/tools/google-search-console-tool.ts Applied schema wrapper to GSC tool input schema
packages/api-seo/src/routes/admin.ts New admin endpoints for triggering workflows with email domain-based auth
packages/api-seo/src/routes/index.ts Registered admin router
apps/seo/src/routes/_authed/admin/route.tsx Frontend admin UI for workflow triggering
apps/seo/src/routeTree.gen.ts Auto-generated route tree with new admin route

Comment on lines +12 to +49
if (jsonSchema.type === "object") {
jsonSchema.additionalProperties = false;
const properties = jsonSchema.properties;
if (properties != null) {
for (const property in properties) {
properties[property] = addAdditionalPropertiesToJsonSchema(
properties[property] as JSONSchema7,
);
}
}
}
if (jsonSchema.type === "array" && jsonSchema.items != null) {
if (Array.isArray(jsonSchema.items)) {
jsonSchema.items = jsonSchema.items.map((item) =>
addAdditionalPropertiesToJsonSchema(item as JSONSchema7),
);
} else {
jsonSchema.items = addAdditionalPropertiesToJsonSchema(
jsonSchema.items as JSONSchema7,
);
}
}
if (jsonSchema.anyOf != null) {
jsonSchema.anyOf = jsonSchema.anyOf.map((schema) =>
addAdditionalPropertiesToJsonSchema(schema as JSONSchema7),
);
}
if (jsonSchema.allOf != null) {
jsonSchema.allOf = jsonSchema.allOf.map((schema) =>
addAdditionalPropertiesToJsonSchema(schema as JSONSchema7),
);
}
if (jsonSchema.oneOf != null) {
jsonSchema.oneOf = jsonSchema.oneOf.map((schema) =>
addAdditionalPropertiesToJsonSchema(schema as JSONSchema7),
);
}
return jsonSchema;
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

The function mutates the input jsonSchema object instead of creating a new object. This can cause unexpected side effects if the same schema object is reused. Consider creating a deep copy at the start or using spread operators to avoid mutations.

Suggested change
if (jsonSchema.type === "object") {
jsonSchema.additionalProperties = false;
const properties = jsonSchema.properties;
if (properties != null) {
for (const property in properties) {
properties[property] = addAdditionalPropertiesToJsonSchema(
properties[property] as JSONSchema7,
);
}
}
}
if (jsonSchema.type === "array" && jsonSchema.items != null) {
if (Array.isArray(jsonSchema.items)) {
jsonSchema.items = jsonSchema.items.map((item) =>
addAdditionalPropertiesToJsonSchema(item as JSONSchema7),
);
} else {
jsonSchema.items = addAdditionalPropertiesToJsonSchema(
jsonSchema.items as JSONSchema7,
);
}
}
if (jsonSchema.anyOf != null) {
jsonSchema.anyOf = jsonSchema.anyOf.map((schema) =>
addAdditionalPropertiesToJsonSchema(schema as JSONSchema7),
);
}
if (jsonSchema.allOf != null) {
jsonSchema.allOf = jsonSchema.allOf.map((schema) =>
addAdditionalPropertiesToJsonSchema(schema as JSONSchema7),
);
}
if (jsonSchema.oneOf != null) {
jsonSchema.oneOf = jsonSchema.oneOf.map((schema) =>
addAdditionalPropertiesToJsonSchema(schema as JSONSchema7),
);
}
return jsonSchema;
// Create a shallow copy so we don't mutate the input schema object.
const updated: JSONSchema7 = { ...jsonSchema };
if (updated.type === "object") {
updated.additionalProperties = false;
const properties = updated.properties;
if (properties != null) {
const newProperties: typeof properties = {};
for (const property in properties) {
if (Object.prototype.hasOwnProperty.call(properties, property)) {
newProperties[property] = addAdditionalPropertiesToJsonSchema(
properties[property] as JSONSchema7,
);
}
}
updated.properties = newProperties;
}
}
if (updated.type === "array" && updated.items != null) {
if (Array.isArray(updated.items)) {
updated.items = updated.items.map((item) =>
addAdditionalPropertiesToJsonSchema(item as JSONSchema7),
);
} else {
updated.items = addAdditionalPropertiesToJsonSchema(
updated.items as JSONSchema7,
);
}
}
if (updated.anyOf != null) {
updated.anyOf = updated.anyOf.map((schema) =>
addAdditionalPropertiesToJsonSchema(schema as JSONSchema7),
);
}
if (updated.allOf != null) {
updated.allOf = updated.allOf.map((schema) =>
addAdditionalPropertiesToJsonSchema(schema as JSONSchema7),
);
}
if (updated.oneOf != null) {
updated.oneOf = updated.oneOf.map((schema) =>
addAdditionalPropertiesToJsonSchema(schema as JSONSchema7),
);
}
return updated;

Copilot uses AI. Check for mistakes.
Comment on lines 5 to 34
function replaceStringEnumWithAnyOf(value: unknown): unknown {
if (Array.isArray(value)) {
return value.map((item) => replaceStringEnumWithAnyOf(item));
}

if (!value || typeof value !== "object") {
return value;
}

const record = value as Record<string, unknown>;
const normalized: Record<string, unknown> = {};

for (const [key, item] of Object.entries(record)) {
normalized[key] = replaceStringEnumWithAnyOf(item);
}

if (
Array.isArray(record.enum) &&
record.enum.every((item) => typeof item === "string")
) {
normalized.anyOf = [...record.enum];
normalized.type = "string";
delete normalized.enum;
}
if (Array.isArray(record.anyOf)) {
normalized.type = "string";
}

return normalized;
}
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

The replaceStringEnumWithAnyOf function mutates the record object and its nested properties. This could cause issues if the input schema is reused elsewhere. Consider using immutable operations or creating a deep copy of the input before transformation.

Copilot uses AI. Check for mistakes.
Comment on lines 24 to 30
const projectResult = await db.query.seoProject.findFirst({
where: eq(schema.seoProject.slug, input.projectSlug),
});

if (!projectResult) {
throw new ORPCError("NOT_FOUND", { message: "Project not found" });
}
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

The admin endpoint allows triggering workflows for any project without verifying the admin user has permission to access that organization's project. While this is an internal admin endpoint, consider adding organization membership validation or at least logging which admin triggered which project's workflow for audit purposes.

Copilot uses AI. Check for mistakes.

function RouteComponent() {
const api = getApiClientRq();
const [projectSlug, setProjectSlug] = useState("");
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

Both forms share the same projectSlug state variable. When a user enters a project slug in one form, it will appear in both forms. This creates a confusing user experience. Each form should have its own independent state variable for the project slug.

Copilot uses AI. Check for mistakes.
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c3f4aebe46

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@github-actions
Copy link
Contributor

Cloudflare Preview URL for WWW 🎈 : https://pr-399.rectangularlabs.com (custom domain)
Cloudflare Preview URL for SEO 🎈 : https://pr-399.fluidposts.com (custom domain)
Cloudflare Preview URL for SEO WWW 🎈 : https://www-pr-399.fluidposts.com (custom domain)
Cloudflare Preview URL for SEO Contact 🎈 : https://contact-pr-399.fluidposts.com (custom domain)

@ElasticBottle ElasticBottle merged commit a59e24d into main Feb 23, 2026
9 checks passed
@ElasticBottle ElasticBottle deleted the winston/hot-fixes branch February 23, 2026 12:18
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