@promptbook/cli 0.112.0-41 → 0.112.0-43
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 +10 -3
- package/esm/apps/agents-server/src/database/acquireMigrationExecutionLock.d.ts +12 -1
- package/esm/apps/agents-server/src/database/runDatabaseMigrations.d.ts +9 -0
- package/esm/index.es.js +1218 -114
- package/esm/index.es.js.map +1 -1
- package/esm/scripts/run-codex-prompts/common/formatUnknownErrorDetails.d.ts +4 -0
- package/esm/scripts/run-codex-prompts/common/waitForPause.d.ts +21 -1
- package/esm/scripts/run-codex-prompts/git/commitChanges.d.ts +2 -2
- package/esm/scripts/run-codex-prompts/prompts/formatPromptAttemptMetadata.d.ts +4 -0
- package/esm/scripts/run-codex-prompts/prompts/markPromptDone.d.ts +1 -1
- package/esm/scripts/run-codex-prompts/prompts/markPromptFailed.d.ts +1 -1
- package/esm/scripts/run-codex-prompts/testing/runPromptTestCommand.d.ts +13 -0
- package/esm/scripts/run-codex-prompts/testing/runPromptWithTestFeedback.d.ts +25 -0
- package/esm/scripts/run-codex-prompts/ui/CoderRunUiState.d.ts +112 -0
- package/esm/scripts/run-codex-prompts/ui/renderCoderRunUi.d.ts +30 -0
- package/esm/scripts/verify-prompts/verify-prompts.d.ts +23 -2
- package/esm/src/book-components/Chat/Chat/ChatProps.d.ts +1 -1
- package/esm/src/cli/cli-commands/coder/getTypescriptModule.d.ts +19 -0
- package/esm/src/cli/cli-commands/coder/getTypescriptModule.test.d.ts +1 -0
- package/esm/src/cli/cli-commands/coder/mergeStringRecordJsonFile.test.d.ts +1 -0
- package/esm/src/cli/cli-commands/coder/verify.test.d.ts +1 -0
- package/esm/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.d.ts +2 -14
- package/esm/src/collection/agent-collection/constructors/agent-collection-in-supabase/createAgentPersistenceRecords.d.ts +40 -0
- package/esm/src/collection/agent-collection/constructors/agent-collection-in-supabase/createAgentPersistenceRecords.test.d.ts +1 -0
- package/esm/src/llm-providers/agent/Agent.test.d.ts +1 -0
- package/esm/src/llm-providers/agent/AgentLlmExecutionTools.d.ts +4 -0
- package/esm/src/llm-providers/agent/AgentOptions.d.ts +8 -0
- package/esm/src/llm-providers/agent/CreateAgentLlmExecutionToolsOptions.d.ts +9 -0
- package/esm/src/version.d.ts +1 -1
- package/package.json +3 -2
- package/umd/apps/agents-server/src/database/acquireMigrationExecutionLock.d.ts +12 -1
- package/umd/apps/agents-server/src/database/runDatabaseMigrations.d.ts +9 -0
- package/umd/index.umd.js +1221 -118
- package/umd/index.umd.js.map +1 -1
- package/umd/scripts/run-codex-prompts/common/formatUnknownErrorDetails.d.ts +4 -0
- package/umd/scripts/run-codex-prompts/common/waitForPause.d.ts +21 -1
- package/umd/scripts/run-codex-prompts/git/commitChanges.d.ts +2 -2
- package/umd/scripts/run-codex-prompts/prompts/formatPromptAttemptMetadata.d.ts +4 -0
- package/umd/scripts/run-codex-prompts/prompts/markPromptDone.d.ts +1 -1
- package/umd/scripts/run-codex-prompts/prompts/markPromptFailed.d.ts +1 -1
- package/umd/scripts/run-codex-prompts/testing/runPromptTestCommand.d.ts +13 -0
- package/umd/scripts/run-codex-prompts/testing/runPromptWithTestFeedback.d.ts +25 -0
- package/umd/scripts/run-codex-prompts/ui/CoderRunUiState.d.ts +112 -0
- package/umd/scripts/run-codex-prompts/ui/renderCoderRunUi.d.ts +30 -0
- package/umd/scripts/verify-prompts/verify-prompts.d.ts +23 -2
- package/umd/src/book-components/Chat/Chat/ChatProps.d.ts +1 -1
- package/umd/src/cli/cli-commands/coder/getTypescriptModule.d.ts +19 -0
- package/umd/src/cli/cli-commands/coder/getTypescriptModule.test.d.ts +1 -0
- package/umd/src/cli/cli-commands/coder/mergeStringRecordJsonFile.test.d.ts +1 -0
- package/umd/src/cli/cli-commands/coder/verify.test.d.ts +1 -0
- package/umd/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.d.ts +2 -14
- package/umd/src/collection/agent-collection/constructors/agent-collection-in-supabase/createAgentPersistenceRecords.d.ts +40 -0
- package/umd/src/collection/agent-collection/constructors/agent-collection-in-supabase/createAgentPersistenceRecords.test.d.ts +1 -0
- package/umd/src/llm-providers/agent/Agent.test.d.ts +1 -0
- package/umd/src/llm-providers/agent/AgentLlmExecutionTools.d.ts +4 -0
- package/umd/src/llm-providers/agent/AgentOptions.d.ts +8 -0
- package/umd/src/llm-providers/agent/CreateAgentLlmExecutionToolsOptions.d.ts +9 -0
- package/umd/src/version.d.ts +1 -1
package/esm/index.es.js
CHANGED
|
@@ -37,6 +37,7 @@ import { spawn } from 'child_process';
|
|
|
37
37
|
import { Client } from 'pg';
|
|
38
38
|
import '@supabase/supabase-js';
|
|
39
39
|
import { dirname as dirname$1 } from 'path/posix';
|
|
40
|
+
import { EventEmitter } from 'events';
|
|
40
41
|
import { Subject, BehaviorSubject } from 'rxjs';
|
|
41
42
|
import { lookup, extension } from 'mime-types';
|
|
42
43
|
import { parse, unparse } from 'papaparse';
|
|
@@ -57,7 +58,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
|
|
|
57
58
|
* @generated
|
|
58
59
|
* @see https://github.com/webgptorg/promptbook
|
|
59
60
|
*/
|
|
60
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.112.0-
|
|
61
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.112.0-43';
|
|
61
62
|
/**
|
|
62
63
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
63
64
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -2320,7 +2321,7 @@ function getDefaultCoderAgentCodingFileContent({ packageJsonScripts, }) {
|
|
|
2320
2321
|
'',
|
|
2321
2322
|
'## Customizing the workflow',
|
|
2322
2323
|
'- Edit `package.json` if you want `npm run coder:run` to use another coding agent, model, thinking level, context file, or wait mode.',
|
|
2323
|
-
'- Use direct CLI commands when you need one-off flags such as `--priority`, `--ignore-git-changes`, `--dry-run`, `--allow-credits`, or `--auto-migrate`.',
|
|
2324
|
+
'- Use direct CLI commands when you need one-off flags such as `--priority`, `--ignore-git-changes`, `--dry-run`, `--test`, `--allow-credits`, or `--auto-migrate`.',
|
|
2324
2325
|
'- Use `npx ptbk coder --help` and `npx ptbk coder <command> --help` for the full CLI reference.',
|
|
2325
2326
|
].join('\n');
|
|
2326
2327
|
}
|
|
@@ -2580,6 +2581,26 @@ class ParseError extends Error {
|
|
|
2580
2581
|
}
|
|
2581
2582
|
// TODO: Maybe split `ParseError` and `ApplyError`
|
|
2582
2583
|
|
|
2584
|
+
/**
|
|
2585
|
+
* Loads the TypeScript runtime used for parsing JSONC-style project files.
|
|
2586
|
+
*
|
|
2587
|
+
* @private internal utility of `coder init`
|
|
2588
|
+
*/
|
|
2589
|
+
async function getTypescriptModule() {
|
|
2590
|
+
return normalizeImportedTypescriptModule((await import('typescript')));
|
|
2591
|
+
}
|
|
2592
|
+
/**
|
|
2593
|
+
* Normalizes CommonJS-via-`default` and direct namespace imports of TypeScript.
|
|
2594
|
+
*
|
|
2595
|
+
* @private internal utility of `getTypescriptModule`
|
|
2596
|
+
*/
|
|
2597
|
+
function normalizeImportedTypescriptModule(importedTypescriptModule) {
|
|
2598
|
+
return 'parseConfigFileTextToJson' in importedTypescriptModule
|
|
2599
|
+
? importedTypescriptModule
|
|
2600
|
+
: importedTypescriptModule.default;
|
|
2601
|
+
}
|
|
2602
|
+
// Note: [🟡] Code for coder init TypeScript loading [getTypescriptModule](src/cli/cli-commands/coder/getTypescriptModule.ts) should never be published outside of `@promptbook/cli`
|
|
2603
|
+
|
|
2583
2604
|
/**
|
|
2584
2605
|
* Default indentation used when creating new JSON configuration files.
|
|
2585
2606
|
*/
|
|
@@ -2625,7 +2646,7 @@ async function parseJsonObjectFile(relativeFilePath, fileContent) {
|
|
|
2625
2646
|
if (fileContent.trim() === '') {
|
|
2626
2647
|
return {};
|
|
2627
2648
|
}
|
|
2628
|
-
const typescript = await
|
|
2649
|
+
const typescript = await getTypescriptModule();
|
|
2629
2650
|
const parsedFile = typescript.parseConfigFileTextToJson(relativeFilePath, fileContent);
|
|
2630
2651
|
if (parsedFile.error) {
|
|
2631
2652
|
throw new ParseError(spaceTrim$1(`
|
|
@@ -2983,7 +3004,9 @@ function $initializeCoderRunCommand(program) {
|
|
|
2983
3004
|
|
|
2984
3005
|
Features:
|
|
2985
3006
|
- Automatically stages and commits changes with agent identity
|
|
3007
|
+
- Optional post-commit git push with explicit --auto-push opt-in
|
|
2986
3008
|
- Supports GPG signing of commits
|
|
3009
|
+
- Optional post-prompt verification with test-feedback retries
|
|
2987
3010
|
- Progress tracking and interactive controls
|
|
2988
3011
|
- Dry-run mode to preview prompts
|
|
2989
3012
|
`));
|
|
@@ -2996,17 +3019,19 @@ function $initializeCoderRunCommand(program) {
|
|
|
2996
3019
|
Gemini examples: gemini-3-flash-preview, default
|
|
2997
3020
|
`));
|
|
2998
3021
|
command.option('--context <context-or-file>', 'Append extra instructions either inline or from a file path relative to the current project');
|
|
3022
|
+
command.option('--test <test-command...>', 'Run a verification command after each prompt; quote it when the command itself contains top-level flags');
|
|
2999
3023
|
command.addOption(new Option('--thinking-level <thinking-level>', `Set reasoning effort for supported runners (${THINKING_LEVEL_VALUES.join(', ')})`).choices([...THINKING_LEVEL_VALUES]));
|
|
3000
3024
|
command.option('--priority <minimum-priority>', 'Filter prompts by minimum priority level', parseIntOption, 0);
|
|
3001
3025
|
command.option('--no-wait', 'Skip user prompts between processing');
|
|
3002
3026
|
command.option('--ignore-git-changes', 'Skip clean working tree check before running prompts', false);
|
|
3003
3027
|
command.option('--allow-credits', 'Allow OpenAI Codex runner to spend credits when rate limits are exhausted', false);
|
|
3004
3028
|
command.option('--no-normalize-line-endings', 'Disable automatic LF normalization for files changed in each coding round');
|
|
3005
|
-
command.option('--
|
|
3029
|
+
command.option('--auto-push', 'Automatically git push after each commit', false);
|
|
3006
3030
|
command.option('--auto-migrate', 'Run testing-server database migrations automatically after each successfully processed prompt');
|
|
3007
3031
|
command.option('--allow-destructive-auto-migrate', 'Allow auto-migrate even when heuristic SQL safety check flags destructive pending migrations');
|
|
3008
3032
|
command.action(handleActionErrors(async (cliOptions) => {
|
|
3009
|
-
const { dryRun, agent, model, context, thinkingLevel, priority, wait, ignoreGitChanges, allowCredits, normalizeLineEndings, autoMigrate, allowDestructiveAutoMigrate,
|
|
3033
|
+
const { dryRun, agent, model, context, test, thinkingLevel, priority, wait, ignoreGitChanges, allowCredits, normalizeLineEndings, autoMigrate, allowDestructiveAutoMigrate, autoPush, } = cliOptions;
|
|
3034
|
+
const testCommand = normalizeCommandOptionValue(test);
|
|
3010
3035
|
// Validate agent
|
|
3011
3036
|
let agentName = undefined;
|
|
3012
3037
|
if (agent) {
|
|
@@ -3035,13 +3060,14 @@ function $initializeCoderRunCommand(program) {
|
|
|
3035
3060
|
agentName,
|
|
3036
3061
|
model,
|
|
3037
3062
|
context,
|
|
3063
|
+
testCommand,
|
|
3038
3064
|
thinkingLevel,
|
|
3039
3065
|
priority,
|
|
3040
3066
|
normalizeLineEndings,
|
|
3041
3067
|
allowCredits,
|
|
3042
3068
|
autoMigrate,
|
|
3043
3069
|
allowDestructiveAutoMigrate,
|
|
3044
|
-
|
|
3070
|
+
autoPush,
|
|
3045
3071
|
};
|
|
3046
3072
|
// Note: Import the function dynamically to avoid loading heavy dependencies until needed
|
|
3047
3073
|
const { runCodexPrompts } = await Promise.resolve().then(function () { return runCodexPrompts$1; });
|
|
@@ -3070,6 +3096,19 @@ function parseIntOption(value) {
|
|
|
3070
3096
|
}
|
|
3071
3097
|
return parsed;
|
|
3072
3098
|
}
|
|
3099
|
+
/**
|
|
3100
|
+
* Joins one Commander option that may be parsed either as a single string or a variadic token array.
|
|
3101
|
+
*
|
|
3102
|
+
* @private internal utility of `coder run` command
|
|
3103
|
+
*/
|
|
3104
|
+
function normalizeCommandOptionValue(value) {
|
|
3105
|
+
if (value === undefined) {
|
|
3106
|
+
return undefined;
|
|
3107
|
+
}
|
|
3108
|
+
const parts = Array.isArray(value) ? value : [value];
|
|
3109
|
+
const normalizedValue = parts.map((part) => part.trim()).filter(Boolean).join(' ').trim();
|
|
3110
|
+
return normalizedValue === '' ? undefined : normalizedValue;
|
|
3111
|
+
}
|
|
3073
3112
|
// Note: [🟡] Code for CLI command [run](src/cli/cli-commands/coder/run.ts) should never be published outside of `@promptbook/cli`
|
|
3074
3113
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
3075
3114
|
|
|
@@ -3091,14 +3130,16 @@ function $initializeCoderVerifyCommand(program) {
|
|
|
3091
3130
|
- Archives verified prompt files to prompts/done/ directory
|
|
3092
3131
|
- Auto-appends repair prompts for incomplete work
|
|
3093
3132
|
- Processes files with all-done prompts first
|
|
3133
|
+
- Supports ignoring matching prompt candidates for one verification run
|
|
3094
3134
|
`));
|
|
3095
3135
|
command.option('--reverse', 'Process prompt files in reverse order', false);
|
|
3136
|
+
command.option('--ignore <candidate-text>', 'Ignore prompt files whose filename or first prompt line contains the given text (repeatable)', collectStringOption, []);
|
|
3096
3137
|
command.action(handleActionErrors(async (cliOptions) => {
|
|
3097
|
-
const { reverse } = cliOptions;
|
|
3138
|
+
const { reverse, ignore } = cliOptions;
|
|
3098
3139
|
// Note: Import the main function dynamically to avoid loading heavy dependencies until needed
|
|
3099
3140
|
const { verifyPrompts } = await Promise.resolve().then(function () { return verifyPrompts$1; });
|
|
3100
3141
|
try {
|
|
3101
|
-
await verifyPrompts(reverse);
|
|
3142
|
+
await verifyPrompts({ reverse, ignore });
|
|
3102
3143
|
}
|
|
3103
3144
|
catch (error) {
|
|
3104
3145
|
console.error(colors.bgRed('Prompt verification failed:'), error);
|
|
@@ -3107,6 +3148,14 @@ function $initializeCoderVerifyCommand(program) {
|
|
|
3107
3148
|
return process.exit(0);
|
|
3108
3149
|
}));
|
|
3109
3150
|
}
|
|
3151
|
+
/**
|
|
3152
|
+
* Collects repeatable string options from Commander.
|
|
3153
|
+
*
|
|
3154
|
+
* @private internal utility of `coder verify` command
|
|
3155
|
+
*/
|
|
3156
|
+
function collectStringOption(value, previousValues) {
|
|
3157
|
+
return [...previousValues, value];
|
|
3158
|
+
}
|
|
3110
3159
|
// Note: [🟡] Code for CLI command [verify](src/cli/cli-commands/coder/verify.ts) should never be published outside of `@promptbook/cli`
|
|
3111
3160
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
3112
3161
|
|
|
@@ -22546,6 +22595,15 @@ const teamToolFunctions = {};
|
|
|
22546
22595
|
* Map of team tool titles.
|
|
22547
22596
|
*/
|
|
22548
22597
|
const teamToolTitles = {};
|
|
22598
|
+
/**
|
|
22599
|
+
* Shared TEAM usage rules appended ahead of teammate listings.
|
|
22600
|
+
*
|
|
22601
|
+
* @private
|
|
22602
|
+
*/
|
|
22603
|
+
const TEAM_SYSTEM_MESSAGE_GUIDANCE_LINES = [
|
|
22604
|
+
'- If a teammate is relevant to the request, consult that teammate using the matching tool.',
|
|
22605
|
+
'- Do not ask the user for information that a listed teammate can provide directly.',
|
|
22606
|
+
];
|
|
22549
22607
|
/**
|
|
22550
22608
|
* Constant for remote agents by Url.
|
|
22551
22609
|
*/
|
|
@@ -22635,12 +22693,9 @@ class TeamCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
22635
22693
|
if (updatedTools.some((tool) => tool.name === entry.toolName)) {
|
|
22636
22694
|
continue;
|
|
22637
22695
|
}
|
|
22638
|
-
const toolDescription = entry.description
|
|
22639
|
-
? `Consult teammate ${entry.teammate.label}\n${entry.description}`
|
|
22640
|
-
: `Consult teammate ${entry.teammate.label}`;
|
|
22641
22696
|
updatedTools.push({
|
|
22642
22697
|
name: entry.toolName,
|
|
22643
|
-
description:
|
|
22698
|
+
description: buildTeamToolDescription(entry),
|
|
22644
22699
|
parameters: {
|
|
22645
22700
|
type: 'object',
|
|
22646
22701
|
properties: {
|
|
@@ -22709,22 +22764,72 @@ function resolveTeamTeammateLabels(teamContent, teammates) {
|
|
|
22709
22764
|
/**
|
|
22710
22765
|
* Builds the textual TEAM section body for the final system message.
|
|
22711
22766
|
*
|
|
22712
|
-
* Each teammate is listed with its tool name
|
|
22713
|
-
* Uses `spaceTrim` to ensure consistent whitespace and indentation.
|
|
22767
|
+
* Each teammate is listed with its tool name, TEAM instructions, and optional profile hints.
|
|
22714
22768
|
*/
|
|
22715
22769
|
function buildTeamSystemMessageBody(teamEntries) {
|
|
22716
|
-
const lines =
|
|
22717
|
-
|
|
22718
|
-
|
|
22719
|
-
|
|
22720
|
-
|
|
22721
|
-
|
|
22722
|
-
|
|
22723
|
-
|
|
22724
|
-
|
|
22725
|
-
});
|
|
22770
|
+
const lines = [
|
|
22771
|
+
...TEAM_SYSTEM_MESSAGE_GUIDANCE_LINES,
|
|
22772
|
+
'',
|
|
22773
|
+
...teamEntries.map((entry, index) => {
|
|
22774
|
+
const toolLine = `${index + 1}) ${entry.teammate.label} tool \`${entry.toolName}\``;
|
|
22775
|
+
const detailLines = collectTeamEntryDetails(entry).map(formatTeamEntryDetailLine);
|
|
22776
|
+
return [toolLine, ...detailLines].join('\n');
|
|
22777
|
+
}),
|
|
22778
|
+
];
|
|
22726
22779
|
return lines.join('\n');
|
|
22727
22780
|
}
|
|
22781
|
+
/**
|
|
22782
|
+
* Builds the model-visible description for one teammate tool.
|
|
22783
|
+
*
|
|
22784
|
+
* @private
|
|
22785
|
+
*/
|
|
22786
|
+
function buildTeamToolDescription(entry) {
|
|
22787
|
+
const detailLines = collectTeamEntryDetails(entry).map(({ label, content }) => `${label}: ${content}`);
|
|
22788
|
+
return [`Consult teammate ${entry.teammate.label}`, ...detailLines].join('\n');
|
|
22789
|
+
}
|
|
22790
|
+
/**
|
|
22791
|
+
* Collects structured teammate details that should stay visible to the model.
|
|
22792
|
+
*
|
|
22793
|
+
* @private
|
|
22794
|
+
*/
|
|
22795
|
+
function collectTeamEntryDetails(entry) {
|
|
22796
|
+
var _a;
|
|
22797
|
+
const details = [];
|
|
22798
|
+
const instructions = entry.teammate.instructions.trim();
|
|
22799
|
+
const description = ((_a = entry.description) === null || _a === void 0 ? void 0 : _a.trim()) || '';
|
|
22800
|
+
if (instructions) {
|
|
22801
|
+
details.push({
|
|
22802
|
+
label: 'TEAM instructions',
|
|
22803
|
+
content: instructions,
|
|
22804
|
+
});
|
|
22805
|
+
}
|
|
22806
|
+
if (description) {
|
|
22807
|
+
details.push({
|
|
22808
|
+
label: 'Profile',
|
|
22809
|
+
content: description,
|
|
22810
|
+
});
|
|
22811
|
+
}
|
|
22812
|
+
return details;
|
|
22813
|
+
}
|
|
22814
|
+
/**
|
|
22815
|
+
* Formats one teammate detail line for the TEAM system-message section.
|
|
22816
|
+
*
|
|
22817
|
+
* @private
|
|
22818
|
+
*/
|
|
22819
|
+
function formatTeamEntryDetailLine(detail) {
|
|
22820
|
+
return indentMultilineText(`${detail.label}: ${detail.content}`, ' ');
|
|
22821
|
+
}
|
|
22822
|
+
/**
|
|
22823
|
+
* Indents all lines of one potentially multi-line text block.
|
|
22824
|
+
*
|
|
22825
|
+
* @private
|
|
22826
|
+
*/
|
|
22827
|
+
function indentMultilineText(text, prefix) {
|
|
22828
|
+
return text
|
|
22829
|
+
.split('\n')
|
|
22830
|
+
.map((line) => `${prefix}${line}`)
|
|
22831
|
+
.join('\n');
|
|
22832
|
+
}
|
|
22728
22833
|
/**
|
|
22729
22834
|
* Registers tool function and title for a teammate tool.
|
|
22730
22835
|
*/
|
|
@@ -40897,7 +41002,7 @@ function createEmptyAgentModelRequirements() {
|
|
|
40897
41002
|
systemMessage: '',
|
|
40898
41003
|
promptSuffix: '',
|
|
40899
41004
|
// modelName: 'gpt-5',
|
|
40900
|
-
modelName: '
|
|
41005
|
+
modelName: 'gpt-5.4-mini',
|
|
40901
41006
|
temperature: 0.7,
|
|
40902
41007
|
topP: 0.9,
|
|
40903
41008
|
topK: 50,
|
|
@@ -44077,7 +44182,26 @@ var findRefactorCandidates$1 = /*#__PURE__*/Object.freeze({
|
|
|
44077
44182
|
/**
|
|
44078
44183
|
* CLI usage text for this script.
|
|
44079
44184
|
*/
|
|
44080
|
-
const USAGE = 'Usage: run-codex-prompts [--dry-run] [--agent <agent-name>] [--model <model>] [--context <context-or-file>] [--thinking-level <thinking-level>] [--priority <minimum-priority>] [--allow-credits] [--auto-migrate] [--allow-destructive-auto-migrate] [--no-wait] [--ignore-git-changes] [--no-normalize-line-endings] [--
|
|
44185
|
+
const USAGE = 'Usage: run-codex-prompts [--dry-run] [--agent <agent-name>] [--model <model>] [--context <context-or-file>] [--test <test-command...>] [--thinking-level <thinking-level>] [--priority <minimum-priority>] [--allow-credits] [--auto-migrate] [--allow-destructive-auto-migrate] [--no-wait] [--ignore-git-changes] [--no-normalize-line-endings] [--auto-push]';
|
|
44186
|
+
/**
|
|
44187
|
+
* Top-level flags supported by this command.
|
|
44188
|
+
*/
|
|
44189
|
+
const KNOWN_OPTION_FLAGS = new Set([
|
|
44190
|
+
'--dry-run',
|
|
44191
|
+
'--agent',
|
|
44192
|
+
'--model',
|
|
44193
|
+
'--context',
|
|
44194
|
+
'--test',
|
|
44195
|
+
'--thinking-level',
|
|
44196
|
+
'--priority',
|
|
44197
|
+
'--allow-credits',
|
|
44198
|
+
'--auto-migrate',
|
|
44199
|
+
'--allow-destructive-auto-migrate',
|
|
44200
|
+
'--no-wait',
|
|
44201
|
+
'--ignore-git-changes',
|
|
44202
|
+
'--no-normalize-line-endings',
|
|
44203
|
+
'--auto-push',
|
|
44204
|
+
]);
|
|
44081
44205
|
/**
|
|
44082
44206
|
* Parses CLI arguments into runner options.
|
|
44083
44207
|
*/
|
|
@@ -44098,6 +44222,8 @@ function parseRunOptions(args) {
|
|
|
44098
44222
|
}
|
|
44099
44223
|
const model = readOptionValue(args, '--model');
|
|
44100
44224
|
const context = readOptionValue(args, '--context');
|
|
44225
|
+
const hasTestCommandFlag = args.includes('--test');
|
|
44226
|
+
const testCommand = readVariadicOptionValue(args, '--test');
|
|
44101
44227
|
const hasThinkingLevelFlag = args.includes('--thinking-level');
|
|
44102
44228
|
const thinkingLevelValue = readOptionValue(args, '--thinking-level');
|
|
44103
44229
|
const hasPriorityFlag = args.includes('--priority');
|
|
@@ -44107,8 +44233,11 @@ function parseRunOptions(args) {
|
|
|
44107
44233
|
const allowCredits = args.includes('--allow-credits');
|
|
44108
44234
|
const autoMigrate = args.includes('--auto-migrate');
|
|
44109
44235
|
const allowDestructiveAutoMigrate = args.includes('--allow-destructive-auto-migrate');
|
|
44110
|
-
const
|
|
44236
|
+
const autoPush = args.includes('--auto-push');
|
|
44111
44237
|
let thinkingLevel;
|
|
44238
|
+
if (hasTestCommandFlag && testCommand === undefined) {
|
|
44239
|
+
exitWithUsageError('Missing value for --test. Use a shell command such as `npm run test` and quote it when it contains top-level CLI flags.');
|
|
44240
|
+
}
|
|
44112
44241
|
if (hasThinkingLevelFlag && thinkingLevelValue === undefined) {
|
|
44113
44242
|
exitWithUsageError(`Missing value for --thinking-level. Use one of: ${THINKING_LEVEL_VALUES.join(', ')}.`);
|
|
44114
44243
|
}
|
|
@@ -44129,10 +44258,11 @@ function parseRunOptions(args) {
|
|
|
44129
44258
|
allowCredits,
|
|
44130
44259
|
autoMigrate,
|
|
44131
44260
|
allowDestructiveAutoMigrate,
|
|
44132
|
-
|
|
44261
|
+
autoPush,
|
|
44133
44262
|
agentName,
|
|
44134
44263
|
model,
|
|
44135
44264
|
context,
|
|
44265
|
+
testCommand,
|
|
44136
44266
|
thinkingLevel,
|
|
44137
44267
|
priority,
|
|
44138
44268
|
};
|
|
@@ -44147,6 +44277,28 @@ function readOptionValue(args, flag) {
|
|
|
44147
44277
|
const index = args.indexOf(flag);
|
|
44148
44278
|
return args[index + 1];
|
|
44149
44279
|
}
|
|
44280
|
+
/**
|
|
44281
|
+
* Reads a multi-token shell command value that follows a given flag.
|
|
44282
|
+
*/
|
|
44283
|
+
function readVariadicOptionValue(args, flag) {
|
|
44284
|
+
if (!args.includes(flag)) {
|
|
44285
|
+
return undefined;
|
|
44286
|
+
}
|
|
44287
|
+
const index = args.indexOf(flag);
|
|
44288
|
+
const valueParts = [];
|
|
44289
|
+
for (let i = index + 1; i < args.length; i++) {
|
|
44290
|
+
const valuePart = args[i];
|
|
44291
|
+
if (valuePart === undefined) {
|
|
44292
|
+
continue;
|
|
44293
|
+
}
|
|
44294
|
+
if (KNOWN_OPTION_FLAGS.has(valuePart)) {
|
|
44295
|
+
break;
|
|
44296
|
+
}
|
|
44297
|
+
valueParts.push(valuePart);
|
|
44298
|
+
}
|
|
44299
|
+
const normalizedValue = valueParts.join(' ').trim();
|
|
44300
|
+
return normalizedValue === '' ? undefined : normalizedValue;
|
|
44301
|
+
}
|
|
44150
44302
|
/**
|
|
44151
44303
|
* Parses and validates the minimum prompt priority.
|
|
44152
44304
|
*/
|
|
@@ -44172,6 +44324,21 @@ function exitWithUsageError(message) {
|
|
|
44172
44324
|
process.exit(1);
|
|
44173
44325
|
}
|
|
44174
44326
|
|
|
44327
|
+
/**
|
|
44328
|
+
* Appends optional coding context to a runner prompt.
|
|
44329
|
+
*/
|
|
44330
|
+
function appendCoderContext(prompt, context) {
|
|
44331
|
+
const normalizedContext = context === null || context === void 0 ? void 0 : context.trim();
|
|
44332
|
+
if (!normalizedContext) {
|
|
44333
|
+
return prompt;
|
|
44334
|
+
}
|
|
44335
|
+
const normalizedPrompt = prompt.trimEnd();
|
|
44336
|
+
if (normalizedPrompt === '') {
|
|
44337
|
+
return normalizedContext;
|
|
44338
|
+
}
|
|
44339
|
+
return `${normalizedPrompt}\n\n${normalizedContext}`;
|
|
44340
|
+
}
|
|
44341
|
+
|
|
44175
44342
|
/**
|
|
44176
44343
|
* Refresh interval for the progress header in milliseconds.
|
|
44177
44344
|
*/
|
|
@@ -44183,7 +44350,7 @@ const PROGRESS_HEADER_RESERVED_LINES = 1;
|
|
|
44183
44350
|
/**
|
|
44184
44351
|
* Calendar formats used when displaying the estimated completion time.
|
|
44185
44352
|
*/
|
|
44186
|
-
const ESTIMATED_DONE_CALENDAR_FORMATS = {
|
|
44353
|
+
const ESTIMATED_DONE_CALENDAR_FORMATS$1 = {
|
|
44187
44354
|
sameDay: '[Today] h:mm',
|
|
44188
44355
|
nextDay: '[Tomorrow] h:mm',
|
|
44189
44356
|
nextWeek: 'dddd h:mm',
|
|
@@ -44282,15 +44449,15 @@ function buildProgressSnapshot(stats, startTime, initialDone) {
|
|
|
44282
44449
|
const sessionTotal = sessionDone + stats.forAgent;
|
|
44283
44450
|
const percentage = totalPrompts > 0 ? Math.round((completedPrompts / totalPrompts) * 100) : 0;
|
|
44284
44451
|
const elapsedDuration = moment.duration(moment().diff(startTime));
|
|
44285
|
-
const elapsedText = formatDurationBrief(elapsedDuration);
|
|
44452
|
+
const elapsedText = formatDurationBrief$1(elapsedDuration);
|
|
44286
44453
|
let estimatedTotalText = '—';
|
|
44287
44454
|
let estimatedLabel = 'unknown';
|
|
44288
44455
|
if (totalPrompts > 0 && completedPrompts > 0) {
|
|
44289
44456
|
const estimatedTotalMs = (elapsedDuration.asMilliseconds() * totalPrompts) / completedPrompts;
|
|
44290
44457
|
const estimatedTotalDuration = moment.duration(estimatedTotalMs);
|
|
44291
44458
|
const estimatedCompletion = startTime.clone().add(estimatedTotalDuration);
|
|
44292
|
-
estimatedTotalText = formatDurationBrief(estimatedTotalDuration);
|
|
44293
|
-
estimatedLabel = estimatedCompletion.calendar(null, ESTIMATED_DONE_CALENDAR_FORMATS);
|
|
44459
|
+
estimatedTotalText = formatDurationBrief$1(estimatedTotalDuration);
|
|
44460
|
+
estimatedLabel = estimatedCompletion.calendar(null, ESTIMATED_DONE_CALENDAR_FORMATS$1);
|
|
44294
44461
|
}
|
|
44295
44462
|
return {
|
|
44296
44463
|
totalPrompts,
|
|
@@ -44306,7 +44473,7 @@ function buildProgressSnapshot(stats, startTime, initialDone) {
|
|
|
44306
44473
|
/**
|
|
44307
44474
|
* Formats a duration into a compact string such as "3h 12m" or "45s".
|
|
44308
44475
|
*/
|
|
44309
|
-
function formatDurationBrief(duration) {
|
|
44476
|
+
function formatDurationBrief$1(duration) {
|
|
44310
44477
|
const totalSeconds = Math.max(0, Math.round(duration.asSeconds()));
|
|
44311
44478
|
const hours = Math.floor(totalSeconds / 3600);
|
|
44312
44479
|
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
@@ -44327,21 +44494,6 @@ function formatDurationBrief(duration) {
|
|
|
44327
44494
|
return parts.join(' ');
|
|
44328
44495
|
}
|
|
44329
44496
|
|
|
44330
|
-
/**
|
|
44331
|
-
* Appends optional coding context to a runner prompt.
|
|
44332
|
-
*/
|
|
44333
|
-
function appendCoderContext(prompt, context) {
|
|
44334
|
-
const normalizedContext = context === null || context === void 0 ? void 0 : context.trim();
|
|
44335
|
-
if (!normalizedContext) {
|
|
44336
|
-
return prompt;
|
|
44337
|
-
}
|
|
44338
|
-
const normalizedPrompt = prompt.trimEnd();
|
|
44339
|
-
if (normalizedPrompt === '') {
|
|
44340
|
-
return normalizedContext;
|
|
44341
|
-
}
|
|
44342
|
-
return `${normalizedPrompt}\n\n${normalizedContext}`;
|
|
44343
|
-
}
|
|
44344
|
-
|
|
44345
44497
|
/**
|
|
44346
44498
|
* Git commands used to list changed and untracked files in the working tree.
|
|
44347
44499
|
*/
|
|
@@ -44611,7 +44763,7 @@ async function waitForEnter(prompt) {
|
|
|
44611
44763
|
}
|
|
44612
44764
|
|
|
44613
44765
|
/**
|
|
44614
|
-
*
|
|
44766
|
+
* Current pause state.
|
|
44615
44767
|
*/
|
|
44616
44768
|
let pauseState = 'RUNNING';
|
|
44617
44769
|
/**
|
|
@@ -44648,17 +44800,48 @@ function listenForPause() {
|
|
|
44648
44800
|
}
|
|
44649
44801
|
/**
|
|
44650
44802
|
* If the execution is paused, it will wait until it is resumed.
|
|
44803
|
+
*
|
|
44804
|
+
* @param options.silent - When `true`, suppresses console output (used when the terminal UI handles display).
|
|
44805
|
+
* @param options.onPaused - Callback invoked when entering the PAUSED state.
|
|
44806
|
+
* @param options.onResumed - Callback invoked when leaving the PAUSED state.
|
|
44651
44807
|
*/
|
|
44652
|
-
async function checkPause() {
|
|
44808
|
+
async function checkPause(options) {
|
|
44809
|
+
var _a, _b;
|
|
44653
44810
|
if (pauseState === 'PAUSING') {
|
|
44654
44811
|
pauseState = 'PAUSED';
|
|
44655
|
-
|
|
44812
|
+
if (!(options === null || options === void 0 ? void 0 : options.silent)) {
|
|
44813
|
+
console.log(colors.bgWhite.black('Paused') + colors.gray(' (Press "p" to resume)'));
|
|
44814
|
+
}
|
|
44815
|
+
(_a = options === null || options === void 0 ? void 0 : options.onPaused) === null || _a === void 0 ? void 0 : _a.call(options);
|
|
44656
44816
|
while (pauseState === 'PAUSED') {
|
|
44657
44817
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
44658
44818
|
}
|
|
44659
|
-
|
|
44819
|
+
(_b = options === null || options === void 0 ? void 0 : options.onResumed) === null || _b === void 0 ? void 0 : _b.call(options);
|
|
44820
|
+
if (!(options === null || options === void 0 ? void 0 : options.silent)) {
|
|
44821
|
+
console.log(colors.green('Resuming...'));
|
|
44822
|
+
}
|
|
44660
44823
|
}
|
|
44661
44824
|
}
|
|
44825
|
+
/**
|
|
44826
|
+
* Returns the current pause state for external consumers such as the terminal UI.
|
|
44827
|
+
*/
|
|
44828
|
+
function getPauseState() {
|
|
44829
|
+
return pauseState;
|
|
44830
|
+
}
|
|
44831
|
+
/**
|
|
44832
|
+
* Requests a pause from an external controller (e.g. the Ink UI).
|
|
44833
|
+
*/
|
|
44834
|
+
function requestPause() {
|
|
44835
|
+
if (pauseState === 'RUNNING') {
|
|
44836
|
+
pauseState = 'PAUSING';
|
|
44837
|
+
}
|
|
44838
|
+
}
|
|
44839
|
+
/**
|
|
44840
|
+
* Resumes execution from an external controller after a pause.
|
|
44841
|
+
*/
|
|
44842
|
+
function requestResume() {
|
|
44843
|
+
pauseState = 'RUNNING';
|
|
44844
|
+
}
|
|
44662
44845
|
|
|
44663
44846
|
/**
|
|
44664
44847
|
* Environment variable that configures the name used for agent commits.
|
|
@@ -45003,7 +45186,7 @@ function stringifyUnknownError$1(error) {
|
|
|
45003
45186
|
|
|
45004
45187
|
/**
|
|
45005
45188
|
* Commits staged changes with the provided message using the dedicated coding-agent identity when configured,
|
|
45006
|
-
* otherwise falls back to the default Git configuration.
|
|
45189
|
+
* otherwise falls back to the default Git configuration. Remote pushing is opt-in via `options.autoPush`.
|
|
45007
45190
|
*/
|
|
45008
45191
|
async function commitChanges(message, options) {
|
|
45009
45192
|
const projectPath = process.cwd();
|
|
@@ -45023,7 +45206,7 @@ async function commitChanges(message, options) {
|
|
|
45023
45206
|
cwd: projectPath,
|
|
45024
45207
|
env: agentEnv,
|
|
45025
45208
|
});
|
|
45026
|
-
if (
|
|
45209
|
+
if (options === null || options === void 0 ? void 0 : options.autoPush) {
|
|
45027
45210
|
await pushCommittedChanges(projectPath, agentEnv);
|
|
45028
45211
|
}
|
|
45029
45212
|
}
|
|
@@ -45389,6 +45572,7 @@ function normalizePathForLogs(value) {
|
|
|
45389
45572
|
return value.split('\\').join('/');
|
|
45390
45573
|
}
|
|
45391
45574
|
|
|
45575
|
+
// cspell:ignore hashtext
|
|
45392
45576
|
/**
|
|
45393
45577
|
* Cross-process advisory lock key guarding migration execution.
|
|
45394
45578
|
*
|
|
@@ -45400,13 +45584,27 @@ const DATABASE_MIGRATION_LOCK_KEY = 'promptbook_agents_server_migrations';
|
|
|
45400
45584
|
*
|
|
45401
45585
|
* @param client Connected PostgreSQL client.
|
|
45402
45586
|
* @param logger Logger used for progress output.
|
|
45587
|
+
* @param mode Whether the caller should block for the lock or skip when it is already held.
|
|
45588
|
+
* @returns `true` when the lock was acquired and migrations may proceed.
|
|
45403
45589
|
*
|
|
45404
45590
|
* @private function of runDatabaseMigrations
|
|
45405
45591
|
*/
|
|
45406
|
-
async function acquireMigrationExecutionLock(client, logger) {
|
|
45592
|
+
async function acquireMigrationExecutionLock(client, logger, mode = 'wait') {
|
|
45593
|
+
var _a;
|
|
45594
|
+
if (mode === 'skip') {
|
|
45595
|
+
logger.info('🔒 Checking migration lock without waiting');
|
|
45596
|
+
const { rows } = await client.query('SELECT pg_try_advisory_lock(hashtext($1)) AS "isMigrationLockAcquired";', [DATABASE_MIGRATION_LOCK_KEY]);
|
|
45597
|
+
if (!((_a = rows[0]) === null || _a === void 0 ? void 0 : _a.isMigrationLockAcquired)) {
|
|
45598
|
+
logger.info('⏭️ Migration lock is already held by another process. Skipping this migration attempt.');
|
|
45599
|
+
return false;
|
|
45600
|
+
}
|
|
45601
|
+
logger.info('🔒 Migration lock acquired');
|
|
45602
|
+
return true;
|
|
45603
|
+
}
|
|
45407
45604
|
logger.info('🔒 Waiting for migration lock');
|
|
45408
45605
|
await client.query('SELECT pg_advisory_lock(hashtext($1));', [DATABASE_MIGRATION_LOCK_KEY]);
|
|
45409
45606
|
logger.info('🔒 Migration lock acquired');
|
|
45607
|
+
return true;
|
|
45410
45608
|
}
|
|
45411
45609
|
/**
|
|
45412
45610
|
* Releases advisory lock used for migration execution.
|
|
@@ -45930,23 +46128,33 @@ async function resolveDatabaseMigrationRuntimeConfiguration(logger = console) {
|
|
|
45930
46128
|
* @returns Aggregated migration summary.
|
|
45931
46129
|
*/
|
|
45932
46130
|
async function runDatabaseMigrations(options) {
|
|
45933
|
-
var _a, _b, _c, _d;
|
|
46131
|
+
var _a, _b, _c, _d, _e;
|
|
45934
46132
|
const logger = (_a = options.logger) !== null && _a !== void 0 ? _a : console;
|
|
45935
46133
|
const selectedPrefixes = selectPrefixesForMigration(options.prefixes, (_b = options.registeredServers) !== null && _b !== void 0 ? _b : [], options.onlyTargets);
|
|
45936
46134
|
const migrationsDirectory = (_c = options.migrationsDirectory) !== null && _c !== void 0 ? _c : (await resolveMigrationsDirectory());
|
|
45937
46135
|
const migrationFiles = await readMigrationFiles(migrationsDirectory);
|
|
46136
|
+
const totalMigrationFiles = migrationFiles.length;
|
|
45938
46137
|
const perPrefix = [];
|
|
45939
|
-
logger.info(`📂 Found ${
|
|
46138
|
+
logger.info(`📂 Found ${totalMigrationFiles} migration files`);
|
|
45940
46139
|
logger.info(`📋 Found ${selectedPrefixes.length} prefixes to migrate: ${selectedPrefixes
|
|
45941
46140
|
.map((prefix) => prefix || '<default>')
|
|
45942
46141
|
.join(', ')}`);
|
|
45943
46142
|
const client = await createPostgresClient(options.connectionString);
|
|
45944
46143
|
let hasExecutionLock = false;
|
|
46144
|
+
let isSkippedDueToActiveMigrationLock = false;
|
|
45945
46145
|
try {
|
|
45946
46146
|
await client.connect();
|
|
45947
46147
|
logger.info('🔌 Connected to database');
|
|
45948
|
-
await acquireMigrationExecutionLock(client, logger);
|
|
45949
|
-
hasExecutionLock
|
|
46148
|
+
hasExecutionLock = await acquireMigrationExecutionLock(client, logger, (_d = options.executionLockMode) !== null && _d !== void 0 ? _d : 'wait');
|
|
46149
|
+
if (!hasExecutionLock) {
|
|
46150
|
+
isSkippedDueToActiveMigrationLock = true;
|
|
46151
|
+
return {
|
|
46152
|
+
processedPrefixes: [],
|
|
46153
|
+
totalMigrationFiles,
|
|
46154
|
+
perPrefix,
|
|
46155
|
+
isSkippedDueToActiveMigrationLock,
|
|
46156
|
+
};
|
|
46157
|
+
}
|
|
45950
46158
|
for (const prefix of selectedPrefixes) {
|
|
45951
46159
|
logger.info(`\n🏗️ Migrating prefix: "${prefix}"`);
|
|
45952
46160
|
const appliedCount = await migratePrefix({
|
|
@@ -45957,7 +46165,7 @@ async function runDatabaseMigrations(options) {
|
|
|
45957
46165
|
logger,
|
|
45958
46166
|
migrationFiles,
|
|
45959
46167
|
migrationsDirectory,
|
|
45960
|
-
logSqlStatements: (
|
|
46168
|
+
logSqlStatements: (_e = options.logSqlStatements) !== null && _e !== void 0 ? _e : false,
|
|
45961
46169
|
});
|
|
45962
46170
|
perPrefix.push({ prefix, appliedCount });
|
|
45963
46171
|
}
|
|
@@ -45970,8 +46178,9 @@ async function runDatabaseMigrations(options) {
|
|
|
45970
46178
|
}
|
|
45971
46179
|
return {
|
|
45972
46180
|
processedPrefixes: selectedPrefixes,
|
|
45973
|
-
totalMigrationFiles
|
|
46181
|
+
totalMigrationFiles,
|
|
45974
46182
|
perPrefix,
|
|
46183
|
+
isSkippedDueToActiveMigrationLock,
|
|
45975
46184
|
};
|
|
45976
46185
|
}
|
|
45977
46186
|
/**
|
|
@@ -46590,6 +46799,19 @@ function formatUsagePrice(usage) {
|
|
|
46590
46799
|
return `${prefix}$${price.toFixed(2)}`;
|
|
46591
46800
|
}
|
|
46592
46801
|
|
|
46802
|
+
/**
|
|
46803
|
+
* Formats optional attempt metadata stored in prompt status lines.
|
|
46804
|
+
*/
|
|
46805
|
+
function formatPromptAttemptMetadata(status, attemptCount) {
|
|
46806
|
+
if (attemptCount <= 1) {
|
|
46807
|
+
return '';
|
|
46808
|
+
}
|
|
46809
|
+
if (status === 'done') {
|
|
46810
|
+
return `(${attemptCount} attempts) `;
|
|
46811
|
+
}
|
|
46812
|
+
return `(failed after ${attemptCount} attempts) `;
|
|
46813
|
+
}
|
|
46814
|
+
|
|
46593
46815
|
/**
|
|
46594
46816
|
* Formats runner details for prompt status lines.
|
|
46595
46817
|
*/
|
|
@@ -46609,7 +46831,7 @@ function formatRunnerSignature(runnerName, modelName) {
|
|
|
46609
46831
|
/**
|
|
46610
46832
|
* Marks a prompt section as done and records usage pricing and runner details.
|
|
46611
46833
|
*/
|
|
46612
|
-
function markPromptDone(file, section, usage, runnerName, modelName, promptExecutionStartedDate) {
|
|
46834
|
+
function markPromptDone(file, section, usage, runnerName, modelName, promptExecutionStartedDate, attemptCount = 1) {
|
|
46613
46835
|
if (section.statusLineIndex === undefined) {
|
|
46614
46836
|
throw new Error(`Prompt ${section.index + 1} in ${file.name} does not have a status line.`);
|
|
46615
46837
|
}
|
|
@@ -46619,16 +46841,17 @@ function markPromptDone(file, section, usage, runnerName, modelName, promptExecu
|
|
|
46619
46841
|
}
|
|
46620
46842
|
const priceString = formatUsagePrice(usage);
|
|
46621
46843
|
const runnerSignature = formatRunnerSignature(runnerName, modelName);
|
|
46844
|
+
const attemptMetadata = formatPromptAttemptMetadata('done', attemptCount);
|
|
46622
46845
|
const duration = moment().diff(promptExecutionStartedDate);
|
|
46623
46846
|
const durationString = moment.duration(duration).humanize();
|
|
46624
46847
|
// Replace "[ ]" or "[ ] !!..." with "[x] $price duration by runner"
|
|
46625
|
-
file.lines[section.statusLineIndex] = line.replace(/\[\s*\]\s*!*\s*$/, `[x] ${priceString} ${durationString} by ${runnerSignature}`);
|
|
46848
|
+
file.lines[section.statusLineIndex] = line.replace(/\[\s*\]\s*!*\s*$/, `[x] ${attemptMetadata}${priceString} ${durationString} by ${runnerSignature}`);
|
|
46626
46849
|
}
|
|
46627
46850
|
|
|
46628
46851
|
/**
|
|
46629
46852
|
* Marks a prompt section as failed and records runner details.
|
|
46630
46853
|
*/
|
|
46631
|
-
function markPromptFailed(file, section, runnerName, modelName, promptExecutionStartedDate) {
|
|
46854
|
+
function markPromptFailed(file, section, runnerName, modelName, promptExecutionStartedDate, attemptCount = 1) {
|
|
46632
46855
|
if (section.statusLineIndex === undefined) {
|
|
46633
46856
|
throw new Error(`Prompt ${section.index + 1} in ${file.name} does not have a status line.`);
|
|
46634
46857
|
}
|
|
@@ -46637,9 +46860,11 @@ function markPromptFailed(file, section, runnerName, modelName, promptExecutionS
|
|
|
46637
46860
|
throw new Error(`Prompt ${section.index + 1} in ${file.name} points to a missing status line.`);
|
|
46638
46861
|
}
|
|
46639
46862
|
const runnerSignature = formatRunnerSignature(runnerName, modelName);
|
|
46863
|
+
const attemptMetadata = formatPromptAttemptMetadata('failed', attemptCount);
|
|
46640
46864
|
const duration = moment().diff(promptExecutionStartedDate);
|
|
46641
46865
|
const durationString = moment.duration(duration).humanize();
|
|
46642
|
-
|
|
46866
|
+
const failureDetails = attemptMetadata === '' ? `failed after ${durationString} by ${runnerSignature}` : `${attemptMetadata}${durationString} by ${runnerSignature}`;
|
|
46867
|
+
file.lines[section.statusLineIndex] = line.replace(/\[\s*\]\s*!*\s*$/, `[!] ${failureDetails}`);
|
|
46643
46868
|
}
|
|
46644
46869
|
|
|
46645
46870
|
/**
|
|
@@ -46756,6 +46981,20 @@ async function waitForPromptStart(file, section, isFirstPrompt) {
|
|
|
46756
46981
|
await waitForEnter(colors.bgWhite(`Press Enter to start the ${label}...`));
|
|
46757
46982
|
}
|
|
46758
46983
|
|
|
46984
|
+
/**
|
|
46985
|
+
* Formats one unknown error-like value into readable text for logs and feedback.
|
|
46986
|
+
*/
|
|
46987
|
+
function formatUnknownErrorDetails(error) {
|
|
46988
|
+
if (error instanceof Error) {
|
|
46989
|
+
return error.stack || error.message;
|
|
46990
|
+
}
|
|
46991
|
+
if (typeof error === 'string') {
|
|
46992
|
+
return error;
|
|
46993
|
+
}
|
|
46994
|
+
const serializedError = JSON.stringify(error, null, 2);
|
|
46995
|
+
return serializedError !== null && serializedError !== void 0 ? serializedError : String(error);
|
|
46996
|
+
}
|
|
46997
|
+
|
|
46759
46998
|
/**
|
|
46760
46999
|
* Writes the failure details for a single prompt run next to the prompt markdown file.
|
|
46761
47000
|
*/
|
|
@@ -46763,7 +47002,7 @@ async function writePromptErrorLog(options) {
|
|
|
46763
47002
|
const logPath = buildPromptErrorLogPath(options.file.path);
|
|
46764
47003
|
const label = buildPromptLabelForDisplay(options.file, options.section);
|
|
46765
47004
|
const summary = buildPromptSummary(options.file, options.section);
|
|
46766
|
-
const details =
|
|
47005
|
+
const details = formatUnknownErrorDetails(options.error);
|
|
46767
47006
|
const modelSuffix = options.modelName ? ` (${options.modelName})` : '';
|
|
46768
47007
|
const runnerLabel = `${options.runnerName || 'unknown'}${modelSuffix}`;
|
|
46769
47008
|
const log = [
|
|
@@ -46790,18 +47029,6 @@ function buildPromptErrorLogPath(promptPath) {
|
|
|
46790
47029
|
}
|
|
46791
47030
|
return `${promptPath}.error.log`;
|
|
46792
47031
|
}
|
|
46793
|
-
/**
|
|
46794
|
-
* Formats unknown error values into a readable log payload.
|
|
46795
|
-
*/
|
|
46796
|
-
function buildErrorDetails(error) {
|
|
46797
|
-
if (error instanceof Error) {
|
|
46798
|
-
return error.stack || error.message;
|
|
46799
|
-
}
|
|
46800
|
-
if (typeof error === 'string') {
|
|
46801
|
-
return error;
|
|
46802
|
-
}
|
|
46803
|
-
return JSON.stringify(error, null, 2);
|
|
46804
|
-
}
|
|
46805
47032
|
|
|
46806
47033
|
/**
|
|
46807
47034
|
* Writes updated prompt file content to disk.
|
|
@@ -47860,6 +48087,647 @@ class OpencodeRunner {
|
|
|
47860
48087
|
}
|
|
47861
48088
|
}
|
|
47862
48089
|
|
|
48090
|
+
/**
|
|
48091
|
+
* Runs the configured verification command inside the project root and returns its output.
|
|
48092
|
+
*/
|
|
48093
|
+
async function runPromptTestCommand(options) {
|
|
48094
|
+
const projectPath = toPosixPath(options.projectPath);
|
|
48095
|
+
return await $runGoScriptWithOutput({
|
|
48096
|
+
scriptPath: options.scriptPath,
|
|
48097
|
+
scriptContent: spaceTrim(`
|
|
48098
|
+
cd "${projectPath}"
|
|
48099
|
+
${options.command}
|
|
48100
|
+
`),
|
|
48101
|
+
});
|
|
48102
|
+
}
|
|
48103
|
+
|
|
48104
|
+
/**
|
|
48105
|
+
* Maximum number of coding attempts allowed for the same prompt when verification keeps failing.
|
|
48106
|
+
*/
|
|
48107
|
+
const MAX_PROMPT_TEST_ATTEMPTS = 3;
|
|
48108
|
+
/**
|
|
48109
|
+
* Maximum amount of verification output sent back to the coding agent as retry feedback.
|
|
48110
|
+
*/
|
|
48111
|
+
const MAX_TEST_FEEDBACK_OUTPUT_CHARS = 12000;
|
|
48112
|
+
/**
|
|
48113
|
+
* Runs one coding prompt and, when configured, verifies it with a shell command that can feed failures back.
|
|
48114
|
+
*/
|
|
48115
|
+
async function runPromptWithTestFeedback(options) {
|
|
48116
|
+
var _a, _b, _c, _d;
|
|
48117
|
+
const normalizedTestCommand = (_a = options.testCommand) === null || _a === void 0 ? void 0 : _a.trim();
|
|
48118
|
+
if (!normalizedTestCommand) {
|
|
48119
|
+
(_b = options.onAttemptStarted) === null || _b === void 0 ? void 0 : _b.call(options, 1);
|
|
48120
|
+
const result = await options.runner.runPrompt({
|
|
48121
|
+
prompt: options.prompt,
|
|
48122
|
+
scriptPath: options.scriptPath,
|
|
48123
|
+
projectPath: options.projectPath,
|
|
48124
|
+
});
|
|
48125
|
+
return { ...result, attemptCount: 1 };
|
|
48126
|
+
}
|
|
48127
|
+
const runPromptTestCommandExecutor = (_c = options.runPromptTestCommandExecutor) !== null && _c !== void 0 ? _c : runPromptTestCommand;
|
|
48128
|
+
let promptForCurrentAttempt = options.prompt;
|
|
48129
|
+
for (let attemptCount = 1; attemptCount <= MAX_PROMPT_TEST_ATTEMPTS; attemptCount++) {
|
|
48130
|
+
(_d = options.onAttemptStarted) === null || _d === void 0 ? void 0 : _d.call(options, attemptCount);
|
|
48131
|
+
const result = await options.runner.runPrompt({
|
|
48132
|
+
prompt: promptForCurrentAttempt,
|
|
48133
|
+
scriptPath: options.scriptPath,
|
|
48134
|
+
projectPath: options.projectPath,
|
|
48135
|
+
});
|
|
48136
|
+
console.info(colors.gray(`Running verification command after attempt #${attemptCount}: ${normalizedTestCommand}`));
|
|
48137
|
+
try {
|
|
48138
|
+
await runPromptTestCommandExecutor({
|
|
48139
|
+
command: normalizedTestCommand,
|
|
48140
|
+
projectPath: options.projectPath,
|
|
48141
|
+
scriptPath: buildPromptTestScriptPath(options.scriptPath),
|
|
48142
|
+
});
|
|
48143
|
+
return { ...result, attemptCount };
|
|
48144
|
+
}
|
|
48145
|
+
catch (error) {
|
|
48146
|
+
const fullVerificationOutput = formatUnknownErrorDetails(error);
|
|
48147
|
+
const feedbackVerificationOutput = limitVerificationOutputForFeedback(fullVerificationOutput);
|
|
48148
|
+
if (attemptCount >= MAX_PROMPT_TEST_ATTEMPTS) {
|
|
48149
|
+
console.error(colors.red(`Verification failed for ${options.promptLabel} after ${attemptCount} attempts.`));
|
|
48150
|
+
throw new Error(buildFinalVerificationFailureMessage({
|
|
48151
|
+
promptLabel: options.promptLabel,
|
|
48152
|
+
testCommand: normalizedTestCommand,
|
|
48153
|
+
attemptCount,
|
|
48154
|
+
verificationOutput: fullVerificationOutput,
|
|
48155
|
+
}));
|
|
48156
|
+
}
|
|
48157
|
+
console.warn(colors.yellow(`Verification failed for ${options.promptLabel} on attempt #${attemptCount}. Sending feedback to ${options.runner.name} and retrying...`));
|
|
48158
|
+
promptForCurrentAttempt = appendCoderContext(options.prompt, buildVerificationFeedback({
|
|
48159
|
+
testCommand: normalizedTestCommand,
|
|
48160
|
+
failedAttemptCount: attemptCount,
|
|
48161
|
+
verificationOutput: feedbackVerificationOutput,
|
|
48162
|
+
}));
|
|
48163
|
+
}
|
|
48164
|
+
}
|
|
48165
|
+
throw new Error('Unexpected prompt verification state.');
|
|
48166
|
+
}
|
|
48167
|
+
/**
|
|
48168
|
+
* Builds one feedback block appended to the next coding attempt after tests fail.
|
|
48169
|
+
*/
|
|
48170
|
+
function buildVerificationFeedback({ testCommand, failedAttemptCount, verificationOutput, }) {
|
|
48171
|
+
const nextAttemptCount = failedAttemptCount + 1;
|
|
48172
|
+
return spaceTrim((block) => `
|
|
48173
|
+
The previous implementation did not pass the required verification command.
|
|
48174
|
+
|
|
48175
|
+
## Automated verification feedback
|
|
48176
|
+
- Retry attempt: ${nextAttemptCount} of ${MAX_PROMPT_TEST_ATTEMPTS}
|
|
48177
|
+
- Verification command: \`${testCommand}\`
|
|
48178
|
+
- Update the current implementation so the verification command passes without breaking the original task requirements.
|
|
48179
|
+
|
|
48180
|
+
### Verification output
|
|
48181
|
+
\`\`\`
|
|
48182
|
+
${block(verificationOutput)}
|
|
48183
|
+
\`\`\`
|
|
48184
|
+
`);
|
|
48185
|
+
}
|
|
48186
|
+
/**
|
|
48187
|
+
* Builds the final error message written when verification still fails after all retries.
|
|
48188
|
+
*/
|
|
48189
|
+
function buildFinalVerificationFailureMessage({ promptLabel, testCommand, attemptCount, verificationOutput, }) {
|
|
48190
|
+
return spaceTrim((block) => `
|
|
48191
|
+
Verification command \`${testCommand}\` failed for \`${promptLabel}\` after ${attemptCount} attempts.
|
|
48192
|
+
|
|
48193
|
+
### Verification output
|
|
48194
|
+
\`\`\`
|
|
48195
|
+
${block(verificationOutput)}
|
|
48196
|
+
\`\`\`
|
|
48197
|
+
`);
|
|
48198
|
+
}
|
|
48199
|
+
/**
|
|
48200
|
+
* Limits verification output before it is embedded back into the next coding prompt.
|
|
48201
|
+
*/
|
|
48202
|
+
function limitVerificationOutputForFeedback(verificationOutput) {
|
|
48203
|
+
const normalizedVerificationOutput = verificationOutput.trim();
|
|
48204
|
+
if (normalizedVerificationOutput.length <= MAX_TEST_FEEDBACK_OUTPUT_CHARS) {
|
|
48205
|
+
return normalizedVerificationOutput;
|
|
48206
|
+
}
|
|
48207
|
+
return spaceTrim(`
|
|
48208
|
+
[...verification output truncated to the last ${MAX_TEST_FEEDBACK_OUTPUT_CHARS} characters...]
|
|
48209
|
+
${normalizedVerificationOutput.slice(-MAX_TEST_FEEDBACK_OUTPUT_CHARS)}
|
|
48210
|
+
`);
|
|
48211
|
+
}
|
|
48212
|
+
/**
|
|
48213
|
+
* Derives a dedicated temp-script path for verification commands.
|
|
48214
|
+
*/
|
|
48215
|
+
function buildPromptTestScriptPath(scriptPath) {
|
|
48216
|
+
if (scriptPath.toLowerCase().endsWith('.sh')) {
|
|
48217
|
+
return `${scriptPath.slice(0, -3)}.test.sh`;
|
|
48218
|
+
}
|
|
48219
|
+
return `${scriptPath}.test.sh`;
|
|
48220
|
+
}
|
|
48221
|
+
|
|
48222
|
+
/**
|
|
48223
|
+
* Maximum number of agent output lines kept in the scrolling output area.
|
|
48224
|
+
*
|
|
48225
|
+
* @private internal constant of coder run UI
|
|
48226
|
+
*/
|
|
48227
|
+
const MAX_AGENT_OUTPUT_LINES = 12;
|
|
48228
|
+
/**
|
|
48229
|
+
* Calendar formats used when displaying the estimated completion time.
|
|
48230
|
+
*
|
|
48231
|
+
* @private internal constant of coder run UI
|
|
48232
|
+
*/
|
|
48233
|
+
const ESTIMATED_DONE_CALENDAR_FORMATS = {
|
|
48234
|
+
sameDay: '[Today] h:mm',
|
|
48235
|
+
nextDay: '[Tomorrow] h:mm',
|
|
48236
|
+
nextWeek: 'dddd h:mm',
|
|
48237
|
+
lastDay: '[Yesterday] h:mm',
|
|
48238
|
+
lastWeek: 'dddd h:mm',
|
|
48239
|
+
sameElse: 'MMM D h:mm',
|
|
48240
|
+
};
|
|
48241
|
+
/**
|
|
48242
|
+
* Reactive state manager for the coder run terminal UI.
|
|
48243
|
+
*
|
|
48244
|
+
* Holds all data the Ink components need and emits `'change'` events
|
|
48245
|
+
* whenever any property is updated so the UI can re-render.
|
|
48246
|
+
*
|
|
48247
|
+
* @private internal utility of coder run UI
|
|
48248
|
+
*/
|
|
48249
|
+
class CoderRunUiState extends EventEmitter {
|
|
48250
|
+
constructor(startTime) {
|
|
48251
|
+
super();
|
|
48252
|
+
this.config = { agentName: '', priority: 0 };
|
|
48253
|
+
this.currentPromptLabel = '';
|
|
48254
|
+
this.currentAttempt = 1;
|
|
48255
|
+
this.maxAttempts = 3;
|
|
48256
|
+
this.agentOutputLines = [];
|
|
48257
|
+
this.phase = 'initializing';
|
|
48258
|
+
this.statusMessage = 'Initializing...';
|
|
48259
|
+
this.errors = [];
|
|
48260
|
+
this.stats = { done: 0, forAgent: 0, belowMinimumPriority: 0, toBeWritten: 0 };
|
|
48261
|
+
/**
|
|
48262
|
+
* Total milliseconds the timer was paused/waiting (excluded from elapsed display).
|
|
48263
|
+
*/
|
|
48264
|
+
this.pausedMs = 0;
|
|
48265
|
+
this.startTime = startTime;
|
|
48266
|
+
// Timer starts paused — callers call `resumeTimer()` when actual work begins.
|
|
48267
|
+
this.pausedSince = startTime.clone();
|
|
48268
|
+
}
|
|
48269
|
+
/**
|
|
48270
|
+
* Pauses the elapsed timer (e.g. while waiting for user input or paused state).
|
|
48271
|
+
*/
|
|
48272
|
+
pauseTimer() {
|
|
48273
|
+
if (this.pausedSince === undefined) {
|
|
48274
|
+
this.pausedSince = moment();
|
|
48275
|
+
}
|
|
48276
|
+
}
|
|
48277
|
+
/**
|
|
48278
|
+
* Resumes the elapsed timer after a pause.
|
|
48279
|
+
*/
|
|
48280
|
+
resumeTimer() {
|
|
48281
|
+
if (this.pausedSince !== undefined) {
|
|
48282
|
+
this.pausedMs += moment().diff(this.pausedSince);
|
|
48283
|
+
this.pausedSince = undefined;
|
|
48284
|
+
}
|
|
48285
|
+
}
|
|
48286
|
+
/**
|
|
48287
|
+
* Replaces the configuration shown in the UI header.
|
|
48288
|
+
*/
|
|
48289
|
+
setConfig(config) {
|
|
48290
|
+
this.config = config;
|
|
48291
|
+
this.emitChange();
|
|
48292
|
+
}
|
|
48293
|
+
/**
|
|
48294
|
+
* Feeds new prompt statistics from the main loop so the progress bar updates.
|
|
48295
|
+
*/
|
|
48296
|
+
updateProgress(stats) {
|
|
48297
|
+
if (this.initialDone === undefined && (stats.done > 0 || stats.forAgent > 0 || stats.toBeWritten > 0)) {
|
|
48298
|
+
this.initialDone = stats.done;
|
|
48299
|
+
}
|
|
48300
|
+
this.stats = stats;
|
|
48301
|
+
this.emitChange();
|
|
48302
|
+
}
|
|
48303
|
+
/**
|
|
48304
|
+
* Computes a progress snapshot on demand so elapsed time ticks with periodic re-renders.
|
|
48305
|
+
*/
|
|
48306
|
+
getProgress() {
|
|
48307
|
+
var _a;
|
|
48308
|
+
const stats = this.stats;
|
|
48309
|
+
const totalPrompts = stats.done + stats.forAgent + stats.toBeWritten;
|
|
48310
|
+
const sessionDone = Math.max(0, stats.done - ((_a = this.initialDone) !== null && _a !== void 0 ? _a : stats.done));
|
|
48311
|
+
const sessionTotal = sessionDone + stats.forAgent;
|
|
48312
|
+
const percentage = totalPrompts > 0 ? Math.round((stats.done / totalPrompts) * 100) : 0;
|
|
48313
|
+
const wallMs = moment().diff(this.startTime);
|
|
48314
|
+
const currentPauseMs = this.pausedSince !== undefined ? moment().diff(this.pausedSince) : 0;
|
|
48315
|
+
const activeMs = Math.max(0, wallMs - this.pausedMs - currentPauseMs);
|
|
48316
|
+
const elapsedDuration = moment.duration(activeMs);
|
|
48317
|
+
const elapsedText = formatDurationBrief(elapsedDuration);
|
|
48318
|
+
let estimatedTotalText = '\u2014';
|
|
48319
|
+
let estimatedLabel = 'unknown';
|
|
48320
|
+
if (totalPrompts > 0 && stats.done > 0) {
|
|
48321
|
+
const estimatedTotalMs = (elapsedDuration.asMilliseconds() * totalPrompts) / stats.done;
|
|
48322
|
+
const estimatedRemainingMs = estimatedTotalMs - elapsedDuration.asMilliseconds();
|
|
48323
|
+
const estimatedTotalDuration = moment.duration(estimatedTotalMs);
|
|
48324
|
+
const estimatedCompletion = moment().add(estimatedRemainingMs, 'milliseconds');
|
|
48325
|
+
estimatedTotalText = formatDurationBrief(estimatedTotalDuration);
|
|
48326
|
+
estimatedLabel = estimatedCompletion.calendar(null, ESTIMATED_DONE_CALENDAR_FORMATS);
|
|
48327
|
+
}
|
|
48328
|
+
return {
|
|
48329
|
+
totalPrompts,
|
|
48330
|
+
sessionDone,
|
|
48331
|
+
sessionTotal,
|
|
48332
|
+
percentage,
|
|
48333
|
+
elapsedText,
|
|
48334
|
+
estimatedTotalText,
|
|
48335
|
+
estimatedLabel,
|
|
48336
|
+
};
|
|
48337
|
+
}
|
|
48338
|
+
/**
|
|
48339
|
+
* Sets the label of the prompt currently being processed and resets per-prompt state.
|
|
48340
|
+
*/
|
|
48341
|
+
setCurrentPrompt(label) {
|
|
48342
|
+
this.currentPromptLabel = label;
|
|
48343
|
+
this.agentOutputLines = [];
|
|
48344
|
+
this.currentAttempt = 1;
|
|
48345
|
+
this.emitChange();
|
|
48346
|
+
}
|
|
48347
|
+
/**
|
|
48348
|
+
* Updates the current retry attempt number.
|
|
48349
|
+
*/
|
|
48350
|
+
setAttempt(attempt) {
|
|
48351
|
+
this.currentAttempt = attempt;
|
|
48352
|
+
this.emitChange();
|
|
48353
|
+
}
|
|
48354
|
+
/**
|
|
48355
|
+
* Appends raw agent output text, keeping only the last `MAX_AGENT_OUTPUT_LINES`.
|
|
48356
|
+
*/
|
|
48357
|
+
addAgentOutput(text) {
|
|
48358
|
+
const lines = text.split(/\r?\n/).filter((line) => line.trim() !== '');
|
|
48359
|
+
if (lines.length === 0) {
|
|
48360
|
+
return;
|
|
48361
|
+
}
|
|
48362
|
+
this.agentOutputLines.push(...lines);
|
|
48363
|
+
if (this.agentOutputLines.length > MAX_AGENT_OUTPUT_LINES) {
|
|
48364
|
+
this.agentOutputLines = this.agentOutputLines.slice(-MAX_AGENT_OUTPUT_LINES);
|
|
48365
|
+
}
|
|
48366
|
+
this.emitChange();
|
|
48367
|
+
}
|
|
48368
|
+
/**
|
|
48369
|
+
* Transitions the execution phase shown in the UI.
|
|
48370
|
+
*/
|
|
48371
|
+
setPhase(phase) {
|
|
48372
|
+
this.phase = phase;
|
|
48373
|
+
this.emitChange();
|
|
48374
|
+
}
|
|
48375
|
+
/**
|
|
48376
|
+
* Updates the status message line beneath the current prompt label.
|
|
48377
|
+
*/
|
|
48378
|
+
setStatusMessage(message) {
|
|
48379
|
+
this.statusMessage = message;
|
|
48380
|
+
this.emitChange();
|
|
48381
|
+
}
|
|
48382
|
+
/**
|
|
48383
|
+
* Appends an error message to the error list shown in the UI.
|
|
48384
|
+
*/
|
|
48385
|
+
addError(errorMessage) {
|
|
48386
|
+
this.errors.push(errorMessage);
|
|
48387
|
+
this.emitChange();
|
|
48388
|
+
}
|
|
48389
|
+
emitChange() {
|
|
48390
|
+
this.emit('change');
|
|
48391
|
+
}
|
|
48392
|
+
}
|
|
48393
|
+
/**
|
|
48394
|
+
* Formats a duration into a compact string such as "3h 12m" or "45s".
|
|
48395
|
+
*
|
|
48396
|
+
* @private internal utility of coder run UI
|
|
48397
|
+
*/
|
|
48398
|
+
function formatDurationBrief(duration) {
|
|
48399
|
+
const totalSeconds = Math.max(0, Math.round(duration.asSeconds()));
|
|
48400
|
+
const hours = Math.floor(totalSeconds / 3600);
|
|
48401
|
+
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
48402
|
+
const seconds = totalSeconds % 60;
|
|
48403
|
+
const parts = [];
|
|
48404
|
+
if (hours > 0) {
|
|
48405
|
+
parts.push(`${hours}h`);
|
|
48406
|
+
}
|
|
48407
|
+
if (minutes > 0) {
|
|
48408
|
+
parts.push(`${minutes}m`);
|
|
48409
|
+
}
|
|
48410
|
+
if (!parts.length && seconds > 0) {
|
|
48411
|
+
parts.push(`${seconds}s`);
|
|
48412
|
+
}
|
|
48413
|
+
if (!parts.length) {
|
|
48414
|
+
parts.push('0s');
|
|
48415
|
+
}
|
|
48416
|
+
return parts.join(' ');
|
|
48417
|
+
}
|
|
48418
|
+
|
|
48419
|
+
/**
|
|
48420
|
+
* Refresh interval for the terminal UI in milliseconds.
|
|
48421
|
+
*
|
|
48422
|
+
* @private internal constant of coder run UI
|
|
48423
|
+
*/
|
|
48424
|
+
const UI_REFRESH_INTERVAL_MS = 200;
|
|
48425
|
+
/**
|
|
48426
|
+
* Character width used for the text progress bar.
|
|
48427
|
+
*
|
|
48428
|
+
* @private internal constant of coder run UI
|
|
48429
|
+
*/
|
|
48430
|
+
const PROGRESS_BAR_WIDTH = 40;
|
|
48431
|
+
/**
|
|
48432
|
+
* Maximum number of output lines reserved for agent output in the UI.
|
|
48433
|
+
*
|
|
48434
|
+
* @private internal constant of coder run UI
|
|
48435
|
+
*/
|
|
48436
|
+
const MAX_VISIBLE_OUTPUT_LINES = 8;
|
|
48437
|
+
/**
|
|
48438
|
+
* Spinner animation frames.
|
|
48439
|
+
*
|
|
48440
|
+
* @private internal constant of coder run UI
|
|
48441
|
+
*/
|
|
48442
|
+
const SPINNER_FRAMES = [
|
|
48443
|
+
'\u280B',
|
|
48444
|
+
'\u2819',
|
|
48445
|
+
'\u2839',
|
|
48446
|
+
'\u2838',
|
|
48447
|
+
'\u283C',
|
|
48448
|
+
'\u2834',
|
|
48449
|
+
'\u2826',
|
|
48450
|
+
'\u2827',
|
|
48451
|
+
'\u2807',
|
|
48452
|
+
'\u280F',
|
|
48453
|
+
];
|
|
48454
|
+
/**
|
|
48455
|
+
* Strips ANSI escape codes from a string.
|
|
48456
|
+
*
|
|
48457
|
+
* @private internal utility of coder run UI
|
|
48458
|
+
*/
|
|
48459
|
+
function stripAnsi(text) {
|
|
48460
|
+
// eslint-disable-next-line no-control-regex
|
|
48461
|
+
return text.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, '');
|
|
48462
|
+
}
|
|
48463
|
+
/**
|
|
48464
|
+
* Returns the usable terminal width, capped at 80.
|
|
48465
|
+
*
|
|
48466
|
+
* @private internal utility of coder run UI
|
|
48467
|
+
*/
|
|
48468
|
+
function getTerminalWidth() {
|
|
48469
|
+
return Math.min(process.stdout.columns || 80, 80);
|
|
48470
|
+
}
|
|
48471
|
+
/**
|
|
48472
|
+
* Builds a text progress bar string from a percentage.
|
|
48473
|
+
*
|
|
48474
|
+
* @private internal utility of coder run UI
|
|
48475
|
+
*/
|
|
48476
|
+
function buildProgressBar(percentage) {
|
|
48477
|
+
const filled = Math.round((percentage / 100) * PROGRESS_BAR_WIDTH);
|
|
48478
|
+
const empty = PROGRESS_BAR_WIDTH - filled;
|
|
48479
|
+
return colors.green('\u2588'.repeat(filled)) + colors.gray('\u2591'.repeat(empty)) + ` ${percentage}%`;
|
|
48480
|
+
}
|
|
48481
|
+
/**
|
|
48482
|
+
* Boots the ANSI terminal UI for `ptbk coder run`.
|
|
48483
|
+
*
|
|
48484
|
+
* The UI reserves a fixed number of terminal lines and repaints them periodically.
|
|
48485
|
+
* Between repaints, any console output from runners is captured and fed into the
|
|
48486
|
+
* scrolling agent-output area.
|
|
48487
|
+
*
|
|
48488
|
+
* On non-interactive (non-TTY) terminals the UI is skipped entirely and
|
|
48489
|
+
* only the state object is provided.
|
|
48490
|
+
*
|
|
48491
|
+
* @private internal entry point of coder run UI
|
|
48492
|
+
*/
|
|
48493
|
+
function renderCoderRunUi(startTime) {
|
|
48494
|
+
const state = new CoderRunUiState(startTime);
|
|
48495
|
+
if (!process.stdout.isTTY) {
|
|
48496
|
+
return {
|
|
48497
|
+
state,
|
|
48498
|
+
startCapturingAgentOutput: () => { },
|
|
48499
|
+
stopCapturingAgentOutput: () => { },
|
|
48500
|
+
cleanup: () => { },
|
|
48501
|
+
};
|
|
48502
|
+
}
|
|
48503
|
+
// --- Console interception ---
|
|
48504
|
+
const originalConsoleInfo = console.info;
|
|
48505
|
+
const originalConsoleWarn = console.warn;
|
|
48506
|
+
const originalConsoleError = console.error;
|
|
48507
|
+
const originalConsoleLog = console.log;
|
|
48508
|
+
let isCapturing = false;
|
|
48509
|
+
console.info = (...args) => {
|
|
48510
|
+
if (isCapturing) {
|
|
48511
|
+
state.addAgentOutput(args.map(String).join(' '));
|
|
48512
|
+
}
|
|
48513
|
+
// In UI mode, non-captured output is intentionally suppressed
|
|
48514
|
+
// so it does not interfere with the repainted frame.
|
|
48515
|
+
};
|
|
48516
|
+
console.warn = (...args) => {
|
|
48517
|
+
if (isCapturing) {
|
|
48518
|
+
state.addAgentOutput(args.map(String).join(' '));
|
|
48519
|
+
}
|
|
48520
|
+
};
|
|
48521
|
+
console.error = (...args) => {
|
|
48522
|
+
if (isCapturing) {
|
|
48523
|
+
state.addError(args.map(String).join(' '));
|
|
48524
|
+
}
|
|
48525
|
+
};
|
|
48526
|
+
console.log = (...args) => {
|
|
48527
|
+
if (isCapturing) {
|
|
48528
|
+
state.addAgentOutput(args.map(String).join(' '));
|
|
48529
|
+
}
|
|
48530
|
+
};
|
|
48531
|
+
// --- Keyboard input (pause) ---
|
|
48532
|
+
const readline = require('readline');
|
|
48533
|
+
readline.emitKeypressEvents(process.stdin);
|
|
48534
|
+
if (process.stdin.isTTY) {
|
|
48535
|
+
process.stdin.setRawMode(true);
|
|
48536
|
+
}
|
|
48537
|
+
const keypressHandler = (_str, key) => {
|
|
48538
|
+
if (key.ctrl && key.name === 'c') {
|
|
48539
|
+
cleanup();
|
|
48540
|
+
process.exit(0);
|
|
48541
|
+
}
|
|
48542
|
+
if (key.name === 'p') {
|
|
48543
|
+
const current = getPauseState();
|
|
48544
|
+
if (current === 'RUNNING') {
|
|
48545
|
+
requestPause();
|
|
48546
|
+
}
|
|
48547
|
+
else {
|
|
48548
|
+
requestResume();
|
|
48549
|
+
}
|
|
48550
|
+
}
|
|
48551
|
+
};
|
|
48552
|
+
process.stdin.on('keypress', keypressHandler);
|
|
48553
|
+
// --- Rendering ---
|
|
48554
|
+
let spinnerFrame = 0;
|
|
48555
|
+
let previousFrameLineCount = 0;
|
|
48556
|
+
let isRendering = false;
|
|
48557
|
+
let renderScheduled = false;
|
|
48558
|
+
/**
|
|
48559
|
+
* Schedules a render on the next tick if one isn't already pending.
|
|
48560
|
+
* Prevents overlapping renders that cause cursor desync.
|
|
48561
|
+
*/
|
|
48562
|
+
function scheduleRender() {
|
|
48563
|
+
if (renderScheduled) {
|
|
48564
|
+
return;
|
|
48565
|
+
}
|
|
48566
|
+
renderScheduled = true;
|
|
48567
|
+
setImmediate(() => {
|
|
48568
|
+
renderScheduled = false;
|
|
48569
|
+
render();
|
|
48570
|
+
});
|
|
48571
|
+
}
|
|
48572
|
+
/**
|
|
48573
|
+
* Clears previously rendered lines and writes a new frame.
|
|
48574
|
+
*/
|
|
48575
|
+
function render() {
|
|
48576
|
+
if (isRendering) {
|
|
48577
|
+
return;
|
|
48578
|
+
}
|
|
48579
|
+
isRendering = true;
|
|
48580
|
+
try {
|
|
48581
|
+
const lines = buildFrame();
|
|
48582
|
+
// Move cursor up to clear the previous frame.
|
|
48583
|
+
if (previousFrameLineCount > 0) {
|
|
48584
|
+
process.stdout.write(`\x1b[${previousFrameLineCount}A`);
|
|
48585
|
+
}
|
|
48586
|
+
for (let i = 0; i < lines.length; i++) {
|
|
48587
|
+
clearLine(process.stdout, 0);
|
|
48588
|
+
cursorTo(process.stdout, 0);
|
|
48589
|
+
process.stdout.write(lines[i]);
|
|
48590
|
+
if (i < lines.length - 1) {
|
|
48591
|
+
process.stdout.write('\n');
|
|
48592
|
+
}
|
|
48593
|
+
}
|
|
48594
|
+
// Clear any leftover lines from a previous longer frame.
|
|
48595
|
+
if (lines.length < previousFrameLineCount) {
|
|
48596
|
+
for (let i = lines.length; i < previousFrameLineCount; i++) {
|
|
48597
|
+
process.stdout.write('\n');
|
|
48598
|
+
clearLine(process.stdout, 0);
|
|
48599
|
+
cursorTo(process.stdout, 0);
|
|
48600
|
+
}
|
|
48601
|
+
// Move back up to the end of the current frame.
|
|
48602
|
+
const overshoot = previousFrameLineCount - lines.length;
|
|
48603
|
+
if (overshoot > 0) {
|
|
48604
|
+
process.stdout.write(`\x1b[${overshoot}A`);
|
|
48605
|
+
}
|
|
48606
|
+
}
|
|
48607
|
+
previousFrameLineCount = lines.length;
|
|
48608
|
+
spinnerFrame = (spinnerFrame + 1) % SPINNER_FRAMES.length;
|
|
48609
|
+
}
|
|
48610
|
+
finally {
|
|
48611
|
+
isRendering = false;
|
|
48612
|
+
}
|
|
48613
|
+
}
|
|
48614
|
+
/**
|
|
48615
|
+
* Builds the complete frame as an array of terminal lines.
|
|
48616
|
+
*/
|
|
48617
|
+
function buildFrame() {
|
|
48618
|
+
const w = getTerminalWidth();
|
|
48619
|
+
const sep = colors.gray('\u2500'.repeat(w - 2));
|
|
48620
|
+
const spinner = SPINNER_FRAMES[spinnerFrame];
|
|
48621
|
+
const { config, phase, currentPromptLabel, currentAttempt, maxAttempts, statusMessage, agentOutputLines, errors, } = state;
|
|
48622
|
+
const progress = state.getProgress();
|
|
48623
|
+
const isPaused = getPauseState() !== 'RUNNING';
|
|
48624
|
+
const isActive = phase === 'running' || phase === 'verifying' || phase === 'loading';
|
|
48625
|
+
const lines = [];
|
|
48626
|
+
// --- Branding ---
|
|
48627
|
+
lines.push(colors.bold.cyan('\u2728 Promptbook Coder'));
|
|
48628
|
+
// --- Config ---
|
|
48629
|
+
let configLine1 = `Agent: ${colors.bold.green(config.agentName)}`;
|
|
48630
|
+
if (config.modelName) {
|
|
48631
|
+
configLine1 += ` \u2502 Model: ${colors.bold(config.modelName)}`;
|
|
48632
|
+
}
|
|
48633
|
+
if (config.thinkingLevel) {
|
|
48634
|
+
configLine1 += ` \u2502 Thinking: ${colors.bold(config.thinkingLevel)}`;
|
|
48635
|
+
}
|
|
48636
|
+
lines.push(configLine1);
|
|
48637
|
+
let configLine2 = '';
|
|
48638
|
+
if (config.context) {
|
|
48639
|
+
configLine2 += `Context: ${colors.yellow(config.context)} \u2502 `;
|
|
48640
|
+
}
|
|
48641
|
+
configLine2 += `Priority: \u2265${config.priority}`;
|
|
48642
|
+
if (config.testCommand) {
|
|
48643
|
+
configLine2 += ` \u2502 Test: ${colors.gray(config.testCommand)}`;
|
|
48644
|
+
}
|
|
48645
|
+
lines.push(configLine2);
|
|
48646
|
+
// --- Separator ---
|
|
48647
|
+
lines.push(sep);
|
|
48648
|
+
// --- Progress ---
|
|
48649
|
+
const progressSummary = [
|
|
48650
|
+
`${progress.sessionDone}/${progress.sessionTotal} Prompts (${progress.totalPrompts} total)`,
|
|
48651
|
+
`${progress.elapsedText}/${progress.estimatedTotalText}`,
|
|
48652
|
+
`Est. done ${progress.estimatedLabel}`,
|
|
48653
|
+
].join(' \u2502 ');
|
|
48654
|
+
lines.push(progressSummary);
|
|
48655
|
+
lines.push(buildProgressBar(progress.percentage));
|
|
48656
|
+
// --- Separator ---
|
|
48657
|
+
lines.push(sep);
|
|
48658
|
+
// --- Current prompt ---
|
|
48659
|
+
if (currentPromptLabel) {
|
|
48660
|
+
const spinnerPrefix = isActive ? colors.yellow(`${spinner} `) : ' ';
|
|
48661
|
+
lines.push(spinnerPrefix + colors.bold(currentPromptLabel));
|
|
48662
|
+
lines.push(colors.gray(`Attempt ${currentAttempt}/${maxAttempts} \u2502 ${statusMessage}`));
|
|
48663
|
+
}
|
|
48664
|
+
else {
|
|
48665
|
+
lines.push(colors.gray(statusMessage));
|
|
48666
|
+
}
|
|
48667
|
+
// --- Agent output ---
|
|
48668
|
+
if (agentOutputLines.length > 0) {
|
|
48669
|
+
lines.push('');
|
|
48670
|
+
lines.push(colors.gray.bold('Agent output:'));
|
|
48671
|
+
const visibleLines = agentOutputLines.slice(-MAX_VISIBLE_OUTPUT_LINES);
|
|
48672
|
+
for (const line of visibleLines) {
|
|
48673
|
+
const cleanLine = stripAnsi(line);
|
|
48674
|
+
// Truncate to terminal width.
|
|
48675
|
+
const truncated = cleanLine.length > w - 2 ? cleanLine.slice(0, w - 5) + '...' : cleanLine;
|
|
48676
|
+
lines.push(colors.gray(truncated));
|
|
48677
|
+
}
|
|
48678
|
+
}
|
|
48679
|
+
// --- Errors ---
|
|
48680
|
+
if (errors.length > 0) {
|
|
48681
|
+
lines.push('');
|
|
48682
|
+
for (const err of errors) {
|
|
48683
|
+
lines.push(colors.red(`\u2717 ${err}`));
|
|
48684
|
+
}
|
|
48685
|
+
}
|
|
48686
|
+
// --- Separator ---
|
|
48687
|
+
lines.push(sep);
|
|
48688
|
+
// --- Controls ---
|
|
48689
|
+
const pauseLabel = isPaused
|
|
48690
|
+
? colors.bgYellow.black(' PAUSED ') + colors.gray(' [P] Resume \u2502 Ctrl+C Exit')
|
|
48691
|
+
: colors.gray('[P] Pause \u2502 Ctrl+C Exit');
|
|
48692
|
+
lines.push(pauseLabel);
|
|
48693
|
+
return lines;
|
|
48694
|
+
}
|
|
48695
|
+
// Initial render.
|
|
48696
|
+
process.stdout.write('\n');
|
|
48697
|
+
render();
|
|
48698
|
+
const interval = setInterval(scheduleRender, UI_REFRESH_INTERVAL_MS);
|
|
48699
|
+
// Listen for state changes and schedule a re-render (debounced).
|
|
48700
|
+
state.on('change', scheduleRender);
|
|
48701
|
+
// --- Cleanup ---
|
|
48702
|
+
function cleanup() {
|
|
48703
|
+
clearInterval(interval);
|
|
48704
|
+
state.off('change', scheduleRender);
|
|
48705
|
+
process.stdin.off('keypress', keypressHandler);
|
|
48706
|
+
if (process.stdin.isTTY) {
|
|
48707
|
+
process.stdin.setRawMode(false);
|
|
48708
|
+
}
|
|
48709
|
+
isCapturing = false;
|
|
48710
|
+
console.info = originalConsoleInfo;
|
|
48711
|
+
console.warn = originalConsoleWarn;
|
|
48712
|
+
console.error = originalConsoleError;
|
|
48713
|
+
console.log = originalConsoleLog;
|
|
48714
|
+
// Render one final frame so the user sees the last state.
|
|
48715
|
+
render();
|
|
48716
|
+
process.stdout.write('\n');
|
|
48717
|
+
}
|
|
48718
|
+
return {
|
|
48719
|
+
state,
|
|
48720
|
+
startCapturingAgentOutput() {
|
|
48721
|
+
isCapturing = true;
|
|
48722
|
+
},
|
|
48723
|
+
stopCapturingAgentOutput() {
|
|
48724
|
+
isCapturing = false;
|
|
48725
|
+
},
|
|
48726
|
+
cleanup,
|
|
48727
|
+
};
|
|
48728
|
+
}
|
|
48729
|
+
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
48730
|
+
|
|
47863
48731
|
/**
|
|
47864
48732
|
* Constant for prompts dir.
|
|
47865
48733
|
*/
|
|
@@ -47922,8 +48790,13 @@ async function runCodexPrompts(providedOptions) {
|
|
|
47922
48790
|
`));
|
|
47923
48791
|
}
|
|
47924
48792
|
const runStartDate = moment();
|
|
47925
|
-
const
|
|
47926
|
-
|
|
48793
|
+
const isUiMode = !options.dryRun && Boolean(process.stdout.isTTY);
|
|
48794
|
+
const progressDisplay = options.dryRun || isUiMode ? undefined : new CliProgressDisplay(runStartDate);
|
|
48795
|
+
const uiHandle = isUiMode ? renderCoderRunUi(runStartDate) : undefined;
|
|
48796
|
+
// When the Ink UI is active it handles keyboard input itself, so skip the raw stdin listener.
|
|
48797
|
+
if (!isUiMode) {
|
|
48798
|
+
listenForPause();
|
|
48799
|
+
}
|
|
47927
48800
|
try {
|
|
47928
48801
|
const resolvedCoderContext = await resolveCoderContext(options.context, process.cwd());
|
|
47929
48802
|
if (options.dryRun) {
|
|
@@ -48022,35 +48895,78 @@ async function runCodexPrompts(providedOptions) {
|
|
|
48022
48895
|
}
|
|
48023
48896
|
console.info(colors.green(`Running prompts with ${runner.name}`));
|
|
48024
48897
|
const runnerMetadata = getRunnerMetadata(options, actualRunnerModel);
|
|
48898
|
+
// Feed configuration into the terminal UI
|
|
48899
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setConfig({
|
|
48900
|
+
agentName: runner.name,
|
|
48901
|
+
modelName: actualRunnerModel,
|
|
48902
|
+
thinkingLevel: options.thinkingLevel,
|
|
48903
|
+
context: options.context,
|
|
48904
|
+
priority: options.priority,
|
|
48905
|
+
testCommand: options.testCommand,
|
|
48906
|
+
});
|
|
48907
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('loading');
|
|
48908
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(`Running prompts with ${runner.name}`);
|
|
48025
48909
|
let hasShownUpcomingTasks = false;
|
|
48026
48910
|
let hasWaitedForStart = false;
|
|
48027
48911
|
while (just(true)) {
|
|
48028
|
-
await checkPause(
|
|
48912
|
+
await checkPause({
|
|
48913
|
+
silent: isUiMode,
|
|
48914
|
+
onPaused: () => {
|
|
48915
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.pauseTimer();
|
|
48916
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('paused');
|
|
48917
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Paused');
|
|
48918
|
+
},
|
|
48919
|
+
onResumed: () => {
|
|
48920
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.resumeTimer();
|
|
48921
|
+
},
|
|
48922
|
+
});
|
|
48923
|
+
if (isUiMode) {
|
|
48924
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('loading');
|
|
48925
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Loading prompts...');
|
|
48926
|
+
}
|
|
48029
48927
|
const promptFiles = await loadPromptFiles(PROMPTS_DIR$1);
|
|
48030
48928
|
const stats = summarizePrompts(promptFiles, options.priority);
|
|
48031
48929
|
progressDisplay === null || progressDisplay === void 0 ? void 0 : progressDisplay.update(stats);
|
|
48032
|
-
|
|
48930
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.updateProgress(stats);
|
|
48931
|
+
if (!isUiMode) {
|
|
48932
|
+
printStats(stats, options.priority);
|
|
48933
|
+
}
|
|
48033
48934
|
const nextPrompt = findNextTodoPrompt(promptFiles, options.priority);
|
|
48034
48935
|
if (!hasShownUpcomingTasks) {
|
|
48035
|
-
if (stats.toBeWritten > 0) {
|
|
48936
|
+
if (stats.toBeWritten > 0 && !isUiMode) {
|
|
48036
48937
|
console.info(colors.yellow('Following prompts need to be written:'));
|
|
48037
48938
|
printPromptsToBeWritten(promptFiles, options.priority);
|
|
48038
48939
|
console.info('');
|
|
48039
48940
|
}
|
|
48040
|
-
|
|
48941
|
+
if (!isUiMode) {
|
|
48942
|
+
printUpcomingTasks(listUpcomingTasks(promptFiles, options.priority));
|
|
48943
|
+
}
|
|
48041
48944
|
hasShownUpcomingTasks = true;
|
|
48042
48945
|
}
|
|
48043
48946
|
if (!nextPrompt) {
|
|
48044
48947
|
if (stats.toBeWritten > 0) {
|
|
48045
|
-
|
|
48948
|
+
const message = 'No prompts ready for agent.';
|
|
48949
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(message);
|
|
48950
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('done');
|
|
48951
|
+
if (!isUiMode) {
|
|
48952
|
+
console.info(colors.yellow(message));
|
|
48953
|
+
}
|
|
48046
48954
|
}
|
|
48047
48955
|
else {
|
|
48048
|
-
|
|
48956
|
+
const message = 'All prompts are done.';
|
|
48957
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(message);
|
|
48958
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('done');
|
|
48959
|
+
if (!isUiMode) {
|
|
48960
|
+
console.info(colors.green(message));
|
|
48961
|
+
}
|
|
48049
48962
|
}
|
|
48050
48963
|
return;
|
|
48051
48964
|
}
|
|
48052
48965
|
if (options.waitForUser) {
|
|
48966
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.pauseTimer();
|
|
48967
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(hasWaitedForStart ? 'Waiting... Press Enter to continue' : 'Waiting... Press Enter to start');
|
|
48053
48968
|
await waitForPromptStart(nextPrompt.file, nextPrompt.section, !hasWaitedForStart);
|
|
48969
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.resumeTimer();
|
|
48054
48970
|
hasWaitedForStart = true;
|
|
48055
48971
|
}
|
|
48056
48972
|
if (!options.ignoreGitChanges) {
|
|
@@ -48060,29 +48976,57 @@ async function runCodexPrompts(providedOptions) {
|
|
|
48060
48976
|
const codexPrompt = appendCoderContext(buildCodexPrompt(nextPrompt.file, nextPrompt.section), resolvedCoderContext);
|
|
48061
48977
|
const scriptPath = buildScriptPath(nextPrompt.file, nextPrompt.section);
|
|
48062
48978
|
const promptLabel = buildPromptLabelForDisplay(nextPrompt.file, nextPrompt.section);
|
|
48063
|
-
|
|
48979
|
+
if (isUiMode) {
|
|
48980
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setCurrentPrompt(promptLabel);
|
|
48981
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('running');
|
|
48982
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Running');
|
|
48983
|
+
}
|
|
48984
|
+
else {
|
|
48985
|
+
console.info(colors.blue(`Processing ${promptLabel}`));
|
|
48986
|
+
}
|
|
48064
48987
|
const promptExecutionStartedDate = moment();
|
|
48988
|
+
let attemptCount = 1;
|
|
48065
48989
|
const roundChangedFilesSnapshot = options.normalizeLineEndings
|
|
48066
48990
|
? await captureChangedFilesSnapshot(process.cwd())
|
|
48067
48991
|
: undefined;
|
|
48068
48992
|
try {
|
|
48069
|
-
|
|
48993
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.startCapturingAgentOutput();
|
|
48994
|
+
const result = await runPromptWithTestFeedback({
|
|
48995
|
+
runner,
|
|
48070
48996
|
prompt: codexPrompt,
|
|
48071
48997
|
scriptPath,
|
|
48072
48998
|
projectPath: process.cwd(),
|
|
48999
|
+
promptLabel,
|
|
49000
|
+
testCommand: options.testCommand,
|
|
49001
|
+
onAttemptStarted: (nextAttemptCount) => {
|
|
49002
|
+
attemptCount = nextAttemptCount;
|
|
49003
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setAttempt(nextAttemptCount);
|
|
49004
|
+
if (nextAttemptCount > 1) {
|
|
49005
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(`Retrying (attempt ${nextAttemptCount})`);
|
|
49006
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('verifying');
|
|
49007
|
+
}
|
|
49008
|
+
},
|
|
48073
49009
|
});
|
|
48074
|
-
|
|
49010
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.stopCapturingAgentOutput();
|
|
49011
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Committing changes');
|
|
49012
|
+
markPromptDone(nextPrompt.file, nextPrompt.section, result.usage, runnerMetadata.runnerName, runnerMetadata.modelName, promptExecutionStartedDate, result.attemptCount);
|
|
48075
49013
|
await writePromptFile(nextPrompt.file);
|
|
48076
49014
|
await normalizeLineEndingsForCurrentRound(options, roundChangedFilesSnapshot);
|
|
48077
49015
|
if (options.waitForUser) {
|
|
49016
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.pauseTimer();
|
|
49017
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Waiting... Press Enter to commit');
|
|
48078
49018
|
printCommitMessage(commitMessage);
|
|
48079
49019
|
await waitForEnter(colors.bgWhite('Press Enter to commit and continue...'));
|
|
49020
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.resumeTimer();
|
|
48080
49021
|
}
|
|
48081
|
-
await commitChanges(commitMessage, {
|
|
49022
|
+
await commitChanges(commitMessage, { autoPush: options.autoPush });
|
|
48082
49023
|
await runPostPromptAutoMigrationIfEnabled(options);
|
|
48083
49024
|
}
|
|
48084
49025
|
catch (error) {
|
|
48085
|
-
|
|
49026
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.stopCapturingAgentOutput();
|
|
49027
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('error');
|
|
49028
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.addError(error instanceof Error ? error.message : String(error));
|
|
49029
|
+
markPromptFailed(nextPrompt.file, nextPrompt.section, runnerMetadata.runnerName, runnerMetadata.modelName, promptExecutionStartedDate, attemptCount);
|
|
48086
49030
|
await writePromptFile(nextPrompt.file);
|
|
48087
49031
|
await writePromptErrorLog({
|
|
48088
49032
|
file: nextPrompt.file,
|
|
@@ -48098,6 +49042,7 @@ async function runCodexPrompts(providedOptions) {
|
|
|
48098
49042
|
}
|
|
48099
49043
|
finally {
|
|
48100
49044
|
progressDisplay === null || progressDisplay === void 0 ? void 0 : progressDisplay.stop();
|
|
49045
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.cleanup();
|
|
48101
49046
|
if (!options.dryRun) {
|
|
48102
49047
|
printAgentGitIdentityTipIfNeeded();
|
|
48103
49048
|
}
|
|
@@ -48159,24 +49104,26 @@ const SNIPPET_CHAR_LIMIT = 900;
|
|
|
48159
49104
|
*/
|
|
48160
49105
|
const MAX_PENDING_FILE_NAMES = 8;
|
|
48161
49106
|
/**
|
|
48162
|
-
*
|
|
49107
|
+
* Default verification options parsed from the current process arguments.
|
|
48163
49108
|
*/
|
|
48164
|
-
const
|
|
49109
|
+
const DEFAULT_VERIFY_PROMPTS_OPTIONS = normalizeVerifyPromptsOptions(parseVerifyPromptsCliOptions(process.argv.slice(2)));
|
|
48165
49110
|
/**
|
|
48166
49111
|
* Starts the verification loop and exits when no `[ ]` prompts remain.
|
|
48167
49112
|
*
|
|
48168
|
-
* @param reverse - Process files in reverse order
|
|
48169
|
-
*
|
|
48170
49113
|
* @public exported from `@promptbook/cli`
|
|
48171
49114
|
*/
|
|
48172
|
-
async function verifyPrompts(
|
|
49115
|
+
async function verifyPrompts(options = DEFAULT_VERIFY_PROMPTS_OPTIONS) {
|
|
49116
|
+
const normalizedOptions = normalizeVerifyPromptsOptions(options);
|
|
48173
49117
|
console.info(colors.cyan.bold('📋 Prompt verification helper'));
|
|
48174
|
-
if (reverse) {
|
|
49118
|
+
if (normalizedOptions.reverse) {
|
|
48175
49119
|
console.info(colors.gray('Processing files in reverse order'));
|
|
48176
49120
|
}
|
|
48177
|
-
|
|
48178
|
-
|
|
48179
|
-
|
|
49121
|
+
if (normalizedOptions.ignore.length > 0) {
|
|
49122
|
+
console.info(colors.gray(`Ignoring candidates matching: ${normalizedOptions.ignore.join(', ')}`));
|
|
49123
|
+
}
|
|
49124
|
+
const { promptFiles: initialFiles, ignoredPromptFiles } = await loadPromptFilesForVerification(normalizedOptions);
|
|
49125
|
+
if (ignoredPromptFiles.length > 0) {
|
|
49126
|
+
console.info(colors.gray(`Ignored ${ignoredPromptFiles.length} prompt file(s) for this run.`));
|
|
48180
49127
|
}
|
|
48181
49128
|
displayTopLevelFileList(initialFiles);
|
|
48182
49129
|
await prepareArchiveDirectory();
|
|
@@ -48191,10 +49138,7 @@ async function verifyPrompts(reverse = REVERSE_ORDER) {
|
|
|
48191
49138
|
if (wasSkipped) {
|
|
48192
49139
|
skippedFiles.add(fileWithAllDone.path);
|
|
48193
49140
|
}
|
|
48194
|
-
promptFiles = await
|
|
48195
|
-
if (REVERSE_ORDER) {
|
|
48196
|
-
promptFiles.reverse();
|
|
48197
|
-
}
|
|
49141
|
+
promptFiles = (await loadPromptFilesForVerification(normalizedOptions)).promptFiles;
|
|
48198
49142
|
continue;
|
|
48199
49143
|
}
|
|
48200
49144
|
// Second priority: process todo prompts
|
|
@@ -48204,11 +49148,56 @@ async function verifyPrompts(reverse = REVERSE_ORDER) {
|
|
|
48204
49148
|
break;
|
|
48205
49149
|
}
|
|
48206
49150
|
await resolvePrompt(nextPrompt);
|
|
48207
|
-
promptFiles = await
|
|
48208
|
-
|
|
48209
|
-
|
|
49151
|
+
promptFiles = (await loadPromptFilesForVerification(normalizedOptions)).promptFiles;
|
|
49152
|
+
}
|
|
49153
|
+
}
|
|
49154
|
+
/**
|
|
49155
|
+
* Parses supported command-line arguments for the standalone verification script.
|
|
49156
|
+
*/
|
|
49157
|
+
function parseVerifyPromptsCliOptions(args) {
|
|
49158
|
+
return {
|
|
49159
|
+
reverse: args.includes('--reverse'),
|
|
49160
|
+
ignore: readRepeatableStringOption(args, '--ignore'),
|
|
49161
|
+
};
|
|
49162
|
+
}
|
|
49163
|
+
/**
|
|
49164
|
+
* Loads prompt files and applies ordering plus ignore filters for one verification pass.
|
|
49165
|
+
*/
|
|
49166
|
+
async function loadPromptFilesForVerification(options) {
|
|
49167
|
+
const loadedPromptFiles = await loadPromptFiles(PROMPTS_DIR);
|
|
49168
|
+
const { promptFiles, ignoredPromptFiles } = partitionPromptFilesByIgnore(loadedPromptFiles, options.ignore);
|
|
49169
|
+
if (options.reverse) {
|
|
49170
|
+
promptFiles.reverse();
|
|
49171
|
+
}
|
|
49172
|
+
return { promptFiles, ignoredPromptFiles };
|
|
49173
|
+
}
|
|
49174
|
+
/**
|
|
49175
|
+
* Splits prompt files into files that should be verified now and files ignored for this run.
|
|
49176
|
+
*
|
|
49177
|
+
* @public exported from `@promptbook/cli`
|
|
49178
|
+
*/
|
|
49179
|
+
function partitionPromptFilesByIgnore(promptFiles, ignoreValues) {
|
|
49180
|
+
const normalizedIgnoreValues = normalizeIgnoreValues(ignoreValues);
|
|
49181
|
+
if (normalizedIgnoreValues.length === 0) {
|
|
49182
|
+
return {
|
|
49183
|
+
promptFiles: [...promptFiles],
|
|
49184
|
+
ignoredPromptFiles: [],
|
|
49185
|
+
};
|
|
49186
|
+
}
|
|
49187
|
+
const promptFilesToVerify = [];
|
|
49188
|
+
const ignoredPromptFiles = [];
|
|
49189
|
+
for (const promptFile of promptFiles) {
|
|
49190
|
+
if (matchesIgnoredPromptFile(promptFile, normalizedIgnoreValues)) {
|
|
49191
|
+
ignoredPromptFiles.push(promptFile);
|
|
49192
|
+
}
|
|
49193
|
+
else {
|
|
49194
|
+
promptFilesToVerify.push(promptFile);
|
|
48210
49195
|
}
|
|
48211
49196
|
}
|
|
49197
|
+
return {
|
|
49198
|
+
promptFiles: promptFilesToVerify,
|
|
49199
|
+
ignoredPromptFiles,
|
|
49200
|
+
};
|
|
48212
49201
|
}
|
|
48213
49202
|
/**
|
|
48214
49203
|
* Ensures the destination directory for completed prompts exists.
|
|
@@ -48216,13 +49205,92 @@ async function verifyPrompts(reverse = REVERSE_ORDER) {
|
|
|
48216
49205
|
async function prepareArchiveDirectory() {
|
|
48217
49206
|
await mkdir(DONE_PROMPTS_DIR, { recursive: true });
|
|
48218
49207
|
}
|
|
49208
|
+
/**
|
|
49209
|
+
* Normalizes verification options so the rest of the flow can assume stable defaults.
|
|
49210
|
+
*/
|
|
49211
|
+
function normalizeVerifyPromptsOptions(options) {
|
|
49212
|
+
var _a, _b;
|
|
49213
|
+
return {
|
|
49214
|
+
reverse: (_a = options.reverse) !== null && _a !== void 0 ? _a : false,
|
|
49215
|
+
ignore: normalizeIgnoreValues((_b = options.ignore) !== null && _b !== void 0 ? _b : []),
|
|
49216
|
+
};
|
|
49217
|
+
}
|
|
49218
|
+
/**
|
|
49219
|
+
* Normalizes ignore values and removes empty or duplicate entries case-insensitively.
|
|
49220
|
+
*/
|
|
49221
|
+
function normalizeIgnoreValues(ignoreValues) {
|
|
49222
|
+
const normalizedIgnoreValues = [];
|
|
49223
|
+
const seenIgnoreValues = new Set();
|
|
49224
|
+
for (const ignoreValue of ignoreValues) {
|
|
49225
|
+
const trimmedIgnoreValue = ignoreValue.trim();
|
|
49226
|
+
if (!trimmedIgnoreValue) {
|
|
49227
|
+
continue;
|
|
49228
|
+
}
|
|
49229
|
+
const lowerCasedIgnoreValue = trimmedIgnoreValue.toLowerCase();
|
|
49230
|
+
if (seenIgnoreValues.has(lowerCasedIgnoreValue)) {
|
|
49231
|
+
continue;
|
|
49232
|
+
}
|
|
49233
|
+
seenIgnoreValues.add(lowerCasedIgnoreValue);
|
|
49234
|
+
normalizedIgnoreValues.push(trimmedIgnoreValue);
|
|
49235
|
+
}
|
|
49236
|
+
return normalizedIgnoreValues;
|
|
49237
|
+
}
|
|
49238
|
+
/**
|
|
49239
|
+
* Reads one repeatable string option from raw CLI arguments.
|
|
49240
|
+
*/
|
|
49241
|
+
function readRepeatableStringOption(args, flag) {
|
|
49242
|
+
const values = [];
|
|
49243
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
49244
|
+
const argument = args[index];
|
|
49245
|
+
if (!argument) {
|
|
49246
|
+
continue;
|
|
49247
|
+
}
|
|
49248
|
+
if (argument === flag) {
|
|
49249
|
+
const nextValue = args[index + 1];
|
|
49250
|
+
if (nextValue !== undefined && !nextValue.startsWith('--')) {
|
|
49251
|
+
values.push(nextValue);
|
|
49252
|
+
index += 1;
|
|
49253
|
+
}
|
|
49254
|
+
continue;
|
|
49255
|
+
}
|
|
49256
|
+
if (argument.startsWith(`${flag}=`)) {
|
|
49257
|
+
values.push(argument.slice(flag.length + 1));
|
|
49258
|
+
}
|
|
49259
|
+
}
|
|
49260
|
+
return values;
|
|
49261
|
+
}
|
|
49262
|
+
/**
|
|
49263
|
+
* Resolves whether a prompt file should be ignored for this verification run.
|
|
49264
|
+
*/
|
|
49265
|
+
function matchesIgnoredPromptFile(promptFile, ignoreValues) {
|
|
49266
|
+
const searchableValues = [promptFile.name, getPromptFileFirstLine(promptFile)].map((value) => value.toLowerCase());
|
|
49267
|
+
return ignoreValues.some((ignoreValue) => {
|
|
49268
|
+
const lowerCasedIgnoreValue = ignoreValue.toLowerCase();
|
|
49269
|
+
return searchableValues.some((searchableValue) => searchableValue.includes(lowerCasedIgnoreValue));
|
|
49270
|
+
});
|
|
49271
|
+
}
|
|
49272
|
+
/**
|
|
49273
|
+
* Returns the first meaningful line of the prompt file after the status line.
|
|
49274
|
+
*/
|
|
49275
|
+
function getPromptFileFirstLine(promptFile) {
|
|
49276
|
+
var _a;
|
|
49277
|
+
const firstSection = promptFile.sections[0];
|
|
49278
|
+
const startLineIndex = (firstSection === null || firstSection === void 0 ? void 0 : firstSection.statusLineIndex) !== undefined ? firstSection.statusLineIndex + 1 : ((_a = firstSection === null || firstSection === void 0 ? void 0 : firstSection.startLine) !== null && _a !== void 0 ? _a : 0);
|
|
49279
|
+
for (let index = startLineIndex; index < promptFile.lines.length; index += 1) {
|
|
49280
|
+
const line = promptFile.lines[index];
|
|
49281
|
+
if (line !== undefined && line.trim() !== '') {
|
|
49282
|
+
return line.trim();
|
|
49283
|
+
}
|
|
49284
|
+
}
|
|
49285
|
+
return '';
|
|
49286
|
+
}
|
|
48219
49287
|
/**
|
|
48220
49288
|
* Displays the list of files that currently live in the prompts root.
|
|
48221
49289
|
*/
|
|
48222
49290
|
function displayTopLevelFileList(promptFiles) {
|
|
48223
49291
|
console.info(colors.cyan('\nTop-level prompt files:'));
|
|
48224
49292
|
if (!promptFiles.length) {
|
|
48225
|
-
console.info(colors.gray(' (no markdown files found in prompts/)'));
|
|
49293
|
+
console.info(colors.gray(' (no prompt markdown files found for this run in prompts/)'));
|
|
48226
49294
|
return;
|
|
48227
49295
|
}
|
|
48228
49296
|
for (const file of promptFiles) {
|
|
@@ -48539,7 +49607,7 @@ function isNotFound(error) {
|
|
|
48539
49607
|
}
|
|
48540
49608
|
// Note: When run as a standalone script, call the exported function
|
|
48541
49609
|
if (require.main === module) {
|
|
48542
|
-
verifyPrompts(
|
|
49610
|
+
verifyPrompts(DEFAULT_VERIFY_PROMPTS_OPTIONS).catch((error) => {
|
|
48543
49611
|
console.error(colors.bgRed('Prompt verification failed:'), error);
|
|
48544
49612
|
process.exit(1);
|
|
48545
49613
|
});
|
|
@@ -48547,7 +49615,8 @@ if (require.main === module) {
|
|
|
48547
49615
|
|
|
48548
49616
|
var verifyPrompts$1 = /*#__PURE__*/Object.freeze({
|
|
48549
49617
|
__proto__: null,
|
|
48550
|
-
verifyPrompts: verifyPrompts
|
|
49618
|
+
verifyPrompts: verifyPrompts,
|
|
49619
|
+
partitionPromptFilesByIgnore: partitionPromptFilesByIgnore
|
|
48551
49620
|
});
|
|
48552
49621
|
|
|
48553
49622
|
/**
|
|
@@ -49596,7 +50665,7 @@ function promptbookifyAiText(text) {
|
|
|
49596
50665
|
/**
|
|
49597
50666
|
* Constant for default agent kit model name.
|
|
49598
50667
|
*/
|
|
49599
|
-
const DEFAULT_AGENT_KIT_MODEL_NAME = 'gpt-5.4-
|
|
50668
|
+
const DEFAULT_AGENT_KIT_MODEL_NAME = 'gpt-5.4-mini';
|
|
49600
50669
|
/**
|
|
49601
50670
|
* Creates one structured log entry for streamed tool-call updates.
|
|
49602
50671
|
*
|
|
@@ -50646,6 +51715,7 @@ class AgentLlmExecutionTools {
|
|
|
50646
51715
|
* @param agentSource The agent source string that defines the agent's behavior
|
|
50647
51716
|
*/
|
|
50648
51717
|
constructor(options) {
|
|
51718
|
+
var _a;
|
|
50649
51719
|
this.options = options;
|
|
50650
51720
|
/**
|
|
50651
51721
|
* Cached model requirements to avoid re-parsing the agent source
|
|
@@ -50655,6 +51725,7 @@ class AgentLlmExecutionTools {
|
|
|
50655
51725
|
* Cached parsed agent information
|
|
50656
51726
|
*/
|
|
50657
51727
|
this._cachedAgentInfo = null;
|
|
51728
|
+
this.precomputedModelRequirements = (_a = options.precomputedModelRequirements) !== null && _a !== void 0 ? _a : null;
|
|
50658
51729
|
}
|
|
50659
51730
|
/**
|
|
50660
51731
|
* Updates the agent source and clears the cache
|
|
@@ -50662,9 +51733,13 @@ class AgentLlmExecutionTools {
|
|
|
50662
51733
|
* @param agentSource The new agent source string
|
|
50663
51734
|
*/
|
|
50664
51735
|
updateAgentSource(agentSource) {
|
|
51736
|
+
if (this.options.agentSource === agentSource) {
|
|
51737
|
+
return;
|
|
51738
|
+
}
|
|
50665
51739
|
this.options.agentSource = agentSource;
|
|
50666
51740
|
this._cachedAgentInfo = null;
|
|
50667
51741
|
this._cachedModelRequirements = null;
|
|
51742
|
+
this.precomputedModelRequirements = null;
|
|
50668
51743
|
}
|
|
50669
51744
|
/**
|
|
50670
51745
|
* Get cached or parse agent information
|
|
@@ -50681,6 +51756,16 @@ class AgentLlmExecutionTools {
|
|
|
50681
51756
|
* Note: [🐤] This is names `getModelRequirements` *(not `getAgentModelRequirements`)* because in future these two will be united
|
|
50682
51757
|
*/
|
|
50683
51758
|
async getModelRequirements() {
|
|
51759
|
+
var _a, _b;
|
|
51760
|
+
if (this.precomputedModelRequirements !== null) {
|
|
51761
|
+
if (this.options.isVerbose) {
|
|
51762
|
+
console.info('[🤰]', 'Using precomputed agent model requirements', {
|
|
51763
|
+
agent: this.title,
|
|
51764
|
+
toolCount: (_b = (_a = this.precomputedModelRequirements.tools) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0,
|
|
51765
|
+
});
|
|
51766
|
+
}
|
|
51767
|
+
return this.precomputedModelRequirements;
|
|
51768
|
+
}
|
|
50684
51769
|
if (this._cachedModelRequirements === null) {
|
|
50685
51770
|
const preparationStartedAtMs = Date.now();
|
|
50686
51771
|
if (this.options.isVerbose) {
|
|
@@ -50790,6 +51875,7 @@ class AgentLlmExecutionTools {
|
|
|
50790
51875
|
* Resolves agent requirements, attachments, and runtime overrides into one forwarded chat prompt.
|
|
50791
51876
|
*/
|
|
50792
51877
|
async prepareChatPrompt(prompt) {
|
|
51878
|
+
var _a;
|
|
50793
51879
|
const chatPrompt = this.requireChatPrompt(prompt);
|
|
50794
51880
|
const { sanitizedRequirements, promptSuffix } = await this.getSanitizedAgentModelRequirements();
|
|
50795
51881
|
const attachments = normalizeChatAttachments(chatPrompt.attachments);
|
|
@@ -50807,7 +51893,16 @@ class AgentLlmExecutionTools {
|
|
|
50807
51893
|
mergedTools,
|
|
50808
51894
|
knowledgeSourcesForAgent,
|
|
50809
51895
|
});
|
|
50810
|
-
|
|
51896
|
+
if (this.options.isVerbose) {
|
|
51897
|
+
console.info('[🤰]', 'Prepared agent chat prompt', {
|
|
51898
|
+
agent: this.title,
|
|
51899
|
+
usedPrecomputedModelRequirements: this.precomputedModelRequirements !== null,
|
|
51900
|
+
toolNames: mergedTools.map((tool) => tool.name),
|
|
51901
|
+
knowledgeSourcesCount: (_a = knowledgeSourcesForAgent === null || knowledgeSourcesForAgent === void 0 ? void 0 : knowledgeSourcesForAgent.length) !== null && _a !== void 0 ? _a : 0,
|
|
51902
|
+
promptSuffixLength: promptSuffix.length,
|
|
51903
|
+
systemMessageLength: sanitizedRequirements.systemMessage.length,
|
|
51904
|
+
});
|
|
51905
|
+
}
|
|
50811
51906
|
return {
|
|
50812
51907
|
forwardedPrompt,
|
|
50813
51908
|
sanitizedRequirements,
|
|
@@ -50994,6 +52089,7 @@ class AgentLlmExecutionTools {
|
|
|
50994
52089
|
* Runs one prepared prompt through the deprecated OpenAI Assistant backend.
|
|
50995
52090
|
*/
|
|
50996
52091
|
async callOpenAiAssistantChatModelStream(options) {
|
|
52092
|
+
var _a, _b, _c, _d;
|
|
50997
52093
|
const assistant = await this.getOrPrepareOpenAiAssistant({
|
|
50998
52094
|
llmTools: options.llmTools,
|
|
50999
52095
|
originalPrompt: options.originalPrompt,
|
|
@@ -51001,7 +52097,14 @@ class AgentLlmExecutionTools {
|
|
|
51001
52097
|
onProgress: options.onProgress,
|
|
51002
52098
|
});
|
|
51003
52099
|
const promptWithAgentModelRequirementsForOpenAiAssistantExecutionTools = createOpenAiAssistantPrompt(options.preparedChatPrompt.forwardedPrompt);
|
|
51004
|
-
|
|
52100
|
+
if (this.options.isVerbose) {
|
|
52101
|
+
console.info('[🤰]', 'Prepared OpenAI Assistant prompt', {
|
|
52102
|
+
agent: this.title,
|
|
52103
|
+
toolNames: (_b = (_a = promptWithAgentModelRequirementsForOpenAiAssistantExecutionTools.modelRequirements.tools) === null || _a === void 0 ? void 0 : _a.map((tool) => tool.name)) !== null && _b !== void 0 ? _b : [],
|
|
52104
|
+
knowledgeSourcesCount: (_d = (_c = promptWithAgentModelRequirementsForOpenAiAssistantExecutionTools.modelRequirements
|
|
52105
|
+
.knowledgeSources) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0,
|
|
52106
|
+
});
|
|
52107
|
+
}
|
|
51005
52108
|
return assistant.callChatModelStream(promptWithAgentModelRequirementsForOpenAiAssistantExecutionTools, options.onProgress, options.streamOptions);
|
|
51006
52109
|
}
|
|
51007
52110
|
/**
|
|
@@ -51692,7 +52795,8 @@ class Agent extends AgentLlmExecutionTools {
|
|
|
51692
52795
|
isVerbose: options.isVerbose,
|
|
51693
52796
|
llmTools: getSingleLlmExecutionTools(options.executionTools.llm),
|
|
51694
52797
|
assistantPreparationMode: options.assistantPreparationMode,
|
|
51695
|
-
agentSource: agentSource.value,
|
|
52798
|
+
agentSource: agentSource.value,
|
|
52799
|
+
precomputedModelRequirements: options.precomputedModelRequirements,
|
|
51696
52800
|
});
|
|
51697
52801
|
this._agentName = undefined;
|
|
51698
52802
|
/**
|