vigthoria-cli 1.10.50 → 1.10.55

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.
@@ -0,0 +1,19 @@
1
+ import { Config } from '../utils/config.js';
2
+ import { Logger } from '../utils/logger.js';
3
+ interface BackgroundOptions {
4
+ json?: boolean;
5
+ limit?: number;
6
+ workspace?: string;
7
+ }
8
+ export declare class BackgroundCommand {
9
+ private config;
10
+ private logger;
11
+ private api;
12
+ constructor(config: Config, logger: Logger);
13
+ start(promptParts: string[], options?: BackgroundOptions): Promise<void>;
14
+ list(options?: BackgroundOptions): Promise<void>;
15
+ status(jobId: string, options?: BackgroundOptions): Promise<void>;
16
+ apply(jobId: string, options?: BackgroundOptions): Promise<void>;
17
+ cancel(jobId: string, options?: BackgroundOptions): Promise<void>;
18
+ }
19
+ export {};
@@ -0,0 +1,160 @@
1
+ import chalk from 'chalk';
2
+ import { createSpinner, CH } from '../utils/logger.js';
3
+ import { APIClient } from '../utils/api.js';
4
+ export class BackgroundCommand {
5
+ config;
6
+ logger;
7
+ api;
8
+ constructor(config, logger) {
9
+ this.config = config;
10
+ this.logger = logger;
11
+ this.api = new APIClient(config, logger);
12
+ }
13
+ async start(promptParts, options = {}) {
14
+ const prompt = promptParts.join(' ').trim();
15
+ if (!prompt) {
16
+ this.logger.error('Usage: vigthoria background start "<task>"');
17
+ return;
18
+ }
19
+ const workspacePath = options.workspace || process.cwd();
20
+ const spinner = createSpinner('Starting background agent job...').start();
21
+ try {
22
+ const job = await this.api.startV3BackgroundJob(prompt, {
23
+ workspacePath,
24
+ projectPath: workspacePath,
25
+ targetPath: workspacePath,
26
+ localMachineCapable: true,
27
+ executionSurface: 'cli',
28
+ clientSurface: 'cli',
29
+ clientToolExecution: false,
30
+ });
31
+ spinner.stop();
32
+ if (options.json) {
33
+ console.log(JSON.stringify(job, null, 2));
34
+ return;
35
+ }
36
+ console.log(chalk.green(`${CH.success} Background job started`));
37
+ console.log(chalk.gray(` Job: ${job.job_id}`));
38
+ console.log(chalk.gray(` Status: ${job.status}`));
39
+ console.log(chalk.gray(` Workspace: ${workspacePath}`));
40
+ console.log();
41
+ console.log(chalk.gray(`Use ${chalk.cyan(`vigthoria background status ${job.job_id}`)} to check progress.`));
42
+ console.log(chalk.gray(`Use ${chalk.cyan(`vigthoria background apply ${job.job_id}`)} when it is completed.`));
43
+ }
44
+ catch (error) {
45
+ spinner.stop();
46
+ this.logger.error(error?.message || String(error));
47
+ }
48
+ }
49
+ async list(options = {}) {
50
+ const spinner = createSpinner('Loading background jobs...').start();
51
+ try {
52
+ const jobs = await this.api.listV3BackgroundJobs(options.limit || 20);
53
+ spinner.stop();
54
+ if (options.json) {
55
+ console.log(JSON.stringify({ jobs }, null, 2));
56
+ return;
57
+ }
58
+ if (jobs.length === 0) {
59
+ console.log(chalk.gray('No background jobs found.'));
60
+ return;
61
+ }
62
+ console.log(chalk.bold(`\n${CH.success} Background Jobs\n`));
63
+ for (const job of jobs) {
64
+ const color = job.status === 'completed' ? chalk.green : job.status === 'failed' ? chalk.red : job.status === 'cancelled' ? chalk.yellow : chalk.cyan;
65
+ console.log(`${color(String(job.status || 'unknown').padEnd(10))} ${chalk.cyan(job.job_id)} ${chalk.gray(job.updated_at || '')}`);
66
+ console.log(chalk.gray(` ${String(job.request || '').slice(0, 100)}`));
67
+ console.log(chalk.gray(` files: ${job.file_count || 0} workspace: ${job.local_workspace_path || job.workspace_name || '-'}`));
68
+ }
69
+ console.log();
70
+ }
71
+ catch (error) {
72
+ spinner.stop();
73
+ this.logger.error(error?.message || String(error));
74
+ }
75
+ }
76
+ async status(jobId, options = {}) {
77
+ if (!jobId) {
78
+ this.logger.error('Usage: vigthoria background status <job-id>');
79
+ return;
80
+ }
81
+ const spinner = createSpinner('Loading background job...').start();
82
+ try {
83
+ const job = await this.api.getV3BackgroundJob(jobId);
84
+ spinner.stop();
85
+ if (options.json) {
86
+ console.log(JSON.stringify(job, null, 2));
87
+ return;
88
+ }
89
+ console.log(chalk.bold(`\nBackground Job ${chalk.cyan(job.job_id)}\n`));
90
+ console.log(`Status: ${job.status}`);
91
+ console.log(`Files: ${job.file_count || 0}`);
92
+ console.log(`Updated: ${job.updated_at || '-'}`);
93
+ console.log(`Workspace: ${job.local_workspace_path || job.workspace_name || '-'}`);
94
+ if (job.error)
95
+ console.log(chalk.red(`Error: ${job.error}`));
96
+ console.log(chalk.gray(`\n${String(job.request || '').slice(0, 500)}`));
97
+ if (job.status === 'completed' && (job.file_count || 0) > 0) {
98
+ console.log(chalk.gray(`\nUse ${chalk.cyan(`vigthoria background apply ${job.job_id}`)} to apply files locally.`));
99
+ }
100
+ }
101
+ catch (error) {
102
+ spinner.stop();
103
+ this.logger.error(error?.message || String(error));
104
+ }
105
+ }
106
+ async apply(jobId, options = {}) {
107
+ if (!jobId) {
108
+ this.logger.error('Usage: vigthoria background apply <job-id>');
109
+ return;
110
+ }
111
+ const workspacePath = options.workspace || process.cwd();
112
+ const spinner = createSpinner('Applying background job files...').start();
113
+ try {
114
+ const result = await this.api.applyV3BackgroundJobFiles(jobId, {
115
+ workspacePath,
116
+ projectPath: workspacePath,
117
+ targetPath: workspacePath,
118
+ });
119
+ spinner.stop();
120
+ if (options.json) {
121
+ console.log(JSON.stringify(result, null, 2));
122
+ return;
123
+ }
124
+ console.log(chalk.green(`${CH.success} Applied ${result.applied.length} file(s) from ${jobId}`));
125
+ for (const file of result.applied.slice(0, 20)) {
126
+ console.log(chalk.gray(` + ${file}`));
127
+ }
128
+ if (result.applied.length > 20) {
129
+ console.log(chalk.gray(` ... and ${result.applied.length - 20} more`));
130
+ }
131
+ if (result.skipped.length > 0) {
132
+ console.log(chalk.yellow(`Skipped ${result.skipped.length} unchanged or unsafe file(s).`));
133
+ }
134
+ }
135
+ catch (error) {
136
+ spinner.stop();
137
+ this.logger.error(error?.message || String(error));
138
+ }
139
+ }
140
+ async cancel(jobId, options = {}) {
141
+ if (!jobId) {
142
+ this.logger.error('Usage: vigthoria background cancel <job-id>');
143
+ return;
144
+ }
145
+ const spinner = createSpinner('Cancelling background job...').start();
146
+ try {
147
+ const result = await this.api.cancelV3BackgroundJob(jobId);
148
+ spinner.stop();
149
+ if (options.json) {
150
+ console.log(JSON.stringify(result, null, 2));
151
+ return;
152
+ }
153
+ console.log(chalk.yellow(`${CH.warn} Background job cancelled: ${jobId}`));
154
+ }
155
+ catch (error) {
156
+ spinner.stop();
157
+ this.logger.error(error?.message || String(error));
158
+ }
159
+ }
160
+ }
@@ -746,6 +746,7 @@ export class ChatCommand {
746
746
  .replace(/^\s*(?:json\s*)?\[\s*\{[\s\S]*?"tool"[\s\S]*$/gim, '')
747
747
  .replace(/^\s*(?:list_dir|read_file|write_file|edit_file|glob|grep|bash)\s*$/gim, '')
748
748
  .replace(/<tool_call>[\s\S]*?<\/tool_call>/gi, '')
749
+ .replace(/<tool_code>[\s\S]*?<\/tool_code>/gi, '')
749
750
  .replace(/\n{3,}/g, '\n\n');
750
751
  return output;
751
752
  }
@@ -918,6 +919,30 @@ export class ChatCommand {
918
919
  spinner.text = 'Vigthoria Executor running...';
919
920
  return;
920
921
  }
922
+ if (event.type === 'model_call_start') {
923
+ if (spinner.isSpinning)
924
+ spinner.stop();
925
+ const model = this.sanitizeServerPath(String(event.model || 'model'));
926
+ const iter = event.iteration ? ` iteration ${event.iteration}` : '';
927
+ const msgCount = Number.isFinite(Number(event.message_count)) ? `, ${event.message_count} messages` : '';
928
+ const toolCount = Number.isFinite(Number(event.tool_count)) ? `, ${event.tool_count} tools available` : '';
929
+ process.stderr.write(chalk.cyan(' [Model] ') + `${model}${iter}: thinking${msgCount}${toolCount}\n`);
930
+ spinner.start();
931
+ spinner.text = `Model ${model} is reasoning...`;
932
+ return;
933
+ }
934
+ if (event.type === 'model_call_complete') {
935
+ if (spinner.isSpinning)
936
+ spinner.stop();
937
+ const model = this.sanitizeServerPath(String(event.model || 'model'));
938
+ const toolCalls = Number.isFinite(Number(event.tool_calls)) ? Number(event.tool_calls) : 0;
939
+ const chars = Number.isFinite(Number(event.content_chars)) ? Number(event.content_chars) : 0;
940
+ const finish = event.finish_reason ? `, ${this.sanitizeServerPath(String(event.finish_reason))}` : '';
941
+ process.stderr.write(chalk.cyan(' [Model] ') + `${model}: produced ${toolCalls} tool call${toolCalls === 1 ? '' : 's'}${chars ? `, ${chars} chars` : ''}${finish}\n`);
942
+ spinner.start();
943
+ spinner.text = toolCalls > 0 ? 'Executing model-selected tools...' : 'Processing model response...';
944
+ return;
945
+ }
921
946
  if (event.type === 'executor_error') {
922
947
  if (spinner.isSpinning)
923
948
  spinner.stop();
@@ -2245,7 +2270,13 @@ export class ChatCommand {
2245
2270
  return /^(ja|ja bitte|ja bitte mach das|mach das|bitte mach das|genau|ok|okay|yes|yes please|please do|do it|go ahead|continue|proceed|make it so)$/.test(normalized);
2246
2271
  }
2247
2272
  taskRequiresWorkspaceChanges(prompt) {
2248
- return /\b(build|create|make|implement|complete|fix|repair|edit|modify|write|generate|add|finish|scaffold|game|app|website|html5|frontend|component|feature)\b/i.test(prompt);
2273
+ const text = String(prompt || '').trim();
2274
+ const readOnlyIntent = /\b(analy[sz]e|analyse|analysis|audit|review|inspect|proof|understand|summari[sz]e|scan|read[\s-]?only|where we left|what is|how does|show me|tell me|identify\s+gaps?|gap\s+analysis|production\s+blockers?)\b/i.test(text);
2275
+ const explicitWriteIntent = /\b(build|create|make|implement|complete|fix|repair|edit|modify|write|generate|add|finish|scaffold|develop|update|change|refactor)\b/i.test(text);
2276
+ if (readOnlyIntent && !explicitWriteIntent) {
2277
+ return false;
2278
+ }
2279
+ return explicitWriteIntent && /\b(file|project|game|app|website|html5|frontend|component|feature|code|workspace|repo)\b/i.test(text);
2249
2280
  }
2250
2281
  getPreviousActionablePrompt() {
2251
2282
  if (this.lastActionableUserInput && !this.isConfirmationFollowUp(this.lastActionableUserInput)) {
@@ -2461,6 +2492,9 @@ export class ChatCommand {
2461
2492
  if (tid)
2462
2493
  liveOutcome.failedTaskIds.add(String(tid));
2463
2494
  liveOutcome.executorFailed = true;
2495
+ const err = typeof summary.error === 'string' ? summary.error.trim() : '';
2496
+ if (err && !liveOutcome.executorError)
2497
+ liveOutcome.executorError = err;
2464
2498
  }
2465
2499
  else if (summary.status === 'completed' || summary.status === 'success') {
2466
2500
  if (tid)
@@ -2603,10 +2637,22 @@ export class ChatCommand {
2603
2637
  const executorSucceeded = !liveOutcome.executorFailed
2604
2638
  && !liveOutcome.plannerError
2605
2639
  && !liveOutcome.executorError
2606
- && workspaceHasOutput
2607
- && (!requiresWorkspaceChanges || changedFileCount > 0);
2640
+ && (requiresWorkspaceChanges ? (workspaceHasOutput && changedFileCount > 0) : true);
2608
2641
  if (!executorSucceeded && requiresWorkspaceChanges && changedFileCount === 0 && !liveOutcome.executorError) {
2609
- liveOutcome.executorError = 'No workspace files were changed for a build/edit request.';
2642
+ const clientToolErrors = this.api.getClientToolErrors();
2643
+ const transportErrors = this.api.getLastChatTransportErrors();
2644
+ if (clientToolErrors.length > 0) {
2645
+ liveOutcome.executorError = clientToolErrors[0];
2646
+ }
2647
+ else if (workspaceHasOutput && changedFileCount === 0) {
2648
+ liveOutcome.executorError = 'Files may exist locally but were not tracked by the agent stream. Try /retry or check your workspace path.';
2649
+ }
2650
+ else {
2651
+ liveOutcome.executorError = 'No workspace files were changed for a build/edit request.';
2652
+ }
2653
+ if (transportErrors.length > 0 && !liveOutcome.plannerError) {
2654
+ liveOutcome.plannerError = transportErrors[0];
2655
+ }
2610
2656
  }
2611
2657
  if (executorSucceeded) {
2612
2658
  taskDisplay.complete(1);
@@ -2618,7 +2664,7 @@ export class ChatCommand {
2618
2664
  taskDisplay.fail(1, failDetail);
2619
2665
  }
2620
2666
  // ── Self-healing validation ──────────────────────────────────────
2621
- if (this.currentProjectPath && !this.jsonOutput && success && executorSucceeded) {
2667
+ if (this.currentProjectPath && !this.jsonOutput && success && executorSucceeded && requiresWorkspaceChanges) {
2622
2668
  try {
2623
2669
  taskDisplay.start(2, 'validating...');
2624
2670
  const healResult = await this.api.runSelfHealingCycle(executionPrompt, this.currentProjectPath, workspaceContext);
@@ -2651,6 +2697,11 @@ export class ChatCommand {
2651
2697
  selfHealStatus = 'failed';
2652
2698
  }
2653
2699
  }
2700
+ else if (!requiresWorkspaceChanges && executorSucceeded) {
2701
+ taskDisplay.complete(2);
2702
+ taskDisplay.skip(3);
2703
+ selfHealStatus = 'skipped';
2704
+ }
2654
2705
  else {
2655
2706
  taskDisplay.skip(2);
2656
2707
  taskDisplay.skip(3);
@@ -2674,6 +2725,12 @@ export class ChatCommand {
2674
2725
  selfHealTool,
2675
2726
  plannerError: liveOutcome.plannerError ? sanitizeUserFacingErrorText(liveOutcome.plannerError) : null,
2676
2727
  executorError: liveOutcome.executorError ? sanitizeUserFacingErrorText(liveOutcome.executorError) : null,
2728
+ clientToolErrors: this.api.getClientToolErrors(),
2729
+ transportErrors: this.api.getLastChatTransportErrors(),
2730
+ workspacePath: workspacePath || null,
2731
+ workspaceSyncIssue: (!executorSucceeded && workspaceHasOutput && changedFileCount === 0)
2732
+ ? 'Local workspace has files but the agent did not confirm tracked changes.'
2733
+ : null,
2677
2734
  finishedAt: Date.now(),
2678
2735
  };
2679
2736
  if (!this.jsonOutput && !this.directPromptMode) {
@@ -2733,6 +2790,10 @@ export class ChatCommand {
2733
2790
  selfHealTool: null,
2734
2791
  plannerError: liveOutcome.plannerError ? sanitizeUserFacingErrorText(liveOutcome.plannerError) : null,
2735
2792
  executorError: liveOutcome.executorError ? sanitizeUserFacingErrorText(liveOutcome.executorError) : safeDetail || null,
2793
+ clientToolErrors: this.api.getClientToolErrors(),
2794
+ transportErrors: this.api.getLastChatTransportErrors(),
2795
+ workspacePath: workspacePath || null,
2796
+ workspaceSyncIssue: null,
2736
2797
  finishedAt: Date.now(),
2737
2798
  };
2738
2799
  if (this.jsonOutput) {
@@ -3095,7 +3156,29 @@ export class ChatCommand {
3095
3156
  console.log(chalk.gray(' Planner: ') + chalk.red(outcome.plannerError.slice(0, 140)));
3096
3157
  }
3097
3158
  if (outcome.executorError) {
3098
- console.log(chalk.gray(' Executor: ') + chalk.red(outcome.executorError.slice(0, 140)));
3159
+ console.log(chalk.gray(' Executor: ') + chalk.red(outcome.executorError.slice(0, 240)));
3160
+ }
3161
+ const hasDiagnostics = outcome.clientToolErrors.length > 0
3162
+ || outcome.transportErrors.length > 0
3163
+ || outcome.workspaceSyncIssue;
3164
+ if (hasDiagnostics) {
3165
+ console.log('');
3166
+ console.log(chalk.gray('Why this run struggled:'));
3167
+ if (outcome.workspacePath) {
3168
+ console.log(' ' + chalk.white(`Workspace: ${outcome.workspacePath}`));
3169
+ }
3170
+ for (const err of outcome.clientToolErrors.slice(0, 3)) {
3171
+ console.log(' ' + chalk.yellow('Local tools: ') + chalk.white(err.slice(0, 220)));
3172
+ }
3173
+ for (const err of outcome.transportErrors.slice(0, 2)) {
3174
+ console.log(' ' + chalk.yellow('Connectivity: ') + chalk.white(err.slice(0, 220)));
3175
+ }
3176
+ if (outcome.workspaceSyncIssue) {
3177
+ console.log(' ' + chalk.yellow('Sync: ') + chalk.white(outcome.workspaceSyncIssue));
3178
+ }
3179
+ if (outcome.clientToolErrors.some((e) => /no pending client tool call|rejected/i.test(e))) {
3180
+ console.log(' ' + chalk.gray('The agent tried to use your local machine for file tools, but the server timed out waiting. /retry usually works after the SSE bridge fix.'));
3181
+ }
3099
3182
  }
3100
3183
  console.log('');
3101
3184
  console.log(chalk.gray('Result:'));
package/dist/index.js CHANGED
@@ -35,6 +35,7 @@ import { HistoryCommand } from './commands/history.js';
35
35
  import { ReplayCommand } from './commands/replay.js';
36
36
  import { ForkCommand } from './commands/fork.js';
37
37
  import { CancelCommand } from './commands/cancel.js';
38
+ import { BackgroundCommand } from './commands/background.js';
38
39
  import { SecurityCommand } from './commands/security.js';
39
40
  import { Config } from './utils/config.js';
40
41
  import { Logger, CH } from './utils/logger.js';
@@ -333,7 +334,7 @@ function isAuthProtectedCommand(command) {
333
334
  'agent', 'a', 'operator', 'op',
334
335
  'edit', 'e', 'generate', 'g', 'explain', 'x', 'fix', 'f', 'review', 'r',
335
336
  'workflow', 'flow', 'hub', 'marketplace', 'deploy', 'host', 'preview', 'device',
336
- 'legion', 'history', 'runs', 'replay', 'fork', 'cancel',
337
+ 'legion', 'history', 'runs', 'replay', 'fork', 'cancel', 'background', 'bg',
337
338
  'repo', 'repository',
338
339
  ]);
339
340
  return protectedCommands.has(command);
@@ -489,7 +490,7 @@ export async function main(args) {
489
490
  const isLegionCortexRequest = invokedBinaryName === 'vigthoria' && argv[2] === 'legion' && argv.includes('--cortex');
490
491
  if (invokedBinaryName === 'vigthoria-chat') {
491
492
  const knownCommands = new Set([
492
- 'chat', 'chat-resume', 'agent', 'edit', 'generate', 'explain', 'fix', 'review', 'cancel',
493
+ 'chat', 'chat-resume', 'agent', 'edit', 'generate', 'explain', 'fix', 'review', 'cancel', 'background', 'bg',
493
494
  'hub', 'repo', 'deploy', 'operator', 'workflow', 'flow', 'device', 'security', 'vsec', 'login', 'logout', 'status', 'config', 'update',
494
495
  '--help', '-h', '--version', '-V', 'help', 'version',
495
496
  ]);
@@ -1088,6 +1089,58 @@ Examples:
1088
1089
  repoCommand.action(() => {
1089
1090
  repoCommand.outputHelp();
1090
1091
  });
1092
+ // ==================== BACKGROUND AGENT JOBS ====================
1093
+ const backgroundCommand = program
1094
+ .command('background')
1095
+ .alias('bg')
1096
+ .description('Run and manage detached Vigthoria Agent jobs');
1097
+ backgroundCommand
1098
+ .command('start <prompt...>')
1099
+ .description('Start an Agent job in the background and return immediately')
1100
+ .option('--workspace <path>', 'Local workspace path', process.cwd())
1101
+ .option('--json', 'Emit JSON output', false)
1102
+ .action(async (prompt, options) => {
1103
+ const bg = new BackgroundCommand(config, logger);
1104
+ await bg.start(prompt, options);
1105
+ });
1106
+ backgroundCommand
1107
+ .command('list')
1108
+ .alias('ls')
1109
+ .description('List recent background jobs')
1110
+ .option('--limit <n>', 'Maximum jobs to show', '20')
1111
+ .option('--json', 'Emit JSON output', false)
1112
+ .action(async (options) => {
1113
+ const bg = new BackgroundCommand(config, logger);
1114
+ await bg.list({ ...options, limit: Number(options.limit) || 20 });
1115
+ });
1116
+ backgroundCommand
1117
+ .command('status <jobId>')
1118
+ .description('Show background job status')
1119
+ .option('--json', 'Emit JSON output', false)
1120
+ .action(async (jobId, options) => {
1121
+ const bg = new BackgroundCommand(config, logger);
1122
+ await bg.status(jobId, options);
1123
+ });
1124
+ backgroundCommand
1125
+ .command('apply <jobId>')
1126
+ .description('Apply completed background job file changes to the local workspace')
1127
+ .option('--workspace <path>', 'Local workspace path', process.cwd())
1128
+ .option('--json', 'Emit JSON output', false)
1129
+ .action(async (jobId, options) => {
1130
+ const bg = new BackgroundCommand(config, logger);
1131
+ await bg.apply(jobId, options);
1132
+ });
1133
+ backgroundCommand
1134
+ .command('cancel <jobId>')
1135
+ .description('Cancel a running background job')
1136
+ .option('--json', 'Emit JSON output', false)
1137
+ .action(async (jobId, options) => {
1138
+ const bg = new BackgroundCommand(config, logger);
1139
+ await bg.cancel(jobId, options);
1140
+ });
1141
+ backgroundCommand.action(() => {
1142
+ backgroundCommand.outputHelp();
1143
+ });
1091
1144
  // ==================== DEPLOY COMMANDS ====================
1092
1145
  // Deploy command - Host projects on Vigthoria
1093
1146
  const deployCommand = program
@@ -224,6 +224,11 @@ export declare class APIClient {
224
224
  private vigFlowTokens;
225
225
  private _httpsAgent;
226
226
  private lastChatTransportErrors;
227
+ private clientToolErrors;
228
+ private pendingV3ClientToolTasks;
229
+ /** Tracks files mutated via client_tool_request during an active V3 SSE stream. */
230
+ private activeV3StreamedFiles;
231
+ private activeV3StreamContext;
227
232
  constructor(config: Config, logger: Logger);
228
233
  /**
229
234
  * Destroy keep-alive sockets so the Node.js event loop can drain
@@ -253,6 +258,7 @@ export declare class APIClient {
253
258
  getV3AgentBaseUrls(preferLocal?: boolean): string[];
254
259
  getV3AgentRunUrl(baseUrl: string): string;
255
260
  getV3AgentContinueUrl(baseUrl: string): string;
261
+ getV3AgentBackgroundUrl(baseUrl: string, suffix?: string): string;
256
262
  getOperatorBaseUrls(): string[];
257
263
  getOperatorStreamUrl(baseUrl: string): string;
258
264
  getMcpBaseUrls(): string[];
@@ -355,6 +361,10 @@ export declare class APIClient {
355
361
  extractExpectedWorkspaceFiles(message?: string, context?: Record<string, any>): string[];
356
362
  captureV3AgentStreamMutation(event: any, streamedFiles: Record<string, string>, serverRoot?: string | null): void;
357
363
  private applyV3AgentStreamEventToWorkspace;
364
+ private resolveV3ClientToolPath;
365
+ private recordV3ClientToolMutation;
366
+ private executeV3ClientToolRequest;
367
+ private handleV3ClientToolRequest;
358
368
  private writeV3AgentWorkspaceFile;
359
369
  private deleteV3AgentWorkspaceFile;
360
370
  recoverAgentWorkspaceFiles(context?: Record<string, any>, streamedFiles?: Record<string, string>, expectedFiles?: string[]): void;
@@ -374,8 +384,25 @@ export declare class APIClient {
374
384
  */
375
385
  private synthesizeAnswerFromV3Events;
376
386
  private sanitizeV3AgentEventForUser;
387
+ private resolveAgentChangedFiles;
388
+ private finalizeV3AgentWorkflowResponse;
377
389
  collectV3AgentStream(response: Response, context?: Record<string, any>): Promise<any>;
378
390
  runV3AgentWorkflow(message: string, context?: Record<string, any>): Promise<V3AgentWorkflowResponse>;
391
+ startV3BackgroundJob(message: string, context?: Record<string, any>): Promise<any>;
392
+ listV3BackgroundJobs(limit?: number): Promise<any[]>;
393
+ getV3BackgroundJob(jobId: string): Promise<any>;
394
+ cancelV3BackgroundJob(jobId: string): Promise<any>;
395
+ getV3BackgroundJobFiles(jobId: string): Promise<{
396
+ status: string;
397
+ files: Record<string, string>;
398
+ file_count: number;
399
+ local_workspace_path?: string;
400
+ }>;
401
+ applyV3BackgroundJobFiles(jobId: string, context?: Record<string, any>): Promise<{
402
+ applied: string[];
403
+ skipped: string[];
404
+ status: string;
405
+ }>;
379
406
  private formatOperatorResponse;
380
407
  runOperatorWorkflow(message: string, context?: Record<string, any>): Promise<OperatorWorkflowResponse>;
381
408
  /**
@@ -515,6 +542,9 @@ export declare class APIClient {
515
542
  }>;
516
543
  mapPreflightEndpointToRoute(endpoint: string): ChatRoutePreference | null;
517
544
  getLastChatTransportErrors(): string[];
545
+ getClientToolErrors(): string[];
546
+ clearAgentRunDiagnostics(): void;
547
+ private recordClientToolError;
518
548
  submitClientToolResult(contextId: string, callId: string, result: {
519
549
  success: boolean;
520
550
  output: string;