@llblab/pi-telegram 0.55.0 → 0.56.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/AGENTS.md +3 -2
- package/BACKLOG.md +4 -1
- package/CHANGELOG.md +14 -0
- package/README.md +27 -18
- package/dist/lib/bindings.d.ts +8 -4
- package/dist/lib/bindings.js +41 -1
- package/dist/lib/bus-follower.d.ts +1 -0
- package/dist/lib/bus-follower.js +5 -1
- package/dist/lib/bus-leader.js +9 -1
- package/dist/lib/bus.d.ts +5 -0
- package/dist/lib/bus.js +17 -6
- package/dist/lib/extension.js +14 -2
- package/dist/lib/lifecycle.d.ts +2 -1
- package/dist/lib/lifecycle.js +28 -20
- package/dist/lib/menu-queue.d.ts +1 -0
- package/dist/lib/menu-queue.js +102 -99
- package/dist/lib/pi.d.ts +3 -2
- package/dist/lib/pi.js +3 -0
- package/dist/lib/polling.js +3 -1
- package/dist/lib/queue.d.ts +57 -5
- package/dist/lib/queue.js +313 -25
- package/dist/lib/routing.d.ts +1 -1
- package/dist/lib/routing.js +261 -29
- package/dist/lib/status.d.ts +1 -2
- package/dist/lib/status.js +6 -7
- package/dist/lib/turns.d.ts +4 -0
- package/dist/lib/turns.js +6 -0
- package/dist/lib/updates.d.ts +10 -6
- package/dist/lib/updates.js +20 -4
- package/dist/package.json +1 -1
- package/docs/README.md +1 -1
- package/docs/architecture.md +17 -14
- package/docs/callback-namespaces.md +4 -0
- package/docs/multi-instance-bus.md +4 -2
- package/docs/ui-style.md +14 -10
- package/lib/bindings.ts +52 -3
- package/lib/bus-follower.ts +5 -0
- package/lib/bus-leader.ts +9 -0
- package/lib/bus.ts +20 -3
- package/lib/extension.ts +14 -1
- package/lib/lifecycle.ts +34 -28
- package/lib/menu-queue.ts +116 -162
- package/lib/pi.ts +8 -0
- package/lib/polling.ts +3 -1
- package/lib/queue.ts +328 -33
- package/lib/routing.ts +299 -29
- package/lib/status.ts +7 -7
- package/lib/turns.ts +7 -0
- package/lib/updates.ts +24 -10
- package/package.json +1 -1
package/lib/bus-leader.ts
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
TELEGRAM_BUS_CAPABILITY_DIRECTORY_DISPLAY_FORMAT,
|
|
24
24
|
TELEGRAM_BUS_CAPABILITY_DURABLE_FOLLOWER_ADMISSION,
|
|
25
25
|
TELEGRAM_BUS_CAPABILITY_QUEUE_HANDOFF,
|
|
26
|
+
hasTelegramBusSteerQueueHandoffCapability,
|
|
26
27
|
TELEGRAM_BUS_CAPABILITY_SELECTED_MENU_DELIVERY,
|
|
27
28
|
TELEGRAM_BUS_CAPABILITY_SESSION_REPLACEMENT_INTENT,
|
|
28
29
|
TELEGRAM_BUS_CAPABILITY_THREAD_DISPLAY_MODE,
|
|
@@ -3273,6 +3274,10 @@ export function createTelegramBusLeaderEnvelopeHandler(
|
|
|
3273
3274
|
"Telegram queue handoff capability was not negotiated.",
|
|
3274
3275
|
);
|
|
3275
3276
|
}
|
|
3277
|
+
if (envelope.payload.queueLane === "steer" &&
|
|
3278
|
+
![deps.protocolIdentity, donor.protocol, recipient?.protocol].every(hasTelegramBusSteerQueueHandoffCapability)) {
|
|
3279
|
+
return rejectTelegramBusRequest(envelope.requestId, "Steer queue handoff capability was not negotiated.");
|
|
3280
|
+
}
|
|
3276
3281
|
if (
|
|
3277
3282
|
!recipient?.registrationGeneration ||
|
|
3278
3283
|
envelope.recipientRegistrationGeneration !==
|
|
@@ -4477,6 +4482,10 @@ export function createTelegramBusLeaderRuntime<TContext>(
|
|
|
4477
4482
|
"Telegram queue handoff capability was not negotiated.",
|
|
4478
4483
|
);
|
|
4479
4484
|
}
|
|
4485
|
+
if (input.payload.queueLane === "steer" &&
|
|
4486
|
+
![deps.protocolIdentity, recipient?.protocol].every(hasTelegramBusSteerQueueHandoffCapability)) {
|
|
4487
|
+
return rejectTelegramBusRequest(input.requestId, "Steer queue handoff capability was not negotiated.");
|
|
4488
|
+
}
|
|
4480
4489
|
if (
|
|
4481
4490
|
!recipient?.registrationGeneration ||
|
|
4482
4491
|
input.recipientRegistrationGeneration !== recipient.registrationGeneration
|
package/lib/bus.ts
CHANGED
|
@@ -142,6 +142,8 @@ export const TELEGRAM_BUS_CAPABILITY_DURABLE_FOLLOWER_ADMISSION =
|
|
|
142
142
|
"durable-follower-admission-v1" as const;
|
|
143
143
|
export const TELEGRAM_BUS_CAPABILITY_QUEUE_HANDOFF =
|
|
144
144
|
"queue-handoff-v1" as const;
|
|
145
|
+
/** Unspent Steer lane codec; independent from baseline receipt handoff support. */
|
|
146
|
+
export const TELEGRAM_BUS_CAPABILITY_QUEUE_STEER = "queue-steer-v1" as const;
|
|
145
147
|
export const TELEGRAM_BUS_CAPABILITY_INPUT_CUSTODY_REFERENCE =
|
|
146
148
|
"input-custody-reference-v1" as const;
|
|
147
149
|
export const TELEGRAM_BUS_CAPABILITY_WORKSPACE_THREAD_RENAME =
|
|
@@ -461,6 +463,11 @@ export function hasTelegramBusCapability(
|
|
|
461
463
|
return identity?.capabilities.includes(capability) ?? false;
|
|
462
464
|
}
|
|
463
465
|
|
|
466
|
+
export function hasTelegramBusSteerQueueHandoffCapability(identity: TelegramBusProtocolIdentity | undefined): boolean {
|
|
467
|
+
return hasTelegramBusCapability(identity, TELEGRAM_BUS_CAPABILITY_QUEUE_HANDOFF) &&
|
|
468
|
+
hasTelegramBusCapability(identity, TELEGRAM_BUS_CAPABILITY_QUEUE_STEER);
|
|
469
|
+
}
|
|
470
|
+
|
|
464
471
|
export function getTelegramInputCustodyPeerReadiness(
|
|
465
472
|
followers: readonly Pick<
|
|
466
473
|
TelegramBusFollowerView,
|
|
@@ -1926,6 +1933,8 @@ export function createTelegramBusForeignOwnedUpdateForwarder<
|
|
|
1926
1933
|
message: TMessage;
|
|
1927
1934
|
ownership: TelegramBusForwardOwnership;
|
|
1928
1935
|
ctx: TContext;
|
|
1936
|
+
/** Process-local source/recipient lifetime; never part of the wire envelope. */
|
|
1937
|
+
assertAuthority?: () => void;
|
|
1929
1938
|
}) => Promise<TelegramBusForeignUpdateSettlement>;
|
|
1930
1939
|
forwardEditedMessage: (input: {
|
|
1931
1940
|
message: TMessage;
|
|
@@ -2057,6 +2066,7 @@ export function createTelegramBusForeignOwnedUpdateForwarder<
|
|
|
2057
2066
|
const send = async (
|
|
2058
2067
|
envelope: TelegramBusDurableForwardEnvelope,
|
|
2059
2068
|
ownership: TelegramBusForwardOwnership,
|
|
2069
|
+
assertAuthority?: () => void,
|
|
2060
2070
|
): Promise<TelegramBusForeignUpdateSettlement> => {
|
|
2061
2071
|
if (
|
|
2062
2072
|
deps.validateForwardOwnership &&
|
|
@@ -2078,10 +2088,15 @@ export function createTelegramBusForeignOwnedUpdateForwarder<
|
|
|
2078
2088
|
socketPath,
|
|
2079
2089
|
envelope,
|
|
2080
2090
|
timeoutMs: deps.timeoutMs ?? TELEGRAM_BUS_FOLLOWER_CONTROL_TIMEOUT_MS,
|
|
2081
|
-
retry: getTelegramBusTransportRetryPolicy({
|
|
2091
|
+
retry: assertAuthority ? { attempts: 1, delayMs: 0 } : getTelegramBusTransportRetryPolicy({
|
|
2082
2092
|
endpoint: socketPath,
|
|
2083
2093
|
operation: "operation",
|
|
2084
2094
|
}),
|
|
2095
|
+
...(assertAuthority || deps.validateForwardOwnership ? { assertAuthority() {
|
|
2096
|
+
assertAuthority?.();
|
|
2097
|
+
if (deps.validateForwardOwnership && !deps.validateForwardOwnership(ownership))
|
|
2098
|
+
throw new Error("Telegram follower forwarding ownership changed.");
|
|
2099
|
+
} } : {}),
|
|
2085
2100
|
});
|
|
2086
2101
|
} catch (error) {
|
|
2087
2102
|
return reject({
|
|
@@ -2178,6 +2193,7 @@ export function createTelegramBusForeignOwnedUpdateForwarder<
|
|
|
2178
2193
|
base: ForwardBase,
|
|
2179
2194
|
sentAtMs: number,
|
|
2180
2195
|
) => TelegramBusDurableForwardEnvelope,
|
|
2196
|
+
assertAuthority?: () => void,
|
|
2181
2197
|
): Promise<TelegramBusForeignUpdateSettlement> => {
|
|
2182
2198
|
const prepared = prepare(kind, value, ownership);
|
|
2183
2199
|
if ("settlement" in prepared) return Promise.resolve(prepared.settlement);
|
|
@@ -2192,6 +2208,7 @@ export function createTelegramBusForeignOwnedUpdateForwarder<
|
|
|
2192
2208
|
? { kind: "leader.wakeInputCustody", ...base, sentAtMs: getNowMs() }
|
|
2193
2209
|
: build(base, getNowMs()),
|
|
2194
2210
|
ownership,
|
|
2211
|
+
assertAuthority,
|
|
2195
2212
|
);
|
|
2196
2213
|
};
|
|
2197
2214
|
return {
|
|
@@ -2214,7 +2231,7 @@ export function createTelegramBusForeignOwnedUpdateForwarder<
|
|
|
2214
2231
|
sentAtMs,
|
|
2215
2232
|
}),
|
|
2216
2233
|
),
|
|
2217
|
-
forwardMessage: ({ message, ownership }) =>
|
|
2234
|
+
forwardMessage: ({ message, ownership, assertAuthority }) =>
|
|
2218
2235
|
forward("leader.forwardMessage", message, ownership, (base, sentAtMs) => {
|
|
2219
2236
|
const forwardCommentBatchPosition =
|
|
2220
2237
|
deps.getForwardCommentBatchPosition?.(message);
|
|
@@ -2227,7 +2244,7 @@ export function createTelegramBusForeignOwnedUpdateForwarder<
|
|
|
2227
2244
|
: {}),
|
|
2228
2245
|
sentAtMs,
|
|
2229
2246
|
};
|
|
2230
|
-
}),
|
|
2247
|
+
}, assertAuthority),
|
|
2231
2248
|
forwardEditedMessage: ({ message, ownership }) =>
|
|
2232
2249
|
forward(
|
|
2233
2250
|
"leader.forwardEditedMessage",
|
package/lib/extension.ts
CHANGED
|
@@ -64,6 +64,7 @@ const telegramBusProtocolIdentity =
|
|
|
64
64
|
Bus.createTelegramCurrentBusProtocolIdentity([
|
|
65
65
|
Bus.TELEGRAM_BUS_CAPABILITY_DURABLE_FOLLOWER_ADMISSION,
|
|
66
66
|
Bus.TELEGRAM_BUS_CAPABILITY_QUEUE_HANDOFF,
|
|
67
|
+
Bus.TELEGRAM_BUS_CAPABILITY_QUEUE_STEER,
|
|
67
68
|
Bus.TELEGRAM_BUS_CAPABILITY_WORKSPACE_FOLLOWER_AUTO_CONNECT,
|
|
68
69
|
Bus.TELEGRAM_BUS_CAPABILITY_WORKSPACE_THREAD_RENAME,
|
|
69
70
|
Bus.TELEGRAM_BUS_CAPABILITY_THREAD_DISPLAY_MODE,
|
|
@@ -717,7 +718,6 @@ export default function (pi: Pi.ExtensionAPI) {
|
|
|
717
718
|
},
|
|
718
719
|
getQueuedItems: telegramQueueStore.getQueuedItems,
|
|
719
720
|
getQueuedItemCount: Queue.countExecutableTelegramQueueItems,
|
|
720
|
-
formatQueuedStatus: Queue.formatQueuedTelegramItemsStatus,
|
|
721
721
|
getRecentRuntimeEvents: runtimeEvents.getEvents,
|
|
722
722
|
getRuntimeLockState: lockRuntime.getStatusLabel,
|
|
723
723
|
...threadStatusProjectionRuntime,
|
|
@@ -1026,6 +1026,7 @@ export default function (pi: Pi.ExtensionAPI) {
|
|
|
1026
1026
|
requestNextDispatchAnnouncement,
|
|
1027
1027
|
cancelNextDispatchAnnouncement,
|
|
1028
1028
|
watchdog: queueDispatchWatchdogRuntime,
|
|
1029
|
+
onTurnEnd: onSteerTurnEnd,
|
|
1029
1030
|
} = Bindings.createTelegramQueueBindingRuntime({
|
|
1030
1031
|
store: telegramQueueStore,
|
|
1031
1032
|
queue,
|
|
@@ -1037,6 +1038,8 @@ export default function (pi: Pi.ExtensionAPI) {
|
|
|
1037
1038
|
promptDispatch: promptDispatchRuntime,
|
|
1038
1039
|
isIdle,
|
|
1039
1040
|
hasPendingMessages,
|
|
1041
|
+
isContextCurrent: telegramSessionContextStore.isCurrent,
|
|
1042
|
+
isContextAborted: Pi.isExtensionContextAbortRequested,
|
|
1040
1043
|
updateStatus,
|
|
1041
1044
|
sendTextReply,
|
|
1042
1045
|
sendUserMessage,
|
|
@@ -1123,6 +1126,7 @@ export default function (pi: Pi.ExtensionAPI) {
|
|
|
1123
1126
|
|
|
1124
1127
|
// --- Queue And Settings Menus ---
|
|
1125
1128
|
const queueMenuRuntime = MenuQueue.createTelegramQueueMenuRuntime({
|
|
1129
|
+
hasPendingDispatch: lifecycle.hasDispatchPending,
|
|
1126
1130
|
telegramQueueStore,
|
|
1127
1131
|
queueMutationRuntime,
|
|
1128
1132
|
sendInteractiveMessage,
|
|
@@ -2331,6 +2335,14 @@ export default function (pi: Pi.ExtensionAPI) {
|
|
|
2331
2335
|
});
|
|
2332
2336
|
queueHandoffReconciliationBinding.set(
|
|
2333
2337
|
Updates.createTelegramQueueHandoffReconciliationRuntimeAssembly({
|
|
2338
|
+
hasPendingDispatch: lifecycle.hasDispatchPending,
|
|
2339
|
+
canHandoffSteerWithRecipient(recipient) {
|
|
2340
|
+
const live = telegramBusFollowerRegistry.get(recipient.instanceId);
|
|
2341
|
+
return live?.registrationGeneration === recipient.registrationGeneration &&
|
|
2342
|
+
[telegramBusProtocolIdentity, live?.protocol,
|
|
2343
|
+
...(telegramBusFollowerRegistrationState.isRegistered() ? [telegramBusFollowerRegistrationState.getLeaderProtocol()] : [])]
|
|
2344
|
+
.every(Bus.hasTelegramBusSteerQueueHandoffCapability);
|
|
2345
|
+
},
|
|
2334
2346
|
ownsDirect: lockRuntime.owns,
|
|
2335
2347
|
isFollowerRegistered: telegramBusFollowerRegistrationState.isRegistered,
|
|
2336
2348
|
isBusEnabled: isTelegramBusRuntimeEnabled,
|
|
@@ -3046,6 +3058,7 @@ export default function (pi: Pi.ExtensionAPI) {
|
|
|
3046
3058
|
sendMarkdownReply,
|
|
3047
3059
|
sendTextReply,
|
|
3048
3060
|
dispatchNextQueuedTelegramTurn,
|
|
3061
|
+
onSteerTurnEnd,
|
|
3049
3062
|
onPromptHandedOff(turn, ctx) {
|
|
3050
3063
|
updateAdmissionRuntimeBinding
|
|
3051
3064
|
.getSettlement()
|
package/lib/lifecycle.ts
CHANGED
|
@@ -26,6 +26,8 @@ import type {
|
|
|
26
26
|
ToolExecutionEndEvent,
|
|
27
27
|
ToolExecutionStartEvent,
|
|
28
28
|
ToolExecutionUpdateEvent,
|
|
29
|
+
TurnEndEvent,
|
|
30
|
+
TurnEndEventResult,
|
|
29
31
|
UIPromptEndEvent,
|
|
30
32
|
UIPromptStartEvent,
|
|
31
33
|
} from "./pi.ts";
|
|
@@ -100,6 +102,7 @@ export interface TelegramLifecycleRegistrationDeps {
|
|
|
100
102
|
event: { model: TelegramLifecycleModel },
|
|
101
103
|
ctx: ExtensionContext,
|
|
102
104
|
) => Promise<void> | void;
|
|
105
|
+
onTurnEnd?: (event: TurnEndEvent, ctx: ExtensionContext) => TurnEndEventResult | undefined;
|
|
103
106
|
onAgentStart: (
|
|
104
107
|
event: AgentStartEvent,
|
|
105
108
|
ctx: ExtensionContext,
|
|
@@ -575,7 +578,6 @@ export function createTelegramBridgeSessionLifecycleAssembly<
|
|
|
575
578
|
>(
|
|
576
579
|
deps: TelegramBridgeSessionLifecycleAssemblyDeps<TQueueItem, TModel>,
|
|
577
580
|
): TelegramSessionLifecycleHooks {
|
|
578
|
-
const isSessionActive = deps.contextStore.isCurrent;
|
|
579
581
|
const suspendForReplacement =
|
|
580
582
|
BusFollower.createTelegramBusFollowerSessionReplacementSuspender({
|
|
581
583
|
registrationState: deps.follower.registrationState,
|
|
@@ -583,32 +585,44 @@ export function createTelegramBridgeSessionLifecycleAssembly<
|
|
|
583
585
|
suspendPolling: deps.follower.suspendPolling,
|
|
584
586
|
recordRuntimeEvent: deps.follower.recordRuntimeEvent,
|
|
585
587
|
});
|
|
586
|
-
|
|
587
|
-
const queueLifecycle =
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
588
|
+
// A reused context can be current for a successor; inner awaits need this invocation's generation too.
|
|
589
|
+
const queueLifecycle = (ctx: ExtensionContext, generation: number, preserveTarget = true) =>
|
|
590
|
+
Queue.createTelegramSessionLifecycleRuntime({
|
|
591
|
+
...deps.queue,
|
|
592
|
+
isSessionActive: () => deps.contextStore.isCurrent(ctx, generation),
|
|
593
|
+
stopPolling: () => suspendForReplacement(preserveTarget),
|
|
594
|
+
clearPendingMediaGroups: deps.services.suspendGroupedInput,
|
|
595
|
+
});
|
|
593
596
|
const servicesLifecycle: TelegramSessionLifecycleHooks = {
|
|
594
597
|
async onSessionStart(event, ctx) {
|
|
598
|
+
const generation = deps.contextStore.getGeneration();
|
|
599
|
+
const isCurrent = () => deps.contextStore.isCurrent(ctx, generation);
|
|
595
600
|
const resumeConnection = deps.services.connection?.prepare(event, ctx);
|
|
596
|
-
await queueLifecycle.onSessionStart(event, ctx);
|
|
597
|
-
if (!
|
|
601
|
+
await queueLifecycle(ctx, generation).onSessionStart(event, ctx);
|
|
602
|
+
if (!isCurrent()) return;
|
|
598
603
|
deps.services.resumeGroupedInput(ctx);
|
|
599
604
|
await deps.services.delivery.onSessionStart();
|
|
600
|
-
if (!
|
|
605
|
+
if (!isCurrent()) return;
|
|
601
606
|
if (resumeConnection) resumeConnection();
|
|
602
607
|
else await deps.services.polling.onSessionStart(event, ctx);
|
|
608
|
+
if (!isCurrent()) return;
|
|
603
609
|
deps.services.capabilityMonitor.start(ctx);
|
|
604
610
|
deps.services.queueWatchdog.start(ctx);
|
|
611
|
+
await BusFollower.createTelegramBusFollowerSessionRefreshHook({
|
|
612
|
+
registrationState: deps.follower.registrationState,
|
|
613
|
+
registrationRuntime: deps.follower.registrationRuntime,
|
|
614
|
+
getLeaderState: deps.follower.getLeaderState,
|
|
615
|
+
isSessionActive: isCurrent,
|
|
616
|
+
updateStatus: deps.follower.updateStatus,
|
|
617
|
+
recordRuntimeEvent: deps.follower.recordRuntimeEvent,
|
|
618
|
+
})(event, ctx);
|
|
605
619
|
},
|
|
606
620
|
async onSessionShutdown(event, ctx) {
|
|
607
621
|
const generation = deps.contextStore.getGeneration();
|
|
608
622
|
const isCurrent = () => deps.contextStore.isCurrent(ctx, generation);
|
|
609
623
|
if (!isCurrent()) return;
|
|
610
624
|
deps.services.connection?.onSessionShutdown(event, ctx);
|
|
611
|
-
preserveTarget = event.reason !== "resume";
|
|
625
|
+
const preserveTarget = event.reason !== "resume";
|
|
612
626
|
let preserveThread: (() => Promise<void>) | undefined;
|
|
613
627
|
if (event.reason === "quit") {
|
|
614
628
|
try {
|
|
@@ -625,7 +639,7 @@ export function createTelegramBridgeSessionLifecycleAssembly<
|
|
|
625
639
|
if (!isCurrent()) return;
|
|
626
640
|
deps.services.queueWatchdog.stop();
|
|
627
641
|
deps.services.capabilityMonitor.stop();
|
|
628
|
-
await queueLifecycle.onSessionShutdown(event, ctx);
|
|
642
|
+
await queueLifecycle(ctx, generation, preserveTarget).onSessionShutdown(event, ctx);
|
|
629
643
|
if (!isCurrent()) return;
|
|
630
644
|
await deps.services.inboundWorker.onSessionShutdown();
|
|
631
645
|
if (!isCurrent()) return;
|
|
@@ -638,23 +652,9 @@ export function createTelegramBridgeSessionLifecycleAssembly<
|
|
|
638
652
|
}
|
|
639
653
|
},
|
|
640
654
|
};
|
|
641
|
-
const followerLifecycle = appendTelegramLifecycleHooks(
|
|
642
|
-
servicesLifecycle,
|
|
643
|
-
{
|
|
644
|
-
onSessionStart: BusFollower.createTelegramBusFollowerSessionRefreshHook({
|
|
645
|
-
registrationState: deps.follower.registrationState,
|
|
646
|
-
registrationRuntime: deps.follower.registrationRuntime,
|
|
647
|
-
getLeaderState: deps.follower.getLeaderState,
|
|
648
|
-
isSessionActive,
|
|
649
|
-
updateStatus: deps.follower.updateStatus,
|
|
650
|
-
recordRuntimeEvent: deps.follower.recordRuntimeEvent,
|
|
651
|
-
}),
|
|
652
|
-
},
|
|
653
|
-
isSessionActive,
|
|
654
|
-
);
|
|
655
655
|
return createTelegramSessionGenerationFence(
|
|
656
656
|
deps.contextStore,
|
|
657
|
-
|
|
657
|
+
servicesLifecycle,
|
|
658
658
|
);
|
|
659
659
|
}
|
|
660
660
|
|
|
@@ -1042,6 +1042,12 @@ export function registerTelegramLifecycleHooks(
|
|
|
1042
1042
|
if (!isActive(ctx)) return;
|
|
1043
1043
|
await deps.onAgentStart(event, ctx);
|
|
1044
1044
|
});
|
|
1045
|
+
if (deps.onTurnEnd) {
|
|
1046
|
+
pi.on("turn_end", (event, ctx) => {
|
|
1047
|
+
if (!isActive(ctx)) return;
|
|
1048
|
+
return deps.onTurnEnd?.(event, ctx);
|
|
1049
|
+
});
|
|
1050
|
+
}
|
|
1045
1051
|
pi.on("tool_execution_start", async (event, ctx) => {
|
|
1046
1052
|
if (!isActive(ctx)) return;
|
|
1047
1053
|
await deps.onToolExecutionStart(event, ctx);
|