Skip to content

Corpora Commander next#97

Merged
skyl merged 15 commits into
mainfrom
commander-returns
Dec 20, 2025
Merged

Corpora Commander next#97
skyl merged 15 commits into
mainfrom
commander-returns

Conversation

@skyl

@skyl skyl commented Nov 25, 2025

Copy link
Copy Markdown
Collaborator

PR Type

enhancement, tests, dependencies


Description

  • Added new API endpoints for rewriting sections and subsections.

  • Introduced a new RewriteWorkspace component for managing rewrite operations.

  • Updated dependencies and added new packages for UI components.

  • Enhanced snapshot management with new API endpoints and schemas.


Diagram Walkthrough

flowchart LR
  A["Add Rewrite Endpoints"] --> B["Enhance UI with RewriteWorkspace"]
  B --> C["Update Dependencies"]
  C --> D["Add Snapshot Management"]
Loading

File Walkthrough

Relevant files
Enhancement
20 files
rewrite.py
Add endpoints for rewriting sections and subsections         
+75/-1   
builder.py
Update markdown and JSON rules                                                     
+10/-8   
llm_client.py
Update completion model to gpt-5.1                                             
+5/-1     
llm_client.py
Modify token handling and remove default max tokens           
+4/-4     
provider_loader.py
Add logging for Claude provider loading                                   
+6/-3     
commander.ts
Add API methods for Claude models and snapshot management
+931/-0 
RewriteWorkspace.tsx
Introduce RewriteWorkspace component                                         
+300/-0 
RewriteSidebar.tsx
Add RewriteSidebar component for section management           
+287/-0 
GenerateRewriteDialog.tsx
Simplify GenerateRewriteDialog component                                 
+8/-240 
RewriteWorkspaceStore.ts
Create store for managing rewrite workspace state               
+274/-0 
RewriteUnitPanel.tsx
Add RewriteUnitPanel component for unit management             
+169/-0 
textarea.tsx
Enhance Textarea component with word count                             
+42/-19 
RewriteHeader.tsx
Add RewriteHeader component for workspace controls             
+106/-0 
SubsectionEditor.tsx
Update SubsectionEditor with new context handling               
+10/-12 
index.ts
Update API schemas with new types                                               
+18/-6   
scroll-area.tsx
Add ScrollArea component for UI scrolling                               
+46/-0   
checkbox.tsx
Add Checkbox component for UI selection                                   
+28/-0   
snapshotOut.ts
Add SnapshotOut schema for snapshot management                     
+18/-0   
claudeModelsRequest.ts
Add ClaudeModelsRequest schema for API requests                   
+15/-0   
snapshotIn.ts
Add SnapshotIn schema for snapshot input                                 
+16/-0   
Additional files
15 files
Dockerfile +1/-0     
custom_cover.tex +2/-3     
requirements-app.txt +1/-0     
package.json +2/-0     
pnpm-lock.yaml +93/-0   
claudeModelsRequestBaseUrl.ts +12/-0   
claudeModelsResponse.ts +11/-0   
completionRequest.ts +1/-1     
snapshotInDescription.ts +9/-0     
snapshotInName.ts +9/-0     
snapshotInSnapshot.ts +10/-0   
snapshotInSnapshotAnyOf.ts +9/-0     
snapshotOutDescription.ts +9/-0     
snapshotOutName.ts +9/-0     
snapshotOutSnapshot.ts +9/-0     

@github-actions

github-actions Bot commented Nov 25, 2025

Copy link
Copy Markdown

PR Reviewer Guide 🔍

(Review updated until commit b412036)

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Hardcoded Max Tokens

The max_tokens parameter is hardcoded to 10000 in the get_data_completion function. This could lead to unexpected behavior if the token limit is exceeded. Consider making this configurable or ensuring it aligns with the model's capabilities.

max_tokens=10000,
API Endpoint Error Handling

The new API endpoints for rewriting sections and subsections do not appear to have error handling for failed requests. Consider adding error handling to improve robustness and user feedback.

export const corporaCommanderApiRewriteRewriteSingleSection = (
  projectId: string,
  sectionId: string,
  rewriteRequest: RewriteRequest,
  options?: AxiosRequestConfig,
): Promise<AxiosResponse<RewriteSection>> => {
  return axios.default.post(
    `/api/commander/projects/${projectId}/rewrite/sections/${sectionId}`,
    rewriteRequest,
    options,
  );
};

export const getCorporaCommanderApiRewriteRewriteSingleSectionMutationOptions =
  <TError = AxiosError<unknown>, TContext = unknown>(options?: {
    mutation?: UseMutationOptions<
      Awaited<
        ReturnType<typeof corporaCommanderApiRewriteRewriteSingleSection>
      >,
      TError,
      { projectId: string; sectionId: string; data: RewriteRequest },
      TContext
    >;
    axios?: AxiosRequestConfig;
  }): UseMutationOptions<
    Awaited<ReturnType<typeof corporaCommanderApiRewriteRewriteSingleSection>>,
    TError,
    { projectId: string; sectionId: string; data: RewriteRequest },
    TContext
  > => {
    const mutationKey = ["corporaCommanderApiRewriteRewriteSingleSection"];
    const { mutation: mutationOptions, axios: axiosOptions } = options
      ? options.mutation &&
        "mutationKey" in options.mutation &&
        options.mutation.mutationKey
        ? options
        : { ...options, mutation: { ...options.mutation, mutationKey } }
      : { mutation: { mutationKey }, axios: undefined };

    const mutationFn: MutationFunction<
      Awaited<
        ReturnType<typeof corporaCommanderApiRewriteRewriteSingleSection>
      >,
      { projectId: string; sectionId: string; data: RewriteRequest }
    > = (props) => {
      const { projectId, sectionId, data } = props ?? {};

      return corporaCommanderApiRewriteRewriteSingleSection(
        projectId,
        sectionId,
        data,
        axiosOptions,
      );
    };

    return { mutationFn, ...mutationOptions };
  };

export type CorporaCommanderApiRewriteRewriteSingleSectionMutationResult =
  NonNullable<
    Awaited<ReturnType<typeof corporaCommanderApiRewriteRewriteSingleSection>>
  >;
export type CorporaCommanderApiRewriteRewriteSingleSectionMutationBody =
  RewriteRequest;
export type CorporaCommanderApiRewriteRewriteSingleSectionMutationError =
  AxiosError<unknown>;

/**
 * @summary Rewrite Single Section
 */
export const useCorporaCommanderApiRewriteRewriteSingleSection = <
  TError = AxiosError<unknown>,
  TContext = unknown,
>(
  options?: {
    mutation?: UseMutationOptions<
      Awaited<
        ReturnType<typeof corporaCommanderApiRewriteRewriteSingleSection>
      >,
      TError,
      { projectId: string; sectionId: string; data: RewriteRequest },
      TContext
    >;
    axios?: AxiosRequestConfig;
  },
  queryClient?: QueryClient,
): UseMutationResult<
  Awaited<ReturnType<typeof corporaCommanderApiRewriteRewriteSingleSection>>,
  TError,
  { projectId: string; sectionId: string; data: RewriteRequest },
  TContext
> => {
  const mutationOptions =
    getCorporaCommanderApiRewriteRewriteSingleSectionMutationOptions(options);

  return useMutation(mutationOptions, queryClient);
};
/**
 * @summary Rewrite Single Subsection
 */
export const corporaCommanderApiRewriteRewriteSingleSubsection = (
  projectId: string,
  subsectionId: string,
  rewriteRequest: RewriteRequest,
  options?: AxiosRequestConfig,
): Promise<AxiosResponse<RewriteSubsection>> => {
  return axios.default.post(
    `/api/commander/projects/${projectId}/rewrite/subsections/${subsectionId}`,
    rewriteRequest,
    options,
  );
};

export const getCorporaCommanderApiRewriteRewriteSingleSubsectionMutationOptions =
  <TError = AxiosError<unknown>, TContext = unknown>(options?: {
    mutation?: UseMutationOptions<
      Awaited<
        ReturnType<typeof corporaCommanderApiRewriteRewriteSingleSubsection>
      >,
      TError,
      { projectId: string; subsectionId: string; data: RewriteRequest },
      TContext
    >;
    axios?: AxiosRequestConfig;
  }): UseMutationOptions<
    Awaited<
      ReturnType<typeof corporaCommanderApiRewriteRewriteSingleSubsection>
    >,
    TError,
    { projectId: string; subsectionId: string; data: RewriteRequest },
    TContext
  > => {
    const mutationKey = ["corporaCommanderApiRewriteRewriteSingleSubsection"];
    const { mutation: mutationOptions, axios: axiosOptions } = options
      ? options.mutation &&
        "mutationKey" in options.mutation &&
        options.mutation.mutationKey
        ? options
        : { ...options, mutation: { ...options.mutation, mutationKey } }
      : { mutation: { mutationKey }, axios: undefined };

    const mutationFn: MutationFunction<
      Awaited<
        ReturnType<typeof corporaCommanderApiRewriteRewriteSingleSubsection>
      >,
      { projectId: string; subsectionId: string; data: RewriteRequest }
    > = (props) => {
      const { projectId, subsectionId, data } = props ?? {};

      return corporaCommanderApiRewriteRewriteSingleSubsection(
        projectId,
        subsectionId,
        data,
        axiosOptions,
      );
    };

    return { mutationFn, ...mutationOptions };
  };

export type CorporaCommanderApiRewriteRewriteSingleSubsectionMutationResult =
  NonNullable<
    Awaited<
      ReturnType<typeof corporaCommanderApiRewriteRewriteSingleSubsection>
    >
  >;
export type CorporaCommanderApiRewriteRewriteSingleSubsectionMutationBody =
  RewriteRequest;
export type CorporaCommanderApiRewriteRewriteSingleSubsectionMutationError =
  AxiosError<unknown>;

/**
 * @summary Rewrite Single Subsection
 */
export const useCorporaCommanderApiRewriteRewriteSingleSubsection = <
  TError = AxiosError<unknown>,
  TContext = unknown,
>(
  options?: {
    mutation?: UseMutationOptions<
      Awaited<
        ReturnType<typeof corporaCommanderApiRewriteRewriteSingleSubsection>
      >,
      TError,
      { projectId: string; subsectionId: string; data: RewriteRequest },
      TContext
    >;
    axios?: AxiosRequestConfig;
  },
  queryClient?: QueryClient,
): UseMutationResult<
  Awaited<
    ReturnType<typeof corporaCommanderApiRewriteRewriteSingleSubsection>
  >,
  TError,
  { projectId: string; subsectionId: string; data: RewriteRequest },
  TContext
> => {
  const mutationOptions =
    getCorporaCommanderApiRewriteRewriteSingleSubsectionMutationOptions(
      options,
    );

  return useMutation(mutationOptions, queryClient);
};

@github-actions

github-actions Bot commented Nov 25, 2025

Copy link
Copy Markdown

PR Code Suggestions ✨

Latest suggestions up to b412036
Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
General
Run tasks in parallel for efficiency

Consider running the runRewriteForKey function in parallel for all selected keys to
improve performance, especially if the number of selected keys is large.

ts/commander/src/components/rewrite/RewriteWorkspace.tsx [203-211]

 const handleRunSelected = async () => {
     const keys = Object.entries(unitStates)
         .filter(([_, s]) => s.selected)
         .map(([key]) => key as UnitKey)
 
-    for (const key of keys) {
-        // sequential for now
-        // eslint-disable-next-line no-await-in-loop
-        await runRewriteForKey(key)
-    }
+    await Promise.all(keys.map(key => runRewriteForKey(key)))
 }
Suggestion importance[1-10]: 8

__

Why: Running the runRewriteForKey function in parallel can significantly improve performance when dealing with multiple selected keys. This change optimizes the code by reducing the overall execution time for batch operations.

Medium
Validate key before activation

Add a check to ensure that the key is valid before setting it as the active key to
avoid potential errors if an invalid key is passed.

ts/commander/src/components/rewrite/RewriteSidebar.tsx [84-88]

 const handleRowKeyDown = (key: UnitKey, e: React.KeyboardEvent) => {
-    if (e.key === "Enter" || e.key === " ") {
+    if ((e.key === "Enter" || e.key === " ") && unitStates[key]) {
         e.preventDefault()
         setActiveKey(key)
     }
 }
Suggestion importance[1-10]: 6

__

Why: Adding a check to ensure the key is valid before setting it as active helps prevent potential errors. This minor improvement enhances the code's reliability by ensuring only valid keys are processed.

Low
Possible issue
Validate object before returning

Ensure that the rewrite object is validated against the expected schema before
returning it to prevent runtime errors if the object structure is incorrect.

py/packages/corpora_commander/api/rewrite.py [134]

+if not isinstance(rewrite, RewriteSection):
+    raise ValueError("Invalid rewrite object returned")
 return rewrite
Suggestion importance[1-10]: 7

__

Why: Validating the rewrite object before returning it can prevent runtime errors by ensuring it matches the expected schema. This enhances code robustness, especially in dynamic environments where object structures might vary.

Medium

Previous suggestions

Suggestions up to commit bf5ed37
CategorySuggestion                                                                                                                                    Impact
General
Replace print statements with logging

Remove or replace the print statements with proper logging to avoid cluttering the
console output. This will help in maintaining clean logs and better control over log
levels.

py/packages/corpora_ai/provider_loader.py [62-72]

-print("Loading Claude provider...")
+import logging
+
+logger = logging.getLogger(__name__)
+
+logger.info("Loading Claude provider...")
 ...
-print("ERROR: ANTHROPIC_API_KEY environment variable is not set.")
+logger.error("ANTHROPIC_API_KEY environment variable is not set.")
 ...
-print("returning Claude client...")
+logger.info("Returning Claude client...")
Suggestion importance[1-10]: 7

__

Why: Replacing print statements with logging improves code maintainability and provides better control over log levels, which is beneficial for production environments.

Medium
Possible issue
Validate max_tokens against limits

Ensure that the max_tokens value is appropriate for the API limits. Setting it too
high may lead to errors or inefficient resource usage.

py/packages/corpora_ai_claude/llm_client.py [78]

-max_tokens=10000,
+max_tokens=min(self.default_max_tokens, 10000),
Suggestion importance[1-10]: 6

__

Why: Ensuring max_tokens is within API limits can prevent potential errors and optimize resource usage, though the suggestion is more of a cautionary note rather than a direct improvement.

Low

@skyl skyl marked this pull request as ready for review November 28, 2025 03:46
@skyl

skyl commented Nov 28, 2025

Copy link
Copy Markdown
Collaborator Author

/describe

@skyl

skyl commented Nov 28, 2025

Copy link
Copy Markdown
Collaborator Author

/review

@github-actions

Copy link
Copy Markdown

Persistent review updated to latest commit b412036

1 similar comment
@github-actions

Copy link
Copy Markdown

Persistent review updated to latest commit b412036

@github-actions

Copy link
Copy Markdown

PR Description updated to latest commit (b412036)

@skyl

skyl commented Dec 20, 2025

Copy link
Copy Markdown
Collaborator Author

Some notes for next steps:

  • Delete image tokens from image manager (and it edits section/subsection)
  • more lively update of tokens (reload when the drawer opens should be fine - after editing the tokens should be fresh)
  • Edit the token in the image manager (and it edits the section/subsection underneath - and deeps the image attached to the token)
  • a checkbox that says whether or not to render the caption in text (eg we don't want a text caption under the image - fix the export so when we patch in the images we decide whether to have a caption or not)
  • persist image instructions on project

non-image area notes:

  • confirmation of delete (main section trashcan for section)
  • different size books (render header template based on project config)
  • name history snapshots

@skyl skyl merged commit 2b3b5c9 into main Dec 20, 2025
2 checks passed
@skyl skyl deleted the commander-returns branch December 20, 2025 00:46
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.

1 participant