@promptbook/cli 0.114.0-24 → 0.114.0-26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/apps/agents-server/src/utils/agentProjects/agentProjectRuntimePm2.ts +56 -10
- package/apps/agents-server/src/utils/userChat/createImmediateUserChatAnswerModelRequirements.ts +1 -0
- package/esm/index.es.js +256 -59
- package/esm/index.es.js.map +1 -1
- package/esm/scripts/run-codex-prompts/runners/common/estimateUsageFromTextLength.d.ts +33 -0
- package/esm/scripts/run-codex-prompts/runners/common/modelPricing.d.ts +41 -0
- package/esm/scripts/run-codex-prompts/runners/gemini/gemini-pricing.d.ts +5 -18
- package/esm/scripts/run-codex-prompts/runners/qwen-code/QwenCodeRunner.d.ts +23 -0
- package/esm/scripts/run-codex-prompts/runners/qwen-code/buildQwenCodeScript.d.ts +8 -0
- package/esm/scripts/run-codex-prompts/runners/qwen-code/parseQwenCodeUsageFromOutput.d.ts +9 -0
- package/esm/scripts/run-codex-prompts/runners/qwen-code/qwen-code-pricing.d.ts +30 -0
- package/esm/src/book-3.0/cliAgentEnv.d.ts +3 -3
- package/esm/src/cli/cli-commands/common/promptRunnerCliOptions.d.ts +8 -2
- package/esm/src/commitments/WRITING_RULES/WRITING_RULES.d.ts +14 -7
- package/esm/src/commitments/index.d.ts +1 -1
- package/esm/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/book-2.0/book-language-documentation/createStandaloneBookLanguageMarkdown.ts +1 -0
- package/src/book-3.0/cliAgentEnv.ts +3 -2
- package/src/cli/cli-commands/common/harness/HarnessDefinition.ts +6 -0
- package/src/cli/cli-commands/common/promptRunnerCliOptions.ts +14 -8
- package/src/commitments/WRITING_RULES/WRITING_RULES.ts +16 -8
- package/src/commitments/index.ts +2 -1
- package/src/other/templates/getTemplatesPipelineCollection.ts +859 -739
- package/src/version.ts +2 -2
- package/src/versions.txt +2 -0
- package/umd/index.umd.js +256 -59
- package/umd/index.umd.js.map +1 -1
- package/umd/scripts/run-codex-prompts/runners/common/estimateUsageFromTextLength.d.ts +33 -0
- package/umd/scripts/run-codex-prompts/runners/common/modelPricing.d.ts +41 -0
- package/umd/scripts/run-codex-prompts/runners/gemini/gemini-pricing.d.ts +5 -18
- package/umd/scripts/run-codex-prompts/runners/qwen-code/QwenCodeRunner.d.ts +23 -0
- package/umd/scripts/run-codex-prompts/runners/qwen-code/buildQwenCodeScript.d.ts +8 -0
- package/umd/scripts/run-codex-prompts/runners/qwen-code/parseQwenCodeUsageFromOutput.d.ts +9 -0
- package/umd/scripts/run-codex-prompts/runners/qwen-code/qwen-code-pricing.d.ts +30 -0
- package/umd/src/book-3.0/cliAgentEnv.d.ts +3 -3
- package/umd/src/cli/cli-commands/common/promptRunnerCliOptions.d.ts +8 -2
- package/umd/src/commitments/WRITING_RULES/WRITING_RULES.d.ts +14 -7
- package/umd/src/commitments/index.d.ts +1 -1
- package/umd/src/version.d.ts +1 -1
package/README.md
CHANGED
|
@@ -549,7 +549,7 @@ Prompts marked with `[-]` are not ready yet, prompts containing `@@@` are treate
|
|
|
549
549
|
|
|
550
550
|
#### Features
|
|
551
551
|
|
|
552
|
-
- **Multi-runner execution:** `openai-codex`, `github-copilot`, `cline`, `claude-code`, `opencode`, `gemini`
|
|
552
|
+
- **Multi-runner execution:** `openai-codex`, `github-copilot`, `cline`, `claude-code`, `opencode`, `gemini`, `qwen-code`
|
|
553
553
|
- **Context injection:** `--agent agents/coding/developer.book --context AGENTS.md` or inline extra instructions
|
|
554
554
|
- **Reasoning control:** `--thinking-level low|medium|high|xhigh` for supported runners
|
|
555
555
|
- **Unattended or interactive runs:** default auto mode, or `--no-auto` to wait for user confirmation before each prompt
|
|
@@ -626,7 +626,7 @@ ptbk coder verify
|
|
|
626
626
|
| Flag | Purpose |
|
|
627
627
|
| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
628
628
|
| `--harness <name>` | Selects the coding harness. |
|
|
629
|
-
| `--model <model>` | Chooses the runner model; required for `openai-codex` and `
|
|
629
|
+
| `--model <model>` | Chooses the runner model; required for `openai-codex`, `gemini` and `qwen-code`, optional for `github-copilot`. |
|
|
630
630
|
| `--context <text-or-file>` | Appends extra instructions inline or from a file like `AGENTS.md`. |
|
|
631
631
|
| `--test <command>` | Runs a verification command after each prompt attempt and feeds failing output back for retries. |
|
|
632
632
|
| `--test-before <mode>` | Runs tests before coding: `no` (default), `yes-and-fail` (stop with results), or `yes-and-fix` (create one repair prompt first); defaults to `npm test` when enabled without `--test`. |
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { execFile } from 'child_process';
|
|
2
2
|
import { createHash } from 'crypto';
|
|
3
3
|
import { promisify } from 'util';
|
|
4
|
+
import { UnexpectedError } from '../../../../../src/errors/UnexpectedError';
|
|
5
|
+
import { spaceTrim } from '../../../../../src/utils/organization/spaceTrim';
|
|
4
6
|
import { AGENT_PROJECT_RUNTIME_HOST } from './agentProjectRuntimeConstants';
|
|
5
7
|
import type { AgentProjectRuntimeMode } from './AgentProjectRuntimeInfo';
|
|
6
8
|
import { resolveAgentProjectRuntimeEnvironmentFlag } from './resolveAgentProjectRuntimeEnvironmentFlag';
|
|
@@ -44,8 +46,18 @@ const AGENT_PROJECT_PM2_PROCESS_LABEL_LENGTH = 36;
|
|
|
44
46
|
|
|
45
47
|
/**
|
|
46
48
|
* Max output retained from pm2 commands.
|
|
49
|
+
*
|
|
50
|
+
* Note: `pm2 jlist` embeds a full environment snapshot into every listed process, so the list grows by tens of
|
|
51
|
+
* kilobytes with each started project. A budget of one megabyte was exhausted by roughly a dozen projects,
|
|
52
|
+
* after which `execFile` killed every `pm2 jlist` call with `ERR_CHILD_PROCESS_STDIO_MAXBUFFER` and pm2
|
|
53
|
+
* appeared to know no process at all.
|
|
54
|
+
*/
|
|
55
|
+
const PM2_COMMAND_MAX_BUFFER_BYTES = 64 * 1024 * 1024;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* pm2 error reported when no process of the requested name is registered.
|
|
47
59
|
*/
|
|
48
|
-
const
|
|
60
|
+
const PM2_MISSING_PROCESS_ERROR_PATTERN = /Process or Namespace .* not found/u;
|
|
49
61
|
|
|
50
62
|
/**
|
|
51
63
|
* Status snapshot for one pm2 process.
|
|
@@ -189,25 +201,46 @@ export async function startAgentProjectRuntimePm2Process(
|
|
|
189
201
|
}
|
|
190
202
|
|
|
191
203
|
/**
|
|
192
|
-
*
|
|
204
|
+
* Deletes every pm2 process registered under one name.
|
|
205
|
+
*
|
|
206
|
+
* Note: The delete is never skipped because pm2 could not be asked for its current process list. `pm2 start`
|
|
207
|
+
* appends another process instead of replacing the existing one when a process of the same name is already
|
|
208
|
+
* registered, so a delete which silently does nothing turns every later start of the same project into one
|
|
209
|
+
* more duplicate. Only pm2 itself reporting an unknown name counts as "already gone", every other failure
|
|
210
|
+
* is reported to the caller, which then must not start the project again.
|
|
193
211
|
*
|
|
194
212
|
* @param processName - pm2 process name.
|
|
195
213
|
*/
|
|
196
214
|
export async function stopAgentProjectRuntimePm2Process(processName: string | null | undefined): Promise<void> {
|
|
197
|
-
if (!processName) {
|
|
215
|
+
if (!processName || !isAgentProjectRuntimePm2Enabled()) {
|
|
198
216
|
return;
|
|
199
217
|
}
|
|
200
218
|
|
|
201
|
-
|
|
219
|
+
try {
|
|
220
|
+
await execFileAsync(PM2_COMMAND, ['delete', processName], {
|
|
221
|
+
maxBuffer: PM2_COMMAND_MAX_BUFFER_BYTES,
|
|
222
|
+
windowsHide: true,
|
|
223
|
+
});
|
|
224
|
+
} catch (error) {
|
|
225
|
+
if (isPm2MissingProcessError(error)) {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
202
228
|
|
|
203
|
-
|
|
204
|
-
|
|
229
|
+
throw new UnexpectedError(
|
|
230
|
+
spaceTrim(
|
|
231
|
+
(block) => `
|
|
232
|
+
Failed to delete the pm2 process \`${processName}\` of an agent project.
|
|
233
|
+
|
|
234
|
+
Starting the project again would register one more pm2 process of the same name instead of
|
|
235
|
+
replacing the existing one, so the project was left alone.
|
|
236
|
+
|
|
237
|
+
**Cause:**
|
|
238
|
+
${block(error instanceof Error ? error.message : String(error))}
|
|
239
|
+
`,
|
|
240
|
+
),
|
|
241
|
+
);
|
|
205
242
|
}
|
|
206
243
|
|
|
207
|
-
await execFileAsync(PM2_COMMAND, ['delete', processName], {
|
|
208
|
-
maxBuffer: PM2_COMMAND_MAX_BUFFER_BYTES,
|
|
209
|
-
windowsHide: true,
|
|
210
|
-
});
|
|
211
244
|
await savePm2ProcessList();
|
|
212
245
|
}
|
|
213
246
|
|
|
@@ -366,6 +399,19 @@ async function savePm2ProcessList(): Promise<void> {
|
|
|
366
399
|
});
|
|
367
400
|
}
|
|
368
401
|
|
|
402
|
+
/**
|
|
403
|
+
* Returns whether one failed pm2 command failed only because pm2 knows no process of the requested name.
|
|
404
|
+
*/
|
|
405
|
+
function isPm2MissingProcessError(error: unknown): boolean {
|
|
406
|
+
if (!error || typeof error !== 'object') {
|
|
407
|
+
return false;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
const { stderr } = error as { readonly stderr?: unknown };
|
|
411
|
+
|
|
412
|
+
return typeof stderr === 'string' && PM2_MISSING_PROCESS_ERROR_PATTERN.test(stderr);
|
|
413
|
+
}
|
|
414
|
+
|
|
369
415
|
/**
|
|
370
416
|
* Creates the fallback status for missing or unavailable pm2 processes.
|
|
371
417
|
*/
|
package/esm/index.es.js
CHANGED
|
@@ -48,7 +48,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
|
|
|
48
48
|
* @generated
|
|
49
49
|
* @see https://github.com/webgptorg/promptbook
|
|
50
50
|
*/
|
|
51
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.114.0-
|
|
51
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.114.0-26';
|
|
52
52
|
/**
|
|
53
53
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
54
54
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -1721,6 +1721,7 @@ const CLI_AGENT_HARNESS_NAMES = [
|
|
|
1721
1721
|
'claude-code',
|
|
1722
1722
|
'opencode',
|
|
1723
1723
|
'gemini',
|
|
1724
|
+
'qwen-code',
|
|
1724
1725
|
];
|
|
1725
1726
|
/**
|
|
1726
1727
|
* All supported thinking-level values for CLI coding-agent runners.
|
|
@@ -1731,8 +1732,8 @@ const CLI_AGENT_THINKING_LEVEL_VALUES = ['low', 'medium', 'high', 'xhigh', 'max'
|
|
|
1731
1732
|
/**
|
|
1732
1733
|
* Environment variable used as the default runner identifier when `--harness` is omitted or not set in `CliAgent`.
|
|
1733
1734
|
*
|
|
1734
|
-
* Set this to one of the harness names (`openai-codex`, `github-copilot`, `cline`, `claude-code`, `opencode`, `gemini
|
|
1735
|
-
* so that `CliAgent` and `ptbk agent exec` can run without an explicit `harness` option.
|
|
1735
|
+
* Set this to one of the harness names (`openai-codex`, `github-copilot`, `cline`, `claude-code`, `opencode`, `gemini`,
|
|
1736
|
+
* `qwen-code`) so that `CliAgent` and `ptbk agent exec` can run without an explicit `harness` option.
|
|
1736
1737
|
*
|
|
1737
1738
|
* @public exported from `@promptbook/node`
|
|
1738
1739
|
*/
|
|
@@ -1817,23 +1818,31 @@ const PROMPT_RUNNER_DESCRIPTION = spaceTrim$1(`
|
|
|
1817
1818
|
- claude-code: Claude Code integration
|
|
1818
1819
|
- opencode: Opencode integration
|
|
1819
1820
|
- gemini: Google Gemini CLI integration (requires --model)
|
|
1821
|
+
- qwen-code: Qwen Code CLI integration (requires --model)
|
|
1820
1822
|
`);
|
|
1821
1823
|
/**
|
|
1822
1824
|
* Commander description for the `--harness` option.
|
|
1823
1825
|
*
|
|
1824
1826
|
* @private internal utility of `promptbookCli`
|
|
1825
1827
|
*/
|
|
1826
|
-
const PROMPT_RUNNER_HARNESS_OPTION_DESCRIPTION =
|
|
1828
|
+
const PROMPT_RUNNER_HARNESS_OPTION_DESCRIPTION = `Select runner: ${PROMPT_RUNNER_HARNESS_NAMES.join(', ')} (required for non-dry-run)`;
|
|
1829
|
+
/**
|
|
1830
|
+
* Runner harness names listed as alternatives of the `--harness` option in error messages.
|
|
1831
|
+
*
|
|
1832
|
+
* @private internal utility of `promptbookCli`
|
|
1833
|
+
*/
|
|
1834
|
+
const PROMPT_RUNNER_HARNESS_OPTION_HINT = `--harness <${PROMPT_RUNNER_HARNESS_NAMES.join('|')}>`;
|
|
1827
1835
|
/**
|
|
1828
1836
|
* Commander description for the `--model` option.
|
|
1829
1837
|
*
|
|
1830
1838
|
* @private internal utility of `promptbookCli`
|
|
1831
1839
|
*/
|
|
1832
1840
|
const PROMPT_RUNNER_MODEL_OPTION_DESCRIPTION = spaceTrim$1(`
|
|
1833
|
-
Model to use (required for openai-codex and
|
|
1841
|
+
Model to use (required for openai-codex, gemini and qwen-code)
|
|
1834
1842
|
|
|
1835
1843
|
OpenAI examples: gpt-5.2-codex, default
|
|
1836
1844
|
Gemini examples: gemini-3-flash-preview, default
|
|
1845
|
+
Qwen examples: qwen3.8-max, default
|
|
1837
1846
|
`);
|
|
1838
1847
|
/**
|
|
1839
1848
|
* Commander description for the `--git-changes` option.
|
|
@@ -1921,7 +1930,7 @@ function resolvePromptRunnerHarnessName(harness, options) {
|
|
|
1921
1930
|
if (!options.isAgentRequired) {
|
|
1922
1931
|
return undefined;
|
|
1923
1932
|
}
|
|
1924
|
-
throw new Error(colors.red(
|
|
1933
|
+
throw new Error(colors.red(`You must choose a harness using ${PROMPT_RUNNER_HARNESS_OPTION_HINT}`));
|
|
1925
1934
|
}
|
|
1926
1935
|
if (isPromptRunnerHarnessName(harness)) {
|
|
1927
1936
|
return harness;
|
|
@@ -20054,29 +20063,36 @@ class UseUserLocationCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
20054
20063
|
/**
|
|
20055
20064
|
* `WRITING RULES` commitment definition.
|
|
20056
20065
|
*
|
|
20057
|
-
*
|
|
20058
|
-
* rather than task-solving behavior.
|
|
20066
|
+
* The `WRITING RULES`/`WRITING RULE` commitment adds constraints that apply strictly to writing style
|
|
20067
|
+
* and presentation rather than task-solving behavior.
|
|
20068
|
+
*
|
|
20069
|
+
* Example usage in agent source:
|
|
20070
|
+
*
|
|
20071
|
+
* ```book
|
|
20072
|
+
* WRITING RULES Keep every response under 120 words
|
|
20073
|
+
* WRITING RULE Always end the message with an emoji
|
|
20074
|
+
* ```
|
|
20059
20075
|
*
|
|
20060
20076
|
* @private [🪔] Maybe export the commitments through some package
|
|
20061
20077
|
*/
|
|
20062
20078
|
class WritingRulesCommitmentDefinition extends BaseCommitmentDefinition {
|
|
20063
|
-
constructor() {
|
|
20064
|
-
super(
|
|
20079
|
+
constructor(type = 'WRITING RULES') {
|
|
20080
|
+
super(type);
|
|
20065
20081
|
}
|
|
20066
20082
|
/**
|
|
20067
|
-
* Short one-line description of `WRITING RULES`.
|
|
20083
|
+
* Short one-line description of `WRITING RULES`/`WRITING RULE`.
|
|
20068
20084
|
*/
|
|
20069
20085
|
get description() {
|
|
20070
20086
|
return 'Add writing-only constraints such as tone, length, formatting, or emoji usage.';
|
|
20071
20087
|
}
|
|
20072
20088
|
/**
|
|
20073
|
-
* Icon for `WRITING RULES`.
|
|
20089
|
+
* Icon for `WRITING RULES`/`WRITING RULE`.
|
|
20074
20090
|
*/
|
|
20075
20091
|
get icon() {
|
|
20076
20092
|
return '📝';
|
|
20077
20093
|
}
|
|
20078
20094
|
/**
|
|
20079
|
-
* Markdown documentation for `WRITING RULES
|
|
20095
|
+
* Markdown documentation for `WRITING RULES`/`WRITING RULE` commitment.
|
|
20080
20096
|
*/
|
|
20081
20097
|
get documentation() {
|
|
20082
20098
|
return spaceTrim$1(`
|
|
@@ -20086,6 +20102,7 @@ class WritingRulesCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
20086
20102
|
|
|
20087
20103
|
## Key aspects
|
|
20088
20104
|
|
|
20105
|
+
- All writing rules are treated equally regardless of singular/plural form.
|
|
20089
20106
|
- Use it for writing-only constraints such as tone, formatting, length, emoji usage, punctuation, or reading level.
|
|
20090
20107
|
- Do **not** use it for problem-solving behavior, policy, tool usage, or decision-making logic. Use \`RULE\` for that.
|
|
20091
20108
|
- Newer writing-rules blocks override conflicting earlier writing-rules blocks.
|
|
@@ -20284,7 +20301,8 @@ const COMMITMENT_REGISTRY = [
|
|
|
20284
20301
|
new LanguageCommitmentDefinition('LANGUAGE'),
|
|
20285
20302
|
new LanguageCommitmentDefinition('LANGUAGES'),
|
|
20286
20303
|
new WritingSampleCommitmentDefinition(),
|
|
20287
|
-
new WritingRulesCommitmentDefinition(),
|
|
20304
|
+
new WritingRulesCommitmentDefinition('WRITING RULES'),
|
|
20305
|
+
new WritingRulesCommitmentDefinition('WRITING RULE'),
|
|
20288
20306
|
new SampleCommitmentDefinition('SAMPLE'),
|
|
20289
20307
|
new SampleCommitmentDefinition('EXAMPLE'),
|
|
20290
20308
|
new FormatCommitmentDefinition('FORMAT'),
|
|
@@ -24133,6 +24151,12 @@ const HARNESS_DEFINITIONS = {
|
|
|
24133
24151
|
commandName: 'gemini',
|
|
24134
24152
|
npmPackageName: '@google/gemini-cli',
|
|
24135
24153
|
},
|
|
24154
|
+
'qwen-code': {
|
|
24155
|
+
harnessName: 'qwen-code',
|
|
24156
|
+
label: 'Qwen Code',
|
|
24157
|
+
commandName: 'qwen',
|
|
24158
|
+
npmPackageName: '@qwen-code/qwen-code',
|
|
24159
|
+
},
|
|
24136
24160
|
};
|
|
24137
24161
|
/**
|
|
24138
24162
|
* Looks up the definition of one supported CLI coding harness.
|
|
@@ -26258,6 +26282,71 @@ function uncertainNumber(value, isUncertain) {
|
|
|
26258
26282
|
return { value };
|
|
26259
26283
|
}
|
|
26260
26284
|
|
|
26285
|
+
/**
|
|
26286
|
+
* An estimation of how many characters are in one token.
|
|
26287
|
+
*/
|
|
26288
|
+
const CHARS_PER_TOKEN = 4;
|
|
26289
|
+
/**
|
|
26290
|
+
* Estimates the usage of one harness run from the length of its prompt and its output.
|
|
26291
|
+
*
|
|
26292
|
+
* Harnesses which do not report their own token counts are billed per token anyway, so the
|
|
26293
|
+
* character counts are the only signal available for a price estimate.
|
|
26294
|
+
*/
|
|
26295
|
+
function estimateUsageFromTextLength(options) {
|
|
26296
|
+
const { harnessLabel, prompt, output, resolvePricing } = options;
|
|
26297
|
+
try {
|
|
26298
|
+
const pricing = resolvePricing();
|
|
26299
|
+
const inputTokens = Math.ceil(prompt.length / CHARS_PER_TOKEN);
|
|
26300
|
+
const outputTokens = Math.ceil(output.length / CHARS_PER_TOKEN);
|
|
26301
|
+
const price = uncertainNumber((inputTokens / 1000000) * pricing.input + (outputTokens / 1000000) * pricing.output);
|
|
26302
|
+
return {
|
|
26303
|
+
...UNCERTAIN_USAGE,
|
|
26304
|
+
price,
|
|
26305
|
+
input: {
|
|
26306
|
+
...UNCERTAIN_USAGE.input,
|
|
26307
|
+
tokensCount: uncertainNumber(inputTokens),
|
|
26308
|
+
},
|
|
26309
|
+
output: {
|
|
26310
|
+
...UNCERTAIN_USAGE.output,
|
|
26311
|
+
tokensCount: uncertainNumber(outputTokens),
|
|
26312
|
+
},
|
|
26313
|
+
};
|
|
26314
|
+
}
|
|
26315
|
+
catch (error) {
|
|
26316
|
+
console.error(colors.bgRed(`Error parsing ${harnessLabel} usage output:`), error);
|
|
26317
|
+
return UNCERTAIN_USAGE;
|
|
26318
|
+
}
|
|
26319
|
+
}
|
|
26320
|
+
|
|
26321
|
+
/**
|
|
26322
|
+
* Resolves the pricing of one model of one harness.
|
|
26323
|
+
*
|
|
26324
|
+
* It first tries exact match, then prefix match, then falls back to the pricing of a stable
|
|
26325
|
+
* default model, because every harness names new models faster than the pricing tables grow.
|
|
26326
|
+
*/
|
|
26327
|
+
function resolveModelPricing(options) {
|
|
26328
|
+
var _a;
|
|
26329
|
+
const { pricingTable, modelNameForEstimation, modelName } = options;
|
|
26330
|
+
const fallbackPricing = pricingTable[modelNameForEstimation];
|
|
26331
|
+
if (fallbackPricing === undefined) {
|
|
26332
|
+
throw new UnexpectedError(spaceTrim(`
|
|
26333
|
+
Missing pricing of the model \`${modelNameForEstimation}\` used for price estimation.
|
|
26334
|
+
|
|
26335
|
+
**The model used for estimation must always be listed in its own pricing table.**
|
|
26336
|
+
`));
|
|
26337
|
+
}
|
|
26338
|
+
if (!modelName) {
|
|
26339
|
+
return fallbackPricing;
|
|
26340
|
+
}
|
|
26341
|
+
const exactMatch = pricingTable[modelName];
|
|
26342
|
+
if (exactMatch) {
|
|
26343
|
+
return exactMatch;
|
|
26344
|
+
}
|
|
26345
|
+
const prefixMatch = (_a = Object.entries(pricingTable).find(([knownModelName]) => modelName.startsWith(knownModelName))) === null || _a === void 0 ? void 0 : _a[1];
|
|
26346
|
+
return prefixMatch !== null && prefixMatch !== void 0 ? prefixMatch : fallbackPricing;
|
|
26347
|
+
}
|
|
26348
|
+
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
26349
|
+
|
|
26261
26350
|
/**
|
|
26262
26351
|
* The pricing for Gemini models per 1 million tokens in USD.
|
|
26263
26352
|
*
|
|
@@ -26277,27 +26366,14 @@ const GEMINI_PRICING = {
|
|
|
26277
26366
|
const GEMINI_MODEL_FOR_ESTIMATION = 'gemini-1.5-flash';
|
|
26278
26367
|
/**
|
|
26279
26368
|
* Resolves Gemini pricing for the requested model.
|
|
26280
|
-
*
|
|
26281
|
-
* It first tries exact match, then prefix match, then falls back to a stable
|
|
26282
|
-
* default pricing model.
|
|
26283
26369
|
*/
|
|
26284
26370
|
function resolveGeminiPricing(modelName) {
|
|
26285
|
-
|
|
26286
|
-
|
|
26287
|
-
|
|
26288
|
-
|
|
26289
|
-
}
|
|
26290
|
-
const exactMatch = GEMINI_PRICING[modelName];
|
|
26291
|
-
if (exactMatch) {
|
|
26292
|
-
return exactMatch;
|
|
26293
|
-
}
|
|
26294
|
-
const prefixMatch = (_a = Object.entries(GEMINI_PRICING).find(([knownModel]) => modelName.startsWith(knownModel))) === null || _a === void 0 ? void 0 : _a[1];
|
|
26295
|
-
return prefixMatch !== null && prefixMatch !== void 0 ? prefixMatch : fallbackPricing;
|
|
26371
|
+
return resolveModelPricing({
|
|
26372
|
+
pricingTable: GEMINI_PRICING,
|
|
26373
|
+
modelNameForEstimation: GEMINI_MODEL_FOR_ESTIMATION,
|
|
26374
|
+
modelName,
|
|
26375
|
+
});
|
|
26296
26376
|
}
|
|
26297
|
-
/**
|
|
26298
|
-
* A an estimation of how many characters are in one token.
|
|
26299
|
-
*/
|
|
26300
|
-
const CHARS_PER_TOKEN = 4;
|
|
26301
26377
|
|
|
26302
26378
|
/**
|
|
26303
26379
|
* Parses Gemini CLI output and extracts usage information.
|
|
@@ -26307,28 +26383,12 @@ const CHARS_PER_TOKEN = 4;
|
|
|
26307
26383
|
* @param modelName The Gemini model used for this run.
|
|
26308
26384
|
*/
|
|
26309
26385
|
function parseGeminiUsageFromOutput(output, prompt, modelName) {
|
|
26310
|
-
|
|
26311
|
-
|
|
26312
|
-
|
|
26313
|
-
|
|
26314
|
-
|
|
26315
|
-
|
|
26316
|
-
...UNCERTAIN_USAGE,
|
|
26317
|
-
price,
|
|
26318
|
-
input: {
|
|
26319
|
-
...UNCERTAIN_USAGE.input,
|
|
26320
|
-
tokensCount: uncertainNumber(inputTokens),
|
|
26321
|
-
},
|
|
26322
|
-
output: {
|
|
26323
|
-
...UNCERTAIN_USAGE.output,
|
|
26324
|
-
tokensCount: uncertainNumber(outputTokens),
|
|
26325
|
-
},
|
|
26326
|
-
};
|
|
26327
|
-
}
|
|
26328
|
-
catch (error) {
|
|
26329
|
-
console.error(colors.bgRed('Error parsing Gemini usage output:'), error);
|
|
26330
|
-
return UNCERTAIN_USAGE;
|
|
26331
|
-
}
|
|
26386
|
+
return estimateUsageFromTextLength({
|
|
26387
|
+
harnessLabel: 'Gemini',
|
|
26388
|
+
prompt,
|
|
26389
|
+
output,
|
|
26390
|
+
resolvePricing: () => resolveGeminiPricing(modelName),
|
|
26391
|
+
});
|
|
26332
26392
|
}
|
|
26333
26393
|
|
|
26334
26394
|
/**
|
|
@@ -27716,6 +27776,114 @@ class OpencodeRunner {
|
|
|
27716
27776
|
}
|
|
27717
27777
|
}
|
|
27718
27778
|
|
|
27779
|
+
/**
|
|
27780
|
+
* Delimiter used for passing large prompts to the Qwen Code CLI.
|
|
27781
|
+
*/
|
|
27782
|
+
const QWEN_CODE_PROMPT_DELIMITER = 'QWEN_CODE_PROMPT';
|
|
27783
|
+
/**
|
|
27784
|
+
* Builds the shell script that runs Qwen Code with the prompt and coding context.
|
|
27785
|
+
*
|
|
27786
|
+
* Note: `-y` runs the harness unattended, because `ptbk coder` approves the whole prompt
|
|
27787
|
+
* up front and there is nobody at the keyboard to confirm the single tool calls.
|
|
27788
|
+
*/
|
|
27789
|
+
function buildQwenCodeScript(options) {
|
|
27790
|
+
return spaceTrim((block) => `
|
|
27791
|
+
qwen -y -m ${options.model} -p "$(cat <<'${QWEN_CODE_PROMPT_DELIMITER}'
|
|
27792
|
+
|
|
27793
|
+
${block(options.prompt)}
|
|
27794
|
+
|
|
27795
|
+
${QWEN_CODE_PROMPT_DELIMITER}
|
|
27796
|
+
)"
|
|
27797
|
+
`);
|
|
27798
|
+
}
|
|
27799
|
+
|
|
27800
|
+
/**
|
|
27801
|
+
* The pricing for Qwen Code models per 1 million tokens in USD.
|
|
27802
|
+
*
|
|
27803
|
+
* Note: This is an estimation.
|
|
27804
|
+
*
|
|
27805
|
+
* @see https://www.alibabacloud.com/help/en/model-studio/models
|
|
27806
|
+
*/
|
|
27807
|
+
const QWEN_CODE_PRICING = {
|
|
27808
|
+
'qwen3-coder-plus': {
|
|
27809
|
+
input: 1,
|
|
27810
|
+
output: 5,
|
|
27811
|
+
},
|
|
27812
|
+
'qwen3-coder-flash': {
|
|
27813
|
+
input: 0.3,
|
|
27814
|
+
output: 1.5,
|
|
27815
|
+
},
|
|
27816
|
+
'qwen3-max': {
|
|
27817
|
+
input: 1.2,
|
|
27818
|
+
output: 6,
|
|
27819
|
+
},
|
|
27820
|
+
};
|
|
27821
|
+
/**
|
|
27822
|
+
* The model to use for price estimation.
|
|
27823
|
+
*/
|
|
27824
|
+
const QWEN_CODE_MODEL_FOR_ESTIMATION = 'qwen3-coder-plus';
|
|
27825
|
+
/**
|
|
27826
|
+
* Resolves Qwen Code pricing for the requested model.
|
|
27827
|
+
*/
|
|
27828
|
+
function resolveQwenCodePricing(modelName) {
|
|
27829
|
+
return resolveModelPricing({
|
|
27830
|
+
pricingTable: QWEN_CODE_PRICING,
|
|
27831
|
+
modelNameForEstimation: QWEN_CODE_MODEL_FOR_ESTIMATION,
|
|
27832
|
+
modelName,
|
|
27833
|
+
});
|
|
27834
|
+
}
|
|
27835
|
+
|
|
27836
|
+
/**
|
|
27837
|
+
* Parses Qwen Code CLI output and extracts usage information.
|
|
27838
|
+
*
|
|
27839
|
+
* @param output The output from the Qwen Code CLI.
|
|
27840
|
+
* @param prompt The prompt that was sent to the Qwen Code CLI.
|
|
27841
|
+
* @param modelName The Qwen Code model used for this run.
|
|
27842
|
+
*/
|
|
27843
|
+
function parseQwenCodeUsageFromOutput(output, prompt, modelName) {
|
|
27844
|
+
return estimateUsageFromTextLength({
|
|
27845
|
+
harnessLabel: 'Qwen Code',
|
|
27846
|
+
prompt,
|
|
27847
|
+
output,
|
|
27848
|
+
resolvePricing: () => resolveQwenCodePricing(modelName),
|
|
27849
|
+
});
|
|
27850
|
+
}
|
|
27851
|
+
|
|
27852
|
+
/**
|
|
27853
|
+
* Default Qwen Code model used by the coding runner.
|
|
27854
|
+
*/
|
|
27855
|
+
const DEFAULT_QWEN_CODE_MODEL = 'qwen3.8-max';
|
|
27856
|
+
/**
|
|
27857
|
+
* Runs prompts via the Qwen Code CLI.
|
|
27858
|
+
*/
|
|
27859
|
+
class QwenCodeRunner {
|
|
27860
|
+
/**
|
|
27861
|
+
* Creates a new Qwen Code runner.
|
|
27862
|
+
*/
|
|
27863
|
+
constructor(options) {
|
|
27864
|
+
this.options = options;
|
|
27865
|
+
this.name = 'qwen-code';
|
|
27866
|
+
}
|
|
27867
|
+
/**
|
|
27868
|
+
* Runs the prompt using Qwen Code and parses usage output.
|
|
27869
|
+
*/
|
|
27870
|
+
async runPrompt(options) {
|
|
27871
|
+
const scriptContent = buildQwenCodeScript({
|
|
27872
|
+
prompt: options.prompt,
|
|
27873
|
+
model: this.options.model,
|
|
27874
|
+
});
|
|
27875
|
+
const output = await $runGoScriptWithOutput({
|
|
27876
|
+
scriptPath: options.scriptPath,
|
|
27877
|
+
scriptContent,
|
|
27878
|
+
logPath: options.logPath,
|
|
27879
|
+
shouldPrintLiveOutput: options.shouldPrintLiveOutput,
|
|
27880
|
+
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
27881
|
+
});
|
|
27882
|
+
const usage = parseQwenCodeUsageFromOutput(output, options.prompt, this.options.model);
|
|
27883
|
+
return { usage };
|
|
27884
|
+
}
|
|
27885
|
+
}
|
|
27886
|
+
|
|
27719
27887
|
/**
|
|
27720
27888
|
* Constant for default codex model.
|
|
27721
27889
|
*/
|
|
@@ -27724,6 +27892,11 @@ const DEFAULT_CODEX_MODEL = 'gpt-5.2-codex';
|
|
|
27724
27892
|
* Constant for cline model.
|
|
27725
27893
|
*/
|
|
27726
27894
|
const CLINE_MODEL = 'gemini:gemini-3-flash-preview';
|
|
27895
|
+
/**
|
|
27896
|
+
* Harnesses which refuse to run without an explicit `--model`, because they expose many models
|
|
27897
|
+
* of very different capability and price and never pick a sensible one on their own.
|
|
27898
|
+
*/
|
|
27899
|
+
const MODEL_REQUIRING_HARNESS_NAMES = ['openai-codex', 'gemini', 'qwen-code'];
|
|
27727
27900
|
/**
|
|
27728
27901
|
* Resolves the configured prompt runner together with status-line metadata.
|
|
27729
27902
|
*
|
|
@@ -27761,6 +27934,9 @@ function resolvePromptRunner(options) {
|
|
|
27761
27934
|
if (agentName === 'gemini') {
|
|
27762
27935
|
return createGeminiRunnerResolution(options);
|
|
27763
27936
|
}
|
|
27937
|
+
if (agentName === 'qwen-code') {
|
|
27938
|
+
return createQwenCodeRunnerResolution(options);
|
|
27939
|
+
}
|
|
27764
27940
|
throw new Error(`Unknown harness: ${agentName}`);
|
|
27765
27941
|
}
|
|
27766
27942
|
/**
|
|
@@ -27802,6 +27978,23 @@ function createGeminiRunnerResolution(options) {
|
|
|
27802
27978
|
model: actualRunnerModel,
|
|
27803
27979
|
}), actualRunnerModel);
|
|
27804
27980
|
}
|
|
27981
|
+
/**
|
|
27982
|
+
* Builds the Qwen Code CLI runner resolution, including required-model validation.
|
|
27983
|
+
*/
|
|
27984
|
+
function createQwenCodeRunnerResolution(options) {
|
|
27985
|
+
const actualRunnerModel = resolveRequiredModel({
|
|
27986
|
+
agentName: 'qwen-code',
|
|
27987
|
+
providedModel: options.model,
|
|
27988
|
+
defaultModel: DEFAULT_QWEN_CODE_MODEL,
|
|
27989
|
+
exampleUsages: [
|
|
27990
|
+
`--harness qwen-code --model ${DEFAULT_QWEN_CODE_MODEL}`,
|
|
27991
|
+
'--harness qwen-code --model default',
|
|
27992
|
+
],
|
|
27993
|
+
});
|
|
27994
|
+
return createRunnerResolution(options, new QwenCodeRunner({
|
|
27995
|
+
model: actualRunnerModel,
|
|
27996
|
+
}), actualRunnerModel);
|
|
27997
|
+
}
|
|
27805
27998
|
/**
|
|
27806
27999
|
* Combines the instantiated runner with prompt status metadata.
|
|
27807
28000
|
*/
|
|
@@ -27817,9 +28010,7 @@ function createRunnerResolution(options, runner, actualRunnerModel) {
|
|
|
27817
28010
|
*/
|
|
27818
28011
|
function getRunnerMetadata(options, actualRunnerModel) {
|
|
27819
28012
|
const runnerName = options.agentName ? getHarnessDefinition(options.agentName).label : 'unknown';
|
|
27820
|
-
if (options.agentName === '
|
|
27821
|
-
options.agentName === 'github-copilot' ||
|
|
27822
|
-
options.agentName === 'gemini') {
|
|
28013
|
+
if (options.agentName === 'github-copilot' || isModelRequiringHarnessName(options.agentName)) {
|
|
27823
28014
|
return { runnerName, modelName: actualRunnerModel };
|
|
27824
28015
|
}
|
|
27825
28016
|
if (options.agentName === 'cline') {
|
|
@@ -27830,6 +28021,12 @@ function getRunnerMetadata(options, actualRunnerModel) {
|
|
|
27830
28021
|
}
|
|
27831
28022
|
return { runnerName };
|
|
27832
28023
|
}
|
|
28024
|
+
/**
|
|
28025
|
+
* Checks whether one harness refuses to run without an explicit `--model`.
|
|
28026
|
+
*/
|
|
28027
|
+
function isModelRequiringHarnessName(agentName) {
|
|
28028
|
+
return MODEL_REQUIRING_HARNESS_NAMES.includes(agentName);
|
|
28029
|
+
}
|
|
27833
28030
|
/**
|
|
27834
28031
|
* Resolves a runner model, allowing `default` but otherwise requiring an explicit value.
|
|
27835
28032
|
*/
|
|
@@ -39981,7 +40178,7 @@ function updateAgentRunUiForPulling(uiHandle, queueSnapshot, statusMessage) {
|
|
|
39981
40178
|
*/
|
|
39982
40179
|
function validateAgentRunOptions(options) {
|
|
39983
40180
|
if (!options.agentName) {
|
|
39984
|
-
throw new NotAllowed(
|
|
40181
|
+
throw new NotAllowed(`You must choose a harness using ${PROMPT_RUNNER_HARNESS_OPTION_HINT}.`);
|
|
39985
40182
|
}
|
|
39986
40183
|
if (options.autoPull && options.noCommit) {
|
|
39987
40184
|
throw new NotAllowed(spaceTrim$1(`
|
|
@@ -74653,7 +74850,7 @@ function parseRunOptions(args) {
|
|
|
74653
74850
|
exitWithUsageError(error instanceof Error ? error.message : String(error));
|
|
74654
74851
|
}
|
|
74655
74852
|
if (!agentName && !dryRun) {
|
|
74656
|
-
exitWithUsageError(
|
|
74853
|
+
exitWithUsageError(`You must choose a harness using ${PROMPT_RUNNER_HARNESS_OPTION_HINT}`);
|
|
74657
74854
|
}
|
|
74658
74855
|
return {
|
|
74659
74856
|
dryRun,
|