llmist 3.0.0 → 4.0.0
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/{chunk-NBPKLSXJ.js → chunk-Q6NQRMYD.js} +2 -2
- package/dist/chunk-Q6NQRMYD.js.map +1 -0
- package/dist/{chunk-67MMSOAT.js → chunk-RHR2M6T6.js} +643 -51
- package/dist/chunk-RHR2M6T6.js.map +1 -0
- package/dist/cli.cjs +914 -84
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +273 -35
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +642 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +43 -6
- package/dist/index.d.ts +43 -6
- package/dist/index.js +2 -2
- package/dist/{mock-stream-COHw8h9b.d.cts → mock-stream-BvNYtrlG.d.cts} +223 -3
- package/dist/{mock-stream-COHw8h9b.d.ts → mock-stream-BvNYtrlG.d.ts} +223 -3
- package/dist/testing/index.cjs +642 -50
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.cts +2 -2
- package/dist/testing/index.d.ts +2 -2
- package/dist/testing/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-67MMSOAT.js.map +0 -1
- package/dist/chunk-NBPKLSXJ.js.map +0 -1
package/dist/testing/index.cjs
CHANGED
|
@@ -3485,7 +3485,7 @@ var init_executor = __esm({
|
|
|
3485
3485
|
init_exceptions();
|
|
3486
3486
|
init_parser();
|
|
3487
3487
|
GadgetExecutor = class {
|
|
3488
|
-
constructor(registry, requestHumanInput, logger, defaultGadgetTimeoutMs, errorFormatterOptions, client, mediaStore, agentConfig, subagentConfig) {
|
|
3488
|
+
constructor(registry, requestHumanInput, logger, defaultGadgetTimeoutMs, errorFormatterOptions, client, mediaStore, agentConfig, subagentConfig, onSubagentEvent) {
|
|
3489
3489
|
this.registry = registry;
|
|
3490
3490
|
this.requestHumanInput = requestHumanInput;
|
|
3491
3491
|
this.defaultGadgetTimeoutMs = defaultGadgetTimeoutMs;
|
|
@@ -3493,6 +3493,7 @@ var init_executor = __esm({
|
|
|
3493
3493
|
this.mediaStore = mediaStore;
|
|
3494
3494
|
this.agentConfig = agentConfig;
|
|
3495
3495
|
this.subagentConfig = subagentConfig;
|
|
3496
|
+
this.onSubagentEvent = onSubagentEvent;
|
|
3496
3497
|
this.logger = logger ?? createLogger({ name: "llmist:executor" });
|
|
3497
3498
|
this.errorFormatter = new GadgetExecutionErrorFormatter(errorFormatterOptions);
|
|
3498
3499
|
this.argPrefix = errorFormatterOptions?.argPrefix ?? GADGET_ARG_PREFIX;
|
|
@@ -3638,7 +3639,9 @@ var init_executor = __esm({
|
|
|
3638
3639
|
llmist: this.client ? new CostReportingLLMistWrapper(this.client, reportCost) : void 0,
|
|
3639
3640
|
signal: abortController.signal,
|
|
3640
3641
|
agentConfig: this.agentConfig,
|
|
3641
|
-
subagentConfig: this.subagentConfig
|
|
3642
|
+
subagentConfig: this.subagentConfig,
|
|
3643
|
+
invocationId: call.invocationId,
|
|
3644
|
+
onSubagentEvent: this.onSubagentEvent
|
|
3642
3645
|
};
|
|
3643
3646
|
let rawResult;
|
|
3644
3647
|
if (timeoutMs && timeoutMs > 0) {
|
|
@@ -3877,14 +3880,21 @@ var init_stream_processor = __esm({
|
|
|
3877
3880
|
options.client,
|
|
3878
3881
|
options.mediaStore,
|
|
3879
3882
|
options.agentConfig,
|
|
3880
|
-
options.subagentConfig
|
|
3883
|
+
options.subagentConfig,
|
|
3884
|
+
options.onSubagentEvent
|
|
3881
3885
|
);
|
|
3882
3886
|
}
|
|
3883
3887
|
/**
|
|
3884
|
-
* Process an LLM stream and
|
|
3888
|
+
* Process an LLM stream and yield events in real-time.
|
|
3889
|
+
*
|
|
3890
|
+
* This is an async generator that yields events immediately as they occur:
|
|
3891
|
+
* - Text events are yielded as text is streamed from the LLM
|
|
3892
|
+
* - gadget_call events are yielded immediately when a gadget call is parsed
|
|
3893
|
+
* - gadget_result events are yielded when gadget execution completes
|
|
3894
|
+
*
|
|
3895
|
+
* The final event is always a StreamCompletionEvent containing metadata.
|
|
3885
3896
|
*/
|
|
3886
|
-
async process(stream2) {
|
|
3887
|
-
const outputs = [];
|
|
3897
|
+
async *process(stream2) {
|
|
3888
3898
|
let finishReason = null;
|
|
3889
3899
|
let usage;
|
|
3890
3900
|
let didExecuteGadgets = false;
|
|
@@ -3930,14 +3940,13 @@ var init_stream_processor = __esm({
|
|
|
3930
3940
|
continue;
|
|
3931
3941
|
}
|
|
3932
3942
|
for (const event of this.parser.feed(processedChunk)) {
|
|
3933
|
-
const
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
shouldBreakLoop = true;
|
|
3943
|
+
for await (const processedEvent of this.processEventGenerator(event)) {
|
|
3944
|
+
yield processedEvent;
|
|
3945
|
+
if (processedEvent.type === "gadget_result") {
|
|
3946
|
+
didExecuteGadgets = true;
|
|
3947
|
+
if (processedEvent.result.breaksLoop) {
|
|
3948
|
+
shouldBreakLoop = true;
|
|
3949
|
+
}
|
|
3941
3950
|
}
|
|
3942
3951
|
}
|
|
3943
3952
|
}
|
|
@@ -3948,25 +3957,23 @@ var init_stream_processor = __esm({
|
|
|
3948
3957
|
}
|
|
3949
3958
|
if (!this.executionHalted) {
|
|
3950
3959
|
for (const event of this.parser.finalize()) {
|
|
3951
|
-
const
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
|
|
3957
|
-
|
|
3958
|
-
shouldBreakLoop = true;
|
|
3960
|
+
for await (const processedEvent of this.processEventGenerator(event)) {
|
|
3961
|
+
yield processedEvent;
|
|
3962
|
+
if (processedEvent.type === "gadget_result") {
|
|
3963
|
+
didExecuteGadgets = true;
|
|
3964
|
+
if (processedEvent.result.breaksLoop) {
|
|
3965
|
+
shouldBreakLoop = true;
|
|
3966
|
+
}
|
|
3959
3967
|
}
|
|
3960
3968
|
}
|
|
3961
3969
|
}
|
|
3962
|
-
const
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
shouldBreakLoop = true;
|
|
3970
|
+
for await (const evt of this.processPendingGadgetsGenerator()) {
|
|
3971
|
+
yield evt;
|
|
3972
|
+
if (evt.type === "gadget_result") {
|
|
3973
|
+
didExecuteGadgets = true;
|
|
3974
|
+
if (evt.result.breaksLoop) {
|
|
3975
|
+
shouldBreakLoop = true;
|
|
3976
|
+
}
|
|
3970
3977
|
}
|
|
3971
3978
|
}
|
|
3972
3979
|
}
|
|
@@ -3979,8 +3986,8 @@ var init_stream_processor = __esm({
|
|
|
3979
3986
|
};
|
|
3980
3987
|
finalMessage = this.hooks.interceptors.interceptAssistantMessage(finalMessage, context);
|
|
3981
3988
|
}
|
|
3982
|
-
|
|
3983
|
-
|
|
3989
|
+
const completionEvent = {
|
|
3990
|
+
type: "stream_complete",
|
|
3984
3991
|
shouldBreakLoop,
|
|
3985
3992
|
didExecuteGadgets,
|
|
3986
3993
|
finishReason,
|
|
@@ -3988,9 +3995,11 @@ var init_stream_processor = __esm({
|
|
|
3988
3995
|
rawResponse: this.responseText,
|
|
3989
3996
|
finalMessage
|
|
3990
3997
|
};
|
|
3998
|
+
yield completionEvent;
|
|
3991
3999
|
}
|
|
3992
4000
|
/**
|
|
3993
4001
|
* Process a single parsed event (text or gadget call).
|
|
4002
|
+
* @deprecated Use processEventGenerator for real-time streaming
|
|
3994
4003
|
*/
|
|
3995
4004
|
async processEvent(event) {
|
|
3996
4005
|
if (event.type === "text") {
|
|
@@ -4000,6 +4009,23 @@ var init_stream_processor = __esm({
|
|
|
4000
4009
|
}
|
|
4001
4010
|
return [event];
|
|
4002
4011
|
}
|
|
4012
|
+
/**
|
|
4013
|
+
* Process a single parsed event, yielding events in real-time.
|
|
4014
|
+
* Generator version of processEvent for streaming support.
|
|
4015
|
+
*/
|
|
4016
|
+
async *processEventGenerator(event) {
|
|
4017
|
+
if (event.type === "text") {
|
|
4018
|
+
for (const e of await this.processTextEvent(event)) {
|
|
4019
|
+
yield e;
|
|
4020
|
+
}
|
|
4021
|
+
} else if (event.type === "gadget_call") {
|
|
4022
|
+
for await (const e of this.processGadgetCallGenerator(event.call)) {
|
|
4023
|
+
yield e;
|
|
4024
|
+
}
|
|
4025
|
+
} else {
|
|
4026
|
+
yield event;
|
|
4027
|
+
}
|
|
4028
|
+
}
|
|
4003
4029
|
/**
|
|
4004
4030
|
* Process a text event through interceptors.
|
|
4005
4031
|
*/
|
|
@@ -4076,9 +4102,68 @@ var init_stream_processor = __esm({
|
|
|
4076
4102
|
events.push(...triggeredEvents);
|
|
4077
4103
|
return events;
|
|
4078
4104
|
}
|
|
4105
|
+
/**
|
|
4106
|
+
* Process a gadget call, yielding events in real-time.
|
|
4107
|
+
*
|
|
4108
|
+
* Key difference from processGadgetCall: yields gadget_call event IMMEDIATELY
|
|
4109
|
+
* when parsed (before execution), enabling real-time UI feedback.
|
|
4110
|
+
*/
|
|
4111
|
+
async *processGadgetCallGenerator(call) {
|
|
4112
|
+
if (this.executionHalted) {
|
|
4113
|
+
this.logger.debug("Skipping gadget execution due to previous error", {
|
|
4114
|
+
gadgetName: call.gadgetName
|
|
4115
|
+
});
|
|
4116
|
+
return;
|
|
4117
|
+
}
|
|
4118
|
+
yield { type: "gadget_call", call };
|
|
4119
|
+
if (call.dependencies.length > 0) {
|
|
4120
|
+
if (call.dependencies.includes(call.invocationId)) {
|
|
4121
|
+
this.logger.warn("Gadget has self-referential dependency (depends on itself)", {
|
|
4122
|
+
gadgetName: call.gadgetName,
|
|
4123
|
+
invocationId: call.invocationId
|
|
4124
|
+
});
|
|
4125
|
+
this.failedInvocations.add(call.invocationId);
|
|
4126
|
+
const skipEvent = {
|
|
4127
|
+
type: "gadget_skipped",
|
|
4128
|
+
gadgetName: call.gadgetName,
|
|
4129
|
+
invocationId: call.invocationId,
|
|
4130
|
+
parameters: call.parameters ?? {},
|
|
4131
|
+
failedDependency: call.invocationId,
|
|
4132
|
+
failedDependencyError: `Gadget "${call.invocationId}" cannot depend on itself (self-referential dependency)`
|
|
4133
|
+
};
|
|
4134
|
+
yield skipEvent;
|
|
4135
|
+
return;
|
|
4136
|
+
}
|
|
4137
|
+
const failedDep = call.dependencies.find((dep) => this.failedInvocations.has(dep));
|
|
4138
|
+
if (failedDep) {
|
|
4139
|
+
const skipEvents = await this.handleFailedDependency(call, failedDep);
|
|
4140
|
+
for (const evt of skipEvents) {
|
|
4141
|
+
yield evt;
|
|
4142
|
+
}
|
|
4143
|
+
return;
|
|
4144
|
+
}
|
|
4145
|
+
const unsatisfied = call.dependencies.filter((dep) => !this.completedResults.has(dep));
|
|
4146
|
+
if (unsatisfied.length > 0) {
|
|
4147
|
+
this.logger.debug("Queueing gadget for later - waiting on dependencies", {
|
|
4148
|
+
gadgetName: call.gadgetName,
|
|
4149
|
+
invocationId: call.invocationId,
|
|
4150
|
+
waitingOn: unsatisfied
|
|
4151
|
+
});
|
|
4152
|
+
this.gadgetsAwaitingDependencies.set(call.invocationId, call);
|
|
4153
|
+
return;
|
|
4154
|
+
}
|
|
4155
|
+
}
|
|
4156
|
+
for await (const evt of this.executeGadgetGenerator(call)) {
|
|
4157
|
+
yield evt;
|
|
4158
|
+
}
|
|
4159
|
+
for await (const evt of this.processPendingGadgetsGenerator()) {
|
|
4160
|
+
yield evt;
|
|
4161
|
+
}
|
|
4162
|
+
}
|
|
4079
4163
|
/**
|
|
4080
4164
|
* Execute a gadget through the full hook lifecycle.
|
|
4081
4165
|
* This is the core execution logic, extracted from processGadgetCall.
|
|
4166
|
+
* @deprecated Use executeGadgetGenerator for real-time streaming
|
|
4082
4167
|
*/
|
|
4083
4168
|
async executeGadgetWithHooks(call) {
|
|
4084
4169
|
const events = [];
|
|
@@ -4231,6 +4316,159 @@ var init_stream_processor = __esm({
|
|
|
4231
4316
|
}
|
|
4232
4317
|
return events;
|
|
4233
4318
|
}
|
|
4319
|
+
/**
|
|
4320
|
+
* Execute a gadget and yield the result event.
|
|
4321
|
+
* Generator version that yields gadget_result immediately when execution completes.
|
|
4322
|
+
*/
|
|
4323
|
+
async *executeGadgetGenerator(call) {
|
|
4324
|
+
if (call.parseError) {
|
|
4325
|
+
this.logger.warn("Gadget has parse error", {
|
|
4326
|
+
gadgetName: call.gadgetName,
|
|
4327
|
+
error: call.parseError,
|
|
4328
|
+
rawParameters: call.parametersRaw
|
|
4329
|
+
});
|
|
4330
|
+
const shouldContinue = await this.checkCanRecoverFromError(
|
|
4331
|
+
call.parseError,
|
|
4332
|
+
call.gadgetName,
|
|
4333
|
+
"parse",
|
|
4334
|
+
call.parameters
|
|
4335
|
+
);
|
|
4336
|
+
if (!shouldContinue) {
|
|
4337
|
+
this.executionHalted = true;
|
|
4338
|
+
}
|
|
4339
|
+
}
|
|
4340
|
+
let parameters = call.parameters ?? {};
|
|
4341
|
+
if (this.hooks.interceptors?.interceptGadgetParameters) {
|
|
4342
|
+
const context = {
|
|
4343
|
+
iteration: this.iteration,
|
|
4344
|
+
gadgetName: call.gadgetName,
|
|
4345
|
+
invocationId: call.invocationId,
|
|
4346
|
+
logger: this.logger
|
|
4347
|
+
};
|
|
4348
|
+
parameters = this.hooks.interceptors.interceptGadgetParameters(parameters, context);
|
|
4349
|
+
}
|
|
4350
|
+
call.parameters = parameters;
|
|
4351
|
+
let shouldSkip = false;
|
|
4352
|
+
let syntheticResult;
|
|
4353
|
+
if (this.hooks.controllers?.beforeGadgetExecution) {
|
|
4354
|
+
const context = {
|
|
4355
|
+
iteration: this.iteration,
|
|
4356
|
+
gadgetName: call.gadgetName,
|
|
4357
|
+
invocationId: call.invocationId,
|
|
4358
|
+
parameters,
|
|
4359
|
+
logger: this.logger
|
|
4360
|
+
};
|
|
4361
|
+
const action = await this.hooks.controllers.beforeGadgetExecution(context);
|
|
4362
|
+
validateBeforeGadgetExecutionAction(action);
|
|
4363
|
+
if (action.action === "skip") {
|
|
4364
|
+
shouldSkip = true;
|
|
4365
|
+
syntheticResult = action.syntheticResult;
|
|
4366
|
+
this.logger.info("Controller skipped gadget execution", {
|
|
4367
|
+
gadgetName: call.gadgetName
|
|
4368
|
+
});
|
|
4369
|
+
}
|
|
4370
|
+
}
|
|
4371
|
+
const startObservers = [];
|
|
4372
|
+
if (this.hooks.observers?.onGadgetExecutionStart) {
|
|
4373
|
+
startObservers.push(async () => {
|
|
4374
|
+
const context = {
|
|
4375
|
+
iteration: this.iteration,
|
|
4376
|
+
gadgetName: call.gadgetName,
|
|
4377
|
+
invocationId: call.invocationId,
|
|
4378
|
+
parameters,
|
|
4379
|
+
logger: this.logger
|
|
4380
|
+
};
|
|
4381
|
+
await this.hooks.observers.onGadgetExecutionStart(context);
|
|
4382
|
+
});
|
|
4383
|
+
}
|
|
4384
|
+
await this.runObserversInParallel(startObservers);
|
|
4385
|
+
let result;
|
|
4386
|
+
if (shouldSkip) {
|
|
4387
|
+
result = {
|
|
4388
|
+
gadgetName: call.gadgetName,
|
|
4389
|
+
invocationId: call.invocationId,
|
|
4390
|
+
parameters,
|
|
4391
|
+
result: syntheticResult ?? "Execution skipped",
|
|
4392
|
+
executionTimeMs: 0
|
|
4393
|
+
};
|
|
4394
|
+
} else {
|
|
4395
|
+
result = await this.executor.execute(call);
|
|
4396
|
+
}
|
|
4397
|
+
const originalResult = result.result;
|
|
4398
|
+
if (result.result && this.hooks.interceptors?.interceptGadgetResult) {
|
|
4399
|
+
const context = {
|
|
4400
|
+
iteration: this.iteration,
|
|
4401
|
+
gadgetName: result.gadgetName,
|
|
4402
|
+
invocationId: result.invocationId,
|
|
4403
|
+
parameters,
|
|
4404
|
+
executionTimeMs: result.executionTimeMs,
|
|
4405
|
+
logger: this.logger
|
|
4406
|
+
};
|
|
4407
|
+
result.result = this.hooks.interceptors.interceptGadgetResult(result.result, context);
|
|
4408
|
+
}
|
|
4409
|
+
if (this.hooks.controllers?.afterGadgetExecution) {
|
|
4410
|
+
const context = {
|
|
4411
|
+
iteration: this.iteration,
|
|
4412
|
+
gadgetName: result.gadgetName,
|
|
4413
|
+
invocationId: result.invocationId,
|
|
4414
|
+
parameters,
|
|
4415
|
+
result: result.result,
|
|
4416
|
+
error: result.error,
|
|
4417
|
+
executionTimeMs: result.executionTimeMs,
|
|
4418
|
+
logger: this.logger
|
|
4419
|
+
};
|
|
4420
|
+
const action = await this.hooks.controllers.afterGadgetExecution(context);
|
|
4421
|
+
validateAfterGadgetExecutionAction(action);
|
|
4422
|
+
if (action.action === "recover" && result.error) {
|
|
4423
|
+
this.logger.info("Controller recovered from gadget error", {
|
|
4424
|
+
gadgetName: result.gadgetName,
|
|
4425
|
+
originalError: result.error
|
|
4426
|
+
});
|
|
4427
|
+
result = {
|
|
4428
|
+
...result,
|
|
4429
|
+
error: void 0,
|
|
4430
|
+
result: action.fallbackResult
|
|
4431
|
+
};
|
|
4432
|
+
}
|
|
4433
|
+
}
|
|
4434
|
+
const completeObservers = [];
|
|
4435
|
+
if (this.hooks.observers?.onGadgetExecutionComplete) {
|
|
4436
|
+
completeObservers.push(async () => {
|
|
4437
|
+
const context = {
|
|
4438
|
+
iteration: this.iteration,
|
|
4439
|
+
gadgetName: result.gadgetName,
|
|
4440
|
+
invocationId: result.invocationId,
|
|
4441
|
+
parameters,
|
|
4442
|
+
originalResult,
|
|
4443
|
+
finalResult: result.result,
|
|
4444
|
+
error: result.error,
|
|
4445
|
+
executionTimeMs: result.executionTimeMs,
|
|
4446
|
+
breaksLoop: result.breaksLoop,
|
|
4447
|
+
cost: result.cost,
|
|
4448
|
+
logger: this.logger
|
|
4449
|
+
};
|
|
4450
|
+
await this.hooks.observers.onGadgetExecutionComplete(context);
|
|
4451
|
+
});
|
|
4452
|
+
}
|
|
4453
|
+
await this.runObserversInParallel(completeObservers);
|
|
4454
|
+
this.completedResults.set(result.invocationId, result);
|
|
4455
|
+
if (result.error) {
|
|
4456
|
+
this.failedInvocations.add(result.invocationId);
|
|
4457
|
+
}
|
|
4458
|
+
yield { type: "gadget_result", result };
|
|
4459
|
+
if (result.error) {
|
|
4460
|
+
const errorType = this.determineErrorType(call, result);
|
|
4461
|
+
const shouldContinue = await this.checkCanRecoverFromError(
|
|
4462
|
+
result.error,
|
|
4463
|
+
result.gadgetName,
|
|
4464
|
+
errorType,
|
|
4465
|
+
result.parameters
|
|
4466
|
+
);
|
|
4467
|
+
if (!shouldContinue) {
|
|
4468
|
+
this.executionHalted = true;
|
|
4469
|
+
}
|
|
4470
|
+
}
|
|
4471
|
+
}
|
|
4234
4472
|
/**
|
|
4235
4473
|
* Handle a gadget that cannot execute because a dependency failed.
|
|
4236
4474
|
* Calls the onDependencySkipped controller to allow customization.
|
|
@@ -4387,6 +4625,99 @@ var init_stream_processor = __esm({
|
|
|
4387
4625
|
}
|
|
4388
4626
|
return events;
|
|
4389
4627
|
}
|
|
4628
|
+
/**
|
|
4629
|
+
* Process pending gadgets, yielding events in real-time.
|
|
4630
|
+
* Generator version that yields events as gadgets complete.
|
|
4631
|
+
*
|
|
4632
|
+
* Note: Gadgets are still executed in parallel for efficiency,
|
|
4633
|
+
* but results are yielded as they become available.
|
|
4634
|
+
*/
|
|
4635
|
+
async *processPendingGadgetsGenerator() {
|
|
4636
|
+
let progress = true;
|
|
4637
|
+
while (progress && this.gadgetsAwaitingDependencies.size > 0) {
|
|
4638
|
+
progress = false;
|
|
4639
|
+
const readyToExecute = [];
|
|
4640
|
+
const readyToSkip = [];
|
|
4641
|
+
for (const [_invocationId, call] of this.gadgetsAwaitingDependencies) {
|
|
4642
|
+
const failedDep = call.dependencies.find((dep) => this.failedInvocations.has(dep));
|
|
4643
|
+
if (failedDep) {
|
|
4644
|
+
readyToSkip.push({ call, failedDep });
|
|
4645
|
+
continue;
|
|
4646
|
+
}
|
|
4647
|
+
const allSatisfied = call.dependencies.every((dep) => this.completedResults.has(dep));
|
|
4648
|
+
if (allSatisfied) {
|
|
4649
|
+
readyToExecute.push(call);
|
|
4650
|
+
}
|
|
4651
|
+
}
|
|
4652
|
+
for (const { call, failedDep } of readyToSkip) {
|
|
4653
|
+
this.gadgetsAwaitingDependencies.delete(call.invocationId);
|
|
4654
|
+
const skipEvents = await this.handleFailedDependency(call, failedDep);
|
|
4655
|
+
for (const evt of skipEvents) {
|
|
4656
|
+
yield evt;
|
|
4657
|
+
}
|
|
4658
|
+
progress = true;
|
|
4659
|
+
}
|
|
4660
|
+
if (readyToExecute.length > 0) {
|
|
4661
|
+
this.logger.debug("Executing ready gadgets in parallel", {
|
|
4662
|
+
count: readyToExecute.length,
|
|
4663
|
+
invocationIds: readyToExecute.map((c) => c.invocationId)
|
|
4664
|
+
});
|
|
4665
|
+
for (const call of readyToExecute) {
|
|
4666
|
+
this.gadgetsAwaitingDependencies.delete(call.invocationId);
|
|
4667
|
+
}
|
|
4668
|
+
const eventSets = await Promise.all(
|
|
4669
|
+
readyToExecute.map(async (call) => {
|
|
4670
|
+
const events = [];
|
|
4671
|
+
for await (const evt of this.executeGadgetGenerator(call)) {
|
|
4672
|
+
events.push(evt);
|
|
4673
|
+
}
|
|
4674
|
+
return events;
|
|
4675
|
+
})
|
|
4676
|
+
);
|
|
4677
|
+
for (const events of eventSets) {
|
|
4678
|
+
for (const evt of events) {
|
|
4679
|
+
yield evt;
|
|
4680
|
+
}
|
|
4681
|
+
}
|
|
4682
|
+
progress = true;
|
|
4683
|
+
}
|
|
4684
|
+
}
|
|
4685
|
+
if (this.gadgetsAwaitingDependencies.size > 0) {
|
|
4686
|
+
const pendingIds = new Set(this.gadgetsAwaitingDependencies.keys());
|
|
4687
|
+
for (const [invocationId, call] of this.gadgetsAwaitingDependencies) {
|
|
4688
|
+
const missingDeps = call.dependencies.filter((dep) => !this.completedResults.has(dep));
|
|
4689
|
+
const circularDeps = missingDeps.filter((dep) => pendingIds.has(dep));
|
|
4690
|
+
const trulyMissingDeps = missingDeps.filter((dep) => !pendingIds.has(dep));
|
|
4691
|
+
let errorMessage;
|
|
4692
|
+
let logLevel = "warn";
|
|
4693
|
+
if (circularDeps.length > 0 && trulyMissingDeps.length > 0) {
|
|
4694
|
+
errorMessage = `Dependencies unresolvable: circular=[${circularDeps.join(", ")}], missing=[${trulyMissingDeps.join(", ")}]`;
|
|
4695
|
+
logLevel = "error";
|
|
4696
|
+
} else if (circularDeps.length > 0) {
|
|
4697
|
+
errorMessage = `Circular dependency detected: "${invocationId}" depends on "${circularDeps[0]}" which also depends on "${invocationId}" (directly or indirectly)`;
|
|
4698
|
+
} else {
|
|
4699
|
+
errorMessage = `Dependency "${missingDeps[0]}" was never executed - check that the invocation ID exists and is spelled correctly`;
|
|
4700
|
+
}
|
|
4701
|
+
this.logger[logLevel]("Gadget has unresolvable dependencies", {
|
|
4702
|
+
gadgetName: call.gadgetName,
|
|
4703
|
+
invocationId,
|
|
4704
|
+
circularDependencies: circularDeps,
|
|
4705
|
+
missingDependencies: trulyMissingDeps
|
|
4706
|
+
});
|
|
4707
|
+
this.failedInvocations.add(invocationId);
|
|
4708
|
+
const skipEvent = {
|
|
4709
|
+
type: "gadget_skipped",
|
|
4710
|
+
gadgetName: call.gadgetName,
|
|
4711
|
+
invocationId,
|
|
4712
|
+
parameters: call.parameters ?? {},
|
|
4713
|
+
failedDependency: missingDeps[0],
|
|
4714
|
+
failedDependencyError: errorMessage
|
|
4715
|
+
};
|
|
4716
|
+
yield skipEvent;
|
|
4717
|
+
}
|
|
4718
|
+
this.gadgetsAwaitingDependencies.clear();
|
|
4719
|
+
}
|
|
4720
|
+
}
|
|
4390
4721
|
/**
|
|
4391
4722
|
* Safely execute an observer, catching and logging any errors.
|
|
4392
4723
|
* Observers are non-critical, so errors are logged but don't crash the system.
|
|
@@ -4509,6 +4840,12 @@ var init_agent = __esm({
|
|
|
4509
4840
|
// Subagent configuration
|
|
4510
4841
|
agentContextConfig;
|
|
4511
4842
|
subagentConfig;
|
|
4843
|
+
// Subagent event callback for subagent gadgets
|
|
4844
|
+
userSubagentEventCallback;
|
|
4845
|
+
// Internal queue for yielding subagent events in run()
|
|
4846
|
+
pendingSubagentEvents = [];
|
|
4847
|
+
// Combined callback that queues events AND calls user callback
|
|
4848
|
+
onSubagentEvent;
|
|
4512
4849
|
/**
|
|
4513
4850
|
* Creates a new Agent instance.
|
|
4514
4851
|
* @internal This constructor is private. Use LLMist.createAgent() or AgentBuilder instead.
|
|
@@ -4586,6 +4923,71 @@ var init_agent = __esm({
|
|
|
4586
4923
|
temperature: this.temperature
|
|
4587
4924
|
};
|
|
4588
4925
|
this.subagentConfig = options.subagentConfig;
|
|
4926
|
+
this.userSubagentEventCallback = options.onSubagentEvent;
|
|
4927
|
+
this.onSubagentEvent = (event) => {
|
|
4928
|
+
this.pendingSubagentEvents.push(event);
|
|
4929
|
+
this.userSubagentEventCallback?.(event);
|
|
4930
|
+
const subagentContext = {
|
|
4931
|
+
parentGadgetInvocationId: event.gadgetInvocationId,
|
|
4932
|
+
depth: event.depth
|
|
4933
|
+
};
|
|
4934
|
+
if (event.type === "llm_call_start") {
|
|
4935
|
+
const info = event.event;
|
|
4936
|
+
void this.hooks?.observers?.onLLMCallStart?.({
|
|
4937
|
+
iteration: info.iteration,
|
|
4938
|
+
options: { model: info.model, messages: [] },
|
|
4939
|
+
logger: this.logger,
|
|
4940
|
+
subagentContext
|
|
4941
|
+
});
|
|
4942
|
+
} else if (event.type === "llm_call_end") {
|
|
4943
|
+
const info = event.event;
|
|
4944
|
+
void this.hooks?.observers?.onLLMCallComplete?.({
|
|
4945
|
+
iteration: info.iteration,
|
|
4946
|
+
options: { model: info.model, messages: [] },
|
|
4947
|
+
finishReason: info.finishReason ?? null,
|
|
4948
|
+
usage: info.outputTokens ? {
|
|
4949
|
+
inputTokens: info.inputTokens ?? 0,
|
|
4950
|
+
outputTokens: info.outputTokens,
|
|
4951
|
+
totalTokens: (info.inputTokens ?? 0) + info.outputTokens
|
|
4952
|
+
} : void 0,
|
|
4953
|
+
rawResponse: "",
|
|
4954
|
+
finalMessage: "",
|
|
4955
|
+
logger: this.logger,
|
|
4956
|
+
subagentContext
|
|
4957
|
+
});
|
|
4958
|
+
} else if (event.type === "gadget_call") {
|
|
4959
|
+
const gadgetEvent = event.event;
|
|
4960
|
+
void this.hooks?.observers?.onGadgetExecutionStart?.({
|
|
4961
|
+
iteration: 0,
|
|
4962
|
+
gadgetName: gadgetEvent.call.gadgetName,
|
|
4963
|
+
invocationId: gadgetEvent.call.invocationId,
|
|
4964
|
+
parameters: gadgetEvent.call.parameters ?? {},
|
|
4965
|
+
logger: this.logger,
|
|
4966
|
+
subagentContext
|
|
4967
|
+
});
|
|
4968
|
+
} else if (event.type === "gadget_result") {
|
|
4969
|
+
const resultEvent = event.event;
|
|
4970
|
+
void this.hooks?.observers?.onGadgetExecutionComplete?.({
|
|
4971
|
+
iteration: 0,
|
|
4972
|
+
gadgetName: resultEvent.result.gadgetName ?? "unknown",
|
|
4973
|
+
invocationId: resultEvent.result.invocationId,
|
|
4974
|
+
parameters: {},
|
|
4975
|
+
executionTimeMs: resultEvent.result.executionTimeMs ?? 0,
|
|
4976
|
+
logger: this.logger,
|
|
4977
|
+
subagentContext
|
|
4978
|
+
});
|
|
4979
|
+
}
|
|
4980
|
+
};
|
|
4981
|
+
}
|
|
4982
|
+
/**
|
|
4983
|
+
* Flush pending subagent events as StreamEvents.
|
|
4984
|
+
* Called from run() to yield queued subagent events from subagent gadgets.
|
|
4985
|
+
*/
|
|
4986
|
+
*flushPendingSubagentEvents() {
|
|
4987
|
+
while (this.pendingSubagentEvents.length > 0) {
|
|
4988
|
+
const event = this.pendingSubagentEvents.shift();
|
|
4989
|
+
yield { type: "subagent_event", subagentEvent: event };
|
|
4990
|
+
}
|
|
4589
4991
|
}
|
|
4590
4992
|
/**
|
|
4591
4993
|
* Get the gadget registry for this agent.
|
|
@@ -4816,12 +5218,31 @@ var init_agent = __esm({
|
|
|
4816
5218
|
client: this.client,
|
|
4817
5219
|
mediaStore: this.mediaStore,
|
|
4818
5220
|
agentConfig: this.agentContextConfig,
|
|
4819
|
-
subagentConfig: this.subagentConfig
|
|
5221
|
+
subagentConfig: this.subagentConfig,
|
|
5222
|
+
onSubagentEvent: this.onSubagentEvent
|
|
4820
5223
|
});
|
|
4821
|
-
|
|
4822
|
-
|
|
4823
|
-
|
|
5224
|
+
let streamMetadata = null;
|
|
5225
|
+
let gadgetCallCount = 0;
|
|
5226
|
+
const textOutputs = [];
|
|
5227
|
+
const gadgetResults = [];
|
|
5228
|
+
for await (const event of processor.process(stream2)) {
|
|
5229
|
+
if (event.type === "stream_complete") {
|
|
5230
|
+
streamMetadata = event;
|
|
5231
|
+
continue;
|
|
5232
|
+
}
|
|
5233
|
+
if (event.type === "text") {
|
|
5234
|
+
textOutputs.push(event.content);
|
|
5235
|
+
} else if (event.type === "gadget_result") {
|
|
5236
|
+
gadgetCallCount++;
|
|
5237
|
+
gadgetResults.push(event);
|
|
5238
|
+
}
|
|
5239
|
+
yield event;
|
|
5240
|
+
yield* this.flushPendingSubagentEvents();
|
|
4824
5241
|
}
|
|
5242
|
+
if (!streamMetadata) {
|
|
5243
|
+
throw new Error("Stream processing completed without metadata event");
|
|
5244
|
+
}
|
|
5245
|
+
const result = streamMetadata;
|
|
4825
5246
|
this.logger.info("LLM response completed", {
|
|
4826
5247
|
finishReason: result.finishReason,
|
|
4827
5248
|
usage: result.usage,
|
|
@@ -4846,9 +5267,6 @@ var init_agent = __esm({
|
|
|
4846
5267
|
});
|
|
4847
5268
|
let finalMessage = result.finalMessage;
|
|
4848
5269
|
if (this.hooks.controllers?.afterLLMCall) {
|
|
4849
|
-
const gadgetCallCount = result.outputs.filter(
|
|
4850
|
-
(output) => output.type === "gadget_result"
|
|
4851
|
-
).length;
|
|
4852
5270
|
const context = {
|
|
4853
5271
|
iteration: currentIteration,
|
|
4854
5272
|
maxIterations: this.maxIterations,
|
|
@@ -4878,9 +5296,7 @@ var init_agent = __esm({
|
|
|
4878
5296
|
}
|
|
4879
5297
|
if (result.didExecuteGadgets) {
|
|
4880
5298
|
if (this.textWithGadgetsHandler) {
|
|
4881
|
-
const textContent =
|
|
4882
|
-
(output) => output.type === "text"
|
|
4883
|
-
).map((output) => output.content).join("");
|
|
5299
|
+
const textContent = textOutputs.join("");
|
|
4884
5300
|
if (textContent.trim()) {
|
|
4885
5301
|
const { gadgetName, parameterMapping, resultMapping } = this.textWithGadgetsHandler;
|
|
4886
5302
|
this.conversation.addGadgetCallResult(
|
|
@@ -4890,7 +5306,7 @@ var init_agent = __esm({
|
|
|
4890
5306
|
);
|
|
4891
5307
|
}
|
|
4892
5308
|
}
|
|
4893
|
-
for (const output of
|
|
5309
|
+
for (const output of gadgetResults) {
|
|
4894
5310
|
if (output.type === "gadget_result") {
|
|
4895
5311
|
const gadgetResult = output.result;
|
|
4896
5312
|
this.conversation.addGadgetCallResult(
|
|
@@ -5127,6 +5543,8 @@ var init_builder = __esm({
|
|
|
5127
5543
|
signal;
|
|
5128
5544
|
trailingMessage;
|
|
5129
5545
|
subagentConfig;
|
|
5546
|
+
subagentEventCallback;
|
|
5547
|
+
parentContext;
|
|
5130
5548
|
constructor(client) {
|
|
5131
5549
|
this.client = client;
|
|
5132
5550
|
}
|
|
@@ -5623,6 +6041,74 @@ var init_builder = __esm({
|
|
|
5623
6041
|
this.subagentConfig = config;
|
|
5624
6042
|
return this;
|
|
5625
6043
|
}
|
|
6044
|
+
/**
|
|
6045
|
+
* Set the callback for subagent events.
|
|
6046
|
+
*
|
|
6047
|
+
* Subagent gadgets (like BrowseWeb) can use ExecutionContext.onSubagentEvent
|
|
6048
|
+
* to report their internal LLM calls and gadget executions in real-time.
|
|
6049
|
+
* This callback receives those events, enabling hierarchical progress display.
|
|
6050
|
+
*
|
|
6051
|
+
* @param callback - Function to handle subagent events
|
|
6052
|
+
* @returns This builder for chaining
|
|
6053
|
+
*
|
|
6054
|
+
* @example
|
|
6055
|
+
* ```typescript
|
|
6056
|
+
* .withSubagentEventCallback((event) => {
|
|
6057
|
+
* if (event.type === "llm_call_start") {
|
|
6058
|
+
* console.log(` Subagent LLM #${event.event.iteration} starting...`);
|
|
6059
|
+
* } else if (event.type === "gadget_call") {
|
|
6060
|
+
* console.log(` ⏵ ${event.event.call.gadgetName}...`);
|
|
6061
|
+
* }
|
|
6062
|
+
* })
|
|
6063
|
+
* ```
|
|
6064
|
+
*/
|
|
6065
|
+
withSubagentEventCallback(callback) {
|
|
6066
|
+
this.subagentEventCallback = callback;
|
|
6067
|
+
return this;
|
|
6068
|
+
}
|
|
6069
|
+
/**
|
|
6070
|
+
* Enable automatic subagent event forwarding to parent agent.
|
|
6071
|
+
*
|
|
6072
|
+
* When building a subagent inside a gadget, call this method to automatically
|
|
6073
|
+
* forward all LLM calls and gadget events to the parent agent. This enables
|
|
6074
|
+
* hierarchical progress display without any manual event handling.
|
|
6075
|
+
*
|
|
6076
|
+
* The method extracts `invocationId` and `onSubagentEvent` from the execution
|
|
6077
|
+
* context and sets up automatic forwarding via hooks and event wrapping.
|
|
6078
|
+
*
|
|
6079
|
+
* @param ctx - ExecutionContext passed to the gadget's execute() method
|
|
6080
|
+
* @param depth - Nesting depth (default: 1 for direct child)
|
|
6081
|
+
* @returns This builder for chaining
|
|
6082
|
+
*
|
|
6083
|
+
* @example
|
|
6084
|
+
* ```typescript
|
|
6085
|
+
* // In a subagent gadget like BrowseWeb - ONE LINE enables auto-forwarding:
|
|
6086
|
+
* execute: async (params, ctx) => {
|
|
6087
|
+
* const agent = new AgentBuilder(client)
|
|
6088
|
+
* .withModel(model)
|
|
6089
|
+
* .withGadgets(Navigate, Click, Screenshot)
|
|
6090
|
+
* .withParentContext(ctx) // <-- This is all you need!
|
|
6091
|
+
* .ask(params.task);
|
|
6092
|
+
*
|
|
6093
|
+
* for await (const event of agent.run()) {
|
|
6094
|
+
* // Events automatically forwarded - just process normally
|
|
6095
|
+
* if (event.type === "text") {
|
|
6096
|
+
* result = event.content;
|
|
6097
|
+
* }
|
|
6098
|
+
* }
|
|
6099
|
+
* }
|
|
6100
|
+
* ```
|
|
6101
|
+
*/
|
|
6102
|
+
withParentContext(ctx, depth = 1) {
|
|
6103
|
+
if (ctx.onSubagentEvent && ctx.invocationId) {
|
|
6104
|
+
this.parentContext = {
|
|
6105
|
+
invocationId: ctx.invocationId,
|
|
6106
|
+
onSubagentEvent: ctx.onSubagentEvent,
|
|
6107
|
+
depth
|
|
6108
|
+
};
|
|
6109
|
+
}
|
|
6110
|
+
return this;
|
|
6111
|
+
}
|
|
5626
6112
|
/**
|
|
5627
6113
|
* Add an ephemeral trailing message that appears at the end of each LLM request.
|
|
5628
6114
|
*
|
|
@@ -5690,14 +6176,92 @@ ${endPrefix}`
|
|
|
5690
6176
|
return this;
|
|
5691
6177
|
}
|
|
5692
6178
|
/**
|
|
5693
|
-
* Compose the final hooks, including
|
|
6179
|
+
* Compose the final hooks, including:
|
|
6180
|
+
* - Trailing message injection (if configured)
|
|
6181
|
+
* - Subagent event forwarding for LLM calls (if parentContext is set)
|
|
5694
6182
|
*/
|
|
5695
6183
|
composeHooks() {
|
|
6184
|
+
let hooks = this.hooks;
|
|
6185
|
+
if (this.parentContext) {
|
|
6186
|
+
const { invocationId, onSubagentEvent, depth } = this.parentContext;
|
|
6187
|
+
const existingOnLLMCallStart = hooks?.observers?.onLLMCallStart;
|
|
6188
|
+
const existingOnLLMCallComplete = hooks?.observers?.onLLMCallComplete;
|
|
6189
|
+
const existingOnGadgetExecutionStart = hooks?.observers?.onGadgetExecutionStart;
|
|
6190
|
+
const existingOnGadgetExecutionComplete = hooks?.observers?.onGadgetExecutionComplete;
|
|
6191
|
+
hooks = {
|
|
6192
|
+
...hooks,
|
|
6193
|
+
observers: {
|
|
6194
|
+
...hooks?.observers,
|
|
6195
|
+
onLLMCallStart: async (context) => {
|
|
6196
|
+
onSubagentEvent({
|
|
6197
|
+
type: "llm_call_start",
|
|
6198
|
+
gadgetInvocationId: invocationId,
|
|
6199
|
+
depth,
|
|
6200
|
+
event: {
|
|
6201
|
+
iteration: context.iteration,
|
|
6202
|
+
model: context.options.model
|
|
6203
|
+
}
|
|
6204
|
+
});
|
|
6205
|
+
if (existingOnLLMCallStart) {
|
|
6206
|
+
await existingOnLLMCallStart(context);
|
|
6207
|
+
}
|
|
6208
|
+
},
|
|
6209
|
+
onLLMCallComplete: async (context) => {
|
|
6210
|
+
onSubagentEvent({
|
|
6211
|
+
type: "llm_call_end",
|
|
6212
|
+
gadgetInvocationId: invocationId,
|
|
6213
|
+
depth,
|
|
6214
|
+
event: {
|
|
6215
|
+
iteration: context.iteration,
|
|
6216
|
+
model: context.options.model,
|
|
6217
|
+
outputTokens: context.usage?.outputTokens,
|
|
6218
|
+
finishReason: context.finishReason
|
|
6219
|
+
}
|
|
6220
|
+
});
|
|
6221
|
+
if (existingOnLLMCallComplete) {
|
|
6222
|
+
await existingOnLLMCallComplete(context);
|
|
6223
|
+
}
|
|
6224
|
+
},
|
|
6225
|
+
onGadgetExecutionStart: async (context) => {
|
|
6226
|
+
onSubagentEvent({
|
|
6227
|
+
type: "gadget_call",
|
|
6228
|
+
gadgetInvocationId: invocationId,
|
|
6229
|
+
depth,
|
|
6230
|
+
event: {
|
|
6231
|
+
call: {
|
|
6232
|
+
invocationId: context.invocationId,
|
|
6233
|
+
gadgetName: context.gadgetName,
|
|
6234
|
+
parameters: context.parameters
|
|
6235
|
+
}
|
|
6236
|
+
}
|
|
6237
|
+
});
|
|
6238
|
+
if (existingOnGadgetExecutionStart) {
|
|
6239
|
+
await existingOnGadgetExecutionStart(context);
|
|
6240
|
+
}
|
|
6241
|
+
},
|
|
6242
|
+
onGadgetExecutionComplete: async (context) => {
|
|
6243
|
+
onSubagentEvent({
|
|
6244
|
+
type: "gadget_result",
|
|
6245
|
+
gadgetInvocationId: invocationId,
|
|
6246
|
+
depth,
|
|
6247
|
+
event: {
|
|
6248
|
+
result: {
|
|
6249
|
+
invocationId: context.invocationId
|
|
6250
|
+
}
|
|
6251
|
+
}
|
|
6252
|
+
});
|
|
6253
|
+
if (existingOnGadgetExecutionComplete) {
|
|
6254
|
+
await existingOnGadgetExecutionComplete(context);
|
|
6255
|
+
}
|
|
6256
|
+
}
|
|
6257
|
+
}
|
|
6258
|
+
};
|
|
6259
|
+
}
|
|
5696
6260
|
if (!this.trailingMessage) {
|
|
5697
|
-
return
|
|
6261
|
+
return hooks;
|
|
5698
6262
|
}
|
|
5699
6263
|
const trailingMsg = this.trailingMessage;
|
|
5700
|
-
const existingBeforeLLMCall =
|
|
6264
|
+
const existingBeforeLLMCall = hooks?.controllers?.beforeLLMCall;
|
|
5701
6265
|
const trailingMessageController = async (ctx) => {
|
|
5702
6266
|
const result = existingBeforeLLMCall ? await existingBeforeLLMCall(ctx) : { action: "proceed" };
|
|
5703
6267
|
if (result.action === "skip") {
|
|
@@ -5712,9 +6276,9 @@ ${endPrefix}`
|
|
|
5712
6276
|
};
|
|
5713
6277
|
};
|
|
5714
6278
|
return {
|
|
5715
|
-
...
|
|
6279
|
+
...hooks,
|
|
5716
6280
|
controllers: {
|
|
5717
|
-
...
|
|
6281
|
+
...hooks?.controllers,
|
|
5718
6282
|
beforeLLMCall: trailingMessageController
|
|
5719
6283
|
}
|
|
5720
6284
|
};
|
|
@@ -5775,6 +6339,19 @@ ${endPrefix}`
|
|
|
5775
6339
|
this.client = new LLMistClass();
|
|
5776
6340
|
}
|
|
5777
6341
|
const registry = GadgetRegistry.from(this.gadgets);
|
|
6342
|
+
let onSubagentEvent = this.subagentEventCallback;
|
|
6343
|
+
if (this.parentContext) {
|
|
6344
|
+
const { invocationId, onSubagentEvent: parentCallback, depth } = this.parentContext;
|
|
6345
|
+
const existingCallback = this.subagentEventCallback;
|
|
6346
|
+
onSubagentEvent = (event) => {
|
|
6347
|
+
parentCallback({
|
|
6348
|
+
...event,
|
|
6349
|
+
gadgetInvocationId: invocationId,
|
|
6350
|
+
depth: event.depth + depth
|
|
6351
|
+
});
|
|
6352
|
+
existingCallback?.(event);
|
|
6353
|
+
};
|
|
6354
|
+
}
|
|
5778
6355
|
return {
|
|
5779
6356
|
client: this.client,
|
|
5780
6357
|
model: this.model ?? "openai:gpt-5-nano",
|
|
@@ -5800,7 +6377,8 @@ ${endPrefix}`
|
|
|
5800
6377
|
gadgetOutputLimitPercent: this.gadgetOutputLimitPercent,
|
|
5801
6378
|
compactionConfig: this.compactionConfig,
|
|
5802
6379
|
signal: this.signal,
|
|
5803
|
-
subagentConfig: this.subagentConfig
|
|
6380
|
+
subagentConfig: this.subagentConfig,
|
|
6381
|
+
onSubagentEvent
|
|
5804
6382
|
};
|
|
5805
6383
|
}
|
|
5806
6384
|
ask(userPrompt) {
|
|
@@ -5957,6 +6535,19 @@ ${endPrefix}`
|
|
|
5957
6535
|
this.client = new LLMistClass();
|
|
5958
6536
|
}
|
|
5959
6537
|
const registry = GadgetRegistry.from(this.gadgets);
|
|
6538
|
+
let onSubagentEvent = this.subagentEventCallback;
|
|
6539
|
+
if (this.parentContext) {
|
|
6540
|
+
const { invocationId, onSubagentEvent: parentCallback, depth } = this.parentContext;
|
|
6541
|
+
const existingCallback = this.subagentEventCallback;
|
|
6542
|
+
onSubagentEvent = (event) => {
|
|
6543
|
+
parentCallback({
|
|
6544
|
+
...event,
|
|
6545
|
+
gadgetInvocationId: invocationId,
|
|
6546
|
+
depth: event.depth + depth
|
|
6547
|
+
});
|
|
6548
|
+
existingCallback?.(event);
|
|
6549
|
+
};
|
|
6550
|
+
}
|
|
5960
6551
|
const options = {
|
|
5961
6552
|
client: this.client,
|
|
5962
6553
|
model: this.model ?? "openai:gpt-5-nano",
|
|
@@ -5982,7 +6573,8 @@ ${endPrefix}`
|
|
|
5982
6573
|
gadgetOutputLimitPercent: this.gadgetOutputLimitPercent,
|
|
5983
6574
|
compactionConfig: this.compactionConfig,
|
|
5984
6575
|
signal: this.signal,
|
|
5985
|
-
subagentConfig: this.subagentConfig
|
|
6576
|
+
subagentConfig: this.subagentConfig,
|
|
6577
|
+
onSubagentEvent
|
|
5986
6578
|
};
|
|
5987
6579
|
return new Agent(AGENT_INTERNAL_KEY, options);
|
|
5988
6580
|
}
|