@vybestack/llxprt-code-agents 0.10.0-nightly.260613.1adad3b34
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/dist/.last_build +0 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/src/agents/executor-prompt-builder.d.ts +19 -0
- package/dist/src/agents/executor-prompt-builder.js +44 -0
- package/dist/src/agents/executor-prompt-builder.js.map +1 -0
- package/dist/src/agents/executor-termination.d.ts +22 -0
- package/dist/src/agents/executor-termination.js +44 -0
- package/dist/src/agents/executor-termination.js.map +1 -0
- package/dist/src/agents/executor-validation.d.ts +17 -0
- package/dist/src/agents/executor-validation.js +35 -0
- package/dist/src/agents/executor-validation.js.map +1 -0
- package/dist/src/agents/executor.d.ts +136 -0
- package/dist/src/agents/executor.js +874 -0
- package/dist/src/agents/executor.js.map +1 -0
- package/dist/src/agents/invocation.d.ts +45 -0
- package/dist/src/agents/invocation.js +118 -0
- package/dist/src/agents/invocation.js.map +1 -0
- package/dist/src/agents/recovery.d.ts +75 -0
- package/dist/src/agents/recovery.js +107 -0
- package/dist/src/agents/recovery.js.map +1 -0
- package/dist/src/agents/types.d.ts +149 -0
- package/dist/src/agents/types.js +18 -0
- package/dist/src/agents/types.js.map +1 -0
- package/dist/src/agents/utils.d.ts +15 -0
- package/dist/src/agents/utils.js +28 -0
- package/dist/src/agents/utils.js.map +1 -0
- package/dist/src/compression/CompressionHandler.d.ts +178 -0
- package/dist/src/compression/CompressionHandler.js +630 -0
- package/dist/src/compression/CompressionHandler.js.map +1 -0
- package/dist/src/compression/HighDensityStrategy.d.ts +113 -0
- package/dist/src/compression/HighDensityStrategy.js +769 -0
- package/dist/src/compression/HighDensityStrategy.js.map +1 -0
- package/dist/src/compression/MiddleOutStrategy.d.ts +27 -0
- package/dist/src/compression/MiddleOutStrategy.js +347 -0
- package/dist/src/compression/MiddleOutStrategy.js.map +1 -0
- package/dist/src/compression/OneShotStrategy.d.ts +22 -0
- package/dist/src/compression/OneShotStrategy.js +235 -0
- package/dist/src/compression/OneShotStrategy.js.map +1 -0
- package/dist/src/compression/TopDownTruncationStrategy.d.ts +13 -0
- package/dist/src/compression/TopDownTruncationStrategy.js +74 -0
- package/dist/src/compression/TopDownTruncationStrategy.js.map +1 -0
- package/dist/src/compression/compressionBudgeting.d.ts +34 -0
- package/dist/src/compression/compressionBudgeting.js +139 -0
- package/dist/src/compression/compressionBudgeting.js.map +1 -0
- package/dist/src/compression/compressionStrategyFactory.d.ts +23 -0
- package/dist/src/compression/compressionStrategyFactory.js +40 -0
- package/dist/src/compression/compressionStrategyFactory.js.map +1 -0
- package/dist/src/compression/index.d.ts +16 -0
- package/dist/src/compression/index.js +17 -0
- package/dist/src/compression/index.js.map +1 -0
- package/dist/src/compression/reasoningUtils.d.ts +18 -0
- package/dist/src/compression/reasoningUtils.js +22 -0
- package/dist/src/compression/reasoningUtils.js.map +1 -0
- package/dist/src/compression/utils.d.ts +114 -0
- package/dist/src/compression/utils.js +316 -0
- package/dist/src/compression/utils.js.map +1 -0
- package/dist/src/core/AgentHookManager.d.ts +41 -0
- package/dist/src/core/AgentHookManager.js +65 -0
- package/dist/src/core/AgentHookManager.js.map +1 -0
- package/dist/src/core/ChatSessionFactory.d.ts +50 -0
- package/dist/src/core/ChatSessionFactory.js +216 -0
- package/dist/src/core/ChatSessionFactory.js.map +1 -0
- package/dist/src/core/ConversationManager.d.ts +113 -0
- package/dist/src/core/ConversationManager.js +311 -0
- package/dist/src/core/ConversationManager.js.map +1 -0
- package/dist/src/core/DirectMessageProcessor.d.ts +79 -0
- package/dist/src/core/DirectMessageProcessor.js +478 -0
- package/dist/src/core/DirectMessageProcessor.js.map +1 -0
- package/dist/src/core/IdeContextTracker.d.ts +56 -0
- package/dist/src/core/IdeContextTracker.js +207 -0
- package/dist/src/core/IdeContextTracker.js.map +1 -0
- package/dist/src/core/MessageConverter.d.ts +78 -0
- package/dist/src/core/MessageConverter.js +492 -0
- package/dist/src/core/MessageConverter.js.map +1 -0
- package/dist/src/core/MessageStreamOrchestrator.d.ts +85 -0
- package/dist/src/core/MessageStreamOrchestrator.js +448 -0
- package/dist/src/core/MessageStreamOrchestrator.js.map +1 -0
- package/dist/src/core/MessageStreamTerminalHandler.d.ts +16 -0
- package/dist/src/core/MessageStreamTerminalHandler.js +170 -0
- package/dist/src/core/MessageStreamTerminalHandler.js.map +1 -0
- package/dist/src/core/StreamProcessor.d.ts +105 -0
- package/dist/src/core/StreamProcessor.js +660 -0
- package/dist/src/core/StreamProcessor.js.map +1 -0
- package/dist/src/core/TodoContinuationService.d.ts +74 -0
- package/dist/src/core/TodoContinuationService.js +312 -0
- package/dist/src/core/TodoContinuationService.js.map +1 -0
- package/dist/src/core/TurnProcessor.d.ts +91 -0
- package/dist/src/core/TurnProcessor.js +540 -0
- package/dist/src/core/TurnProcessor.js.map +1 -0
- package/dist/src/core/baseLlmClient.d.ts +115 -0
- package/dist/src/core/baseLlmClient.js +231 -0
- package/dist/src/core/baseLlmClient.js.map +1 -0
- package/dist/src/core/bucketFailoverIntegration.d.ts +62 -0
- package/dist/src/core/bucketFailoverIntegration.js +186 -0
- package/dist/src/core/bucketFailoverIntegration.js.map +1 -0
- package/dist/src/core/chatSession.d.ts +121 -0
- package/dist/src/core/chatSession.js +720 -0
- package/dist/src/core/chatSession.js.map +1 -0
- package/dist/src/core/client.d.ts +132 -0
- package/dist/src/core/client.js +524 -0
- package/dist/src/core/client.js.map +1 -0
- package/dist/src/core/clientHelpers.d.ts +15 -0
- package/dist/src/core/clientHelpers.js +122 -0
- package/dist/src/core/clientHelpers.js.map +1 -0
- package/dist/src/core/clientLlmUtilities.d.ts +30 -0
- package/dist/src/core/clientLlmUtilities.js +125 -0
- package/dist/src/core/clientLlmUtilities.js.map +1 -0
- package/dist/src/core/clientToolGovernance.d.ts +37 -0
- package/dist/src/core/clientToolGovernance.js +104 -0
- package/dist/src/core/clientToolGovernance.js.map +1 -0
- package/dist/src/core/compression-config.d.ts +12 -0
- package/dist/src/core/compression-config.js +21 -0
- package/dist/src/core/compression-config.js.map +1 -0
- package/dist/src/core/coreToolScheduler.d.ts +105 -0
- package/dist/src/core/coreToolScheduler.js +453 -0
- package/dist/src/core/coreToolScheduler.js.map +1 -0
- package/dist/src/core/hookToolRestrictions.d.ts +18 -0
- package/dist/src/core/hookToolRestrictions.js +187 -0
- package/dist/src/core/hookToolRestrictions.js.map +1 -0
- package/dist/src/core/nonInteractiveToolExecutor.d.ts +17 -0
- package/dist/src/core/nonInteractiveToolExecutor.js +102 -0
- package/dist/src/core/nonInteractiveToolExecutor.js.map +1 -0
- package/dist/src/core/subagent.d.ts +105 -0
- package/dist/src/core/subagent.js +650 -0
- package/dist/src/core/subagent.js.map +1 -0
- package/dist/src/core/subagentExecution.d.ts +104 -0
- package/dist/src/core/subagentExecution.js +275 -0
- package/dist/src/core/subagentExecution.js.map +1 -0
- package/dist/src/core/subagentOrchestrator.d.ts +84 -0
- package/dist/src/core/subagentOrchestrator.js +503 -0
- package/dist/src/core/subagentOrchestrator.js.map +1 -0
- package/dist/src/core/subagentRuntimeSetup.d.ts +75 -0
- package/dist/src/core/subagentRuntimeSetup.js +387 -0
- package/dist/src/core/subagentRuntimeSetup.js.map +1 -0
- package/dist/src/core/subagentScheduler.d.ts +17 -0
- package/dist/src/core/subagentScheduler.js +7 -0
- package/dist/src/core/subagentScheduler.js.map +1 -0
- package/dist/src/core/subagentToolProcessing.d.ts +51 -0
- package/dist/src/core/subagentToolProcessing.js +359 -0
- package/dist/src/core/subagentToolProcessing.js.map +1 -0
- package/dist/src/core/toolGovernance.d.ts +18 -0
- package/dist/src/core/toolGovernance.js +50 -0
- package/dist/src/core/toolGovernance.js.map +1 -0
- package/dist/src/core/turn.d.ts +47 -0
- package/dist/src/core/turn.js +455 -0
- package/dist/src/core/turn.js.map +1 -0
- package/dist/src/core/turnLogging.d.ts +35 -0
- package/dist/src/core/turnLogging.js +80 -0
- package/dist/src/core/turnLogging.js.map +1 -0
- package/dist/src/index.d.ts +32 -0
- package/dist/src/index.js +44 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/scheduler/confirmation-coordinator.d.ts +139 -0
- package/dist/src/scheduler/confirmation-coordinator.js +443 -0
- package/dist/src/scheduler/confirmation-coordinator.js.map +1 -0
- package/dist/src/scheduler/result-aggregator.d.ts +127 -0
- package/dist/src/scheduler/result-aggregator.js +302 -0
- package/dist/src/scheduler/result-aggregator.js.map +1 -0
- package/dist/src/scheduler/status-transitions.d.ts +39 -0
- package/dist/src/scheduler/status-transitions.js +184 -0
- package/dist/src/scheduler/status-transitions.js.map +1 -0
- package/dist/src/scheduler/tool-dispatcher.d.ts +40 -0
- package/dist/src/scheduler/tool-dispatcher.js +120 -0
- package/dist/src/scheduler/tool-dispatcher.js.map +1 -0
- package/dist/src/scheduler/tool-executor.d.ts +44 -0
- package/dist/src/scheduler/tool-executor.js +117 -0
- package/dist/src/scheduler/tool-executor.js.map +1 -0
- package/dist/src/scheduler/utils.d.ts +11 -0
- package/dist/src/scheduler/utils.js +19 -0
- package/dist/src/scheduler/utils.js.map +1 -0
- package/dist/src/tools/task.d.ts +128 -0
- package/dist/src/tools/task.js +932 -0
- package/dist/src/tools/task.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* @internal
|
|
8
|
+
* Owns result buffering, ordered publishing, and batch output-limit computation.
|
|
9
|
+
* Extracted from CoreToolScheduler as part of the Phase 2 decomposition
|
|
10
|
+
* (issue 1580).
|
|
11
|
+
*
|
|
12
|
+
* Ordering guarantee: results are published in `executionIndex` order
|
|
13
|
+
* regardless of which tool finishes first, using a reentrancy-guarded loop
|
|
14
|
+
* with a `setImmediate` recovery path for the race where a result arrives
|
|
15
|
+
* after the loop exits but before the flag is cleared.
|
|
16
|
+
*/
|
|
17
|
+
import type { ToolCallResponseInfo } from '../core/turn.js';
|
|
18
|
+
import type { ToolResult } from '@vybestack/llxprt-code-tools';
|
|
19
|
+
import { type ToolOutputSettingsProvider } from '@vybestack/llxprt-code-core/utils/toolOutputLimiter.js';
|
|
20
|
+
import type { ScheduledToolCall } from '@vybestack/llxprt-code-core/scheduler/types.js';
|
|
21
|
+
/**
|
|
22
|
+
* Callbacks provided by CoreToolScheduler so ResultAggregator can publish
|
|
23
|
+
* without importing the scheduler class (prevents circular dependency).
|
|
24
|
+
*/
|
|
25
|
+
export interface ResultPublishCallbacks {
|
|
26
|
+
/** Transition a call to the 'success' terminal state. */
|
|
27
|
+
setSuccess(callId: string, response: ToolCallResponseInfo): void;
|
|
28
|
+
/** Transition a call to the 'error' terminal state. */
|
|
29
|
+
setError(callId: string, response: ToolCallResponseInfo): void;
|
|
30
|
+
/**
|
|
31
|
+
* Returns the active Config (or equivalent provider) so ResultAggregator
|
|
32
|
+
* can compute per-tool token limits when no batch override is in effect.
|
|
33
|
+
*/
|
|
34
|
+
getFallbackOutputConfig(): ToolOutputSettingsProvider;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* @internal
|
|
38
|
+
*/
|
|
39
|
+
export declare class ResultAggregator {
|
|
40
|
+
private readonly callbacks;
|
|
41
|
+
/** Pending tool results keyed by callId. */
|
|
42
|
+
private readonly pendingResults;
|
|
43
|
+
/** The executionIndex of the next result to publish. */
|
|
44
|
+
private nextPublishIndex;
|
|
45
|
+
/** Total tools in the current batch; set by {@link beginBatch}. */
|
|
46
|
+
private currentBatchSize;
|
|
47
|
+
/**
|
|
48
|
+
* Per-tool output config derived by dividing the batch token budget equally.
|
|
49
|
+
* Undefined when the batch has ≤ 1 tool.
|
|
50
|
+
*/
|
|
51
|
+
private batchOutputConfig;
|
|
52
|
+
/** Reentrancy guard for {@link publishBufferedResults}. */
|
|
53
|
+
private isPublishingBufferedResults;
|
|
54
|
+
/** Set when a second publish is requested during an active publish pass. */
|
|
55
|
+
private pendingPublishRequest;
|
|
56
|
+
constructor(callbacks: ResultPublishCallbacks);
|
|
57
|
+
/** Store a successful tool result for ordered publishing. */
|
|
58
|
+
bufferResult(callId: string, toolName: string, scheduledCall: ScheduledToolCall, result: ToolResult, executionIndex: number): void;
|
|
59
|
+
/** Store an error result (ToolResult with `.error` set) for ordered publishing. */
|
|
60
|
+
bufferError(callId: string, toolName: string, scheduledCall: ScheduledToolCall, error: Error, executionIndex: number): void;
|
|
61
|
+
/**
|
|
62
|
+
* Store a placeholder for a cancelled call so the ordered-publish loop can
|
|
63
|
+
* advance past this index. The call is already in 'cancelled' terminal state
|
|
64
|
+
* so no callback is fired — the entry is simply discarded after its index is
|
|
65
|
+
* consumed.
|
|
66
|
+
*/
|
|
67
|
+
bufferCancelled(callId: string, scheduledCall: ScheduledToolCall, executionIndex: number): void;
|
|
68
|
+
/**
|
|
69
|
+
* Called once at the start of each execution batch to record how many tools
|
|
70
|
+
* are participating and to apply proportional output-token limits when the
|
|
71
|
+
* batch has more than one tool.
|
|
72
|
+
*/
|
|
73
|
+
beginBatch(size: number): void;
|
|
74
|
+
/**
|
|
75
|
+
* Publishes buffered results in `executionIndex` order.
|
|
76
|
+
*
|
|
77
|
+
* Reentrancy guard: if called while a publish pass is already running the
|
|
78
|
+
* call sets `pendingPublishRequest` and returns immediately. The running
|
|
79
|
+
* pass will loop once more before releasing the lock.
|
|
80
|
+
*
|
|
81
|
+
* Recovery path: after releasing the lock we check whether any buffered
|
|
82
|
+
* results are ready (i.e. the next expected index is present) and schedule
|
|
83
|
+
* a follow-up via `setImmediate` to avoid missing results that arrived while
|
|
84
|
+
* the lock was held.
|
|
85
|
+
*/
|
|
86
|
+
publishBufferedResults(signal: AbortSignal): Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* Clears all buffered state. Called by `CoreToolScheduler.cancelAll()` and
|
|
89
|
+
* indirectly by `dispose()`.
|
|
90
|
+
*/
|
|
91
|
+
reset(): void;
|
|
92
|
+
/** Find a buffered entry by its executionIndex. */
|
|
93
|
+
private findByExecutionIndex;
|
|
94
|
+
/**
|
|
95
|
+
* Issue #987 fix: if tools complete before `beginBatch` is called,
|
|
96
|
+
* `currentBatchSize` may still be 0. Recover it from the actual pending
|
|
97
|
+
* entries so publishing can proceed.
|
|
98
|
+
*/
|
|
99
|
+
private recoverBatchSizeIfNeeded;
|
|
100
|
+
/** When the entire batch has been published, reset counters for the next batch. */
|
|
101
|
+
private resetBatchIfComplete;
|
|
102
|
+
private publishBufferedResultsPass;
|
|
103
|
+
/**
|
|
104
|
+
* After releasing the reentrancy lock, schedule a follow-up publish via
|
|
105
|
+
* `setImmediate` when the next expected result is already buffered. This
|
|
106
|
+
* handles the race where:
|
|
107
|
+
* 1. We break the inner `while` loop waiting for result N.
|
|
108
|
+
* 2. Result N arrives and calls `publishBufferedResults`.
|
|
109
|
+
* 3. That call sees the lock held, sets `pendingPublishRequest`, and returns.
|
|
110
|
+
* 4. We exit the `do-while` without seeing the flag (it was set after the check).
|
|
111
|
+
*/
|
|
112
|
+
private scheduleFollowUpIfNeeded;
|
|
113
|
+
/**
|
|
114
|
+
* Convert a buffered result to a `ToolCallResponseInfo` and invoke the
|
|
115
|
+
* appropriate status callback (`setSuccess` or `setError`).
|
|
116
|
+
*/
|
|
117
|
+
private publishResult;
|
|
118
|
+
/**
|
|
119
|
+
* Apply batch-level output limits for parallel tool batches. (#1301)
|
|
120
|
+
*
|
|
121
|
+
* `tool-output-max-tokens` is treated as a budget for the entire batch.
|
|
122
|
+
* For batches of 2+ tools this method divides the budget equally and stores
|
|
123
|
+
* the reduced per-tool limit in {@link batchOutputConfig}, which
|
|
124
|
+
* {@link publishResult} picks up when building function-response parts.
|
|
125
|
+
*/
|
|
126
|
+
private applyBatchOutputLimits;
|
|
127
|
+
}
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { ToolErrorType } from '@vybestack/llxprt-code-tools';
|
|
7
|
+
import { DEFAULT_AGENT_ID } from '../core/turn.js';
|
|
8
|
+
import { convertToFunctionResponse, extractAgentIdFromMetadata, createErrorResponse, } from '@vybestack/llxprt-code-core/utils/generateContentResponseUtilities.js';
|
|
9
|
+
import { DEFAULT_MAX_TOKENS, } from '@vybestack/llxprt-code-core/utils/toolOutputLimiter.js';
|
|
10
|
+
import { DebugLogger } from '@vybestack/llxprt-code-core/debug/index.js';
|
|
11
|
+
const logger = new DebugLogger('llxprt:scheduler:result-aggregator');
|
|
12
|
+
// ---- ResultAggregator -------------------------------------------------------
|
|
13
|
+
/**
|
|
14
|
+
* @internal
|
|
15
|
+
*/
|
|
16
|
+
export class ResultAggregator {
|
|
17
|
+
callbacks;
|
|
18
|
+
/** Pending tool results keyed by callId. */
|
|
19
|
+
pendingResults = new Map();
|
|
20
|
+
/** The executionIndex of the next result to publish. */
|
|
21
|
+
nextPublishIndex = 0;
|
|
22
|
+
/** Total tools in the current batch; set by {@link beginBatch}. */
|
|
23
|
+
currentBatchSize = 0;
|
|
24
|
+
/**
|
|
25
|
+
* Per-tool output config derived by dividing the batch token budget equally.
|
|
26
|
+
* Undefined when the batch has ≤ 1 tool.
|
|
27
|
+
*/
|
|
28
|
+
batchOutputConfig = undefined;
|
|
29
|
+
/** Reentrancy guard for {@link publishBufferedResults}. */
|
|
30
|
+
isPublishingBufferedResults = false;
|
|
31
|
+
/** Set when a second publish is requested during an active publish pass. */
|
|
32
|
+
pendingPublishRequest = false;
|
|
33
|
+
constructor(callbacks) {
|
|
34
|
+
this.callbacks = callbacks;
|
|
35
|
+
}
|
|
36
|
+
// ---- public buffering API ------------------------------------------------
|
|
37
|
+
/** Store a successful tool result for ordered publishing. */
|
|
38
|
+
bufferResult(callId, toolName, scheduledCall, result, executionIndex) {
|
|
39
|
+
this.pendingResults.set(callId, {
|
|
40
|
+
result,
|
|
41
|
+
callId,
|
|
42
|
+
toolName,
|
|
43
|
+
scheduledCall,
|
|
44
|
+
executionIndex,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
/** Store an error result (ToolResult with `.error` set) for ordered publishing. */
|
|
48
|
+
bufferError(callId, toolName, scheduledCall, error, executionIndex) {
|
|
49
|
+
const errorResult = {
|
|
50
|
+
error: {
|
|
51
|
+
message: error.message,
|
|
52
|
+
type: ToolErrorType.UNHANDLED_EXCEPTION,
|
|
53
|
+
},
|
|
54
|
+
llmContent: error.message,
|
|
55
|
+
returnDisplay: error.message,
|
|
56
|
+
};
|
|
57
|
+
this.pendingResults.set(callId, {
|
|
58
|
+
result: errorResult,
|
|
59
|
+
callId,
|
|
60
|
+
toolName,
|
|
61
|
+
scheduledCall,
|
|
62
|
+
executionIndex,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Store a placeholder for a cancelled call so the ordered-publish loop can
|
|
67
|
+
* advance past this index. The call is already in 'cancelled' terminal state
|
|
68
|
+
* so no callback is fired — the entry is simply discarded after its index is
|
|
69
|
+
* consumed.
|
|
70
|
+
*/
|
|
71
|
+
bufferCancelled(callId, scheduledCall, executionIndex) {
|
|
72
|
+
const cancelledResult = {
|
|
73
|
+
error: {
|
|
74
|
+
message: 'Tool call cancelled by user.',
|
|
75
|
+
type: ToolErrorType.EXECUTION_FAILED,
|
|
76
|
+
},
|
|
77
|
+
llmContent: 'Tool call cancelled by user.',
|
|
78
|
+
returnDisplay: 'Cancelled',
|
|
79
|
+
};
|
|
80
|
+
this.pendingResults.set(callId, {
|
|
81
|
+
result: cancelledResult,
|
|
82
|
+
callId,
|
|
83
|
+
toolName: scheduledCall.request.name,
|
|
84
|
+
scheduledCall,
|
|
85
|
+
executionIndex,
|
|
86
|
+
isCancelled: true,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
// ---- batch initialisation ------------------------------------------------
|
|
90
|
+
/**
|
|
91
|
+
* Called once at the start of each execution batch to record how many tools
|
|
92
|
+
* are participating and to apply proportional output-token limits when the
|
|
93
|
+
* batch has more than one tool.
|
|
94
|
+
*/
|
|
95
|
+
beginBatch(size) {
|
|
96
|
+
this.currentBatchSize = size;
|
|
97
|
+
this.applyBatchOutputLimits(size);
|
|
98
|
+
}
|
|
99
|
+
// ---- publishing ----------------------------------------------------------
|
|
100
|
+
/**
|
|
101
|
+
* Publishes buffered results in `executionIndex` order.
|
|
102
|
+
*
|
|
103
|
+
* Reentrancy guard: if called while a publish pass is already running the
|
|
104
|
+
* call sets `pendingPublishRequest` and returns immediately. The running
|
|
105
|
+
* pass will loop once more before releasing the lock.
|
|
106
|
+
*
|
|
107
|
+
* Recovery path: after releasing the lock we check whether any buffered
|
|
108
|
+
* results are ready (i.e. the next expected index is present) and schedule
|
|
109
|
+
* a follow-up via `setImmediate` to avoid missing results that arrived while
|
|
110
|
+
* the lock was held.
|
|
111
|
+
*/
|
|
112
|
+
async publishBufferedResults(signal) {
|
|
113
|
+
if (this.isPublishingBufferedResults) {
|
|
114
|
+
this.pendingPublishRequest = true;
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
this.isPublishingBufferedResults = true;
|
|
118
|
+
this.pendingPublishRequest = false;
|
|
119
|
+
try {
|
|
120
|
+
await this.publishBufferedResultsPass(signal);
|
|
121
|
+
}
|
|
122
|
+
finally {
|
|
123
|
+
this.isPublishingBufferedResults = false;
|
|
124
|
+
this.scheduleFollowUpIfNeeded(signal);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// ---- state reset ---------------------------------------------------------
|
|
128
|
+
/**
|
|
129
|
+
* Clears all buffered state. Called by `CoreToolScheduler.cancelAll()` and
|
|
130
|
+
* indirectly by `dispose()`.
|
|
131
|
+
*/
|
|
132
|
+
reset() {
|
|
133
|
+
this.pendingResults.clear();
|
|
134
|
+
this.nextPublishIndex = 0;
|
|
135
|
+
this.currentBatchSize = 0;
|
|
136
|
+
this.isPublishingBufferedResults = false;
|
|
137
|
+
this.pendingPublishRequest = false;
|
|
138
|
+
this.batchOutputConfig = undefined;
|
|
139
|
+
}
|
|
140
|
+
// ---- private helpers -----------------------------------------------------
|
|
141
|
+
/** Find a buffered entry by its executionIndex. */
|
|
142
|
+
findByExecutionIndex(index) {
|
|
143
|
+
for (const entry of this.pendingResults.values()) {
|
|
144
|
+
if (entry.executionIndex === index) {
|
|
145
|
+
return entry;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return undefined;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Issue #987 fix: if tools complete before `beginBatch` is called,
|
|
152
|
+
* `currentBatchSize` may still be 0. Recover it from the actual pending
|
|
153
|
+
* entries so publishing can proceed.
|
|
154
|
+
*/
|
|
155
|
+
recoverBatchSizeIfNeeded() {
|
|
156
|
+
if (this.currentBatchSize !== 0 || this.pendingResults.size === 0) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
let maxIndex = -1;
|
|
160
|
+
for (const entry of this.pendingResults.values()) {
|
|
161
|
+
if (entry.executionIndex > maxIndex) {
|
|
162
|
+
maxIndex = entry.executionIndex;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const recovered = Math.min(maxIndex + 1, this.pendingResults.size);
|
|
166
|
+
this.currentBatchSize = recovered > 0 ? recovered : 1;
|
|
167
|
+
if (logger.enabled) {
|
|
168
|
+
logger.debug(() => `Recovered batch size from pending results: currentBatchSize=${this.currentBatchSize}, ` +
|
|
169
|
+
`pendingResults.size=${this.pendingResults.size}, maxIndex=${maxIndex}`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/** When the entire batch has been published, reset counters for the next batch. */
|
|
173
|
+
resetBatchIfComplete() {
|
|
174
|
+
if (this.nextPublishIndex === this.currentBatchSize &&
|
|
175
|
+
this.currentBatchSize > 0) {
|
|
176
|
+
this.nextPublishIndex = 0;
|
|
177
|
+
this.currentBatchSize = 0;
|
|
178
|
+
this.pendingResults.clear();
|
|
179
|
+
this.batchOutputConfig = undefined;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
async publishBufferedResultsPass(signal) {
|
|
183
|
+
this.pendingPublishRequest = false;
|
|
184
|
+
this.recoverBatchSizeIfNeeded();
|
|
185
|
+
while (this.nextPublishIndex < this.currentBatchSize) {
|
|
186
|
+
const nextBuffered = this.findByExecutionIndex(this.nextPublishIndex);
|
|
187
|
+
if (!nextBuffered) {
|
|
188
|
+
break; // Gap — wait for the missing result to arrive
|
|
189
|
+
}
|
|
190
|
+
if (nextBuffered.isCancelled !== true) {
|
|
191
|
+
await this.publishResult(nextBuffered, signal);
|
|
192
|
+
}
|
|
193
|
+
this.pendingResults.delete(nextBuffered.callId);
|
|
194
|
+
this.nextPublishIndex++;
|
|
195
|
+
}
|
|
196
|
+
this.resetBatchIfComplete();
|
|
197
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- Async publish reentrancy can flip this flag while awaiting result publication.
|
|
198
|
+
if (this.pendingPublishRequest) {
|
|
199
|
+
await this.publishBufferedResultsPass(signal);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* After releasing the reentrancy lock, schedule a follow-up publish via
|
|
204
|
+
* `setImmediate` when the next expected result is already buffered. This
|
|
205
|
+
* handles the race where:
|
|
206
|
+
* 1. We break the inner `while` loop waiting for result N.
|
|
207
|
+
* 2. Result N arrives and calls `publishBufferedResults`.
|
|
208
|
+
* 3. That call sees the lock held, sets `pendingPublishRequest`, and returns.
|
|
209
|
+
* 4. We exit the `do-while` without seeing the flag (it was set after the check).
|
|
210
|
+
*/
|
|
211
|
+
scheduleFollowUpIfNeeded(signal) {
|
|
212
|
+
if (this.pendingResults.size === 0) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
const hasNext = this.findByExecutionIndex(this.nextPublishIndex) !== undefined;
|
|
216
|
+
if (hasNext) {
|
|
217
|
+
setImmediate(() => {
|
|
218
|
+
void this.publishBufferedResults(signal);
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Convert a buffered result to a `ToolCallResponseInfo` and invoke the
|
|
224
|
+
* appropriate status callback (`setSuccess` or `setError`).
|
|
225
|
+
*/
|
|
226
|
+
async publishResult(buffered, _signal) {
|
|
227
|
+
const { result, callId, toolName, scheduledCall } = buffered;
|
|
228
|
+
if (result.error === undefined) {
|
|
229
|
+
const outputConfig = this.batchOutputConfig ?? this.callbacks.getFallbackOutputConfig();
|
|
230
|
+
const responseParts = convertToFunctionResponse(toolName, callId, result.llmContent, outputConfig);
|
|
231
|
+
const metadataAgentId = extractAgentIdFromMetadata(result.metadata);
|
|
232
|
+
const successResponse = {
|
|
233
|
+
callId,
|
|
234
|
+
responseParts,
|
|
235
|
+
resultDisplay: result.returnDisplay,
|
|
236
|
+
error: undefined,
|
|
237
|
+
errorType: undefined,
|
|
238
|
+
agentId: metadataAgentId ?? scheduledCall.request.agentId ?? DEFAULT_AGENT_ID,
|
|
239
|
+
...(result.suppressDisplay !== undefined && {
|
|
240
|
+
suppressDisplay: result.suppressDisplay,
|
|
241
|
+
}),
|
|
242
|
+
};
|
|
243
|
+
logger.debug(`callId=${callId}, toolName=${toolName}, returnDisplay type=${typeof result.returnDisplay}, hasValue=${Boolean(result.returnDisplay)}`);
|
|
244
|
+
this.callbacks.setSuccess(callId, successResponse);
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
const error = new Error(result.error.message);
|
|
248
|
+
const errorResponse = createErrorResponse(scheduledCall.request, error, result.error.type);
|
|
249
|
+
this.callbacks.setError(callId, errorResponse);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Apply batch-level output limits for parallel tool batches. (#1301)
|
|
254
|
+
*
|
|
255
|
+
* `tool-output-max-tokens` is treated as a budget for the entire batch.
|
|
256
|
+
* For batches of 2+ tools this method divides the budget equally and stores
|
|
257
|
+
* the reduced per-tool limit in {@link batchOutputConfig}, which
|
|
258
|
+
* {@link publishResult} picks up when building function-response parts.
|
|
259
|
+
*/
|
|
260
|
+
applyBatchOutputLimits(batchSize) {
|
|
261
|
+
if (batchSize <= 1) {
|
|
262
|
+
this.batchOutputConfig = undefined;
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
try {
|
|
266
|
+
const fallback = this.callbacks.getFallbackOutputConfig();
|
|
267
|
+
const ephemeral = typeof fallback.getEphemeralSettings === 'function'
|
|
268
|
+
? fallback.getEphemeralSettings()
|
|
269
|
+
: {};
|
|
270
|
+
const maxBatchTokens = ephemeral['tool-output-max-tokens'] ??
|
|
271
|
+
DEFAULT_MAX_TOKENS;
|
|
272
|
+
const perToolBudget = Math.max(1000, Math.floor(maxBatchTokens / batchSize));
|
|
273
|
+
if (logger.enabled) {
|
|
274
|
+
logger.debug(() => `Batch of ${batchSize} tools: applying per-tool output limit ` +
|
|
275
|
+
`of ${perToolBudget} tokens (batch budget: ${maxBatchTokens}).`);
|
|
276
|
+
}
|
|
277
|
+
this.batchOutputConfig = {
|
|
278
|
+
getEphemeralSettings: () => ({
|
|
279
|
+
...ephemeral,
|
|
280
|
+
'tool-output-max-tokens': perToolBudget,
|
|
281
|
+
// eslint-disable-next-line sonarjs/expression-complexity -- Existing structure is intentionally preserved; refactoring this boundary is outside the lint slice.
|
|
282
|
+
...(ephemeral['tool-output-truncate-mode'] !== undefined &&
|
|
283
|
+
ephemeral['tool-output-truncate-mode'] !== null &&
|
|
284
|
+
ephemeral['tool-output-truncate-mode'] !== false &&
|
|
285
|
+
ephemeral['tool-output-truncate-mode'] !== 0 &&
|
|
286
|
+
ephemeral['tool-output-truncate-mode'] !== '' &&
|
|
287
|
+
!(typeof ephemeral['tool-output-truncate-mode'] === 'number' &&
|
|
288
|
+
Number.isNaN(ephemeral['tool-output-truncate-mode']))
|
|
289
|
+
? {}
|
|
290
|
+
: { 'tool-output-truncate-mode': 'truncate' }),
|
|
291
|
+
}),
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
catch (error) {
|
|
295
|
+
if (logger.enabled) {
|
|
296
|
+
logger.debug(() => `Failed to compute batch output limits; skipping budget guard: ${error}`);
|
|
297
|
+
}
|
|
298
|
+
this.batchOutputConfig = undefined;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
//# sourceMappingURL=result-aggregator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result-aggregator.js","sourceRoot":"","sources":["../../../src/scheduler/result-aggregator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Pure transition builder functions for ToolCall state machine.
|
|
8
|
+
* Extracted from CoreToolScheduler.setStatusInternal to keep functions under 80 lines.
|
|
9
|
+
*/
|
|
10
|
+
import type { ToolCall, ValidatingToolCall, ScheduledToolCall, ExecutingToolCall, SuccessfulToolCall, ErroredToolCall, CancelledToolCall, WaitingToolCall, Status } from '@vybestack/llxprt-code-core/scheduler/types.js';
|
|
11
|
+
import type { ToolCallResponseInfo } from '@vybestack/llxprt-code-core/core/turn.js';
|
|
12
|
+
import type { ToolCallConfirmationDetails } from '@vybestack/llxprt-code-tools';
|
|
13
|
+
import type { SerializableConfirmationDetails } from '@vybestack/llxprt-code-core/confirmation-bus/types.js';
|
|
14
|
+
/**
|
|
15
|
+
* Common context extracted from a non-terminal tool call for building transitions.
|
|
16
|
+
*/
|
|
17
|
+
interface TransitionContext {
|
|
18
|
+
request: ToolCall['request'];
|
|
19
|
+
tool: Exclude<ToolCall, ErroredToolCall>['tool'];
|
|
20
|
+
invocation: Exclude<ToolCall, ErroredToolCall | WaitingToolCall>['invocation'];
|
|
21
|
+
startTime?: number;
|
|
22
|
+
outcome?: ToolCall['outcome'];
|
|
23
|
+
}
|
|
24
|
+
export declare function buildSuccessTransition(ctx: TransitionContext, response: ToolCallResponseInfo): SuccessfulToolCall;
|
|
25
|
+
export declare function buildErrorTransition(ctx: TransitionContext, response: ToolCallResponseInfo): ErroredToolCall;
|
|
26
|
+
export declare function buildCancelledTransition(ctx: TransitionContext, reason: string, currentStatus: Status, currentCall: ToolCall): CancelledToolCall;
|
|
27
|
+
export declare function buildAwaitingApprovalTransition(ctx: TransitionContext, confirmationDetails: ToolCallConfirmationDetails | SerializableConfirmationDetails): WaitingToolCall;
|
|
28
|
+
export declare function buildSimpleTransition(ctx: TransitionContext, status: 'scheduled' | 'validating' | 'executing'): ScheduledToolCall | ValidatingToolCall | ExecutingToolCall;
|
|
29
|
+
/**
|
|
30
|
+
* Build a cancelled tool call from cancelAll() — simpler than the setStatusInternal
|
|
31
|
+
* path because we don't need to check for edit confirmations or use a reason string.
|
|
32
|
+
*/
|
|
33
|
+
export declare function buildCancelAllEntry(call: ValidatingToolCall | ScheduledToolCall | ExecutingToolCall | WaitingToolCall): CancelledToolCall;
|
|
34
|
+
/**
|
|
35
|
+
* Apply a status transition to a single tool call.
|
|
36
|
+
* Returns the original call if it's in a terminal state or doesn't match the target callId.
|
|
37
|
+
*/
|
|
38
|
+
export declare function applyTransition(currentCall: ToolCall, targetCallId: string, newStatus: Status, auxiliaryData?: unknown): ToolCall;
|
|
39
|
+
export {};
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { DEFAULT_AGENT_ID } from '@vybestack/llxprt-code-core/core/turn.js';
|
|
7
|
+
import { ToolConfirmationOutcome } from '@vybestack/llxprt-code-tools';
|
|
8
|
+
function getTransitionContext(call) {
|
|
9
|
+
// Terminal states cannot transition further
|
|
10
|
+
if (call.status === 'success' ||
|
|
11
|
+
call.status === 'error' ||
|
|
12
|
+
call.status === 'cancelled') {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
request: call.request,
|
|
17
|
+
tool: call.tool,
|
|
18
|
+
invocation: call.invocation,
|
|
19
|
+
startTime: call.startTime,
|
|
20
|
+
outcome: call.outcome,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function computeDuration(startTime) {
|
|
24
|
+
return startTime != null ? Date.now() - startTime : undefined;
|
|
25
|
+
}
|
|
26
|
+
function ensureAgentId(response, request) {
|
|
27
|
+
const copy = { ...response };
|
|
28
|
+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- intentional falsy coalescing: agentId is string | undefined, empty string should fall through
|
|
29
|
+
if (!copy.agentId) {
|
|
30
|
+
copy.agentId = request.agentId ?? DEFAULT_AGENT_ID;
|
|
31
|
+
}
|
|
32
|
+
return copy;
|
|
33
|
+
}
|
|
34
|
+
export function buildSuccessTransition(ctx, response) {
|
|
35
|
+
return {
|
|
36
|
+
request: ctx.request,
|
|
37
|
+
tool: ctx.tool,
|
|
38
|
+
invocation: ctx.invocation,
|
|
39
|
+
status: 'success',
|
|
40
|
+
response: ensureAgentId(response, ctx.request),
|
|
41
|
+
durationMs: computeDuration(ctx.startTime),
|
|
42
|
+
outcome: ctx.outcome,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export function buildErrorTransition(ctx, response) {
|
|
46
|
+
return {
|
|
47
|
+
request: ctx.request,
|
|
48
|
+
status: 'error',
|
|
49
|
+
tool: ctx.tool,
|
|
50
|
+
invocation: ctx.invocation,
|
|
51
|
+
response: ensureAgentId(response, ctx.request),
|
|
52
|
+
durationMs: computeDuration(ctx.startTime),
|
|
53
|
+
outcome: ctx.outcome,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export function buildCancelledTransition(ctx, reason, currentStatus, currentCall) {
|
|
57
|
+
// Preserve diff for cancelled edit operations
|
|
58
|
+
let resultDisplay = undefined;
|
|
59
|
+
if (currentStatus === 'awaiting_approval') {
|
|
60
|
+
const waitingCall = currentCall;
|
|
61
|
+
if (waitingCall.confirmationDetails.type === 'edit') {
|
|
62
|
+
resultDisplay = {
|
|
63
|
+
fileDiff: waitingCall.confirmationDetails.fileDiff,
|
|
64
|
+
fileName: waitingCall.confirmationDetails.fileName,
|
|
65
|
+
originalContent: waitingCall.confirmationDetails.originalContent,
|
|
66
|
+
newContent: waitingCall.confirmationDetails.newContent,
|
|
67
|
+
filePath: waitingCall.confirmationDetails.filePath,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
request: ctx.request,
|
|
73
|
+
tool: ctx.tool,
|
|
74
|
+
invocation: ctx.invocation,
|
|
75
|
+
status: 'cancelled',
|
|
76
|
+
response: {
|
|
77
|
+
callId: ctx.request.callId,
|
|
78
|
+
responseParts: [
|
|
79
|
+
{
|
|
80
|
+
functionResponse: {
|
|
81
|
+
id: ctx.request.callId,
|
|
82
|
+
name: ctx.request.name,
|
|
83
|
+
response: {
|
|
84
|
+
error: `[Operation Cancelled] Reason: ${reason}`,
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
resultDisplay,
|
|
90
|
+
error: undefined,
|
|
91
|
+
errorType: undefined,
|
|
92
|
+
agentId: ctx.request.agentId ?? DEFAULT_AGENT_ID,
|
|
93
|
+
},
|
|
94
|
+
durationMs: computeDuration(ctx.startTime),
|
|
95
|
+
outcome: ctx.outcome,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
export function buildAwaitingApprovalTransition(ctx, confirmationDetails) {
|
|
99
|
+
return {
|
|
100
|
+
request: ctx.request,
|
|
101
|
+
tool: ctx.tool,
|
|
102
|
+
status: 'awaiting_approval',
|
|
103
|
+
confirmationDetails,
|
|
104
|
+
startTime: ctx.startTime,
|
|
105
|
+
outcome: ctx.outcome,
|
|
106
|
+
invocation: ctx.invocation,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
export function buildSimpleTransition(ctx, status) {
|
|
110
|
+
return {
|
|
111
|
+
request: ctx.request,
|
|
112
|
+
tool: ctx.tool,
|
|
113
|
+
status,
|
|
114
|
+
startTime: ctx.startTime,
|
|
115
|
+
outcome: ctx.outcome,
|
|
116
|
+
invocation: ctx.invocation,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Build a cancelled tool call from cancelAll() — simpler than the setStatusInternal
|
|
121
|
+
* path because we don't need to check for edit confirmations or use a reason string.
|
|
122
|
+
*/
|
|
123
|
+
export function buildCancelAllEntry(call) {
|
|
124
|
+
return {
|
|
125
|
+
status: 'cancelled',
|
|
126
|
+
request: call.request,
|
|
127
|
+
response: {
|
|
128
|
+
callId: call.request.callId,
|
|
129
|
+
responseParts: [
|
|
130
|
+
{
|
|
131
|
+
functionResponse: {
|
|
132
|
+
id: call.request.callId,
|
|
133
|
+
name: call.request.name,
|
|
134
|
+
response: {
|
|
135
|
+
error: 'Tool call cancelled by user.',
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
],
|
|
140
|
+
resultDisplay: undefined,
|
|
141
|
+
error: undefined,
|
|
142
|
+
errorType: undefined,
|
|
143
|
+
agentId: call.request.agentId ?? DEFAULT_AGENT_ID,
|
|
144
|
+
},
|
|
145
|
+
tool: call.tool,
|
|
146
|
+
invocation: call.invocation,
|
|
147
|
+
durationMs: call.startTime != null ? Date.now() - call.startTime : undefined,
|
|
148
|
+
outcome: ToolConfirmationOutcome.Cancel,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Apply a status transition to a single tool call.
|
|
153
|
+
* Returns the original call if it's in a terminal state or doesn't match the target callId.
|
|
154
|
+
*/
|
|
155
|
+
export function applyTransition(currentCall, targetCallId, newStatus, auxiliaryData) {
|
|
156
|
+
if (currentCall.request.callId !== targetCallId ||
|
|
157
|
+
currentCall.status === 'success' ||
|
|
158
|
+
currentCall.status === 'error' ||
|
|
159
|
+
currentCall.status === 'cancelled') {
|
|
160
|
+
return currentCall;
|
|
161
|
+
}
|
|
162
|
+
const ctx = getTransitionContext(currentCall);
|
|
163
|
+
if (!ctx)
|
|
164
|
+
return currentCall;
|
|
165
|
+
switch (newStatus) {
|
|
166
|
+
case 'success':
|
|
167
|
+
return buildSuccessTransition(ctx, auxiliaryData);
|
|
168
|
+
case 'error':
|
|
169
|
+
return buildErrorTransition(ctx, auxiliaryData);
|
|
170
|
+
case 'cancelled':
|
|
171
|
+
return buildCancelledTransition(ctx, auxiliaryData, currentCall.status, currentCall);
|
|
172
|
+
case 'awaiting_approval':
|
|
173
|
+
return buildAwaitingApprovalTransition(ctx, auxiliaryData);
|
|
174
|
+
case 'scheduled':
|
|
175
|
+
case 'validating':
|
|
176
|
+
case 'executing':
|
|
177
|
+
return buildSimpleTransition(ctx, newStatus);
|
|
178
|
+
default: {
|
|
179
|
+
const exhaustiveCheck = newStatus;
|
|
180
|
+
return exhaustiveCheck;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=status-transitions.js.map
|