Tree: Add actions engine and optimize inline config action

Subcommands are run from command-line-args and then pushed to
the common action runner. If an action is run, exit the main application.

For the inline config action, if a config already exists, don't do anything
to prevent overwrites. This behavior can be changed depending on user
feedback.

Signed-off-by: kingbri <8082010+kingbri1@users.noreply.github.com>
This commit is contained in:
kingbri
2025-06-24 14:01:24 -04:00
parent 6f10b32c5c
commit b324356be5
3 changed files with 70 additions and 16 deletions

View File

@@ -1,23 +1,31 @@
import { config } from "./config.ts";
import commandLineArgs from "command-line-args";
import * as Path from "@std/path";
import * as YAML from "@std/yaml";
import { config } from "./config.ts";
import { InlineConfigSchema, StrippedModelConfig } from "./configModels.ts";
import { logger } from "./logging.ts";
export async function createInlineConfig() {
export async function genInlineConfigAction() {
if (!config.model.model_name) {
throw new Error(
"Please provide a model name to generate an inline config.",
);
}
const modelName = config.model.model_name.replace(".gguf", "");
// Check if an inline config already exists and exit if so
const inlineConfigPath = config.model.model_dir +
`${config.model.model_name}.yml`;
const inlineConfigPath = Path.join(
config.model.model_dir,
`${modelName}.yml`,
);
const fileInfo = await Deno.stat(inlineConfigPath).catch(() => null);
if (!fileInfo?.isFile) {
if (fileInfo?.isFile) {
throw new Error(
"Inline config already found for provided model." +
" Delete it and try again",
"Inline config already found for " +
`provided model name. ${modelName}` +
"Delete it and try again.",
);
}
@@ -29,4 +37,16 @@ export async function createInlineConfig() {
const inlineYaml = YAML.stringify(inlineConfig);
await Deno.writeTextFile(inlineConfigPath, inlineYaml);
logger.info(`Successfully wrote inline config to ${inlineConfigPath}`);
}
export async function runAction(args: commandLineArgs.CommandLineOptions) {
switch (args.actions.subcommand) {
case "gen-inline-config":
await genInlineConfigAction();
return true;
default:
return false;
}
}

View File

@@ -108,14 +108,42 @@ export function parseArgs() {
raw: true,
};
// For subcommands
const actionDefs: commandLineUsage.OptionDefinition[] = [
{ name: "subcommand", defaultOption: true, group: "actions" },
];
const actionGroup: commandLineUsage.Section = {
header: "Positional arguments",
content: [
{
name: "gen-inline-config",
description: "Creates an inline config yaml from " +
"args and main config.yml",
},
],
};
// Fetch arg groups for config
const configGroups = configToArgs();
const optionGroups = [...configGroups, helpGroup];
const usage = commandLineUsage([...optionGroups, epilog]);
const cliOptions: commandLineUsage.OptionDefinition[] = optionGroups
.flatMap((option) => option.optionList ?? []);
// Combine help sections and create help menu
const usageSections = [actionGroup, helpGroup, ...configGroups];
const usage = commandLineUsage([...usageSections, epilog]);
// Filter help sections to parseable options
const cliOptions: commandLineUsage.OptionDefinition[] = [
...actionDefs,
...usageSections.flatMap((section) =>
"optionList" in section ? section.optionList ?? [] : []
),
];
// Parse the options
const args = commandLineArgs(cliOptions, { argv: Deno.args });
const args = commandLineArgs(cliOptions, {
argv: Deno.args,
stopAtFirstUnknown: true,
});
// Replace keys with underscores for config parsing
for (const groupName of Object.keys(args)) {

12
main.ts
View File

@@ -1,4 +1,6 @@
import { createApi } from "@/api/server.ts";
import { loadYalsBindings } from "@/bindings/lib.ts";
import { runAction } from "@/common/actions.ts";
import { loadAuthKeys } from "@/common/auth.ts";
import { parseArgs } from "@/common/args.ts";
import { config, loadConfig } from "@/common/config.ts";
@@ -6,7 +8,6 @@ import { logger } from "@/common/logging.ts";
import { loadModel } from "@/common/modelContainer.ts";
import { elevateProcessPriority, getYalsVersion } from "@/common/utils.ts";
import { overridesFromFile } from "@/common/samplerOverrides.ts";
import { loadYalsBindings } from "@/bindings/lib.ts";
if (import.meta.main) {
// Use Promise resolution to avoid nested try/catch
@@ -21,7 +22,7 @@ if (import.meta.main) {
// Load bindings
loadYalsBindings();
//Parse CLI args
// Parse CLI args
const { args, usage } = parseArgs();
// Display help message if needed
@@ -32,9 +33,14 @@ if (import.meta.main) {
await loadConfig(args);
// Defer to an action if specified in invocation
const ranAction = await runAction(args);
if (ranAction) {
Deno.exit();
}
// Load model if present
if (config.model.model_name) {
// Load model in bindings
await loadModel(config.model);
}