Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion src/SharpInference.Cli/RunCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ public sealed class Settings : CommandSettings

[CommandOption("-p|--prompt")]
[Description("Input prompt (default: interactive chat)")]
public string? Prompt { get; init; }
public string? Prompt { get; set; }

[CommandOption("-f|--file")]
[Description("Read the prompt from a file (llama.cpp -f/--file). Overrides -p when both are given; useful for prompts longer than the shell's command-line limit.")]
public string? PromptFile { get; init; }

[CommandOption("-n|--n-predict")]
[Description("Number of tokens to predict (default: 512)")]
Expand Down Expand Up @@ -188,6 +192,29 @@ public sealed class Settings : CommandSettings

protected override int Execute(CommandContext context, Settings settings, CancellationToken cancellation)
{
// --file/-f (llama.cpp): load the prompt from a file. Overrides -p; lets prompts exceed
// the shell command-line length limit. Read as-is (no trailing-newline stripping).
if (settings.PromptFile is { Length: > 0 } promptFile)
{
if (!File.Exists(promptFile))
{
AnsiConsole.MarkupLine($"[red]Prompt file not found:[/] {Markup.Escape(promptFile)}");
return 1;
}
// Read failures (locked file, permissions, bad path) should fail loud + clean, not
// throw a stack trace; Escape the message since paths can carry Spectre markup chars.
try
{
settings.Prompt = File.ReadAllText(promptFile);
}
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException
or System.Security.SecurityException or NotSupportedException)
{
AnsiConsole.MarkupLine($"[red]Error reading prompt file:[/] {Markup.Escape(ex.Message)}");
return 1;
}
}
Comment on lines +197 to +216

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

There are two issues in this block:

  1. Spectre.Console Markup Parsing Error: If promptFile contains square brackets (e.g., [path]), AnsiConsole.MarkupLine will attempt to parse it as markup, leading to incorrect rendering or exceptions. Use Markup.Escape(promptFile) to prevent this.
  2. Unhandled I/O Exceptions: File.ReadAllText can throw exceptions (e.g., UnauthorizedAccessException, IOException) if the file is locked or permissions are insufficient. Wrapping it in a try-catch block ensures the CLI exits gracefully with a clean error message instead of crashing with a stack trace.
        if (settings.PromptFile is { Length: > 0 } promptFile)
        {
            if (!File.Exists(promptFile))
            {
                AnsiConsole.MarkupLine($"[red]Prompt file not found:[/] {Markup.Escape(promptFile)}");
                return 1;
            }
            try
            {
                settings.Prompt = File.ReadAllText(promptFile);
            }
            catch (Exception ex)
            {
                AnsiConsole.MarkupLine($"[red]Error reading prompt file:[/] {Markup.Escape(ex.Message)}");
                return 1;
            }
        }

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed: Markup.Escape on both the not-found and read-error messages, and File.ReadAllText is wrapped in try/catch (IOException/UnauthorizedAccessException/SecurityException/NotSupportedException) → clean message + exit 1. Verified a bracketed missing path renders correctly.


if (settings.MinBatchBlas > 0)
SimdKernels.MinBatchForBlas = settings.MinBatchBlas;

Expand Down