@ganglion/xacpx 0.11.0 → 0.12.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/bridge/bridge-main.js +23 -1
- package/dist/cli.js +87 -16
- package/dist/commands/handlers/session-handler.d.ts +8 -2
- package/dist/commands/router-types.d.ts +4 -1
- package/dist/control/control-event-bus.d.ts +6 -0
- package/dist/control/workspace-fs.d.ts +12 -0
- package/dist/transport/types.d.ts +10 -0
- package/dist/weixin/agent/interface.d.ts +5 -0
- package/package.json +1 -1
|
@@ -68,6 +68,10 @@ function encodeBridgePromptPlanEvent(event) {
|
|
|
68
68
|
return `${JSON.stringify(event)}
|
|
69
69
|
`;
|
|
70
70
|
}
|
|
71
|
+
function encodeBridgePromptUsageEvent(event) {
|
|
72
|
+
return `${JSON.stringify(event)}
|
|
73
|
+
`;
|
|
74
|
+
}
|
|
71
75
|
function encodeBridgeSessionProgressEvent(event) {
|
|
72
76
|
return `${JSON.stringify(event)}
|
|
73
77
|
`;
|
|
@@ -424,6 +428,7 @@ function createStreamingPromptState(formatToolCalls = false, options) {
|
|
|
424
428
|
let onToolEvent;
|
|
425
429
|
let onThought;
|
|
426
430
|
let onPlan;
|
|
431
|
+
let onUsage;
|
|
427
432
|
let rawStream = false;
|
|
428
433
|
if (options === undefined) {
|
|
429
434
|
toolEventMode = "text";
|
|
@@ -435,6 +440,7 @@ function createStreamingPromptState(formatToolCalls = false, options) {
|
|
|
435
440
|
onToolEvent = options.onToolEvent;
|
|
436
441
|
onThought = options.onThought;
|
|
437
442
|
onPlan = options.onPlan;
|
|
443
|
+
onUsage = options.onUsage;
|
|
438
444
|
rawStream = options.rawStream ?? false;
|
|
439
445
|
toolEventMode = resolveToolEventMode({
|
|
440
446
|
toolEventMode: options.mode,
|
|
@@ -453,6 +459,7 @@ function createStreamingPromptState(formatToolCalls = false, options) {
|
|
|
453
459
|
onToolEvent,
|
|
454
460
|
onThought,
|
|
455
461
|
onPlan,
|
|
462
|
+
onUsage,
|
|
456
463
|
finalize() {
|
|
457
464
|
if (this.pendingLine.trim().length > 0) {
|
|
458
465
|
parseStreamingChunks(this, this.pendingLine);
|
|
@@ -517,6 +524,13 @@ function parseStreamingChunks(state, line) {
|
|
|
517
524
|
state.onPlan?.(entries);
|
|
518
525
|
return;
|
|
519
526
|
}
|
|
527
|
+
if (update.sessionUpdate === "usage_update") {
|
|
528
|
+
const used = typeof update.used === "number" && Number.isFinite(update.used) ? update.used : undefined;
|
|
529
|
+
const size = typeof update.size === "number" && Number.isFinite(update.size) ? update.size : undefined;
|
|
530
|
+
if (used !== undefined && size !== undefined && size > 0)
|
|
531
|
+
state.onUsage?.({ used, size });
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
520
534
|
const isThoughtChunk = update.sessionUpdate === "agent_thought_chunk" && update.content?.type === "text" && typeof update.content.text === "string";
|
|
521
535
|
if (isThoughtChunk) {
|
|
522
536
|
const chunk2 = update.content.text;
|
|
@@ -3989,7 +4003,8 @@ async function runStreamingPrompt(command, args, onEvent, options = {}) {
|
|
|
3989
4003
|
rawStream,
|
|
3990
4004
|
...onEvent && (toolEventMode === "structured" || toolEventMode === "both") ? { onToolEvent: (toolEvent) => onEvent({ type: "prompt.tool_event", event: toolEvent }) } : {},
|
|
3991
4005
|
...onEvent ? { onThought: (chunk) => onEvent({ type: "prompt.thought", text: chunk }) } : {},
|
|
3992
|
-
...onEvent ? { onPlan: (entries) => onEvent({ type: "prompt.plan", entries }) } : {}
|
|
4006
|
+
...onEvent ? { onPlan: (entries) => onEvent({ type: "prompt.plan", entries }) } : {},
|
|
4007
|
+
...onEvent ? { onUsage: (usage) => onEvent({ type: "prompt.usage", used: usage.used, size: usage.size }) } : {}
|
|
3993
4008
|
});
|
|
3994
4009
|
let lastReplyAt = now();
|
|
3995
4010
|
const flushBuffer = () => {
|
|
@@ -4280,6 +4295,13 @@ class BridgeServer {
|
|
|
4280
4295
|
event: "prompt.plan",
|
|
4281
4296
|
entries: event.entries
|
|
4282
4297
|
}));
|
|
4298
|
+
} else if (event.type === "prompt.usage") {
|
|
4299
|
+
writeLine?.(encodeBridgePromptUsageEvent({
|
|
4300
|
+
id: requestId,
|
|
4301
|
+
event: "prompt.usage",
|
|
4302
|
+
used: event.used,
|
|
4303
|
+
size: event.size
|
|
4304
|
+
}));
|
|
4283
4305
|
}
|
|
4284
4306
|
});
|
|
4285
4307
|
case "resumeAgentSession":
|
package/dist/cli.js
CHANGED
|
@@ -22355,7 +22355,7 @@ async function handleSessionRemove(context, chatKey, alias) {
|
|
|
22355
22355
|
return { text: lines.join(`
|
|
22356
22356
|
`) };
|
|
22357
22357
|
}
|
|
22358
|
-
async function promptWithSession(context, session3, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan) {
|
|
22358
|
+
async function promptWithSession(context, session3, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan, onUsage) {
|
|
22359
22359
|
const effectiveReplyMode = resolveEffectiveReplyMode(context.config, chatKey, session3.replyMode);
|
|
22360
22360
|
if (!session3.replyMode)
|
|
22361
22361
|
session3.replyMode = effectiveReplyMode;
|
|
@@ -22387,7 +22387,7 @@ async function promptWithSession(context, session3, chatKey, text, reply, replyC
|
|
|
22387
22387
|
const { promptText, taskIds, groupIds, claimHumanReply } = await preparePromptWithFallback(context, session3, chatKey, text, replyContextToken, accountId);
|
|
22388
22388
|
try {
|
|
22389
22389
|
const replyContext = transportReply && context.quota && getChannelIdFromChatKey(chatKey) === "weixin" ? { chatKey, quota: context.quota } : undefined;
|
|
22390
|
-
const result = await context.interaction.promptTransportSession(session3, promptText, transportReply, replyContext, media, abortSignal, onToolEvent, onThought, perfSpan, onPlan);
|
|
22390
|
+
const result = await context.interaction.promptTransportSession(session3, promptText, transportReply, replyContext, media, abortSignal, onToolEvent, onThought, perfSpan, onPlan, onUsage);
|
|
22391
22391
|
if (claimHumanReply) {
|
|
22392
22392
|
try {
|
|
22393
22393
|
await context.orchestration?.claimActiveHumanReply?.(claimHumanReply);
|
|
@@ -22407,23 +22407,23 @@ async function promptWithSession(context, session3, chatKey, text, reply, replyC
|
|
|
22407
22407
|
throw error2;
|
|
22408
22408
|
}
|
|
22409
22409
|
}
|
|
22410
|
-
async function handlePromptWithSession(context, session3, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan) {
|
|
22410
|
+
async function handlePromptWithSession(context, session3, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan, onUsage) {
|
|
22411
22411
|
try {
|
|
22412
|
-
return await promptWithSession(context, session3, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan);
|
|
22412
|
+
return await promptWithSession(context, session3, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan, onUsage);
|
|
22413
22413
|
} catch (error2) {
|
|
22414
22414
|
const recovered = await context.recovery.tryRecoverMissingSession(session3, error2);
|
|
22415
22415
|
if (recovered) {
|
|
22416
|
-
return await promptWithSession(context, recovered, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan);
|
|
22416
|
+
return await promptWithSession(context, recovered, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan, onUsage);
|
|
22417
22417
|
}
|
|
22418
22418
|
return context.recovery.renderTransportError(session3, error2);
|
|
22419
22419
|
}
|
|
22420
22420
|
}
|
|
22421
|
-
async function handlePrompt(context, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan) {
|
|
22421
|
+
async function handlePrompt(context, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan, onUsage) {
|
|
22422
22422
|
const session3 = metadata?.boundSessionAlias ? context.sessions.getResolvedSessionByInternalAlias(metadata.boundSessionAlias) : await context.sessions.getCurrentSession(chatKey);
|
|
22423
22423
|
if (!session3) {
|
|
22424
22424
|
return { text: t().session.noCurrent };
|
|
22425
22425
|
}
|
|
22426
|
-
return await handlePromptWithSession(context, session3, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan);
|
|
22426
|
+
return await handlePromptWithSession(context, session3, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan, onUsage);
|
|
22427
22427
|
}
|
|
22428
22428
|
function toCoordinatorRouteChatMetadata(metadata) {
|
|
22429
22429
|
if (!metadata) {
|
|
@@ -24682,7 +24682,7 @@ class CommandRouter {
|
|
|
24682
24682
|
this.logger = logger2 ?? createNoopAppLogger();
|
|
24683
24683
|
this.activeTurns = activeTurns;
|
|
24684
24684
|
}
|
|
24685
|
-
async handle(chatKey, input, reply, replyContextToken, accountId, media, metadata, abortSignal, onToolEvent, onThought, perfSpan, onPlan) {
|
|
24685
|
+
async handle(chatKey, input, reply, replyContextToken, accountId, media, metadata, abortSignal, onToolEvent, onThought, perfSpan, onPlan, onUsage) {
|
|
24686
24686
|
const startedAt = Date.now();
|
|
24687
24687
|
let command = parseCommand(input);
|
|
24688
24688
|
if (metadata?.channel === "control" && command.kind !== "prompt") {
|
|
@@ -24842,16 +24842,16 @@ class CommandRouter {
|
|
|
24842
24842
|
...this.sessions.resolveSession(descriptor.alias, descriptor.agent, descriptor.workspace, descriptor.transportSession),
|
|
24843
24843
|
transient: true
|
|
24844
24844
|
};
|
|
24845
|
-
return await handlePromptWithSession(sessionContext, transientSession, chatKey, command.text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan);
|
|
24845
|
+
return await handlePromptWithSession(sessionContext, transientSession, chatKey, command.text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan, onUsage);
|
|
24846
24846
|
}
|
|
24847
24847
|
if (metadata?.scheduledSessionAlias) {
|
|
24848
24848
|
const scheduledSession = await this.sessions.getSession(metadata.scheduledSessionAlias);
|
|
24849
24849
|
if (!scheduledSession) {
|
|
24850
24850
|
throw new Error(`session "${metadata.scheduledSessionAlias}" not found for scheduled prompt`);
|
|
24851
24851
|
}
|
|
24852
|
-
return await handlePromptWithSession(sessionContext, scheduledSession, chatKey, command.text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan);
|
|
24852
|
+
return await handlePromptWithSession(sessionContext, scheduledSession, chatKey, command.text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan, onUsage);
|
|
24853
24853
|
}
|
|
24854
|
-
return await handlePrompt(sessionContext, chatKey, command.text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan);
|
|
24854
|
+
return await handlePrompt(sessionContext, chatKey, command.text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan, onUsage);
|
|
24855
24855
|
}
|
|
24856
24856
|
}
|
|
24857
24857
|
});
|
|
@@ -24999,7 +24999,7 @@ class CommandRouter {
|
|
|
24999
24999
|
setModelTransportSession: (session3, modelId) => this.setModelTransportSession(session3, modelId),
|
|
25000
25000
|
getModelTransportSession: (session3) => this.getModelTransportSession(session3),
|
|
25001
25001
|
cancelTransportSession: (session3) => this.cancelTransportSession(session3),
|
|
25002
|
-
promptTransportSession: (session3, text, reply, replyContext, media, abortSignal, onToolEvent, onThought, perfSpanOverride, onPlan) => this.promptTransportSession(session3, text, reply, replyContext, media, abortSignal, onToolEvent, onThought, perfSpanOverride ?? perfSpan, onPlan)
|
|
25002
|
+
promptTransportSession: (session3, text, reply, replyContext, media, abortSignal, onToolEvent, onThought, perfSpanOverride, onPlan, onUsage) => this.promptTransportSession(session3, text, reply, replyContext, media, abortSignal, onToolEvent, onThought, perfSpanOverride ?? perfSpan, onPlan, onUsage)
|
|
25003
25003
|
};
|
|
25004
25004
|
}
|
|
25005
25005
|
createSessionRenderRecoveryOps() {
|
|
@@ -25178,7 +25178,7 @@ class CommandRouter {
|
|
|
25178
25178
|
async checkTransportSession(session3) {
|
|
25179
25179
|
return await this.measureTransportCall("has_session", session3, () => this.transport.hasSession(session3));
|
|
25180
25180
|
}
|
|
25181
|
-
async promptTransportSession(session3, text, reply, replyContext, media, abortSignal, onToolEvent, onThought, perfSpan, onPlan) {
|
|
25181
|
+
async promptTransportSession(session3, text, reply, replyContext, media, abortSignal, onToolEvent, onThought, perfSpan, onPlan, onUsage) {
|
|
25182
25182
|
session3.mcpCoordinatorSession ??= stableCoordinatorSession(session3.transportSession);
|
|
25183
25183
|
let done = false;
|
|
25184
25184
|
let abortRequested = false;
|
|
@@ -25236,7 +25236,8 @@ class CommandRouter {
|
|
|
25236
25236
|
...reply ? { onSegment } : {},
|
|
25237
25237
|
...onToolEvent ? { onToolEvent } : {},
|
|
25238
25238
|
...onThought ? { onThought } : {},
|
|
25239
|
-
...onPlan ? { onPlan } : {}
|
|
25239
|
+
...onPlan ? { onPlan } : {},
|
|
25240
|
+
...onUsage ? { onUsage } : {}
|
|
25240
25241
|
}));
|
|
25241
25242
|
} catch (error2) {
|
|
25242
25243
|
localOutcome = isAbortError2(error2) || abortRequested ? "aborted" : "error";
|
|
@@ -25422,7 +25423,7 @@ class ConsoleAgent {
|
|
|
25422
25423
|
...m.fileName ? { fileName: m.fileName } : {}
|
|
25423
25424
|
})) : undefined;
|
|
25424
25425
|
request.perfSpan?.mark("agent.dispatched");
|
|
25425
|
-
return await this.router.handle(request.conversationId, request.text, request.reply, request.replyContextToken, request.accountId, promptMedia, request.metadata, request.abortSignal, request.onToolEvent, request.onThought, request.perfSpan, request.onPlan);
|
|
25426
|
+
return await this.router.handle(request.conversationId, request.text, request.reply, request.replyContextToken, request.accountId, promptMedia, request.metadata, request.abortSignal, request.onToolEvent, request.onThought, request.perfSpan, request.onPlan, request.onUsage);
|
|
25426
25427
|
}
|
|
25427
25428
|
isKnownCommand(text) {
|
|
25428
25429
|
return isKnownXacpxCommandText(text);
|
|
@@ -30478,6 +30479,10 @@ function encodeBridgePromptPlanEvent(event) {
|
|
|
30478
30479
|
return `${JSON.stringify(event)}
|
|
30479
30480
|
`;
|
|
30480
30481
|
}
|
|
30482
|
+
function encodeBridgePromptUsageEvent(event) {
|
|
30483
|
+
return `${JSON.stringify(event)}
|
|
30484
|
+
`;
|
|
30485
|
+
}
|
|
30481
30486
|
function encodeBridgeSessionProgressEvent(event) {
|
|
30482
30487
|
return `${JSON.stringify(event)}
|
|
30483
30488
|
`;
|
|
@@ -30780,6 +30785,12 @@ class AcpxBridgeClient {
|
|
|
30780
30785
|
type: "prompt.plan",
|
|
30781
30786
|
entries: message.entries
|
|
30782
30787
|
});
|
|
30788
|
+
} else if (message.event === "prompt.usage") {
|
|
30789
|
+
pending.onEvent?.({
|
|
30790
|
+
type: "prompt.usage",
|
|
30791
|
+
used: message.used,
|
|
30792
|
+
size: message.size
|
|
30793
|
+
});
|
|
30783
30794
|
} else if (message.event === "session.progress") {
|
|
30784
30795
|
pending.onEvent?.({
|
|
30785
30796
|
type: "session.progress",
|
|
@@ -31239,6 +31250,8 @@ class AcpxBridgeTransport {
|
|
|
31239
31250
|
let thoughtChain = Promise.resolve();
|
|
31240
31251
|
let planError;
|
|
31241
31252
|
let planChain = Promise.resolve();
|
|
31253
|
+
let usageError;
|
|
31254
|
+
let usageChain = Promise.resolve();
|
|
31242
31255
|
let toolEventMode = resolveToolEventMode(options);
|
|
31243
31256
|
if ((toolEventMode === "structured" || toolEventMode === "both") && !options?.onToolEvent) {
|
|
31244
31257
|
toolEventMode = "text";
|
|
@@ -31291,11 +31304,22 @@ class AcpxBridgeTransport {
|
|
|
31291
31304
|
}
|
|
31292
31305
|
return;
|
|
31293
31306
|
}
|
|
31307
|
+
if (event.type === "prompt.usage") {
|
|
31308
|
+
const onUsage = options?.onUsage;
|
|
31309
|
+
if (onUsage) {
|
|
31310
|
+
const usage = { used: event.used, size: event.size };
|
|
31311
|
+
usageChain = usageChain.then(() => onUsage(usage)).catch((error2) => {
|
|
31312
|
+
usageError ??= error2;
|
|
31313
|
+
});
|
|
31314
|
+
}
|
|
31315
|
+
return;
|
|
31316
|
+
}
|
|
31294
31317
|
});
|
|
31295
31318
|
await segmentChain;
|
|
31296
31319
|
await toolEventChain;
|
|
31297
31320
|
await thoughtChain;
|
|
31298
31321
|
await planChain;
|
|
31322
|
+
await usageChain;
|
|
31299
31323
|
if (sink) {
|
|
31300
31324
|
const { overflowCount } = sink.finalize();
|
|
31301
31325
|
await sink.drain({ timeoutMs: 30000 });
|
|
@@ -31316,6 +31340,9 @@ class AcpxBridgeTransport {
|
|
|
31316
31340
|
if (planError) {
|
|
31317
31341
|
throw planError;
|
|
31318
31342
|
}
|
|
31343
|
+
if (usageError) {
|
|
31344
|
+
throw usageError;
|
|
31345
|
+
}
|
|
31319
31346
|
return { text: summary ? `${summary}
|
|
31320
31347
|
|
|
31321
31348
|
${result.text}` : "" };
|
|
@@ -31332,6 +31359,9 @@ ${result.text}` : "" };
|
|
|
31332
31359
|
if (planError) {
|
|
31333
31360
|
throw planError;
|
|
31334
31361
|
}
|
|
31362
|
+
if (usageError) {
|
|
31363
|
+
throw usageError;
|
|
31364
|
+
}
|
|
31335
31365
|
return result;
|
|
31336
31366
|
}
|
|
31337
31367
|
async setMode(session3, modeId) {
|
|
@@ -31537,6 +31567,7 @@ function createStreamingPromptState(formatToolCalls = false, options) {
|
|
|
31537
31567
|
let onToolEvent;
|
|
31538
31568
|
let onThought;
|
|
31539
31569
|
let onPlan;
|
|
31570
|
+
let onUsage;
|
|
31540
31571
|
let rawStream = false;
|
|
31541
31572
|
if (options === undefined) {
|
|
31542
31573
|
toolEventMode = "text";
|
|
@@ -31548,6 +31579,7 @@ function createStreamingPromptState(formatToolCalls = false, options) {
|
|
|
31548
31579
|
onToolEvent = options.onToolEvent;
|
|
31549
31580
|
onThought = options.onThought;
|
|
31550
31581
|
onPlan = options.onPlan;
|
|
31582
|
+
onUsage = options.onUsage;
|
|
31551
31583
|
rawStream = options.rawStream ?? false;
|
|
31552
31584
|
toolEventMode = resolveToolEventMode({
|
|
31553
31585
|
toolEventMode: options.mode,
|
|
@@ -31566,6 +31598,7 @@ function createStreamingPromptState(formatToolCalls = false, options) {
|
|
|
31566
31598
|
onToolEvent,
|
|
31567
31599
|
onThought,
|
|
31568
31600
|
onPlan,
|
|
31601
|
+
onUsage,
|
|
31569
31602
|
finalize() {
|
|
31570
31603
|
if (this.pendingLine.trim().length > 0) {
|
|
31571
31604
|
parseStreamingChunks(this, this.pendingLine);
|
|
@@ -31630,6 +31663,13 @@ function parseStreamingChunks(state, line) {
|
|
|
31630
31663
|
state.onPlan?.(entries);
|
|
31631
31664
|
return;
|
|
31632
31665
|
}
|
|
31666
|
+
if (update.sessionUpdate === "usage_update") {
|
|
31667
|
+
const used = typeof update.used === "number" && Number.isFinite(update.used) ? update.used : undefined;
|
|
31668
|
+
const size = typeof update.size === "number" && Number.isFinite(update.size) ? update.size : undefined;
|
|
31669
|
+
if (used !== undefined && size !== undefined && size > 0)
|
|
31670
|
+
state.onUsage?.({ used, size });
|
|
31671
|
+
return;
|
|
31672
|
+
}
|
|
31633
31673
|
const isThoughtChunk = update.sessionUpdate === "agent_thought_chunk" && update.content?.type === "text" && typeof update.content.text === "string";
|
|
31634
31674
|
if (isThoughtChunk) {
|
|
31635
31675
|
const chunk2 = update.content.text;
|
|
@@ -33259,7 +33299,29 @@ class WorkspaceFs {
|
|
|
33259
33299
|
}
|
|
33260
33300
|
}
|
|
33261
33301
|
const truncated = diff.length > DIFF_CAP;
|
|
33262
|
-
return { workspace: workspace3, files, diff: truncated ? diff.slice(0, DIFF_CAP) : diff, truncated };
|
|
33302
|
+
return { workspace: workspace3, files, diff: truncated ? diff.slice(0, DIFF_CAP) : diff, truncated, ...await this.gitContext(root) };
|
|
33303
|
+
}
|
|
33304
|
+
async gitContext(root) {
|
|
33305
|
+
const run = async (...args) => {
|
|
33306
|
+
try {
|
|
33307
|
+
return (await execFileAsync("git", ["-C", root, ...args], { maxBuffer: GIT_MAX_BUFFER })).stdout.trim();
|
|
33308
|
+
} catch {
|
|
33309
|
+
return null;
|
|
33310
|
+
}
|
|
33311
|
+
};
|
|
33312
|
+
const ctx = {};
|
|
33313
|
+
const head = await run("rev-parse", "--abbrev-ref", "HEAD");
|
|
33314
|
+
if (head === "HEAD")
|
|
33315
|
+
ctx.detached = true;
|
|
33316
|
+
else if (head)
|
|
33317
|
+
ctx.branch = head;
|
|
33318
|
+
const top = await run("rev-parse", "--show-toplevel");
|
|
33319
|
+
if (top) {
|
|
33320
|
+
const gitDir = await run("rev-parse", "--absolute-git-dir");
|
|
33321
|
+
const commonDir = await run("rev-parse", "--path-format=absolute", "--git-common-dir");
|
|
33322
|
+
ctx.worktree = { root: top, linked: !!gitDir && !!commonDir && gitDir !== commonDir };
|
|
33323
|
+
}
|
|
33324
|
+
return ctx;
|
|
33263
33325
|
}
|
|
33264
33326
|
}
|
|
33265
33327
|
var execFileAsync, MAX_ENTRIES = 2000, FILE_READ_CAP, DIFF_CAP, GIT_MAX_BUFFER, SEARCH_MAX_RESULTS = 200, SEARCH_MAX_SCAN = 20000, SEARCH_SKIP_DIRS;
|
|
@@ -33526,6 +33588,15 @@ ${chunk}` : chunk
|
|
|
33526
33588
|
sessionAlias: params.sessionAlias,
|
|
33527
33589
|
entries
|
|
33528
33590
|
});
|
|
33591
|
+
},
|
|
33592
|
+
onUsage: (usage) => {
|
|
33593
|
+
this.deps.events.emit({
|
|
33594
|
+
type: "turn-usage",
|
|
33595
|
+
chatKey: params.chatKey,
|
|
33596
|
+
sessionAlias: params.sessionAlias,
|
|
33597
|
+
used: usage.used,
|
|
33598
|
+
size: usage.size
|
|
33599
|
+
});
|
|
33529
33600
|
}
|
|
33530
33601
|
});
|
|
33531
33602
|
if (response.text) {
|
|
@@ -38,5 +38,11 @@ export declare function handleCancel(context: SessionHandlerContext, chatKey: st
|
|
|
38
38
|
export declare function handleSessionReset(context: SessionHandlerContext, chatKey: string): Promise<RouterResponse>;
|
|
39
39
|
export declare function handleSessionTail(context: SessionHandlerContext, chatKey: string, lines?: number): Promise<RouterResponse>;
|
|
40
40
|
export declare function handleSessionRemove(context: SessionHandlerContext, chatKey: string, alias: string): Promise<RouterResponse>;
|
|
41
|
-
export declare function handlePromptWithSession(context: SessionHandlerContext, session: ResolvedSession, chatKey: string, text: string, reply?: (text: string) => Promise<void>, replyContextToken?: string, accountId?: string, media?: PromptMediaInput, abortSignal?: AbortSignal, onToolEvent?: (event: ToolUseEvent) => void | Promise<void>, onThought?: (chunk: string) => void | Promise<void>, perfSpan?: PerfSpan, metadata?: ChatRequestMetadata, onPlan?: (entries: PlanEntry[]) => void | Promise<void
|
|
42
|
-
|
|
41
|
+
export declare function handlePromptWithSession(context: SessionHandlerContext, session: ResolvedSession, chatKey: string, text: string, reply?: (text: string) => Promise<void>, replyContextToken?: string, accountId?: string, media?: PromptMediaInput, abortSignal?: AbortSignal, onToolEvent?: (event: ToolUseEvent) => void | Promise<void>, onThought?: (chunk: string) => void | Promise<void>, perfSpan?: PerfSpan, metadata?: ChatRequestMetadata, onPlan?: (entries: PlanEntry[]) => void | Promise<void>, onUsage?: (usage: {
|
|
42
|
+
used: number;
|
|
43
|
+
size: number;
|
|
44
|
+
}) => void | Promise<void>): Promise<RouterResponse>;
|
|
45
|
+
export declare function handlePrompt(context: SessionHandlerContext, chatKey: string, text: string, reply?: (text: string) => Promise<void>, replyContextToken?: string, accountId?: string, media?: PromptMediaInput, abortSignal?: AbortSignal, onToolEvent?: (event: ToolUseEvent) => void | Promise<void>, onThought?: (chunk: string) => void | Promise<void>, perfSpan?: PerfSpan, metadata?: ChatRequestMetadata, onPlan?: (entries: PlanEntry[]) => void | Promise<void>, onUsage?: (usage: {
|
|
46
|
+
used: number;
|
|
47
|
+
size: number;
|
|
48
|
+
}) => void | Promise<void>): Promise<RouterResponse>;
|
|
@@ -113,7 +113,10 @@ export interface SessionInteractionOps {
|
|
|
113
113
|
cancelled: boolean;
|
|
114
114
|
message: string;
|
|
115
115
|
}>;
|
|
116
|
-
promptTransportSession: (session: import("../transport/types").ResolvedSession, text: string, reply?: (text: string) => Promise<void>, replyContext?: ReplyQuotaContext, media?: PromptMediaInput, abortSignal?: AbortSignal, onToolEvent?: (event: ToolUseEvent) => void | Promise<void>, onThought?: (chunk: string) => void | Promise<void>, perfSpan?: PerfSpan, onPlan?: (entries: PlanEntry[]) => void | Promise<void
|
|
116
|
+
promptTransportSession: (session: import("../transport/types").ResolvedSession, text: string, reply?: (text: string) => Promise<void>, replyContext?: ReplyQuotaContext, media?: PromptMediaInput, abortSignal?: AbortSignal, onToolEvent?: (event: ToolUseEvent) => void | Promise<void>, onThought?: (chunk: string) => void | Promise<void>, perfSpan?: PerfSpan, onPlan?: (entries: PlanEntry[]) => void | Promise<void>, onUsage?: (usage: {
|
|
117
|
+
used: number;
|
|
118
|
+
size: number;
|
|
119
|
+
}) => void | Promise<void>) => Promise<{
|
|
117
120
|
text: string;
|
|
118
121
|
}>;
|
|
119
122
|
}
|
|
@@ -31,6 +31,12 @@ export type ControlEvent = {
|
|
|
31
31
|
chatKey: string;
|
|
32
32
|
sessionAlias: string;
|
|
33
33
|
entries: PlanEntry[];
|
|
34
|
+
} | {
|
|
35
|
+
type: "turn-usage";
|
|
36
|
+
chatKey: string;
|
|
37
|
+
sessionAlias: string;
|
|
38
|
+
used: number;
|
|
39
|
+
size: number;
|
|
34
40
|
} | {
|
|
35
41
|
type: "turn-finished";
|
|
36
42
|
chatKey: string;
|
|
@@ -31,6 +31,15 @@ export interface WorkspaceDiff {
|
|
|
31
31
|
files: DiffFile[];
|
|
32
32
|
diff: string;
|
|
33
33
|
truncated: boolean;
|
|
34
|
+
/** Symbolic branch name (abbrev-ref HEAD); omitted when HEAD is detached. */
|
|
35
|
+
branch?: string;
|
|
36
|
+
/** True when HEAD is detached (no branch). */
|
|
37
|
+
detached?: boolean;
|
|
38
|
+
/** Working-tree context: its top-level root, and whether it's a linked (non-primary) worktree. */
|
|
39
|
+
worktree?: {
|
|
40
|
+
root: string;
|
|
41
|
+
linked: boolean;
|
|
42
|
+
};
|
|
34
43
|
}
|
|
35
44
|
export interface WorkspaceRef {
|
|
36
45
|
name: string;
|
|
@@ -49,4 +58,7 @@ export declare class WorkspaceFs {
|
|
|
49
58
|
* (so it stays contained), bounded by a scan budget and a result cap. */
|
|
50
59
|
search(workspace: string, query: string): Promise<SearchResult>;
|
|
51
60
|
gitDiff(workspace: string, relPath?: string): Promise<WorkspaceDiff>;
|
|
61
|
+
/** Branch + worktree context for a repo root. Best-effort: any git hiccup just
|
|
62
|
+
* omits the fields so the diff itself still returns. */
|
|
63
|
+
private gitContext;
|
|
52
64
|
}
|
|
@@ -114,6 +114,16 @@ export interface PromptOptions {
|
|
|
114
114
|
* re-sent on every update (REPLACE, not append). Optional — text channels omit it.
|
|
115
115
|
*/
|
|
116
116
|
onPlan?: (entries: PlanEntry[]) => void | Promise<void>;
|
|
117
|
+
/**
|
|
118
|
+
* Context-usage side-channel: the agent's ACP `usage_update` — `used` tokens
|
|
119
|
+
* currently in context and `size`, the model's total context window. Replace-latest
|
|
120
|
+
* scalar (re-sent during a turn). Optional — only agents that report it fire this
|
|
121
|
+
* (e.g. claude does, codex does not), and text channels omit the handler.
|
|
122
|
+
*/
|
|
123
|
+
onUsage?: (usage: {
|
|
124
|
+
used: number;
|
|
125
|
+
size: number;
|
|
126
|
+
}) => void | Promise<void>;
|
|
117
127
|
/**
|
|
118
128
|
* How tool_call / tool_call_update events are surfaced for this prompt.
|
|
119
129
|
*
|
|
@@ -50,6 +50,11 @@ export interface ChatRequest {
|
|
|
50
50
|
onThought?: (chunk: string) => void | Promise<void>;
|
|
51
51
|
/** Structured plan/todo side-channel; see PromptOptions.onPlan. */
|
|
52
52
|
onPlan?: (entries: PlanEntry[]) => void | Promise<void>;
|
|
53
|
+
/** Context-usage side-channel; see PromptOptions.onUsage. */
|
|
54
|
+
onUsage?: (usage: {
|
|
55
|
+
used: number;
|
|
56
|
+
size: number;
|
|
57
|
+
}) => void | Promise<void>;
|
|
53
58
|
/**
|
|
54
59
|
* Optional per-turn performance tracing span. When `logging.perf.enabled` is
|
|
55
60
|
* true, the channel handler attaches a `PerfSpan` so downstream layers can
|