feat: per-model max output tokens and a conversation-time thinking level backed by agent settings (#28)

Co-authored-by: Alice <alice@prismshadow.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Yaowei Zheng
2026-07-22 22:22:41 +08:00
committed by GitHub
parent 99f391f379
commit cabbab1c16
36 changed files with 797 additions and 42 deletions
+12 -1
View File
@@ -2,7 +2,7 @@
* `penguin config` — manages a Project's model credentials, default model, model list,
* Agent-level vault environment variables, and UI language.
*
* penguin config model add --model-id <upstream id> --provider <group> [--api-key <key>] [--context-window <n>] [--set-default] [--root <dir>]
* penguin config model add --model-id <upstream id> --provider <group> [--api-key <key>] [--context-window <n>] [--max-tokens <n>] [--set-default] [--root <dir>]
* penguin config model default --model-id <upstream id> --provider <group> [--root <dir>]
* penguin config model vision --model-id <upstream id> --provider <group> [--root <dir>]
* penguin config model list [--root <dir>]
@@ -120,6 +120,7 @@ export function registerConfigCommand(program: Command, t: Messages): void {
.option("--api-key <key>", t.config.addApiKey)
.option("--base-url <url>", t.config.addBaseUrl)
.option("--context-window <n>", t.config.addContextWindow, parseIntArg)
.option("--max-tokens <n>", t.config.addMaxTokens, parseIntArg)
.option("--client-type <type>", t.config.addClientType)
// Tri-state: --vision marks it supported / --no-vision marks it unsupported / neither given keeps the existing value (defaults to supported).
.option("--vision", t.config.addVision)
@@ -131,6 +132,15 @@ export function registerConfigCommand(program: Command, t: Messages): void {
.option("--set-default", t.config.addSetDefault, false)
.option("--root <dir>", t.common.root)
.action(async (opts) => {
// Output cap: parseIntArg already rejects non-numbers; 0/negative must not reach the config either.
const maxTokens: number | undefined = opts.maxTokens;
if (maxTokens !== undefined && maxTokens <= 0) {
process.stderr.write(
`${t.error(`--max-tokens must be a positive integer: got "${maxTokens}".`)}\n`,
);
process.exitCode = 1;
return;
}
const root = resolveRootOption(opts.root);
// --model-id takes the upstream id, paired with the required --provider as a
// reference; the group is never guessed, so --api-key can only ever land on the
@@ -164,6 +174,7 @@ export function registerConfigCommand(program: Command, t: Messages): void {
provider,
model_id: modelId,
...(opts.contextWindow !== undefined ? { context_window: opts.contextWindow } : {}),
...(maxTokens !== undefined ? { max_tokens: maxTokens } : {}),
...(clientType !== undefined ? { client_type: clientType } : {}),
...(opts.vision !== undefined ? { vision: opts.vision } : {}),
...(Object.keys(pricing).length > 0 ? { pricing } : {}),