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/cli.cjs
CHANGED
|
@@ -3496,7 +3496,7 @@ var init_executor = __esm({
|
|
|
3496
3496
|
init_exceptions();
|
|
3497
3497
|
init_parser();
|
|
3498
3498
|
GadgetExecutor = class {
|
|
3499
|
-
constructor(registry, requestHumanInput, logger, defaultGadgetTimeoutMs, errorFormatterOptions, client, mediaStore, agentConfig, subagentConfig) {
|
|
3499
|
+
constructor(registry, requestHumanInput, logger, defaultGadgetTimeoutMs, errorFormatterOptions, client, mediaStore, agentConfig, subagentConfig, onSubagentEvent) {
|
|
3500
3500
|
this.registry = registry;
|
|
3501
3501
|
this.requestHumanInput = requestHumanInput;
|
|
3502
3502
|
this.defaultGadgetTimeoutMs = defaultGadgetTimeoutMs;
|
|
@@ -3504,6 +3504,7 @@ var init_executor = __esm({
|
|
|
3504
3504
|
this.mediaStore = mediaStore;
|
|
3505
3505
|
this.agentConfig = agentConfig;
|
|
3506
3506
|
this.subagentConfig = subagentConfig;
|
|
3507
|
+
this.onSubagentEvent = onSubagentEvent;
|
|
3507
3508
|
this.logger = logger ?? createLogger({ name: "llmist:executor" });
|
|
3508
3509
|
this.errorFormatter = new GadgetExecutionErrorFormatter(errorFormatterOptions);
|
|
3509
3510
|
this.argPrefix = errorFormatterOptions?.argPrefix ?? GADGET_ARG_PREFIX;
|
|
@@ -3649,7 +3650,9 @@ var init_executor = __esm({
|
|
|
3649
3650
|
llmist: this.client ? new CostReportingLLMistWrapper(this.client, reportCost) : void 0,
|
|
3650
3651
|
signal: abortController.signal,
|
|
3651
3652
|
agentConfig: this.agentConfig,
|
|
3652
|
-
subagentConfig: this.subagentConfig
|
|
3653
|
+
subagentConfig: this.subagentConfig,
|
|
3654
|
+
invocationId: call.invocationId,
|
|
3655
|
+
onSubagentEvent: this.onSubagentEvent
|
|
3653
3656
|
};
|
|
3654
3657
|
let rawResult;
|
|
3655
3658
|
if (timeoutMs && timeoutMs > 0) {
|
|
@@ -3888,14 +3891,21 @@ var init_stream_processor = __esm({
|
|
|
3888
3891
|
options.client,
|
|
3889
3892
|
options.mediaStore,
|
|
3890
3893
|
options.agentConfig,
|
|
3891
|
-
options.subagentConfig
|
|
3894
|
+
options.subagentConfig,
|
|
3895
|
+
options.onSubagentEvent
|
|
3892
3896
|
);
|
|
3893
3897
|
}
|
|
3894
3898
|
/**
|
|
3895
|
-
* Process an LLM stream and
|
|
3899
|
+
* Process an LLM stream and yield events in real-time.
|
|
3900
|
+
*
|
|
3901
|
+
* This is an async generator that yields events immediately as they occur:
|
|
3902
|
+
* - Text events are yielded as text is streamed from the LLM
|
|
3903
|
+
* - gadget_call events are yielded immediately when a gadget call is parsed
|
|
3904
|
+
* - gadget_result events are yielded when gadget execution completes
|
|
3905
|
+
*
|
|
3906
|
+
* The final event is always a StreamCompletionEvent containing metadata.
|
|
3896
3907
|
*/
|
|
3897
|
-
async process(stream2) {
|
|
3898
|
-
const outputs = [];
|
|
3908
|
+
async *process(stream2) {
|
|
3899
3909
|
let finishReason = null;
|
|
3900
3910
|
let usage;
|
|
3901
3911
|
let didExecuteGadgets = false;
|
|
@@ -3941,14 +3951,13 @@ var init_stream_processor = __esm({
|
|
|
3941
3951
|
continue;
|
|
3942
3952
|
}
|
|
3943
3953
|
for (const event of this.parser.feed(processedChunk)) {
|
|
3944
|
-
const
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
shouldBreakLoop = true;
|
|
3954
|
+
for await (const processedEvent of this.processEventGenerator(event)) {
|
|
3955
|
+
yield processedEvent;
|
|
3956
|
+
if (processedEvent.type === "gadget_result") {
|
|
3957
|
+
didExecuteGadgets = true;
|
|
3958
|
+
if (processedEvent.result.breaksLoop) {
|
|
3959
|
+
shouldBreakLoop = true;
|
|
3960
|
+
}
|
|
3952
3961
|
}
|
|
3953
3962
|
}
|
|
3954
3963
|
}
|
|
@@ -3959,25 +3968,23 @@ var init_stream_processor = __esm({
|
|
|
3959
3968
|
}
|
|
3960
3969
|
if (!this.executionHalted) {
|
|
3961
3970
|
for (const event of this.parser.finalize()) {
|
|
3962
|
-
const
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
shouldBreakLoop = true;
|
|
3971
|
+
for await (const processedEvent of this.processEventGenerator(event)) {
|
|
3972
|
+
yield processedEvent;
|
|
3973
|
+
if (processedEvent.type === "gadget_result") {
|
|
3974
|
+
didExecuteGadgets = true;
|
|
3975
|
+
if (processedEvent.result.breaksLoop) {
|
|
3976
|
+
shouldBreakLoop = true;
|
|
3977
|
+
}
|
|
3970
3978
|
}
|
|
3971
3979
|
}
|
|
3972
3980
|
}
|
|
3973
|
-
const
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
shouldBreakLoop = true;
|
|
3981
|
+
for await (const evt of this.processPendingGadgetsGenerator()) {
|
|
3982
|
+
yield evt;
|
|
3983
|
+
if (evt.type === "gadget_result") {
|
|
3984
|
+
didExecuteGadgets = true;
|
|
3985
|
+
if (evt.result.breaksLoop) {
|
|
3986
|
+
shouldBreakLoop = true;
|
|
3987
|
+
}
|
|
3981
3988
|
}
|
|
3982
3989
|
}
|
|
3983
3990
|
}
|
|
@@ -3990,8 +3997,8 @@ var init_stream_processor = __esm({
|
|
|
3990
3997
|
};
|
|
3991
3998
|
finalMessage = this.hooks.interceptors.interceptAssistantMessage(finalMessage, context);
|
|
3992
3999
|
}
|
|
3993
|
-
|
|
3994
|
-
|
|
4000
|
+
const completionEvent = {
|
|
4001
|
+
type: "stream_complete",
|
|
3995
4002
|
shouldBreakLoop,
|
|
3996
4003
|
didExecuteGadgets,
|
|
3997
4004
|
finishReason,
|
|
@@ -3999,9 +4006,11 @@ var init_stream_processor = __esm({
|
|
|
3999
4006
|
rawResponse: this.responseText,
|
|
4000
4007
|
finalMessage
|
|
4001
4008
|
};
|
|
4009
|
+
yield completionEvent;
|
|
4002
4010
|
}
|
|
4003
4011
|
/**
|
|
4004
4012
|
* Process a single parsed event (text or gadget call).
|
|
4013
|
+
* @deprecated Use processEventGenerator for real-time streaming
|
|
4005
4014
|
*/
|
|
4006
4015
|
async processEvent(event) {
|
|
4007
4016
|
if (event.type === "text") {
|
|
@@ -4011,6 +4020,23 @@ var init_stream_processor = __esm({
|
|
|
4011
4020
|
}
|
|
4012
4021
|
return [event];
|
|
4013
4022
|
}
|
|
4023
|
+
/**
|
|
4024
|
+
* Process a single parsed event, yielding events in real-time.
|
|
4025
|
+
* Generator version of processEvent for streaming support.
|
|
4026
|
+
*/
|
|
4027
|
+
async *processEventGenerator(event) {
|
|
4028
|
+
if (event.type === "text") {
|
|
4029
|
+
for (const e of await this.processTextEvent(event)) {
|
|
4030
|
+
yield e;
|
|
4031
|
+
}
|
|
4032
|
+
} else if (event.type === "gadget_call") {
|
|
4033
|
+
for await (const e of this.processGadgetCallGenerator(event.call)) {
|
|
4034
|
+
yield e;
|
|
4035
|
+
}
|
|
4036
|
+
} else {
|
|
4037
|
+
yield event;
|
|
4038
|
+
}
|
|
4039
|
+
}
|
|
4014
4040
|
/**
|
|
4015
4041
|
* Process a text event through interceptors.
|
|
4016
4042
|
*/
|
|
@@ -4087,9 +4113,68 @@ var init_stream_processor = __esm({
|
|
|
4087
4113
|
events.push(...triggeredEvents);
|
|
4088
4114
|
return events;
|
|
4089
4115
|
}
|
|
4116
|
+
/**
|
|
4117
|
+
* Process a gadget call, yielding events in real-time.
|
|
4118
|
+
*
|
|
4119
|
+
* Key difference from processGadgetCall: yields gadget_call event IMMEDIATELY
|
|
4120
|
+
* when parsed (before execution), enabling real-time UI feedback.
|
|
4121
|
+
*/
|
|
4122
|
+
async *processGadgetCallGenerator(call) {
|
|
4123
|
+
if (this.executionHalted) {
|
|
4124
|
+
this.logger.debug("Skipping gadget execution due to previous error", {
|
|
4125
|
+
gadgetName: call.gadgetName
|
|
4126
|
+
});
|
|
4127
|
+
return;
|
|
4128
|
+
}
|
|
4129
|
+
yield { type: "gadget_call", call };
|
|
4130
|
+
if (call.dependencies.length > 0) {
|
|
4131
|
+
if (call.dependencies.includes(call.invocationId)) {
|
|
4132
|
+
this.logger.warn("Gadget has self-referential dependency (depends on itself)", {
|
|
4133
|
+
gadgetName: call.gadgetName,
|
|
4134
|
+
invocationId: call.invocationId
|
|
4135
|
+
});
|
|
4136
|
+
this.failedInvocations.add(call.invocationId);
|
|
4137
|
+
const skipEvent = {
|
|
4138
|
+
type: "gadget_skipped",
|
|
4139
|
+
gadgetName: call.gadgetName,
|
|
4140
|
+
invocationId: call.invocationId,
|
|
4141
|
+
parameters: call.parameters ?? {},
|
|
4142
|
+
failedDependency: call.invocationId,
|
|
4143
|
+
failedDependencyError: `Gadget "${call.invocationId}" cannot depend on itself (self-referential dependency)`
|
|
4144
|
+
};
|
|
4145
|
+
yield skipEvent;
|
|
4146
|
+
return;
|
|
4147
|
+
}
|
|
4148
|
+
const failedDep = call.dependencies.find((dep) => this.failedInvocations.has(dep));
|
|
4149
|
+
if (failedDep) {
|
|
4150
|
+
const skipEvents = await this.handleFailedDependency(call, failedDep);
|
|
4151
|
+
for (const evt of skipEvents) {
|
|
4152
|
+
yield evt;
|
|
4153
|
+
}
|
|
4154
|
+
return;
|
|
4155
|
+
}
|
|
4156
|
+
const unsatisfied = call.dependencies.filter((dep) => !this.completedResults.has(dep));
|
|
4157
|
+
if (unsatisfied.length > 0) {
|
|
4158
|
+
this.logger.debug("Queueing gadget for later - waiting on dependencies", {
|
|
4159
|
+
gadgetName: call.gadgetName,
|
|
4160
|
+
invocationId: call.invocationId,
|
|
4161
|
+
waitingOn: unsatisfied
|
|
4162
|
+
});
|
|
4163
|
+
this.gadgetsAwaitingDependencies.set(call.invocationId, call);
|
|
4164
|
+
return;
|
|
4165
|
+
}
|
|
4166
|
+
}
|
|
4167
|
+
for await (const evt of this.executeGadgetGenerator(call)) {
|
|
4168
|
+
yield evt;
|
|
4169
|
+
}
|
|
4170
|
+
for await (const evt of this.processPendingGadgetsGenerator()) {
|
|
4171
|
+
yield evt;
|
|
4172
|
+
}
|
|
4173
|
+
}
|
|
4090
4174
|
/**
|
|
4091
4175
|
* Execute a gadget through the full hook lifecycle.
|
|
4092
4176
|
* This is the core execution logic, extracted from processGadgetCall.
|
|
4177
|
+
* @deprecated Use executeGadgetGenerator for real-time streaming
|
|
4093
4178
|
*/
|
|
4094
4179
|
async executeGadgetWithHooks(call) {
|
|
4095
4180
|
const events = [];
|
|
@@ -4242,6 +4327,159 @@ var init_stream_processor = __esm({
|
|
|
4242
4327
|
}
|
|
4243
4328
|
return events;
|
|
4244
4329
|
}
|
|
4330
|
+
/**
|
|
4331
|
+
* Execute a gadget and yield the result event.
|
|
4332
|
+
* Generator version that yields gadget_result immediately when execution completes.
|
|
4333
|
+
*/
|
|
4334
|
+
async *executeGadgetGenerator(call) {
|
|
4335
|
+
if (call.parseError) {
|
|
4336
|
+
this.logger.warn("Gadget has parse error", {
|
|
4337
|
+
gadgetName: call.gadgetName,
|
|
4338
|
+
error: call.parseError,
|
|
4339
|
+
rawParameters: call.parametersRaw
|
|
4340
|
+
});
|
|
4341
|
+
const shouldContinue = await this.checkCanRecoverFromError(
|
|
4342
|
+
call.parseError,
|
|
4343
|
+
call.gadgetName,
|
|
4344
|
+
"parse",
|
|
4345
|
+
call.parameters
|
|
4346
|
+
);
|
|
4347
|
+
if (!shouldContinue) {
|
|
4348
|
+
this.executionHalted = true;
|
|
4349
|
+
}
|
|
4350
|
+
}
|
|
4351
|
+
let parameters = call.parameters ?? {};
|
|
4352
|
+
if (this.hooks.interceptors?.interceptGadgetParameters) {
|
|
4353
|
+
const context = {
|
|
4354
|
+
iteration: this.iteration,
|
|
4355
|
+
gadgetName: call.gadgetName,
|
|
4356
|
+
invocationId: call.invocationId,
|
|
4357
|
+
logger: this.logger
|
|
4358
|
+
};
|
|
4359
|
+
parameters = this.hooks.interceptors.interceptGadgetParameters(parameters, context);
|
|
4360
|
+
}
|
|
4361
|
+
call.parameters = parameters;
|
|
4362
|
+
let shouldSkip = false;
|
|
4363
|
+
let syntheticResult;
|
|
4364
|
+
if (this.hooks.controllers?.beforeGadgetExecution) {
|
|
4365
|
+
const context = {
|
|
4366
|
+
iteration: this.iteration,
|
|
4367
|
+
gadgetName: call.gadgetName,
|
|
4368
|
+
invocationId: call.invocationId,
|
|
4369
|
+
parameters,
|
|
4370
|
+
logger: this.logger
|
|
4371
|
+
};
|
|
4372
|
+
const action = await this.hooks.controllers.beforeGadgetExecution(context);
|
|
4373
|
+
validateBeforeGadgetExecutionAction(action);
|
|
4374
|
+
if (action.action === "skip") {
|
|
4375
|
+
shouldSkip = true;
|
|
4376
|
+
syntheticResult = action.syntheticResult;
|
|
4377
|
+
this.logger.info("Controller skipped gadget execution", {
|
|
4378
|
+
gadgetName: call.gadgetName
|
|
4379
|
+
});
|
|
4380
|
+
}
|
|
4381
|
+
}
|
|
4382
|
+
const startObservers = [];
|
|
4383
|
+
if (this.hooks.observers?.onGadgetExecutionStart) {
|
|
4384
|
+
startObservers.push(async () => {
|
|
4385
|
+
const context = {
|
|
4386
|
+
iteration: this.iteration,
|
|
4387
|
+
gadgetName: call.gadgetName,
|
|
4388
|
+
invocationId: call.invocationId,
|
|
4389
|
+
parameters,
|
|
4390
|
+
logger: this.logger
|
|
4391
|
+
};
|
|
4392
|
+
await this.hooks.observers.onGadgetExecutionStart(context);
|
|
4393
|
+
});
|
|
4394
|
+
}
|
|
4395
|
+
await this.runObserversInParallel(startObservers);
|
|
4396
|
+
let result;
|
|
4397
|
+
if (shouldSkip) {
|
|
4398
|
+
result = {
|
|
4399
|
+
gadgetName: call.gadgetName,
|
|
4400
|
+
invocationId: call.invocationId,
|
|
4401
|
+
parameters,
|
|
4402
|
+
result: syntheticResult ?? "Execution skipped",
|
|
4403
|
+
executionTimeMs: 0
|
|
4404
|
+
};
|
|
4405
|
+
} else {
|
|
4406
|
+
result = await this.executor.execute(call);
|
|
4407
|
+
}
|
|
4408
|
+
const originalResult = result.result;
|
|
4409
|
+
if (result.result && this.hooks.interceptors?.interceptGadgetResult) {
|
|
4410
|
+
const context = {
|
|
4411
|
+
iteration: this.iteration,
|
|
4412
|
+
gadgetName: result.gadgetName,
|
|
4413
|
+
invocationId: result.invocationId,
|
|
4414
|
+
parameters,
|
|
4415
|
+
executionTimeMs: result.executionTimeMs,
|
|
4416
|
+
logger: this.logger
|
|
4417
|
+
};
|
|
4418
|
+
result.result = this.hooks.interceptors.interceptGadgetResult(result.result, context);
|
|
4419
|
+
}
|
|
4420
|
+
if (this.hooks.controllers?.afterGadgetExecution) {
|
|
4421
|
+
const context = {
|
|
4422
|
+
iteration: this.iteration,
|
|
4423
|
+
gadgetName: result.gadgetName,
|
|
4424
|
+
invocationId: result.invocationId,
|
|
4425
|
+
parameters,
|
|
4426
|
+
result: result.result,
|
|
4427
|
+
error: result.error,
|
|
4428
|
+
executionTimeMs: result.executionTimeMs,
|
|
4429
|
+
logger: this.logger
|
|
4430
|
+
};
|
|
4431
|
+
const action = await this.hooks.controllers.afterGadgetExecution(context);
|
|
4432
|
+
validateAfterGadgetExecutionAction(action);
|
|
4433
|
+
if (action.action === "recover" && result.error) {
|
|
4434
|
+
this.logger.info("Controller recovered from gadget error", {
|
|
4435
|
+
gadgetName: result.gadgetName,
|
|
4436
|
+
originalError: result.error
|
|
4437
|
+
});
|
|
4438
|
+
result = {
|
|
4439
|
+
...result,
|
|
4440
|
+
error: void 0,
|
|
4441
|
+
result: action.fallbackResult
|
|
4442
|
+
};
|
|
4443
|
+
}
|
|
4444
|
+
}
|
|
4445
|
+
const completeObservers = [];
|
|
4446
|
+
if (this.hooks.observers?.onGadgetExecutionComplete) {
|
|
4447
|
+
completeObservers.push(async () => {
|
|
4448
|
+
const context = {
|
|
4449
|
+
iteration: this.iteration,
|
|
4450
|
+
gadgetName: result.gadgetName,
|
|
4451
|
+
invocationId: result.invocationId,
|
|
4452
|
+
parameters,
|
|
4453
|
+
originalResult,
|
|
4454
|
+
finalResult: result.result,
|
|
4455
|
+
error: result.error,
|
|
4456
|
+
executionTimeMs: result.executionTimeMs,
|
|
4457
|
+
breaksLoop: result.breaksLoop,
|
|
4458
|
+
cost: result.cost,
|
|
4459
|
+
logger: this.logger
|
|
4460
|
+
};
|
|
4461
|
+
await this.hooks.observers.onGadgetExecutionComplete(context);
|
|
4462
|
+
});
|
|
4463
|
+
}
|
|
4464
|
+
await this.runObserversInParallel(completeObservers);
|
|
4465
|
+
this.completedResults.set(result.invocationId, result);
|
|
4466
|
+
if (result.error) {
|
|
4467
|
+
this.failedInvocations.add(result.invocationId);
|
|
4468
|
+
}
|
|
4469
|
+
yield { type: "gadget_result", result };
|
|
4470
|
+
if (result.error) {
|
|
4471
|
+
const errorType = this.determineErrorType(call, result);
|
|
4472
|
+
const shouldContinue = await this.checkCanRecoverFromError(
|
|
4473
|
+
result.error,
|
|
4474
|
+
result.gadgetName,
|
|
4475
|
+
errorType,
|
|
4476
|
+
result.parameters
|
|
4477
|
+
);
|
|
4478
|
+
if (!shouldContinue) {
|
|
4479
|
+
this.executionHalted = true;
|
|
4480
|
+
}
|
|
4481
|
+
}
|
|
4482
|
+
}
|
|
4245
4483
|
/**
|
|
4246
4484
|
* Handle a gadget that cannot execute because a dependency failed.
|
|
4247
4485
|
* Calls the onDependencySkipped controller to allow customization.
|
|
@@ -4398,6 +4636,99 @@ var init_stream_processor = __esm({
|
|
|
4398
4636
|
}
|
|
4399
4637
|
return events;
|
|
4400
4638
|
}
|
|
4639
|
+
/**
|
|
4640
|
+
* Process pending gadgets, yielding events in real-time.
|
|
4641
|
+
* Generator version that yields events as gadgets complete.
|
|
4642
|
+
*
|
|
4643
|
+
* Note: Gadgets are still executed in parallel for efficiency,
|
|
4644
|
+
* but results are yielded as they become available.
|
|
4645
|
+
*/
|
|
4646
|
+
async *processPendingGadgetsGenerator() {
|
|
4647
|
+
let progress = true;
|
|
4648
|
+
while (progress && this.gadgetsAwaitingDependencies.size > 0) {
|
|
4649
|
+
progress = false;
|
|
4650
|
+
const readyToExecute = [];
|
|
4651
|
+
const readyToSkip = [];
|
|
4652
|
+
for (const [_invocationId, call] of this.gadgetsAwaitingDependencies) {
|
|
4653
|
+
const failedDep = call.dependencies.find((dep) => this.failedInvocations.has(dep));
|
|
4654
|
+
if (failedDep) {
|
|
4655
|
+
readyToSkip.push({ call, failedDep });
|
|
4656
|
+
continue;
|
|
4657
|
+
}
|
|
4658
|
+
const allSatisfied = call.dependencies.every((dep) => this.completedResults.has(dep));
|
|
4659
|
+
if (allSatisfied) {
|
|
4660
|
+
readyToExecute.push(call);
|
|
4661
|
+
}
|
|
4662
|
+
}
|
|
4663
|
+
for (const { call, failedDep } of readyToSkip) {
|
|
4664
|
+
this.gadgetsAwaitingDependencies.delete(call.invocationId);
|
|
4665
|
+
const skipEvents = await this.handleFailedDependency(call, failedDep);
|
|
4666
|
+
for (const evt of skipEvents) {
|
|
4667
|
+
yield evt;
|
|
4668
|
+
}
|
|
4669
|
+
progress = true;
|
|
4670
|
+
}
|
|
4671
|
+
if (readyToExecute.length > 0) {
|
|
4672
|
+
this.logger.debug("Executing ready gadgets in parallel", {
|
|
4673
|
+
count: readyToExecute.length,
|
|
4674
|
+
invocationIds: readyToExecute.map((c) => c.invocationId)
|
|
4675
|
+
});
|
|
4676
|
+
for (const call of readyToExecute) {
|
|
4677
|
+
this.gadgetsAwaitingDependencies.delete(call.invocationId);
|
|
4678
|
+
}
|
|
4679
|
+
const eventSets = await Promise.all(
|
|
4680
|
+
readyToExecute.map(async (call) => {
|
|
4681
|
+
const events = [];
|
|
4682
|
+
for await (const evt of this.executeGadgetGenerator(call)) {
|
|
4683
|
+
events.push(evt);
|
|
4684
|
+
}
|
|
4685
|
+
return events;
|
|
4686
|
+
})
|
|
4687
|
+
);
|
|
4688
|
+
for (const events of eventSets) {
|
|
4689
|
+
for (const evt of events) {
|
|
4690
|
+
yield evt;
|
|
4691
|
+
}
|
|
4692
|
+
}
|
|
4693
|
+
progress = true;
|
|
4694
|
+
}
|
|
4695
|
+
}
|
|
4696
|
+
if (this.gadgetsAwaitingDependencies.size > 0) {
|
|
4697
|
+
const pendingIds = new Set(this.gadgetsAwaitingDependencies.keys());
|
|
4698
|
+
for (const [invocationId, call] of this.gadgetsAwaitingDependencies) {
|
|
4699
|
+
const missingDeps = call.dependencies.filter((dep) => !this.completedResults.has(dep));
|
|
4700
|
+
const circularDeps = missingDeps.filter((dep) => pendingIds.has(dep));
|
|
4701
|
+
const trulyMissingDeps = missingDeps.filter((dep) => !pendingIds.has(dep));
|
|
4702
|
+
let errorMessage;
|
|
4703
|
+
let logLevel = "warn";
|
|
4704
|
+
if (circularDeps.length > 0 && trulyMissingDeps.length > 0) {
|
|
4705
|
+
errorMessage = `Dependencies unresolvable: circular=[${circularDeps.join(", ")}], missing=[${trulyMissingDeps.join(", ")}]`;
|
|
4706
|
+
logLevel = "error";
|
|
4707
|
+
} else if (circularDeps.length > 0) {
|
|
4708
|
+
errorMessage = `Circular dependency detected: "${invocationId}" depends on "${circularDeps[0]}" which also depends on "${invocationId}" (directly or indirectly)`;
|
|
4709
|
+
} else {
|
|
4710
|
+
errorMessage = `Dependency "${missingDeps[0]}" was never executed - check that the invocation ID exists and is spelled correctly`;
|
|
4711
|
+
}
|
|
4712
|
+
this.logger[logLevel]("Gadget has unresolvable dependencies", {
|
|
4713
|
+
gadgetName: call.gadgetName,
|
|
4714
|
+
invocationId,
|
|
4715
|
+
circularDependencies: circularDeps,
|
|
4716
|
+
missingDependencies: trulyMissingDeps
|
|
4717
|
+
});
|
|
4718
|
+
this.failedInvocations.add(invocationId);
|
|
4719
|
+
const skipEvent = {
|
|
4720
|
+
type: "gadget_skipped",
|
|
4721
|
+
gadgetName: call.gadgetName,
|
|
4722
|
+
invocationId,
|
|
4723
|
+
parameters: call.parameters ?? {},
|
|
4724
|
+
failedDependency: missingDeps[0],
|
|
4725
|
+
failedDependencyError: errorMessage
|
|
4726
|
+
};
|
|
4727
|
+
yield skipEvent;
|
|
4728
|
+
}
|
|
4729
|
+
this.gadgetsAwaitingDependencies.clear();
|
|
4730
|
+
}
|
|
4731
|
+
}
|
|
4401
4732
|
/**
|
|
4402
4733
|
* Safely execute an observer, catching and logging any errors.
|
|
4403
4734
|
* Observers are non-critical, so errors are logged but don't crash the system.
|
|
@@ -4520,6 +4851,12 @@ var init_agent = __esm({
|
|
|
4520
4851
|
// Subagent configuration
|
|
4521
4852
|
agentContextConfig;
|
|
4522
4853
|
subagentConfig;
|
|
4854
|
+
// Subagent event callback for subagent gadgets
|
|
4855
|
+
userSubagentEventCallback;
|
|
4856
|
+
// Internal queue for yielding subagent events in run()
|
|
4857
|
+
pendingSubagentEvents = [];
|
|
4858
|
+
// Combined callback that queues events AND calls user callback
|
|
4859
|
+
onSubagentEvent;
|
|
4523
4860
|
/**
|
|
4524
4861
|
* Creates a new Agent instance.
|
|
4525
4862
|
* @internal This constructor is private. Use LLMist.createAgent() or AgentBuilder instead.
|
|
@@ -4597,6 +4934,71 @@ var init_agent = __esm({
|
|
|
4597
4934
|
temperature: this.temperature
|
|
4598
4935
|
};
|
|
4599
4936
|
this.subagentConfig = options.subagentConfig;
|
|
4937
|
+
this.userSubagentEventCallback = options.onSubagentEvent;
|
|
4938
|
+
this.onSubagentEvent = (event) => {
|
|
4939
|
+
this.pendingSubagentEvents.push(event);
|
|
4940
|
+
this.userSubagentEventCallback?.(event);
|
|
4941
|
+
const subagentContext = {
|
|
4942
|
+
parentGadgetInvocationId: event.gadgetInvocationId,
|
|
4943
|
+
depth: event.depth
|
|
4944
|
+
};
|
|
4945
|
+
if (event.type === "llm_call_start") {
|
|
4946
|
+
const info = event.event;
|
|
4947
|
+
void this.hooks?.observers?.onLLMCallStart?.({
|
|
4948
|
+
iteration: info.iteration,
|
|
4949
|
+
options: { model: info.model, messages: [] },
|
|
4950
|
+
logger: this.logger,
|
|
4951
|
+
subagentContext
|
|
4952
|
+
});
|
|
4953
|
+
} else if (event.type === "llm_call_end") {
|
|
4954
|
+
const info = event.event;
|
|
4955
|
+
void this.hooks?.observers?.onLLMCallComplete?.({
|
|
4956
|
+
iteration: info.iteration,
|
|
4957
|
+
options: { model: info.model, messages: [] },
|
|
4958
|
+
finishReason: info.finishReason ?? null,
|
|
4959
|
+
usage: info.outputTokens ? {
|
|
4960
|
+
inputTokens: info.inputTokens ?? 0,
|
|
4961
|
+
outputTokens: info.outputTokens,
|
|
4962
|
+
totalTokens: (info.inputTokens ?? 0) + info.outputTokens
|
|
4963
|
+
} : void 0,
|
|
4964
|
+
rawResponse: "",
|
|
4965
|
+
finalMessage: "",
|
|
4966
|
+
logger: this.logger,
|
|
4967
|
+
subagentContext
|
|
4968
|
+
});
|
|
4969
|
+
} else if (event.type === "gadget_call") {
|
|
4970
|
+
const gadgetEvent = event.event;
|
|
4971
|
+
void this.hooks?.observers?.onGadgetExecutionStart?.({
|
|
4972
|
+
iteration: 0,
|
|
4973
|
+
gadgetName: gadgetEvent.call.gadgetName,
|
|
4974
|
+
invocationId: gadgetEvent.call.invocationId,
|
|
4975
|
+
parameters: gadgetEvent.call.parameters ?? {},
|
|
4976
|
+
logger: this.logger,
|
|
4977
|
+
subagentContext
|
|
4978
|
+
});
|
|
4979
|
+
} else if (event.type === "gadget_result") {
|
|
4980
|
+
const resultEvent = event.event;
|
|
4981
|
+
void this.hooks?.observers?.onGadgetExecutionComplete?.({
|
|
4982
|
+
iteration: 0,
|
|
4983
|
+
gadgetName: resultEvent.result.gadgetName ?? "unknown",
|
|
4984
|
+
invocationId: resultEvent.result.invocationId,
|
|
4985
|
+
parameters: {},
|
|
4986
|
+
executionTimeMs: resultEvent.result.executionTimeMs ?? 0,
|
|
4987
|
+
logger: this.logger,
|
|
4988
|
+
subagentContext
|
|
4989
|
+
});
|
|
4990
|
+
}
|
|
4991
|
+
};
|
|
4992
|
+
}
|
|
4993
|
+
/**
|
|
4994
|
+
* Flush pending subagent events as StreamEvents.
|
|
4995
|
+
* Called from run() to yield queued subagent events from subagent gadgets.
|
|
4996
|
+
*/
|
|
4997
|
+
*flushPendingSubagentEvents() {
|
|
4998
|
+
while (this.pendingSubagentEvents.length > 0) {
|
|
4999
|
+
const event = this.pendingSubagentEvents.shift();
|
|
5000
|
+
yield { type: "subagent_event", subagentEvent: event };
|
|
5001
|
+
}
|
|
4600
5002
|
}
|
|
4601
5003
|
/**
|
|
4602
5004
|
* Get the gadget registry for this agent.
|
|
@@ -4827,12 +5229,31 @@ var init_agent = __esm({
|
|
|
4827
5229
|
client: this.client,
|
|
4828
5230
|
mediaStore: this.mediaStore,
|
|
4829
5231
|
agentConfig: this.agentContextConfig,
|
|
4830
|
-
subagentConfig: this.subagentConfig
|
|
5232
|
+
subagentConfig: this.subagentConfig,
|
|
5233
|
+
onSubagentEvent: this.onSubagentEvent
|
|
4831
5234
|
});
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
5235
|
+
let streamMetadata = null;
|
|
5236
|
+
let gadgetCallCount = 0;
|
|
5237
|
+
const textOutputs = [];
|
|
5238
|
+
const gadgetResults = [];
|
|
5239
|
+
for await (const event of processor.process(stream2)) {
|
|
5240
|
+
if (event.type === "stream_complete") {
|
|
5241
|
+
streamMetadata = event;
|
|
5242
|
+
continue;
|
|
5243
|
+
}
|
|
5244
|
+
if (event.type === "text") {
|
|
5245
|
+
textOutputs.push(event.content);
|
|
5246
|
+
} else if (event.type === "gadget_result") {
|
|
5247
|
+
gadgetCallCount++;
|
|
5248
|
+
gadgetResults.push(event);
|
|
5249
|
+
}
|
|
5250
|
+
yield event;
|
|
5251
|
+
yield* this.flushPendingSubagentEvents();
|
|
5252
|
+
}
|
|
5253
|
+
if (!streamMetadata) {
|
|
5254
|
+
throw new Error("Stream processing completed without metadata event");
|
|
4835
5255
|
}
|
|
5256
|
+
const result = streamMetadata;
|
|
4836
5257
|
this.logger.info("LLM response completed", {
|
|
4837
5258
|
finishReason: result.finishReason,
|
|
4838
5259
|
usage: result.usage,
|
|
@@ -4857,9 +5278,6 @@ var init_agent = __esm({
|
|
|
4857
5278
|
});
|
|
4858
5279
|
let finalMessage = result.finalMessage;
|
|
4859
5280
|
if (this.hooks.controllers?.afterLLMCall) {
|
|
4860
|
-
const gadgetCallCount = result.outputs.filter(
|
|
4861
|
-
(output) => output.type === "gadget_result"
|
|
4862
|
-
).length;
|
|
4863
5281
|
const context = {
|
|
4864
5282
|
iteration: currentIteration,
|
|
4865
5283
|
maxIterations: this.maxIterations,
|
|
@@ -4889,9 +5307,7 @@ var init_agent = __esm({
|
|
|
4889
5307
|
}
|
|
4890
5308
|
if (result.didExecuteGadgets) {
|
|
4891
5309
|
if (this.textWithGadgetsHandler) {
|
|
4892
|
-
const textContent =
|
|
4893
|
-
(output) => output.type === "text"
|
|
4894
|
-
).map((output) => output.content).join("");
|
|
5310
|
+
const textContent = textOutputs.join("");
|
|
4895
5311
|
if (textContent.trim()) {
|
|
4896
5312
|
const { gadgetName, parameterMapping, resultMapping } = this.textWithGadgetsHandler;
|
|
4897
5313
|
this.conversation.addGadgetCallResult(
|
|
@@ -4901,7 +5317,7 @@ var init_agent = __esm({
|
|
|
4901
5317
|
);
|
|
4902
5318
|
}
|
|
4903
5319
|
}
|
|
4904
|
-
for (const output of
|
|
5320
|
+
for (const output of gadgetResults) {
|
|
4905
5321
|
if (output.type === "gadget_result") {
|
|
4906
5322
|
const gadgetResult = output.result;
|
|
4907
5323
|
this.conversation.addGadgetCallResult(
|
|
@@ -8409,6 +8825,8 @@ var init_builder = __esm({
|
|
|
8409
8825
|
signal;
|
|
8410
8826
|
trailingMessage;
|
|
8411
8827
|
subagentConfig;
|
|
8828
|
+
subagentEventCallback;
|
|
8829
|
+
parentContext;
|
|
8412
8830
|
constructor(client) {
|
|
8413
8831
|
this.client = client;
|
|
8414
8832
|
}
|
|
@@ -8905,6 +9323,74 @@ var init_builder = __esm({
|
|
|
8905
9323
|
this.subagentConfig = config;
|
|
8906
9324
|
return this;
|
|
8907
9325
|
}
|
|
9326
|
+
/**
|
|
9327
|
+
* Set the callback for subagent events.
|
|
9328
|
+
*
|
|
9329
|
+
* Subagent gadgets (like BrowseWeb) can use ExecutionContext.onSubagentEvent
|
|
9330
|
+
* to report their internal LLM calls and gadget executions in real-time.
|
|
9331
|
+
* This callback receives those events, enabling hierarchical progress display.
|
|
9332
|
+
*
|
|
9333
|
+
* @param callback - Function to handle subagent events
|
|
9334
|
+
* @returns This builder for chaining
|
|
9335
|
+
*
|
|
9336
|
+
* @example
|
|
9337
|
+
* ```typescript
|
|
9338
|
+
* .withSubagentEventCallback((event) => {
|
|
9339
|
+
* if (event.type === "llm_call_start") {
|
|
9340
|
+
* console.log(` Subagent LLM #${event.event.iteration} starting...`);
|
|
9341
|
+
* } else if (event.type === "gadget_call") {
|
|
9342
|
+
* console.log(` ⏵ ${event.event.call.gadgetName}...`);
|
|
9343
|
+
* }
|
|
9344
|
+
* })
|
|
9345
|
+
* ```
|
|
9346
|
+
*/
|
|
9347
|
+
withSubagentEventCallback(callback) {
|
|
9348
|
+
this.subagentEventCallback = callback;
|
|
9349
|
+
return this;
|
|
9350
|
+
}
|
|
9351
|
+
/**
|
|
9352
|
+
* Enable automatic subagent event forwarding to parent agent.
|
|
9353
|
+
*
|
|
9354
|
+
* When building a subagent inside a gadget, call this method to automatically
|
|
9355
|
+
* forward all LLM calls and gadget events to the parent agent. This enables
|
|
9356
|
+
* hierarchical progress display without any manual event handling.
|
|
9357
|
+
*
|
|
9358
|
+
* The method extracts `invocationId` and `onSubagentEvent` from the execution
|
|
9359
|
+
* context and sets up automatic forwarding via hooks and event wrapping.
|
|
9360
|
+
*
|
|
9361
|
+
* @param ctx - ExecutionContext passed to the gadget's execute() method
|
|
9362
|
+
* @param depth - Nesting depth (default: 1 for direct child)
|
|
9363
|
+
* @returns This builder for chaining
|
|
9364
|
+
*
|
|
9365
|
+
* @example
|
|
9366
|
+
* ```typescript
|
|
9367
|
+
* // In a subagent gadget like BrowseWeb - ONE LINE enables auto-forwarding:
|
|
9368
|
+
* execute: async (params, ctx) => {
|
|
9369
|
+
* const agent = new AgentBuilder(client)
|
|
9370
|
+
* .withModel(model)
|
|
9371
|
+
* .withGadgets(Navigate, Click, Screenshot)
|
|
9372
|
+
* .withParentContext(ctx) // <-- This is all you need!
|
|
9373
|
+
* .ask(params.task);
|
|
9374
|
+
*
|
|
9375
|
+
* for await (const event of agent.run()) {
|
|
9376
|
+
* // Events automatically forwarded - just process normally
|
|
9377
|
+
* if (event.type === "text") {
|
|
9378
|
+
* result = event.content;
|
|
9379
|
+
* }
|
|
9380
|
+
* }
|
|
9381
|
+
* }
|
|
9382
|
+
* ```
|
|
9383
|
+
*/
|
|
9384
|
+
withParentContext(ctx, depth = 1) {
|
|
9385
|
+
if (ctx.onSubagentEvent && ctx.invocationId) {
|
|
9386
|
+
this.parentContext = {
|
|
9387
|
+
invocationId: ctx.invocationId,
|
|
9388
|
+
onSubagentEvent: ctx.onSubagentEvent,
|
|
9389
|
+
depth
|
|
9390
|
+
};
|
|
9391
|
+
}
|
|
9392
|
+
return this;
|
|
9393
|
+
}
|
|
8908
9394
|
/**
|
|
8909
9395
|
* Add an ephemeral trailing message that appears at the end of each LLM request.
|
|
8910
9396
|
*
|
|
@@ -8972,14 +9458,92 @@ ${endPrefix}`
|
|
|
8972
9458
|
return this;
|
|
8973
9459
|
}
|
|
8974
9460
|
/**
|
|
8975
|
-
* Compose the final hooks, including
|
|
9461
|
+
* Compose the final hooks, including:
|
|
9462
|
+
* - Trailing message injection (if configured)
|
|
9463
|
+
* - Subagent event forwarding for LLM calls (if parentContext is set)
|
|
8976
9464
|
*/
|
|
8977
9465
|
composeHooks() {
|
|
9466
|
+
let hooks = this.hooks;
|
|
9467
|
+
if (this.parentContext) {
|
|
9468
|
+
const { invocationId, onSubagentEvent, depth } = this.parentContext;
|
|
9469
|
+
const existingOnLLMCallStart = hooks?.observers?.onLLMCallStart;
|
|
9470
|
+
const existingOnLLMCallComplete = hooks?.observers?.onLLMCallComplete;
|
|
9471
|
+
const existingOnGadgetExecutionStart = hooks?.observers?.onGadgetExecutionStart;
|
|
9472
|
+
const existingOnGadgetExecutionComplete = hooks?.observers?.onGadgetExecutionComplete;
|
|
9473
|
+
hooks = {
|
|
9474
|
+
...hooks,
|
|
9475
|
+
observers: {
|
|
9476
|
+
...hooks?.observers,
|
|
9477
|
+
onLLMCallStart: async (context) => {
|
|
9478
|
+
onSubagentEvent({
|
|
9479
|
+
type: "llm_call_start",
|
|
9480
|
+
gadgetInvocationId: invocationId,
|
|
9481
|
+
depth,
|
|
9482
|
+
event: {
|
|
9483
|
+
iteration: context.iteration,
|
|
9484
|
+
model: context.options.model
|
|
9485
|
+
}
|
|
9486
|
+
});
|
|
9487
|
+
if (existingOnLLMCallStart) {
|
|
9488
|
+
await existingOnLLMCallStart(context);
|
|
9489
|
+
}
|
|
9490
|
+
},
|
|
9491
|
+
onLLMCallComplete: async (context) => {
|
|
9492
|
+
onSubagentEvent({
|
|
9493
|
+
type: "llm_call_end",
|
|
9494
|
+
gadgetInvocationId: invocationId,
|
|
9495
|
+
depth,
|
|
9496
|
+
event: {
|
|
9497
|
+
iteration: context.iteration,
|
|
9498
|
+
model: context.options.model,
|
|
9499
|
+
outputTokens: context.usage?.outputTokens,
|
|
9500
|
+
finishReason: context.finishReason
|
|
9501
|
+
}
|
|
9502
|
+
});
|
|
9503
|
+
if (existingOnLLMCallComplete) {
|
|
9504
|
+
await existingOnLLMCallComplete(context);
|
|
9505
|
+
}
|
|
9506
|
+
},
|
|
9507
|
+
onGadgetExecutionStart: async (context) => {
|
|
9508
|
+
onSubagentEvent({
|
|
9509
|
+
type: "gadget_call",
|
|
9510
|
+
gadgetInvocationId: invocationId,
|
|
9511
|
+
depth,
|
|
9512
|
+
event: {
|
|
9513
|
+
call: {
|
|
9514
|
+
invocationId: context.invocationId,
|
|
9515
|
+
gadgetName: context.gadgetName,
|
|
9516
|
+
parameters: context.parameters
|
|
9517
|
+
}
|
|
9518
|
+
}
|
|
9519
|
+
});
|
|
9520
|
+
if (existingOnGadgetExecutionStart) {
|
|
9521
|
+
await existingOnGadgetExecutionStart(context);
|
|
9522
|
+
}
|
|
9523
|
+
},
|
|
9524
|
+
onGadgetExecutionComplete: async (context) => {
|
|
9525
|
+
onSubagentEvent({
|
|
9526
|
+
type: "gadget_result",
|
|
9527
|
+
gadgetInvocationId: invocationId,
|
|
9528
|
+
depth,
|
|
9529
|
+
event: {
|
|
9530
|
+
result: {
|
|
9531
|
+
invocationId: context.invocationId
|
|
9532
|
+
}
|
|
9533
|
+
}
|
|
9534
|
+
});
|
|
9535
|
+
if (existingOnGadgetExecutionComplete) {
|
|
9536
|
+
await existingOnGadgetExecutionComplete(context);
|
|
9537
|
+
}
|
|
9538
|
+
}
|
|
9539
|
+
}
|
|
9540
|
+
};
|
|
9541
|
+
}
|
|
8978
9542
|
if (!this.trailingMessage) {
|
|
8979
|
-
return
|
|
9543
|
+
return hooks;
|
|
8980
9544
|
}
|
|
8981
9545
|
const trailingMsg = this.trailingMessage;
|
|
8982
|
-
const existingBeforeLLMCall =
|
|
9546
|
+
const existingBeforeLLMCall = hooks?.controllers?.beforeLLMCall;
|
|
8983
9547
|
const trailingMessageController = async (ctx) => {
|
|
8984
9548
|
const result = existingBeforeLLMCall ? await existingBeforeLLMCall(ctx) : { action: "proceed" };
|
|
8985
9549
|
if (result.action === "skip") {
|
|
@@ -8994,9 +9558,9 @@ ${endPrefix}`
|
|
|
8994
9558
|
};
|
|
8995
9559
|
};
|
|
8996
9560
|
return {
|
|
8997
|
-
...
|
|
9561
|
+
...hooks,
|
|
8998
9562
|
controllers: {
|
|
8999
|
-
...
|
|
9563
|
+
...hooks?.controllers,
|
|
9000
9564
|
beforeLLMCall: trailingMessageController
|
|
9001
9565
|
}
|
|
9002
9566
|
};
|
|
@@ -9057,6 +9621,19 @@ ${endPrefix}`
|
|
|
9057
9621
|
this.client = new LLMistClass();
|
|
9058
9622
|
}
|
|
9059
9623
|
const registry = GadgetRegistry.from(this.gadgets);
|
|
9624
|
+
let onSubagentEvent = this.subagentEventCallback;
|
|
9625
|
+
if (this.parentContext) {
|
|
9626
|
+
const { invocationId, onSubagentEvent: parentCallback, depth } = this.parentContext;
|
|
9627
|
+
const existingCallback = this.subagentEventCallback;
|
|
9628
|
+
onSubagentEvent = (event) => {
|
|
9629
|
+
parentCallback({
|
|
9630
|
+
...event,
|
|
9631
|
+
gadgetInvocationId: invocationId,
|
|
9632
|
+
depth: event.depth + depth
|
|
9633
|
+
});
|
|
9634
|
+
existingCallback?.(event);
|
|
9635
|
+
};
|
|
9636
|
+
}
|
|
9060
9637
|
return {
|
|
9061
9638
|
client: this.client,
|
|
9062
9639
|
model: this.model ?? "openai:gpt-5-nano",
|
|
@@ -9082,7 +9659,8 @@ ${endPrefix}`
|
|
|
9082
9659
|
gadgetOutputLimitPercent: this.gadgetOutputLimitPercent,
|
|
9083
9660
|
compactionConfig: this.compactionConfig,
|
|
9084
9661
|
signal: this.signal,
|
|
9085
|
-
subagentConfig: this.subagentConfig
|
|
9662
|
+
subagentConfig: this.subagentConfig,
|
|
9663
|
+
onSubagentEvent
|
|
9086
9664
|
};
|
|
9087
9665
|
}
|
|
9088
9666
|
ask(userPrompt) {
|
|
@@ -9239,6 +9817,19 @@ ${endPrefix}`
|
|
|
9239
9817
|
this.client = new LLMistClass();
|
|
9240
9818
|
}
|
|
9241
9819
|
const registry = GadgetRegistry.from(this.gadgets);
|
|
9820
|
+
let onSubagentEvent = this.subagentEventCallback;
|
|
9821
|
+
if (this.parentContext) {
|
|
9822
|
+
const { invocationId, onSubagentEvent: parentCallback, depth } = this.parentContext;
|
|
9823
|
+
const existingCallback = this.subagentEventCallback;
|
|
9824
|
+
onSubagentEvent = (event) => {
|
|
9825
|
+
parentCallback({
|
|
9826
|
+
...event,
|
|
9827
|
+
gadgetInvocationId: invocationId,
|
|
9828
|
+
depth: event.depth + depth
|
|
9829
|
+
});
|
|
9830
|
+
existingCallback?.(event);
|
|
9831
|
+
};
|
|
9832
|
+
}
|
|
9242
9833
|
const options = {
|
|
9243
9834
|
client: this.client,
|
|
9244
9835
|
model: this.model ?? "openai:gpt-5-nano",
|
|
@@ -9264,7 +9855,8 @@ ${endPrefix}`
|
|
|
9264
9855
|
gadgetOutputLimitPercent: this.gadgetOutputLimitPercent,
|
|
9265
9856
|
compactionConfig: this.compactionConfig,
|
|
9266
9857
|
signal: this.signal,
|
|
9267
|
-
subagentConfig: this.subagentConfig
|
|
9858
|
+
subagentConfig: this.subagentConfig,
|
|
9859
|
+
onSubagentEvent
|
|
9268
9860
|
};
|
|
9269
9861
|
return new Agent(AGENT_INTERNAL_KEY, options);
|
|
9270
9862
|
}
|
|
@@ -9359,7 +9951,7 @@ var import_commander2 = require("commander");
|
|
|
9359
9951
|
// package.json
|
|
9360
9952
|
var package_default = {
|
|
9361
9953
|
name: "llmist",
|
|
9362
|
-
version: "3.
|
|
9954
|
+
version: "3.1.0",
|
|
9363
9955
|
description: "TypeScript LLM client with streaming tool execution. Tools fire mid-stream. Built-in function calling works with any model\u2014no structured outputs or native tool support required.",
|
|
9364
9956
|
type: "module",
|
|
9365
9957
|
main: "dist/index.cjs",
|
|
@@ -12370,20 +12962,53 @@ function renderOverallSummary(metadata) {
|
|
|
12370
12962
|
}
|
|
12371
12963
|
return parts.join(import_chalk3.default.dim(" | "));
|
|
12372
12964
|
}
|
|
12373
|
-
function
|
|
12965
|
+
function getRawValue(value) {
|
|
12966
|
+
if (typeof value === "string") {
|
|
12967
|
+
return value;
|
|
12968
|
+
}
|
|
12969
|
+
if (typeof value === "boolean" || typeof value === "number") {
|
|
12970
|
+
return String(value);
|
|
12971
|
+
}
|
|
12972
|
+
return JSON.stringify(value);
|
|
12973
|
+
}
|
|
12974
|
+
function truncateValue(str, maxLen) {
|
|
12975
|
+
if (maxLen <= 0) return "";
|
|
12976
|
+
if (str.length <= maxLen) return str;
|
|
12977
|
+
return `${str.slice(0, maxLen)}\u2026`;
|
|
12978
|
+
}
|
|
12979
|
+
function formatParametersInline(params, maxWidth) {
|
|
12374
12980
|
if (!params || Object.keys(params).length === 0) {
|
|
12375
12981
|
return "";
|
|
12376
12982
|
}
|
|
12377
|
-
|
|
12378
|
-
|
|
12379
|
-
|
|
12380
|
-
|
|
12381
|
-
|
|
12382
|
-
|
|
12983
|
+
const entries = Object.entries(params);
|
|
12984
|
+
const defaultLimit = 30;
|
|
12985
|
+
const rawValues = entries.map(([, value]) => getRawValue(value));
|
|
12986
|
+
const overhead = entries.reduce((sum, [key], i) => {
|
|
12987
|
+
return sum + key.length + 1 + (i > 0 ? 2 : 0);
|
|
12988
|
+
}, 0);
|
|
12989
|
+
let limits;
|
|
12990
|
+
if (maxWidth && maxWidth > overhead) {
|
|
12991
|
+
const availableForValues = maxWidth - overhead;
|
|
12992
|
+
const totalRawLength = rawValues.reduce((sum, v) => sum + v.length, 0);
|
|
12993
|
+
if (totalRawLength <= availableForValues) {
|
|
12994
|
+
limits = rawValues.map(() => Infinity);
|
|
12383
12995
|
} else {
|
|
12384
|
-
const
|
|
12385
|
-
|
|
12996
|
+
const minPerValue = 10;
|
|
12997
|
+
const minTotal = entries.length * minPerValue;
|
|
12998
|
+
if (availableForValues <= minTotal) {
|
|
12999
|
+
limits = rawValues.map(() => Math.max(1, Math.floor(availableForValues / entries.length)));
|
|
13000
|
+
} else {
|
|
13001
|
+
limits = rawValues.map((v) => {
|
|
13002
|
+
const proportion = v.length / totalRawLength;
|
|
13003
|
+
return Math.max(minPerValue, Math.floor(proportion * availableForValues));
|
|
13004
|
+
});
|
|
13005
|
+
}
|
|
12386
13006
|
}
|
|
13007
|
+
} else {
|
|
13008
|
+
limits = rawValues.map(() => defaultLimit);
|
|
13009
|
+
}
|
|
13010
|
+
return entries.map(([key, _], i) => {
|
|
13011
|
+
const formatted = truncateValue(rawValues[i], limits[i]);
|
|
12387
13012
|
return `${import_chalk3.default.dim(key)}${import_chalk3.default.dim("=")}${import_chalk3.default.cyan(formatted)}`;
|
|
12388
13013
|
}).join(import_chalk3.default.dim(", "));
|
|
12389
13014
|
}
|
|
@@ -12419,23 +13044,28 @@ function formatMediaLine(media) {
|
|
|
12419
13044
|
return `${import_chalk3.default.dim("[")}${icon} ${id} ${mimeType} ${size}${import_chalk3.default.dim("]")} ${import_chalk3.default.dim("\u2192")} ${path6}`;
|
|
12420
13045
|
}
|
|
12421
13046
|
function formatGadgetSummary2(result) {
|
|
13047
|
+
const terminalWidth = process.stdout.columns || 80;
|
|
12422
13048
|
const gadgetLabel = import_chalk3.default.magenta.bold(result.gadgetName);
|
|
12423
|
-
const
|
|
12424
|
-
const
|
|
12425
|
-
|
|
12426
|
-
if (result.error) {
|
|
12427
|
-
const errorMsg = result.error.length > 50 ? `${result.error.slice(0, 50)}\u2026` : result.error;
|
|
12428
|
-
return `${import_chalk3.default.red("\u2717")} ${gadgetLabel}${paramsLabel} ${import_chalk3.default.red("error:")} ${errorMsg} ${timeLabel}`;
|
|
12429
|
-
}
|
|
12430
|
-
let outputLabel;
|
|
13049
|
+
const timeStr = result.executionTimeMs >= 1e3 ? `${(result.executionTimeMs / 1e3).toFixed(1)}s` : `${Math.round(result.executionTimeMs)}ms`;
|
|
13050
|
+
const timeLabel = import_chalk3.default.dim(timeStr);
|
|
13051
|
+
let outputStr;
|
|
12431
13052
|
if (result.tokenCount !== void 0 && result.tokenCount > 0) {
|
|
12432
|
-
|
|
13053
|
+
outputStr = `${formatTokens(result.tokenCount)} tokens`;
|
|
12433
13054
|
} else if (result.result) {
|
|
12434
13055
|
const outputBytes = Buffer.byteLength(result.result, "utf-8");
|
|
12435
|
-
|
|
13056
|
+
outputStr = outputBytes > 0 ? formatBytes(outputBytes) : "no output";
|
|
12436
13057
|
} else {
|
|
12437
|
-
|
|
13058
|
+
outputStr = "no output";
|
|
12438
13059
|
}
|
|
13060
|
+
const fixedLength = 2 + result.gadgetName.length + 2 + 3 + outputStr.length + 1 + timeStr.length;
|
|
13061
|
+
const availableForParams = Math.max(40, terminalWidth - fixedLength - 2);
|
|
13062
|
+
const paramsStr = formatParametersInline(result.parameters, availableForParams);
|
|
13063
|
+
const paramsLabel = paramsStr ? `${import_chalk3.default.dim("(")}${paramsStr}${import_chalk3.default.dim(")")}` : "";
|
|
13064
|
+
if (result.error) {
|
|
13065
|
+
const errorMsg = result.error.length > 50 ? `${result.error.slice(0, 50)}\u2026` : result.error;
|
|
13066
|
+
return `${import_chalk3.default.red("\u2717")} ${gadgetLabel}${paramsLabel} ${import_chalk3.default.red("error:")} ${errorMsg} ${timeLabel}`;
|
|
13067
|
+
}
|
|
13068
|
+
const outputLabel = outputStr === "no output" ? import_chalk3.default.dim(outputStr) : import_chalk3.default.green(outputStr);
|
|
12439
13069
|
const icon = result.breaksLoop ? import_chalk3.default.yellow("\u23F9") : import_chalk3.default.green("\u2713");
|
|
12440
13070
|
let summaryLine = `${icon} ${gadgetLabel}${paramsLabel} ${import_chalk3.default.dim("\u2192")} ${outputLabel} ${timeLabel}`;
|
|
12441
13071
|
if (result.media && result.media.length > 0) {
|
|
@@ -12588,6 +13218,8 @@ var StreamProgress = class {
|
|
|
12588
13218
|
delayTimeout = null;
|
|
12589
13219
|
isRunning = false;
|
|
12590
13220
|
hasRendered = false;
|
|
13221
|
+
lastRenderLineCount = 0;
|
|
13222
|
+
// Track lines rendered for multi-line clearing
|
|
12591
13223
|
// Current call stats (streaming mode)
|
|
12592
13224
|
mode = "cumulative";
|
|
12593
13225
|
model = "";
|
|
@@ -12607,6 +13239,111 @@ var StreamProgress = class {
|
|
|
12607
13239
|
totalCost = 0;
|
|
12608
13240
|
iterations = 0;
|
|
12609
13241
|
currentIteration = 0;
|
|
13242
|
+
// In-flight gadget tracking for concurrent status display
|
|
13243
|
+
inFlightGadgets = /* @__PURE__ */ new Map();
|
|
13244
|
+
// Nested agent tracking for hierarchical subagent display
|
|
13245
|
+
nestedAgents = /* @__PURE__ */ new Map();
|
|
13246
|
+
// Nested gadget tracking for hierarchical subagent display
|
|
13247
|
+
nestedGadgets = /* @__PURE__ */ new Map();
|
|
13248
|
+
/**
|
|
13249
|
+
* Add a gadget to the in-flight tracking (called when gadget_call event received).
|
|
13250
|
+
* Triggers re-render to show the gadget in the status display.
|
|
13251
|
+
*/
|
|
13252
|
+
addGadget(invocationId, name, params) {
|
|
13253
|
+
this.inFlightGadgets.set(invocationId, { name, params, startTime: Date.now() });
|
|
13254
|
+
if (this.isRunning && this.isTTY) {
|
|
13255
|
+
this.render();
|
|
13256
|
+
}
|
|
13257
|
+
}
|
|
13258
|
+
/**
|
|
13259
|
+
* Remove a gadget from in-flight tracking (called when gadget_result event received).
|
|
13260
|
+
* Triggers re-render to update the status display.
|
|
13261
|
+
*/
|
|
13262
|
+
removeGadget(invocationId) {
|
|
13263
|
+
this.inFlightGadgets.delete(invocationId);
|
|
13264
|
+
if (this.isRunning && this.isTTY) {
|
|
13265
|
+
this.render();
|
|
13266
|
+
}
|
|
13267
|
+
}
|
|
13268
|
+
/**
|
|
13269
|
+
* Check if there are any gadgets currently in flight.
|
|
13270
|
+
*/
|
|
13271
|
+
hasInFlightGadgets() {
|
|
13272
|
+
return this.inFlightGadgets.size > 0;
|
|
13273
|
+
}
|
|
13274
|
+
/**
|
|
13275
|
+
* Add a nested agent LLM call (called when nested llm_call_start event received).
|
|
13276
|
+
* Used to display hierarchical progress for subagent gadgets.
|
|
13277
|
+
*/
|
|
13278
|
+
addNestedAgent(id, parentInvocationId, depth, model, iteration, inputTokens) {
|
|
13279
|
+
this.nestedAgents.set(id, {
|
|
13280
|
+
parentInvocationId,
|
|
13281
|
+
depth,
|
|
13282
|
+
model,
|
|
13283
|
+
iteration,
|
|
13284
|
+
startTime: Date.now(),
|
|
13285
|
+
inputTokens
|
|
13286
|
+
});
|
|
13287
|
+
if (this.isRunning && this.isTTY) {
|
|
13288
|
+
this.render();
|
|
13289
|
+
}
|
|
13290
|
+
}
|
|
13291
|
+
/**
|
|
13292
|
+
* Update a nested agent with completion info (called when nested llm_call_end event received).
|
|
13293
|
+
*/
|
|
13294
|
+
updateNestedAgent(id, outputTokens) {
|
|
13295
|
+
const agent = this.nestedAgents.get(id);
|
|
13296
|
+
if (agent) {
|
|
13297
|
+
agent.outputTokens = outputTokens;
|
|
13298
|
+
if (this.isRunning && this.isTTY) {
|
|
13299
|
+
this.render();
|
|
13300
|
+
}
|
|
13301
|
+
}
|
|
13302
|
+
}
|
|
13303
|
+
/**
|
|
13304
|
+
* Remove a nested agent (called when the nested LLM call completes).
|
|
13305
|
+
*/
|
|
13306
|
+
removeNestedAgent(id) {
|
|
13307
|
+
this.nestedAgents.delete(id);
|
|
13308
|
+
if (this.isRunning && this.isTTY) {
|
|
13309
|
+
this.render();
|
|
13310
|
+
}
|
|
13311
|
+
}
|
|
13312
|
+
/**
|
|
13313
|
+
* Add a nested gadget call (called when nested gadget_call event received).
|
|
13314
|
+
*/
|
|
13315
|
+
addNestedGadget(id, depth, parentInvocationId, name) {
|
|
13316
|
+
this.nestedGadgets.set(id, {
|
|
13317
|
+
depth,
|
|
13318
|
+
parentInvocationId,
|
|
13319
|
+
name,
|
|
13320
|
+
startTime: Date.now()
|
|
13321
|
+
});
|
|
13322
|
+
if (this.isRunning && this.isTTY) {
|
|
13323
|
+
this.render();
|
|
13324
|
+
}
|
|
13325
|
+
}
|
|
13326
|
+
/**
|
|
13327
|
+
* Remove a nested gadget (called when nested gadget_result event received).
|
|
13328
|
+
*/
|
|
13329
|
+
removeNestedGadget(id) {
|
|
13330
|
+
this.nestedGadgets.delete(id);
|
|
13331
|
+
if (this.isRunning && this.isTTY) {
|
|
13332
|
+
this.render();
|
|
13333
|
+
}
|
|
13334
|
+
}
|
|
13335
|
+
/**
|
|
13336
|
+
* Mark a nested gadget as completed (keeps it visible with ✓ indicator).
|
|
13337
|
+
*/
|
|
13338
|
+
completeNestedGadget(id) {
|
|
13339
|
+
const gadget = this.nestedGadgets.get(id);
|
|
13340
|
+
if (gadget) {
|
|
13341
|
+
gadget.completed = true;
|
|
13342
|
+
if (this.isRunning && this.isTTY) {
|
|
13343
|
+
this.render();
|
|
13344
|
+
}
|
|
13345
|
+
}
|
|
13346
|
+
}
|
|
12610
13347
|
/**
|
|
12611
13348
|
* Starts a new LLM call. Switches to streaming mode.
|
|
12612
13349
|
* @param model - Model name being used
|
|
@@ -12733,15 +13470,58 @@ var StreamProgress = class {
|
|
|
12733
13470
|
this.isStreaming = true;
|
|
12734
13471
|
}
|
|
12735
13472
|
render() {
|
|
13473
|
+
this.clearRenderedLines();
|
|
12736
13474
|
const spinner = SPINNER_FRAMES[this.frameIndex++ % SPINNER_FRAMES.length];
|
|
13475
|
+
const lines = [];
|
|
12737
13476
|
if (this.mode === "streaming") {
|
|
12738
|
-
this.
|
|
13477
|
+
lines.push(this.formatStreamingLine(spinner));
|
|
12739
13478
|
} else {
|
|
12740
|
-
this.
|
|
12741
|
-
}
|
|
13479
|
+
lines.push(this.formatCumulativeLine(spinner));
|
|
13480
|
+
}
|
|
13481
|
+
if (this.isTTY) {
|
|
13482
|
+
for (const [gadgetId, gadget] of this.inFlightGadgets) {
|
|
13483
|
+
const elapsed = ((Date.now() - gadget.startTime) / 1e3).toFixed(1);
|
|
13484
|
+
const gadgetLine = ` ${import_chalk4.default.blue("\u23F5")} ${import_chalk4.default.magenta.bold(gadget.name)}${import_chalk4.default.dim("(...)")} ${import_chalk4.default.dim(elapsed + "s")}`;
|
|
13485
|
+
lines.push(gadgetLine);
|
|
13486
|
+
for (const [_agentId, nested] of this.nestedAgents) {
|
|
13487
|
+
if (nested.parentInvocationId !== gadgetId) continue;
|
|
13488
|
+
const indent = " ".repeat(nested.depth + 1);
|
|
13489
|
+
const nestedElapsed = ((Date.now() - nested.startTime) / 1e3).toFixed(1);
|
|
13490
|
+
const tokens = nested.inputTokens ? ` ${import_chalk4.default.dim("\u2191")}${import_chalk4.default.yellow(formatTokens(nested.inputTokens))}` : "";
|
|
13491
|
+
const outTokens = nested.outputTokens ? ` ${import_chalk4.default.dim("\u2193")}${import_chalk4.default.green(formatTokens(nested.outputTokens))}` : "";
|
|
13492
|
+
const nestedLine = `${indent}${import_chalk4.default.cyan(`#${nested.iteration}`)} ${import_chalk4.default.dim(nested.model)}${tokens}${outTokens} ${import_chalk4.default.dim(nestedElapsed + "s")} ${import_chalk4.default.cyan(spinner)}`;
|
|
13493
|
+
lines.push(nestedLine);
|
|
13494
|
+
}
|
|
13495
|
+
for (const [nestedId, nestedGadget] of this.nestedGadgets) {
|
|
13496
|
+
if (nestedGadget.parentInvocationId === gadgetId) {
|
|
13497
|
+
const indent = " ".repeat(nestedGadget.depth + 1);
|
|
13498
|
+
const nestedElapsed = ((Date.now() - nestedGadget.startTime) / 1e3).toFixed(1);
|
|
13499
|
+
const icon = nestedGadget.completed ? import_chalk4.default.green("\u2713") : import_chalk4.default.blue("\u23F5");
|
|
13500
|
+
const nestedGadgetLine = `${indent}${icon} ${import_chalk4.default.dim(nestedGadget.name + "(...)")} ${import_chalk4.default.dim(nestedElapsed + "s")}`;
|
|
13501
|
+
lines.push(nestedGadgetLine);
|
|
13502
|
+
}
|
|
13503
|
+
}
|
|
13504
|
+
}
|
|
13505
|
+
}
|
|
13506
|
+
this.lastRenderLineCount = lines.length;
|
|
13507
|
+
this.target.write("\r" + lines.join("\n"));
|
|
12742
13508
|
this.hasRendered = true;
|
|
12743
13509
|
}
|
|
12744
|
-
|
|
13510
|
+
/**
|
|
13511
|
+
* Clears the previously rendered lines (for multi-line status display).
|
|
13512
|
+
*/
|
|
13513
|
+
clearRenderedLines() {
|
|
13514
|
+
if (!this.hasRendered || this.lastRenderLineCount === 0) return;
|
|
13515
|
+
this.target.write("\r\x1B[K");
|
|
13516
|
+
for (let i = 1; i < this.lastRenderLineCount; i++) {
|
|
13517
|
+
this.target.write("\x1B[1A\x1B[K");
|
|
13518
|
+
}
|
|
13519
|
+
this.target.write("\r");
|
|
13520
|
+
}
|
|
13521
|
+
/**
|
|
13522
|
+
* Format the streaming mode progress line (returns string, doesn't write).
|
|
13523
|
+
*/
|
|
13524
|
+
formatStreamingLine(spinner) {
|
|
12745
13525
|
const elapsed = ((Date.now() - this.callStartTime) / 1e3).toFixed(1);
|
|
12746
13526
|
const outTokens = this.callOutputTokensEstimated ? Math.round(this.callOutputChars / FALLBACK_CHARS_PER_TOKEN) : this.callOutputTokens;
|
|
12747
13527
|
const parts = [];
|
|
@@ -12775,7 +13555,7 @@ var StreamProgress = class {
|
|
|
12775
13555
|
if (callCost > 0) {
|
|
12776
13556
|
parts.push(import_chalk4.default.cyan(`$${formatCost(callCost)}`));
|
|
12777
13557
|
}
|
|
12778
|
-
|
|
13558
|
+
return `${parts.join(import_chalk4.default.dim(" | "))} ${import_chalk4.default.cyan(spinner)}`;
|
|
12779
13559
|
}
|
|
12780
13560
|
/**
|
|
12781
13561
|
* Calculates live cost estimate for the current streaming call.
|
|
@@ -12812,7 +13592,10 @@ var StreamProgress = class {
|
|
|
12812
13592
|
}
|
|
12813
13593
|
return this.callInputTokens / limits.contextWindow * 100;
|
|
12814
13594
|
}
|
|
12815
|
-
|
|
13595
|
+
/**
|
|
13596
|
+
* Format the cumulative mode progress line (returns string, doesn't write).
|
|
13597
|
+
*/
|
|
13598
|
+
formatCumulativeLine(spinner) {
|
|
12816
13599
|
const elapsed = ((Date.now() - this.totalStartTime) / 1e3).toFixed(1);
|
|
12817
13600
|
const parts = [];
|
|
12818
13601
|
if (this.model) {
|
|
@@ -12828,10 +13611,10 @@ var StreamProgress = class {
|
|
|
12828
13611
|
parts.push(import_chalk4.default.dim("cost:") + import_chalk4.default.cyan(` $${formatCost(this.totalCost)}`));
|
|
12829
13612
|
}
|
|
12830
13613
|
parts.push(import_chalk4.default.dim(`${elapsed}s`));
|
|
12831
|
-
|
|
13614
|
+
return `${parts.join(import_chalk4.default.dim(" | "))} ${import_chalk4.default.cyan(spinner)}`;
|
|
12832
13615
|
}
|
|
12833
13616
|
/**
|
|
12834
|
-
* Pauses the progress indicator and clears
|
|
13617
|
+
* Pauses the progress indicator and clears all rendered lines.
|
|
12835
13618
|
* Can be resumed with start().
|
|
12836
13619
|
*/
|
|
12837
13620
|
pause() {
|
|
@@ -12845,10 +13628,9 @@ var StreamProgress = class {
|
|
|
12845
13628
|
this.interval = null;
|
|
12846
13629
|
}
|
|
12847
13630
|
this.isRunning = false;
|
|
12848
|
-
|
|
12849
|
-
|
|
12850
|
-
|
|
12851
|
-
}
|
|
13631
|
+
this.clearRenderedLines();
|
|
13632
|
+
this.hasRendered = false;
|
|
13633
|
+
this.lastRenderLineCount = 0;
|
|
12852
13634
|
}
|
|
12853
13635
|
/**
|
|
12854
13636
|
* Completes the progress indicator and clears the line.
|
|
@@ -13425,6 +14207,38 @@ Denied: ${result.reason ?? "by user"}`
|
|
|
13425
14207
|
"Maximize efficiency by batching independent operations in a single response."
|
|
13426
14208
|
].join(" ")
|
|
13427
14209
|
);
|
|
14210
|
+
if (!options.quiet) {
|
|
14211
|
+
builder.withSubagentEventCallback((subagentEvent) => {
|
|
14212
|
+
if (subagentEvent.type === "llm_call_start") {
|
|
14213
|
+
const info = subagentEvent.event;
|
|
14214
|
+
const subagentId = `${subagentEvent.gadgetInvocationId}:${info.iteration}`;
|
|
14215
|
+
progress.addNestedAgent(
|
|
14216
|
+
subagentId,
|
|
14217
|
+
subagentEvent.gadgetInvocationId,
|
|
14218
|
+
subagentEvent.depth,
|
|
14219
|
+
info.model,
|
|
14220
|
+
info.iteration,
|
|
14221
|
+
info.inputTokens
|
|
14222
|
+
);
|
|
14223
|
+
} else if (subagentEvent.type === "llm_call_end") {
|
|
14224
|
+
const info = subagentEvent.event;
|
|
14225
|
+
const subagentId = `${subagentEvent.gadgetInvocationId}:${info.iteration}`;
|
|
14226
|
+
progress.updateNestedAgent(subagentId, info.outputTokens);
|
|
14227
|
+
setTimeout(() => progress.removeNestedAgent(subagentId), 100);
|
|
14228
|
+
} else if (subagentEvent.type === "gadget_call") {
|
|
14229
|
+
const gadgetEvent = subagentEvent.event;
|
|
14230
|
+
progress.addNestedGadget(
|
|
14231
|
+
gadgetEvent.call.invocationId,
|
|
14232
|
+
subagentEvent.depth,
|
|
14233
|
+
subagentEvent.gadgetInvocationId,
|
|
14234
|
+
gadgetEvent.call.gadgetName
|
|
14235
|
+
);
|
|
14236
|
+
} else if (subagentEvent.type === "gadget_result") {
|
|
14237
|
+
const resultEvent = subagentEvent.event;
|
|
14238
|
+
progress.completeNestedGadget(resultEvent.result.invocationId);
|
|
14239
|
+
}
|
|
14240
|
+
});
|
|
14241
|
+
}
|
|
13428
14242
|
let agent;
|
|
13429
14243
|
if (options.image || options.audio) {
|
|
13430
14244
|
const parts = [text(prompt)];
|
|
@@ -13449,10 +14263,22 @@ Denied: ${result.reason ?? "by user"}`
|
|
|
13449
14263
|
try {
|
|
13450
14264
|
for await (const event of agent.run()) {
|
|
13451
14265
|
if (event.type === "text") {
|
|
13452
|
-
progress.pause();
|
|
13453
14266
|
textBuffer += event.content;
|
|
14267
|
+
} else if (event.type === "gadget_call") {
|
|
14268
|
+
flushTextBuffer();
|
|
14269
|
+
if (!options.quiet) {
|
|
14270
|
+
progress.addGadget(
|
|
14271
|
+
event.call.invocationId,
|
|
14272
|
+
event.call.gadgetName,
|
|
14273
|
+
event.call.parameters
|
|
14274
|
+
);
|
|
14275
|
+
progress.start();
|
|
14276
|
+
}
|
|
13454
14277
|
} else if (event.type === "gadget_result") {
|
|
13455
14278
|
flushTextBuffer();
|
|
14279
|
+
if (!options.quiet) {
|
|
14280
|
+
progress.removeGadget(event.result.invocationId);
|
|
14281
|
+
}
|
|
13456
14282
|
progress.pause();
|
|
13457
14283
|
if (options.quiet) {
|
|
13458
14284
|
if (event.result.gadgetName === "TellUser" && event.result.parameters?.message) {
|
|
@@ -13467,6 +14293,10 @@ Denied: ${result.reason ?? "by user"}`
|
|
|
13467
14293
|
`
|
|
13468
14294
|
);
|
|
13469
14295
|
}
|
|
14296
|
+
if (progress.hasInFlightGadgets()) {
|
|
14297
|
+
progress.start();
|
|
14298
|
+
}
|
|
14299
|
+
} else if (event.type === "subagent_event") {
|
|
13470
14300
|
}
|
|
13471
14301
|
}
|
|
13472
14302
|
} catch (error) {
|