@lobehub/lobehub 2.0.0-next.190 → 2.0.0-next.191
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/CHANGELOG.md +25 -0
- package/changelog/v1.json +9 -0
- package/package.json +1 -1
- package/packages/const/src/utils/merge.test.ts +679 -0
- package/packages/context-engine/src/processors/__tests__/AgentCouncilFlatten.test.ts +0 -20
- package/packages/context-engine/src/processors/__tests__/MessageContent.test.ts +5 -23
- package/packages/context-engine/src/providers/SystemRoleInjector.ts +0 -1
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/agentCouncil/simple.json +4 -19
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/agentCouncil/with-supervisor-reply.json +4 -23
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/agentGroup/speak-different-agent.json +3 -13
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/assistant-chain-with-followup.json +3 -8
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/assistantGroup/assistant-with-tools.json +21 -17
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/assistantGroup/tools-with-branches.json +15 -15
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/branch/active-index-1.json +3 -13
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/branch/assistant-branch.json +2 -9
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/branch/assistant-group-branches.json +0 -11
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/branch/assistant-user-branch.json +5 -15
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/branch/conversation.json +4 -14
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/branch/multi-assistant-group.json +0 -13
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/branch/nested.json +2 -15
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/compare/simple.json +4 -9
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/compare/with-tools.json +8 -17
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/linear-conversation.json +3 -7
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/tasks/simple.json +1 -7
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/tasks/with-summary.json +10 -11
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/agentCouncil/simple.json +2 -32
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/agentCouncil/with-supervisor-reply.json +8 -46
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/agentGroup/speak-different-agent.json +5 -24
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/assistant-chain-with-followup.json +5 -13
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/assistantGroup/assistant-with-tools.json +6 -16
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/assistantGroup/tools-with-branches.json +6 -17
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/active-index-1.json +4 -18
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/assistant-branch.json +4 -16
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/assistant-group-branches.json +0 -19
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/assistant-user-branch.json +8 -24
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/conversation.json +7 -23
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/multi-assistant-group.json +0 -15
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/nested.json +4 -25
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/compare/simple.json +2 -13
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/compare/with-tools.json +4 -20
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/linear-conversation.json +4 -12
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/tasks/simple.json +2 -14
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/tasks/with-summary.json +20 -22
- package/packages/conversation-flow/src/__tests__/indexing.test.ts +0 -35
- package/packages/conversation-flow/src/__tests__/structuring.test.ts +0 -41
- package/packages/conversation-flow/src/transformation/FlatListBuilder.ts +0 -4
- package/packages/conversation-flow/src/transformation/__tests__/BranchResolver.test.ts +0 -10
- package/packages/conversation-flow/src/transformation/__tests__/ContextTreeBuilder.test.ts +0 -19
- package/packages/conversation-flow/src/transformation/__tests__/FlatListBuilder.test.ts +0 -37
- package/packages/conversation-flow/src/transformation/__tests__/MessageCollector.test.ts +0 -12
- package/packages/conversation-flow/src/transformation/__tests__/MessageTransformer.test.ts +0 -2
- package/packages/database/src/models/message.ts +0 -1
- package/packages/prompts/src/prompts/chatMessages/index.test.ts +0 -1
- package/packages/prompts/src/prompts/groupChat/__snapshots__/index.test.ts.snap +0 -21
- package/packages/prompts/src/prompts/groupChat/index.test.ts +0 -3
- package/packages/types/src/message/ui/chat.ts +0 -2
- package/src/features/Conversation/store/slices/data/action.test.ts +0 -14
- package/src/features/Conversation/store/slices/data/reducer.test.ts +0 -21
- package/src/features/Conversation/store/slices/data/reducer.ts +1 -1
- package/src/features/Conversation/store/slices/message/action/crud.test.ts +0 -10
- package/src/server/modules/Mecha/ContextEngineering/__tests__/serverMessagesEngine.test.ts +3 -5
- package/src/server/routers/lambda/__tests__/message.test.ts +1 -2
- package/src/server/services/agentRuntime/AgentRuntimeService.ts +109 -109
- package/src/server/services/agentRuntime/types.ts +8 -8
- package/src/server/services/doc/index.tsx +2 -2
- package/src/server/services/generation/index.ts +2 -2
- package/src/server/services/message/index.ts +3 -3
- package/src/server/services/usage/index.ts +4 -4
- package/src/services/chat/chat.test.ts +0 -6
- package/src/services/chat/mecha/contextEngineering.test.ts +3 -29
- package/src/services/chat/mecha/modelParamsResolver.test.ts +803 -0
- package/src/store/chat/agents/GroupOrchestration/createGroupOrchestrationExecutors.ts +0 -2
- package/src/store/chat/agents/__tests__/createAgentExecutors/call-tool.test.ts +0 -6
- package/src/store/chat/agents/__tests__/createAgentExecutors/fixtures/mockMessages.ts +0 -3
- package/src/store/chat/agents/createAgentExecutors.ts +4 -4
- package/src/store/chat/slices/aiAgent/actions/__tests__/agentGroup.test.ts +0 -2
- package/src/store/chat/slices/aiAgent/actions/__tests__/runAgent.test.ts +0 -3
- package/src/store/chat/slices/aiChat/actions/conversationLifecycle.ts +0 -1
- package/src/store/chat/slices/builtinTool/actions/__tests__/search.test.ts +0 -4
- package/src/store/chat/slices/message/reducer.test.ts +0 -5
- package/src/store/chat/slices/message/reducer.ts +1 -1
- package/src/store/chat/slices/message/selectors/displayMessage.test.ts +0 -13
- package/src/store/chat/slices/message/selectors/displayMessage.ts +3 -34
- package/src/store/chat/slices/portal/selectors.test.ts +0 -7
- package/src/store/chat/slices/thread/action.test.ts +0 -1
- package/src/store/chat/slices/translate/action.test.ts +0 -1
- package/src/store/tool/slices/oldStore/action.test.ts +0 -1
|
@@ -43,36 +43,36 @@ const log = debug('lobe-server:agent-runtime-service');
|
|
|
43
43
|
|
|
44
44
|
export interface AgentRuntimeServiceOptions {
|
|
45
45
|
/**
|
|
46
|
-
* Coordinator
|
|
47
|
-
*
|
|
46
|
+
* Coordinator configuration options
|
|
47
|
+
* Allows injection of custom stateManager and streamEventManager
|
|
48
48
|
*/
|
|
49
49
|
coordinatorOptions?: AgentRuntimeCoordinatorOptions;
|
|
50
50
|
/**
|
|
51
|
-
*
|
|
52
|
-
*
|
|
51
|
+
* Custom QueueService
|
|
52
|
+
* Set to null to disable queue scheduling (for synchronous execution tests)
|
|
53
53
|
*/
|
|
54
54
|
queueService?: QueueService | null;
|
|
55
55
|
/**
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
56
|
+
* Custom StreamEventManager
|
|
57
|
+
* Defaults to Redis-based StreamEventManager
|
|
58
|
+
* Can pass InMemoryStreamEventManager in test environments
|
|
59
59
|
*/
|
|
60
60
|
streamEventManager?: IStreamEventManager;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
/**
|
|
64
64
|
* Agent Runtime Service
|
|
65
|
-
*
|
|
65
|
+
* Encapsulates Agent execution logic and provides a unified service interface
|
|
66
66
|
*
|
|
67
|
-
*
|
|
67
|
+
* Supports dependency injection for testing with in-memory implementations:
|
|
68
68
|
* ```ts
|
|
69
|
-
* //
|
|
69
|
+
* // Production environment (uses Redis by default)
|
|
70
70
|
* const service = new AgentRuntimeService(db, userId);
|
|
71
71
|
*
|
|
72
|
-
* //
|
|
72
|
+
* // Test environment
|
|
73
73
|
* const service = new AgentRuntimeService(db, userId, {
|
|
74
74
|
* streamEventManager: new InMemoryStreamEventManager(),
|
|
75
|
-
* queueService: null, //
|
|
75
|
+
* queueService: null, // Disable queue, use executeSync
|
|
76
76
|
* });
|
|
77
77
|
* ```
|
|
78
78
|
*/
|
|
@@ -82,7 +82,7 @@ export class AgentRuntimeService {
|
|
|
82
82
|
private queueService: QueueService | null;
|
|
83
83
|
private toolExecutionService: ToolExecutionService;
|
|
84
84
|
/**
|
|
85
|
-
* Step
|
|
85
|
+
* Step lifecycle callback registry
|
|
86
86
|
* key: operationId, value: callbacks
|
|
87
87
|
*/
|
|
88
88
|
private stepCallbacks: Map<string, StepLifecycleCallbacks> = new Map();
|
|
@@ -148,9 +148,9 @@ export class AgentRuntimeService {
|
|
|
148
148
|
// ==================== Step Lifecycle Callbacks ====================
|
|
149
149
|
|
|
150
150
|
/**
|
|
151
|
-
*
|
|
152
|
-
* @param operationId -
|
|
153
|
-
* @param callbacks -
|
|
151
|
+
* Register step lifecycle callbacks
|
|
152
|
+
* @param operationId - Operation ID
|
|
153
|
+
* @param callbacks - Callback function collection
|
|
154
154
|
*/
|
|
155
155
|
registerStepCallbacks(operationId: string, callbacks: StepLifecycleCallbacks): void {
|
|
156
156
|
this.stepCallbacks.set(operationId, callbacks);
|
|
@@ -158,8 +158,8 @@ export class AgentRuntimeService {
|
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
/**
|
|
161
|
-
*
|
|
162
|
-
* @param operationId -
|
|
161
|
+
* Remove step lifecycle callbacks
|
|
162
|
+
* @param operationId - Operation ID
|
|
163
163
|
*/
|
|
164
164
|
unregisterStepCallbacks(operationId: string): void {
|
|
165
165
|
this.stepCallbacks.delete(operationId);
|
|
@@ -167,8 +167,8 @@ export class AgentRuntimeService {
|
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
/**
|
|
170
|
-
*
|
|
171
|
-
* @param operationId -
|
|
170
|
+
* Get step lifecycle callbacks
|
|
171
|
+
* @param operationId - Operation ID
|
|
172
172
|
*/
|
|
173
173
|
getStepCallbacks(operationId: string): StepLifecycleCallbacks | undefined {
|
|
174
174
|
return this.stepCallbacks.get(operationId);
|
|
@@ -177,7 +177,7 @@ export class AgentRuntimeService {
|
|
|
177
177
|
// ==================== Operation Management ====================
|
|
178
178
|
|
|
179
179
|
/**
|
|
180
|
-
*
|
|
180
|
+
* Create a new Agent operation
|
|
181
181
|
*/
|
|
182
182
|
async createOperation(params: OperationCreationParams): Promise<OperationCreationResult> {
|
|
183
183
|
const {
|
|
@@ -197,13 +197,13 @@ export class AgentRuntimeService {
|
|
|
197
197
|
try {
|
|
198
198
|
log('[%s] Creating new operation (autoStart: %s)', operationId, autoStart);
|
|
199
199
|
|
|
200
|
-
//
|
|
200
|
+
// Initialize operation state - create state before saving
|
|
201
201
|
const initialState = {
|
|
202
202
|
createdAt: new Date().toISOString(),
|
|
203
203
|
// Store initialContext for executeSync to use
|
|
204
204
|
initialContext,
|
|
205
205
|
lastModified: new Date().toISOString(),
|
|
206
|
-
//
|
|
206
|
+
// Use the passed initial messages
|
|
207
207
|
messages: initialMessages,
|
|
208
208
|
metadata: {
|
|
209
209
|
agentConfig,
|
|
@@ -221,17 +221,17 @@ export class AgentRuntimeService {
|
|
|
221
221
|
tools,
|
|
222
222
|
} as Partial<AgentState>;
|
|
223
223
|
|
|
224
|
-
//
|
|
224
|
+
// Use coordinator to create operation, automatically sends initialization event
|
|
225
225
|
await this.coordinator.createAgentOperation(operationId, {
|
|
226
226
|
agentConfig,
|
|
227
227
|
modelRuntimeConfig,
|
|
228
228
|
userId,
|
|
229
229
|
});
|
|
230
230
|
|
|
231
|
-
//
|
|
231
|
+
// Save initial state
|
|
232
232
|
await this.coordinator.saveAgentState(operationId, initialState as any);
|
|
233
233
|
|
|
234
|
-
//
|
|
234
|
+
// Register step lifecycle callbacks
|
|
235
235
|
if (stepCallbacks) {
|
|
236
236
|
this.registerStepCallbacks(operationId, stepCallbacks);
|
|
237
237
|
}
|
|
@@ -245,7 +245,7 @@ export class AgentRuntimeService {
|
|
|
245
245
|
// QStashQueueServiceImpl schedules HTTP requests
|
|
246
246
|
messageId = await this.queueService.scheduleMessage({
|
|
247
247
|
context: initialContext,
|
|
248
|
-
delay: 50, //
|
|
248
|
+
delay: 50, // Short delay for startup
|
|
249
249
|
endpoint: `${this.baseURL}/run`,
|
|
250
250
|
operationId,
|
|
251
251
|
priority: 'high',
|
|
@@ -267,26 +267,26 @@ export class AgentRuntimeService {
|
|
|
267
267
|
}
|
|
268
268
|
|
|
269
269
|
/**
|
|
270
|
-
*
|
|
270
|
+
* Execute Agent step
|
|
271
271
|
*/
|
|
272
272
|
async executeStep(params: AgentExecutionParams): Promise<AgentExecutionResult> {
|
|
273
273
|
const { operationId, stepIndex, context, humanInput, approvedToolCall, rejectionReason } =
|
|
274
274
|
params;
|
|
275
275
|
|
|
276
|
-
//
|
|
276
|
+
// Get registered callbacks
|
|
277
277
|
const callbacks = this.getStepCallbacks(operationId);
|
|
278
278
|
|
|
279
279
|
try {
|
|
280
280
|
log('[%s] Executing step %d', operationId, stepIndex);
|
|
281
281
|
|
|
282
|
-
//
|
|
282
|
+
// Publish step start event
|
|
283
283
|
await this.streamManager.publishStreamEvent(operationId, {
|
|
284
284
|
data: {},
|
|
285
285
|
stepIndex,
|
|
286
286
|
type: 'step_start',
|
|
287
287
|
});
|
|
288
288
|
|
|
289
|
-
//
|
|
289
|
+
// Get operation state and metadata
|
|
290
290
|
const [agentState, operationMetadata] = await Promise.all([
|
|
291
291
|
this.coordinator.loadAgentState(operationId),
|
|
292
292
|
this.coordinator.getOperationMetadata(operationId),
|
|
@@ -296,7 +296,7 @@ export class AgentRuntimeService {
|
|
|
296
296
|
throw new Error(`Agent state not found for operation ${operationId}`);
|
|
297
297
|
}
|
|
298
298
|
|
|
299
|
-
//
|
|
299
|
+
// Call onBeforeStep callback
|
|
300
300
|
if (callbacks?.onBeforeStep) {
|
|
301
301
|
try {
|
|
302
302
|
await callbacks.onBeforeStep({
|
|
@@ -310,14 +310,14 @@ export class AgentRuntimeService {
|
|
|
310
310
|
}
|
|
311
311
|
}
|
|
312
312
|
|
|
313
|
-
//
|
|
313
|
+
// Create Agent and Runtime instances
|
|
314
314
|
const { runtime } = await this.createAgentRuntime({
|
|
315
315
|
metadata: operationMetadata,
|
|
316
316
|
operationId,
|
|
317
317
|
stepIndex,
|
|
318
318
|
});
|
|
319
319
|
|
|
320
|
-
//
|
|
320
|
+
// Handle human intervention
|
|
321
321
|
let currentContext = context;
|
|
322
322
|
let currentState = agentState;
|
|
323
323
|
|
|
@@ -331,25 +331,25 @@ export class AgentRuntimeService {
|
|
|
331
331
|
currentContext = interventionResult.nextContext;
|
|
332
332
|
}
|
|
333
333
|
|
|
334
|
-
//
|
|
334
|
+
// Execute step
|
|
335
335
|
const startAt = Date.now();
|
|
336
336
|
const stepResult = await runtime.step(currentState, currentContext);
|
|
337
337
|
|
|
338
|
-
//
|
|
338
|
+
// Save state, coordinator will handle event sending automatically
|
|
339
339
|
await this.coordinator.saveStepResult(operationId, {
|
|
340
340
|
...stepResult,
|
|
341
341
|
executionTime: Date.now() - startAt,
|
|
342
342
|
stepIndex, // placeholder
|
|
343
343
|
});
|
|
344
344
|
|
|
345
|
-
//
|
|
345
|
+
// Decide whether to schedule next step
|
|
346
346
|
const shouldContinue = this.shouldContinueExecution(
|
|
347
347
|
stepResult.newState,
|
|
348
348
|
stepResult.nextContext,
|
|
349
349
|
);
|
|
350
350
|
let nextStepScheduled = false;
|
|
351
351
|
|
|
352
|
-
//
|
|
352
|
+
// Publish step complete event
|
|
353
353
|
await this.streamManager.publishStreamEvent(operationId, {
|
|
354
354
|
data: {
|
|
355
355
|
finalState: stepResult.newState,
|
|
@@ -362,7 +362,7 @@ export class AgentRuntimeService {
|
|
|
362
362
|
|
|
363
363
|
log('[%s] Step %d completed', operationId, stepIndex);
|
|
364
364
|
|
|
365
|
-
//
|
|
365
|
+
// Call onAfterStep callback
|
|
366
366
|
if (callbacks?.onAfterStep) {
|
|
367
367
|
try {
|
|
368
368
|
await callbacks.onAfterStep({
|
|
@@ -395,7 +395,7 @@ export class AgentRuntimeService {
|
|
|
395
395
|
log('[%s] Scheduled next step %d', operationId, nextStepIndex);
|
|
396
396
|
}
|
|
397
397
|
|
|
398
|
-
//
|
|
398
|
+
// Check if operation is complete, call onComplete callback
|
|
399
399
|
if (!shouldContinue && callbacks?.onComplete) {
|
|
400
400
|
const reason = this.determineCompletionReason(stepResult.newState);
|
|
401
401
|
try {
|
|
@@ -404,7 +404,7 @@ export class AgentRuntimeService {
|
|
|
404
404
|
operationId,
|
|
405
405
|
reason,
|
|
406
406
|
});
|
|
407
|
-
//
|
|
407
|
+
// Clean up callbacks after operation completes
|
|
408
408
|
this.unregisterStepCallbacks(operationId);
|
|
409
409
|
} catch (callbackError) {
|
|
410
410
|
log('[%s] onComplete callback error: %O', operationId, callbackError);
|
|
@@ -420,7 +420,7 @@ export class AgentRuntimeService {
|
|
|
420
420
|
} catch (error) {
|
|
421
421
|
log('Step %d failed for operation %s: %O', stepIndex, operationId, error);
|
|
422
422
|
|
|
423
|
-
//
|
|
423
|
+
// Publish error event
|
|
424
424
|
await this.streamManager.publishStreamEvent(operationId, {
|
|
425
425
|
data: {
|
|
426
426
|
error: (error as Error).message,
|
|
@@ -431,7 +431,7 @@ export class AgentRuntimeService {
|
|
|
431
431
|
type: 'error',
|
|
432
432
|
});
|
|
433
433
|
|
|
434
|
-
//
|
|
434
|
+
// Also call onComplete callback when execution fails
|
|
435
435
|
if (callbacks?.onComplete) {
|
|
436
436
|
try {
|
|
437
437
|
const errorState = await this.coordinator.loadAgentState(operationId);
|
|
@@ -451,7 +451,7 @@ export class AgentRuntimeService {
|
|
|
451
451
|
}
|
|
452
452
|
|
|
453
453
|
/**
|
|
454
|
-
*
|
|
454
|
+
* Get operation status
|
|
455
455
|
*/
|
|
456
456
|
async getOperationStatus(params: {
|
|
457
457
|
historyLimit?: number;
|
|
@@ -463,19 +463,19 @@ export class AgentRuntimeService {
|
|
|
463
463
|
try {
|
|
464
464
|
log('Getting operation status for %s', operationId);
|
|
465
465
|
|
|
466
|
-
//
|
|
466
|
+
// Get current state and metadata
|
|
467
467
|
const [currentState, operationMetadata] = await Promise.all([
|
|
468
468
|
this.coordinator.loadAgentState(operationId),
|
|
469
469
|
this.coordinator.getOperationMetadata(operationId),
|
|
470
470
|
]);
|
|
471
471
|
|
|
472
|
-
// Operation
|
|
472
|
+
// Operation may have expired or does not exist, return null
|
|
473
473
|
if (!currentState || !operationMetadata) {
|
|
474
474
|
log('Operation %s not found (may have expired)', operationId);
|
|
475
475
|
return null;
|
|
476
476
|
}
|
|
477
477
|
|
|
478
|
-
//
|
|
478
|
+
// Get execution history (if needed)
|
|
479
479
|
let executionHistory;
|
|
480
480
|
if (includeHistory) {
|
|
481
481
|
try {
|
|
@@ -486,7 +486,7 @@ export class AgentRuntimeService {
|
|
|
486
486
|
}
|
|
487
487
|
}
|
|
488
488
|
|
|
489
|
-
//
|
|
489
|
+
// Get recent stream events (for debugging)
|
|
490
490
|
let recentEvents;
|
|
491
491
|
if (includeHistory) {
|
|
492
492
|
try {
|
|
@@ -497,7 +497,7 @@ export class AgentRuntimeService {
|
|
|
497
497
|
}
|
|
498
498
|
}
|
|
499
499
|
|
|
500
|
-
//
|
|
500
|
+
// Calculate operation statistics
|
|
501
501
|
const stats = {
|
|
502
502
|
lastActiveTime: operationMetadata.lastActiveAt
|
|
503
503
|
? Date.now() - new Date(operationMetadata.lastActiveAt).getTime()
|
|
@@ -542,7 +542,7 @@ export class AgentRuntimeService {
|
|
|
542
542
|
}
|
|
543
543
|
|
|
544
544
|
/**
|
|
545
|
-
*
|
|
545
|
+
* Get list of pending human interventions
|
|
546
546
|
*/
|
|
547
547
|
async getPendingInterventions(params: {
|
|
548
548
|
operationId?: string;
|
|
@@ -558,11 +558,11 @@ export class AgentRuntimeService {
|
|
|
558
558
|
if (operationId) {
|
|
559
559
|
operations = [operationId];
|
|
560
560
|
} else if (userId) {
|
|
561
|
-
//
|
|
561
|
+
// Get all active operations for the user
|
|
562
562
|
try {
|
|
563
563
|
const activeOperations = await this.coordinator.getActiveOperations();
|
|
564
564
|
|
|
565
|
-
//
|
|
565
|
+
// Filter operations belonging to this user
|
|
566
566
|
const userOperations = [];
|
|
567
567
|
for (const operation of activeOperations) {
|
|
568
568
|
try {
|
|
@@ -581,7 +581,7 @@ export class AgentRuntimeService {
|
|
|
581
581
|
}
|
|
582
582
|
}
|
|
583
583
|
|
|
584
|
-
//
|
|
584
|
+
// Check status of each operation
|
|
585
585
|
const pendingInterventions = [];
|
|
586
586
|
|
|
587
587
|
for (const operation of operations) {
|
|
@@ -601,7 +601,7 @@ export class AgentRuntimeService {
|
|
|
601
601
|
userId: metadata?.userId,
|
|
602
602
|
};
|
|
603
603
|
|
|
604
|
-
//
|
|
604
|
+
// Add specific pending content
|
|
605
605
|
if (state.pendingToolsCalling) {
|
|
606
606
|
intervention.type = 'tool_approval';
|
|
607
607
|
intervention.pendingToolsCalling = state.pendingToolsCalling;
|
|
@@ -632,7 +632,7 @@ export class AgentRuntimeService {
|
|
|
632
632
|
}
|
|
633
633
|
|
|
634
634
|
/**
|
|
635
|
-
*
|
|
635
|
+
* Explicitly start operation execution
|
|
636
636
|
*/
|
|
637
637
|
async startExecution(params: StartExecutionParams): Promise<StartExecutionResult> {
|
|
638
638
|
const { operationId, context, priority = 'normal', delay = 50 } = params;
|
|
@@ -640,19 +640,19 @@ export class AgentRuntimeService {
|
|
|
640
640
|
try {
|
|
641
641
|
log('Starting execution for operation %s', operationId);
|
|
642
642
|
|
|
643
|
-
//
|
|
643
|
+
// Check if operation exists
|
|
644
644
|
const operationMetadata = await this.coordinator.getOperationMetadata(operationId);
|
|
645
645
|
if (!operationMetadata) {
|
|
646
646
|
throw new Error(`Operation ${operationId} not found`);
|
|
647
647
|
}
|
|
648
648
|
|
|
649
|
-
//
|
|
649
|
+
// Get current state
|
|
650
650
|
const currentState = await this.coordinator.loadAgentState(operationId);
|
|
651
651
|
if (!currentState) {
|
|
652
652
|
throw new Error(`Agent state not found for operation ${operationId}`);
|
|
653
653
|
}
|
|
654
654
|
|
|
655
|
-
//
|
|
655
|
+
// Check operation status
|
|
656
656
|
if (currentState.status === 'running') {
|
|
657
657
|
throw new Error(`Operation ${operationId} is already running`);
|
|
658
658
|
}
|
|
@@ -665,10 +665,10 @@ export class AgentRuntimeService {
|
|
|
665
665
|
throw new Error(`Operation ${operationId} is in error state`);
|
|
666
666
|
}
|
|
667
667
|
|
|
668
|
-
//
|
|
668
|
+
// Build execution context
|
|
669
669
|
let executionContext = context;
|
|
670
670
|
if (!executionContext) {
|
|
671
|
-
//
|
|
671
|
+
// If no context provided, build default context from metadata
|
|
672
672
|
// Note: AgentRuntimeContext requires sessionId for compatibility with @lobechat/agent-runtime
|
|
673
673
|
executionContext = {
|
|
674
674
|
payload: {
|
|
@@ -685,14 +685,14 @@ export class AgentRuntimeService {
|
|
|
685
685
|
};
|
|
686
686
|
}
|
|
687
687
|
|
|
688
|
-
//
|
|
688
|
+
// Update operation status to running
|
|
689
689
|
await this.coordinator.saveAgentState(operationId, {
|
|
690
690
|
...currentState,
|
|
691
691
|
lastModified: new Date().toISOString(),
|
|
692
692
|
status: 'running',
|
|
693
693
|
});
|
|
694
694
|
|
|
695
|
-
//
|
|
695
|
+
// Schedule execution (if queue service is available)
|
|
696
696
|
let messageId: string | undefined;
|
|
697
697
|
if (this.queueService) {
|
|
698
698
|
messageId = await this.queueService.scheduleMessage({
|
|
@@ -721,7 +721,7 @@ export class AgentRuntimeService {
|
|
|
721
721
|
}
|
|
722
722
|
|
|
723
723
|
/**
|
|
724
|
-
*
|
|
724
|
+
* Process human intervention
|
|
725
725
|
*/
|
|
726
726
|
async processHumanIntervention(params: {
|
|
727
727
|
action: 'approve' | 'reject' | 'input' | 'select';
|
|
@@ -742,11 +742,11 @@ export class AgentRuntimeService {
|
|
|
742
742
|
action,
|
|
743
743
|
);
|
|
744
744
|
|
|
745
|
-
//
|
|
745
|
+
// Schedule execution with high priority (if queue service is available)
|
|
746
746
|
let messageId: string | undefined;
|
|
747
747
|
if (this.queueService) {
|
|
748
748
|
messageId = await this.queueService.scheduleMessage({
|
|
749
|
-
context: undefined, //
|
|
749
|
+
context: undefined, // Will be retrieved from state manager
|
|
750
750
|
delay: 100,
|
|
751
751
|
endpoint: `${this.baseURL}/run`,
|
|
752
752
|
operationId,
|
|
@@ -771,7 +771,7 @@ export class AgentRuntimeService {
|
|
|
771
771
|
}
|
|
772
772
|
|
|
773
773
|
/**
|
|
774
|
-
*
|
|
774
|
+
* Create Agent Runtime instance
|
|
775
775
|
*/
|
|
776
776
|
private async createAgentRuntime({
|
|
777
777
|
metadata,
|
|
@@ -782,7 +782,7 @@ export class AgentRuntimeService {
|
|
|
782
782
|
operationId: string;
|
|
783
783
|
stepIndex: number;
|
|
784
784
|
}) {
|
|
785
|
-
//
|
|
785
|
+
// Create Durable Agent instance
|
|
786
786
|
const agent = new GeneralChatAgent({
|
|
787
787
|
agentConfig: metadata?.agentConfig,
|
|
788
788
|
modelRuntimeConfig: metadata?.modelRuntimeConfig,
|
|
@@ -790,7 +790,7 @@ export class AgentRuntimeService {
|
|
|
790
790
|
userId: metadata?.userId,
|
|
791
791
|
});
|
|
792
792
|
|
|
793
|
-
//
|
|
793
|
+
// Create streaming executor context
|
|
794
794
|
const executorContext: RuntimeExecutorContext = {
|
|
795
795
|
messageModel: this.messageModel,
|
|
796
796
|
operationId,
|
|
@@ -800,7 +800,7 @@ export class AgentRuntimeService {
|
|
|
800
800
|
userId: metadata?.userId,
|
|
801
801
|
};
|
|
802
802
|
|
|
803
|
-
//
|
|
803
|
+
// Create Agent Runtime instance
|
|
804
804
|
const runtime = new AgentRuntime(agent as any, {
|
|
805
805
|
executors: createRuntimeExecutors(executorContext),
|
|
806
806
|
});
|
|
@@ -809,7 +809,7 @@ export class AgentRuntimeService {
|
|
|
809
809
|
}
|
|
810
810
|
|
|
811
811
|
/**
|
|
812
|
-
*
|
|
812
|
+
* Handle human intervention logic
|
|
813
813
|
*/
|
|
814
814
|
private async handleHumanIntervention(
|
|
815
815
|
runtime: AgentRuntime,
|
|
@@ -819,13 +819,13 @@ export class AgentRuntimeService {
|
|
|
819
819
|
const { humanInput, approvedToolCall, rejectionReason } = intervention;
|
|
820
820
|
|
|
821
821
|
if (approvedToolCall && state.status === 'waiting_for_human') {
|
|
822
|
-
// TODO:
|
|
822
|
+
// TODO: implement approveToolCall logic
|
|
823
823
|
return { newState: state, nextContext: undefined };
|
|
824
824
|
} else if (rejectionReason && state.status === 'waiting_for_human') {
|
|
825
|
-
// TODO:
|
|
825
|
+
// TODO: implement rejectToolCall logic
|
|
826
826
|
return { newState: state, nextContext: undefined };
|
|
827
827
|
} else if (humanInput) {
|
|
828
|
-
// TODO:
|
|
828
|
+
// TODO: implement processHumanInput logic
|
|
829
829
|
return { newState: state, nextContext: undefined };
|
|
830
830
|
}
|
|
831
831
|
|
|
@@ -833,47 +833,47 @@ export class AgentRuntimeService {
|
|
|
833
833
|
}
|
|
834
834
|
|
|
835
835
|
/**
|
|
836
|
-
*
|
|
836
|
+
* Decide whether to continue execution
|
|
837
837
|
*/
|
|
838
838
|
private shouldContinueExecution(state: any, context?: any): boolean {
|
|
839
|
-
//
|
|
839
|
+
// Completed
|
|
840
840
|
if (state.status === 'done') return false;
|
|
841
841
|
|
|
842
|
-
//
|
|
842
|
+
// Needs human intervention
|
|
843
843
|
if (state.status === 'waiting_for_human') return false;
|
|
844
844
|
|
|
845
|
-
//
|
|
845
|
+
// Error occurred
|
|
846
846
|
if (state.status === 'error') return false;
|
|
847
847
|
|
|
848
|
-
//
|
|
848
|
+
// Interrupted
|
|
849
849
|
if (state.status === 'interrupted') return false;
|
|
850
850
|
|
|
851
|
-
//
|
|
851
|
+
// Reached maximum steps
|
|
852
852
|
if (state.maxSteps && state.stepCount >= state.maxSteps) return false;
|
|
853
853
|
|
|
854
|
-
//
|
|
854
|
+
// Exceeded cost limit
|
|
855
855
|
if (state.costLimit && state.cost?.total >= state.costLimit.maxTotalCost) {
|
|
856
856
|
return state.costLimit.onExceeded !== 'stop';
|
|
857
857
|
}
|
|
858
858
|
|
|
859
|
-
//
|
|
859
|
+
// No next context
|
|
860
860
|
if (!context) return false;
|
|
861
861
|
|
|
862
862
|
return true;
|
|
863
863
|
}
|
|
864
864
|
|
|
865
865
|
/**
|
|
866
|
-
*
|
|
866
|
+
* Calculate step delay
|
|
867
867
|
*/
|
|
868
868
|
private calculateStepDelay(stepResult: any): number {
|
|
869
869
|
const baseDelay = 50;
|
|
870
870
|
|
|
871
|
-
//
|
|
871
|
+
// If there are tool calls, add longer delay
|
|
872
872
|
if (stepResult.events?.some((e: any) => e.type === 'tool_result')) {
|
|
873
873
|
return baseDelay + 50;
|
|
874
874
|
}
|
|
875
875
|
|
|
876
|
-
//
|
|
876
|
+
// If there are errors, use exponential backoff
|
|
877
877
|
if (stepResult.events?.some((e: any) => e.type === 'error')) {
|
|
878
878
|
return Math.min(baseDelay * 2, 1000);
|
|
879
879
|
}
|
|
@@ -882,15 +882,15 @@ export class AgentRuntimeService {
|
|
|
882
882
|
}
|
|
883
883
|
|
|
884
884
|
/**
|
|
885
|
-
*
|
|
885
|
+
* Calculate priority
|
|
886
886
|
*/
|
|
887
887
|
private calculatePriority(stepResult: any): 'high' | 'normal' | 'low' {
|
|
888
|
-
//
|
|
888
|
+
// If human intervention needed, high priority
|
|
889
889
|
if (stepResult.newState?.status === 'waiting_for_human') {
|
|
890
890
|
return 'high';
|
|
891
891
|
}
|
|
892
892
|
|
|
893
|
-
//
|
|
893
|
+
// If there are errors, normal priority
|
|
894
894
|
if (stepResult.events?.some((e: any) => e.type === 'error')) {
|
|
895
895
|
return 'normal';
|
|
896
896
|
}
|
|
@@ -899,7 +899,7 @@ export class AgentRuntimeService {
|
|
|
899
899
|
}
|
|
900
900
|
|
|
901
901
|
/**
|
|
902
|
-
*
|
|
902
|
+
* Determine operation completion reason
|
|
903
903
|
*/
|
|
904
904
|
private determineCompletionReason(state: AgentState): StepCompletionReason {
|
|
905
905
|
if (state.status === 'done') return 'done';
|
|
@@ -912,20 +912,20 @@ export class AgentRuntimeService {
|
|
|
912
912
|
}
|
|
913
913
|
|
|
914
914
|
/**
|
|
915
|
-
*
|
|
915
|
+
* Synchronously execute Agent operation until completion
|
|
916
916
|
*
|
|
917
|
-
*
|
|
917
|
+
* Used in test scenarios, doesn't depend on QueueService, executes all steps directly in the current process.
|
|
918
918
|
*
|
|
919
|
-
* @param operationId
|
|
920
|
-
* @param options
|
|
921
|
-
* @returns
|
|
919
|
+
* @param operationId Operation ID
|
|
920
|
+
* @param options Execution options
|
|
921
|
+
* @returns Final state
|
|
922
922
|
*
|
|
923
923
|
* @example
|
|
924
924
|
* ```ts
|
|
925
|
-
* //
|
|
925
|
+
* // Create operation (without auto-starting queue)
|
|
926
926
|
* const result = await service.createOperation({ ...params, autoStart: false });
|
|
927
927
|
*
|
|
928
|
-
* //
|
|
928
|
+
* // Synchronously execute to completion
|
|
929
929
|
* const finalState = await service.executeSync(result.operationId);
|
|
930
930
|
* expect(finalState.status).toBe('done');
|
|
931
931
|
* ```
|
|
@@ -933,11 +933,11 @@ export class AgentRuntimeService {
|
|
|
933
933
|
async executeSync(
|
|
934
934
|
operationId: string,
|
|
935
935
|
options?: {
|
|
936
|
-
/**
|
|
936
|
+
/** Initial context (if not provided, inferred from state) */
|
|
937
937
|
initialContext?: AgentRuntimeContext;
|
|
938
|
-
/**
|
|
938
|
+
/** Maximum step limit to prevent infinite loops, defaults to 9999 */
|
|
939
939
|
maxSteps?: number;
|
|
940
|
-
/**
|
|
940
|
+
/** Callback after each step execution (for debugging) */
|
|
941
941
|
onStepComplete?: (stepIndex: number, state: AgentState) => void;
|
|
942
942
|
},
|
|
943
943
|
): Promise<AgentState> {
|
|
@@ -945,7 +945,7 @@ export class AgentRuntimeService {
|
|
|
945
945
|
|
|
946
946
|
log('[%s] Starting sync execution (maxSteps: %d)', operationId, maxSteps);
|
|
947
947
|
|
|
948
|
-
//
|
|
948
|
+
// Load initial state
|
|
949
949
|
const initialState = await this.coordinator.loadAgentState(operationId);
|
|
950
950
|
if (!initialState) {
|
|
951
951
|
throw new Error(`Agent state not found for operation ${operationId}`);
|
|
@@ -953,7 +953,7 @@ export class AgentRuntimeService {
|
|
|
953
953
|
|
|
954
954
|
let state: AgentState = initialState;
|
|
955
955
|
|
|
956
|
-
//
|
|
956
|
+
// Build initial context
|
|
957
957
|
// Priority: explicit initialContext param > saved initialContext in state > default
|
|
958
958
|
let context: AgentRuntimeContext | undefined =
|
|
959
959
|
initialContext ??
|
|
@@ -971,21 +971,21 @@ export class AgentRuntimeService {
|
|
|
971
971
|
|
|
972
972
|
let stepIndex = state.stepCount;
|
|
973
973
|
|
|
974
|
-
//
|
|
974
|
+
// Execution loop
|
|
975
975
|
while (stepIndex < maxSteps) {
|
|
976
|
-
//
|
|
976
|
+
// Check termination conditions
|
|
977
977
|
if (state.status === 'done' || state.status === 'error' || state.status === 'interrupted') {
|
|
978
978
|
log('[%s] Sync execution finished with status: %s', operationId, state.status);
|
|
979
979
|
break;
|
|
980
980
|
}
|
|
981
981
|
|
|
982
|
-
//
|
|
982
|
+
// Check if human intervention is needed
|
|
983
983
|
if (state.status === 'waiting_for_human') {
|
|
984
984
|
log('[%s] Sync execution paused: waiting for human intervention', operationId);
|
|
985
985
|
break;
|
|
986
986
|
}
|
|
987
987
|
|
|
988
|
-
//
|
|
988
|
+
// Execute one step
|
|
989
989
|
log('[%s] Executing step %d', operationId, stepIndex);
|
|
990
990
|
const result = await this.executeStep({
|
|
991
991
|
context,
|
|
@@ -997,12 +997,12 @@ export class AgentRuntimeService {
|
|
|
997
997
|
context = result.stepResult.nextContext;
|
|
998
998
|
stepIndex++;
|
|
999
999
|
|
|
1000
|
-
//
|
|
1000
|
+
// Callback
|
|
1001
1001
|
if (onStepComplete) {
|
|
1002
1002
|
onStepComplete(stepIndex, state);
|
|
1003
1003
|
}
|
|
1004
1004
|
|
|
1005
|
-
//
|
|
1005
|
+
// Check if should continue
|
|
1006
1006
|
if (!this.shouldContinueExecution(state, context)) {
|
|
1007
1007
|
log('[%s] Sync execution stopped: shouldContinue=false', operationId);
|
|
1008
1008
|
break;
|
|
@@ -1011,8 +1011,8 @@ export class AgentRuntimeService {
|
|
|
1011
1011
|
|
|
1012
1012
|
if (stepIndex >= maxSteps) {
|
|
1013
1013
|
log('[%s] Sync execution stopped: reached maxSteps (%d)', operationId, maxSteps);
|
|
1014
|
-
//
|
|
1015
|
-
//
|
|
1014
|
+
// If stopped due to executeSync's maxSteps limit, need to manually call onComplete
|
|
1015
|
+
// Note: If stopped due to state.maxSteps being reached, onComplete has already been called in executeStep
|
|
1016
1016
|
const callbacks = this.getStepCallbacks(operationId);
|
|
1017
1017
|
if (callbacks?.onComplete && state.status !== 'done' && state.status !== 'error') {
|
|
1018
1018
|
try {
|
|
@@ -1032,7 +1032,7 @@ export class AgentRuntimeService {
|
|
|
1032
1032
|
}
|
|
1033
1033
|
|
|
1034
1034
|
/**
|
|
1035
|
-
*
|
|
1035
|
+
* Get Coordinator instance (for testing)
|
|
1036
1036
|
*/
|
|
1037
1037
|
getCoordinator(): AgentRuntimeCoordinator {
|
|
1038
1038
|
return this.coordinator;
|