@ai-setting/roy-agent-cli 1.7.56 → 1.7.58
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/bin/roy-agent.js +863 -105
- package/dist/index.js +863 -105
- package/dist/roy-agent-linux-x64/bin/roy-agent +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -364,25 +364,46 @@ var exports_stream_output_service = {};
|
|
|
364
364
|
__export(exports_stream_output_service, {
|
|
365
365
|
streamAbortSignal: () => streamAbortSignal,
|
|
366
366
|
resetStreamAbort: () => resetStreamAbort,
|
|
367
|
+
isStreamAborted: () => isStreamAborted,
|
|
367
368
|
hasNumericUsage: () => hasNumericUsage,
|
|
368
369
|
abortStream: () => abortStream,
|
|
370
|
+
__resetAllStreamAbortForTest: () => __resetAllStreamAbortForTest,
|
|
369
371
|
StreamOutputService: () => StreamOutputService,
|
|
370
372
|
COLORS: () => COLORS
|
|
371
373
|
});
|
|
372
374
|
import chalk2 from "chalk";
|
|
373
375
|
import { createLogger as createLogger2, TracedAs as TracedAs2 } from "@ai-setting/roy-agent-core";
|
|
374
|
-
function resetStreamAbort() {
|
|
375
|
-
|
|
376
|
+
function resetStreamAbort(scope) {
|
|
377
|
+
if (scope === undefined) {
|
|
378
|
+
streamAbortSignal.aborted = false;
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
abortedRuns.delete(scope);
|
|
382
|
+
}
|
|
383
|
+
function abortStream(scope) {
|
|
384
|
+
if (scope === undefined) {
|
|
385
|
+
streamAbortSignal.aborted = true;
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
abortedRuns.add(scope);
|
|
389
|
+
}
|
|
390
|
+
function isStreamAborted(scope) {
|
|
391
|
+
if (streamAbortSignal.aborted)
|
|
392
|
+
return true;
|
|
393
|
+
if (scope === undefined)
|
|
394
|
+
return false;
|
|
395
|
+
return abortedRuns.has(scope);
|
|
376
396
|
}
|
|
377
|
-
function
|
|
378
|
-
streamAbortSignal.aborted =
|
|
397
|
+
function __resetAllStreamAbortForTest() {
|
|
398
|
+
streamAbortSignal.aborted = false;
|
|
399
|
+
abortedRuns.clear();
|
|
379
400
|
}
|
|
380
401
|
function hasNumericUsage(usage) {
|
|
381
402
|
if (!usage)
|
|
382
403
|
return false;
|
|
383
404
|
return typeof usage.promptTokens === "number" || typeof usage.completionTokens === "number" || typeof usage.totalTokens === "number" || typeof usage.cacheRead === "number" || typeof usage.cacheWrite === "number" || typeof usage.promptTokensTotal === "number";
|
|
384
405
|
}
|
|
385
|
-
var logger2, COLORS, streamAbortSignal, StreamOutputService;
|
|
406
|
+
var logger2, COLORS, streamAbortSignal, abortedRuns, StreamOutputService;
|
|
386
407
|
var init_stream_output_service = __esm(() => {
|
|
387
408
|
init_markdown_renderer();
|
|
388
409
|
logger2 = createLogger2("stream-output");
|
|
@@ -405,6 +426,7 @@ var init_stream_output_service = __esm(() => {
|
|
|
405
426
|
streamAbortSignal = {
|
|
406
427
|
aborted: false
|
|
407
428
|
};
|
|
429
|
+
abortedRuns = new Set;
|
|
408
430
|
StreamOutputService = class StreamOutputService {
|
|
409
431
|
fullText = "";
|
|
410
432
|
fullReasoning = "";
|
|
@@ -420,6 +442,9 @@ var init_stream_output_service = __esm(() => {
|
|
|
420
442
|
reasoningClosedByText = false;
|
|
421
443
|
chunkCallback = undefined;
|
|
422
444
|
silent = false;
|
|
445
|
+
sessionFilter = undefined;
|
|
446
|
+
acceptsSidelessEvents = true;
|
|
447
|
+
runId = undefined;
|
|
423
448
|
constructor(options = {}) {
|
|
424
449
|
this.options = options;
|
|
425
450
|
this.silent = options.silent ?? false;
|
|
@@ -434,6 +459,15 @@ var init_stream_output_service = __esm(() => {
|
|
|
434
459
|
setChunkCallback(cb) {
|
|
435
460
|
this.chunkCallback = cb;
|
|
436
461
|
}
|
|
462
|
+
setSessionFilter(sessionId) {
|
|
463
|
+
this.sessionFilter = sessionId;
|
|
464
|
+
}
|
|
465
|
+
setAcceptsSidelessEvents(accepts) {
|
|
466
|
+
this.acceptsSidelessEvents = accepts;
|
|
467
|
+
}
|
|
468
|
+
setRunId(runId) {
|
|
469
|
+
this.runId = runId;
|
|
470
|
+
}
|
|
437
471
|
emitChunk(event) {
|
|
438
472
|
if (!this.chunkCallback)
|
|
439
473
|
return;
|
|
@@ -454,7 +488,8 @@ var init_stream_output_service = __esm(() => {
|
|
|
454
488
|
console.log(message);
|
|
455
489
|
}
|
|
456
490
|
checkAbort() {
|
|
457
|
-
|
|
491
|
+
const aborted = this.runId !== undefined ? isStreamAborted(this.runId) : streamAbortSignal.aborted;
|
|
492
|
+
if (aborted) {
|
|
458
493
|
this.logStdout(`
|
|
459
494
|
${COLORS.system("[已中断]")}
|
|
460
495
|
`);
|
|
@@ -462,7 +497,25 @@ ${COLORS.system("[已中断]")}
|
|
|
462
497
|
}
|
|
463
498
|
return false;
|
|
464
499
|
}
|
|
500
|
+
extractEventSessionId(event) {
|
|
501
|
+
const fromMeta = event?.metadata?.sessionId;
|
|
502
|
+
if (typeof fromMeta === "string" && fromMeta.length > 0)
|
|
503
|
+
return fromMeta;
|
|
504
|
+
const fromPayload = event?.payload?.metadata?.sessionId;
|
|
505
|
+
if (typeof fromPayload === "string" && fromPayload.length > 0)
|
|
506
|
+
return fromPayload;
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
465
509
|
handleEvent(event) {
|
|
510
|
+
if (this.sessionFilter !== undefined) {
|
|
511
|
+
const eventSessionId = this.extractEventSessionId(event);
|
|
512
|
+
if (eventSessionId === undefined) {
|
|
513
|
+
if (!this.acceptsSidelessEvents)
|
|
514
|
+
return;
|
|
515
|
+
} else if (eventSessionId !== this.sessionFilter) {
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
466
519
|
if (this.checkAbort()) {
|
|
467
520
|
return;
|
|
468
521
|
}
|
|
@@ -9585,7 +9638,7 @@ class CliQuietModeService {
|
|
|
9585
9638
|
// package.json
|
|
9586
9639
|
var package_default = {
|
|
9587
9640
|
name: "@ai-setting/roy-agent-cli",
|
|
9588
|
-
version: "1.7.
|
|
9641
|
+
version: "1.7.58",
|
|
9589
9642
|
type: "module",
|
|
9590
9643
|
description: "CLI for roy-agent - Non-interactive command execution",
|
|
9591
9644
|
main: "./dist/index.js",
|
|
@@ -11238,6 +11291,9 @@ class QueryExecutor {
|
|
|
11238
11291
|
showToolResults: false
|
|
11239
11292
|
};
|
|
11240
11293
|
_pendingContextConfig = null;
|
|
11294
|
+
_pendingSessionScope = undefined;
|
|
11295
|
+
_pendingAcceptsSideless = undefined;
|
|
11296
|
+
_sidelessPolicyExplicit = false;
|
|
11241
11297
|
_pendingChunkCallback = undefined;
|
|
11242
11298
|
failureNotifier;
|
|
11243
11299
|
constructor(options) {
|
|
@@ -11276,6 +11332,14 @@ class QueryExecutor {
|
|
|
11276
11332
|
this.streamService.setChunkCallback(this._pendingChunkCallback);
|
|
11277
11333
|
this._pendingChunkCallback = undefined;
|
|
11278
11334
|
}
|
|
11335
|
+
if (this._pendingAcceptsSideless !== undefined) {
|
|
11336
|
+
this.streamService.setAcceptsSidelessEvents(this._pendingAcceptsSideless);
|
|
11337
|
+
this._pendingAcceptsSideless = undefined;
|
|
11338
|
+
}
|
|
11339
|
+
if (this._pendingSessionScope !== undefined) {
|
|
11340
|
+
this.streamService.setSessionFilter(this._pendingSessionScope);
|
|
11341
|
+
this.streamService.setRunId(this._pendingSessionScope);
|
|
11342
|
+
}
|
|
11279
11343
|
if (this._pendingContextConfig) {
|
|
11280
11344
|
this.streamService.setContextInfo(this._pendingContextConfig.contextWindow, this._pendingContextConfig.contextWindow * this._pendingContextConfig.thresholdRatio);
|
|
11281
11345
|
this._pendingContextConfig = null;
|
|
@@ -11301,6 +11365,18 @@ class QueryExecutor {
|
|
|
11301
11365
|
this._pendingChunkCallback = cb;
|
|
11302
11366
|
}
|
|
11303
11367
|
}
|
|
11368
|
+
setSessionScope(sessionId) {
|
|
11369
|
+
this._pendingSessionScope = sessionId;
|
|
11370
|
+
if (this.streamService) {
|
|
11371
|
+
this.streamService.setSessionFilter(sessionId);
|
|
11372
|
+
this.streamService.setRunId(sessionId);
|
|
11373
|
+
}
|
|
11374
|
+
}
|
|
11375
|
+
setAcceptsSidelessEvents(accepts) {
|
|
11376
|
+
this._pendingAcceptsSideless = accepts;
|
|
11377
|
+
this._sidelessPolicyExplicit = true;
|
|
11378
|
+
this.streamService?.setAcceptsSidelessEvents(accepts);
|
|
11379
|
+
}
|
|
11304
11380
|
handleEvent(event) {
|
|
11305
11381
|
if (event.type === "context.threshold_exceeded" && !this.quiet) {
|
|
11306
11382
|
const payload = event.payload;
|
|
@@ -11321,6 +11397,13 @@ class QueryExecutor {
|
|
|
11321
11397
|
showToolResults: streamOptions?.showToolResults ?? this.streamOptions.showToolResults
|
|
11322
11398
|
};
|
|
11323
11399
|
this.subscribeToEvents(options);
|
|
11400
|
+
if (sessionId) {
|
|
11401
|
+
this.streamService?.setSessionFilter(sessionId);
|
|
11402
|
+
this.streamService?.setRunId(sessionId);
|
|
11403
|
+
if (!this._sidelessPolicyExplicit) {
|
|
11404
|
+
this.streamService?.setAcceptsSidelessEvents(true);
|
|
11405
|
+
}
|
|
11406
|
+
}
|
|
11324
11407
|
this.streamService?.reset();
|
|
11325
11408
|
if (!this.quiet) {
|
|
11326
11409
|
this.output.info(`执行: ${message}`);
|
|
@@ -11695,8 +11778,268 @@ import {
|
|
|
11695
11778
|
} from "@ai-setting/roy-agent-core";
|
|
11696
11779
|
|
|
11697
11780
|
// src/commands/shared/event-handler.ts
|
|
11781
|
+
import {
|
|
11782
|
+
getEnvContext,
|
|
11783
|
+
runWithEnvContextAsync
|
|
11784
|
+
} from "@ai-setting/roy-agent-core/env";
|
|
11698
11785
|
import { TracedAs as TracedAs5 } from "@ai-setting/roy-agent-core";
|
|
11699
11786
|
import { notifyReactFailure as notifyReactFailure2 } from "@ai-setting/roy-agent-core/env/error-reply";
|
|
11787
|
+
|
|
11788
|
+
// src/commands/shared/telemetry-notice.ts
|
|
11789
|
+
import { spawn } from "node:child_process";
|
|
11790
|
+
import { normalizeLarkAtMentions } from "@ai-setting/roy-agent-core/env/lark-mention-utils";
|
|
11791
|
+
import { deriveIdempotencyKey } from "@ai-setting/roy-agent-core/env/event-source/idempotency-key";
|
|
11792
|
+
var TELEMETRY_EVENT_TYPES = new Set([
|
|
11793
|
+
"task.background.started",
|
|
11794
|
+
"task.background.progress"
|
|
11795
|
+
]);
|
|
11796
|
+
function isTelemetryEvent(type) {
|
|
11797
|
+
if (!type)
|
|
11798
|
+
return false;
|
|
11799
|
+
return TELEMETRY_EVENT_TYPES.has(type);
|
|
11800
|
+
}
|
|
11801
|
+
var MAX_TITLE_CHARS = 40;
|
|
11802
|
+
function pad2(n) {
|
|
11803
|
+
return n < 10 ? `0${n}` : String(n);
|
|
11804
|
+
}
|
|
11805
|
+
function formatElapsed(ms) {
|
|
11806
|
+
if (!Number.isFinite(ms) || ms <= 0)
|
|
11807
|
+
return "0m";
|
|
11808
|
+
const totalMin = Math.floor(ms / 60000);
|
|
11809
|
+
if (totalMin < 60)
|
|
11810
|
+
return `${totalMin}m`;
|
|
11811
|
+
const totalHour = Math.floor(totalMin / 60);
|
|
11812
|
+
const min = totalMin % 60;
|
|
11813
|
+
if (totalHour < 24) {
|
|
11814
|
+
return min === 0 ? `${totalHour}h` : `${totalHour}h${min}m`;
|
|
11815
|
+
}
|
|
11816
|
+
const day = Math.floor(totalHour / 24);
|
|
11817
|
+
const hour = totalHour % 24;
|
|
11818
|
+
return hour === 0 ? `${day}d` : `${day}d${hour}h`;
|
|
11819
|
+
}
|
|
11820
|
+
function formatClock(ts) {
|
|
11821
|
+
const d = new Date(ts);
|
|
11822
|
+
return `${pad2(d.getHours())}:${pad2(d.getMinutes())}`;
|
|
11823
|
+
}
|
|
11824
|
+
function formatTimeoutLabel(ms) {
|
|
11825
|
+
if (!Number.isFinite(ms) || ms <= 0)
|
|
11826
|
+
return "0m";
|
|
11827
|
+
return formatElapsed(ms);
|
|
11828
|
+
}
|
|
11829
|
+
function truncateTitle(raw) {
|
|
11830
|
+
const s = raw.trim();
|
|
11831
|
+
if (s.length <= MAX_TITLE_CHARS)
|
|
11832
|
+
return s;
|
|
11833
|
+
return `${s.slice(0, MAX_TITLE_CHARS)}…`;
|
|
11834
|
+
}
|
|
11835
|
+
function pickString(v) {
|
|
11836
|
+
return typeof v === "string" && v.length > 0 ? v : undefined;
|
|
11837
|
+
}
|
|
11838
|
+
function pickNumber(v) {
|
|
11839
|
+
return typeof v === "number" && Number.isFinite(v) ? v : undefined;
|
|
11840
|
+
}
|
|
11841
|
+
function buildTelemetryNoticeText(type, payload, now = Date.now()) {
|
|
11842
|
+
const p = payload ?? {};
|
|
11843
|
+
const taskId = pickNumber(p.associatedTaskId);
|
|
11844
|
+
const bgId = pickString(p.backgroundTaskId);
|
|
11845
|
+
const desc = truncateTitle(pickString(p.description) ?? "后台任务");
|
|
11846
|
+
let label;
|
|
11847
|
+
if (taskId !== undefined)
|
|
11848
|
+
label = `Task #${taskId}`;
|
|
11849
|
+
else if (bgId)
|
|
11850
|
+
label = bgId;
|
|
11851
|
+
else
|
|
11852
|
+
label = "后台任务";
|
|
11853
|
+
const head = type === "task.background.started" ? `\uD83D\uDD14 ${label}「${desc}」已启动` : `\uD83D\uDD04 ${label}「${desc}」后台运行中`;
|
|
11854
|
+
const parts = [];
|
|
11855
|
+
const startedAt = pickNumber(p.startedAt);
|
|
11856
|
+
const timeoutMs = pickNumber(p.timeoutMs);
|
|
11857
|
+
if (type !== "task.background.started" && startedAt !== undefined) {
|
|
11858
|
+
parts.push(`已跑 ${formatElapsed(now - startedAt)}`);
|
|
11859
|
+
}
|
|
11860
|
+
if (startedAt !== undefined && timeoutMs !== undefined) {
|
|
11861
|
+
parts.push(`预计 ${formatClock(startedAt + timeoutMs)} 超时(timeout ${formatTimeoutLabel(timeoutMs)})`);
|
|
11862
|
+
}
|
|
11863
|
+
let text = head;
|
|
11864
|
+
if (parts.length > 0)
|
|
11865
|
+
text += `
|
|
11866
|
+
${parts.join(",")}`;
|
|
11867
|
+
const progressMessage = pickString(p.progressMessage);
|
|
11868
|
+
if (progressMessage)
|
|
11869
|
+
text += `
|
|
11870
|
+
${progressMessage}`;
|
|
11871
|
+
return text;
|
|
11872
|
+
}
|
|
11873
|
+
var DEFAULT_SEND_TIMEOUT_MS = 5000;
|
|
11874
|
+
var MAX_IDEMPOTENCY_KEY_LEN = 50;
|
|
11875
|
+
function deriveTelemetryIdempotencyKey(eventId, chatId) {
|
|
11876
|
+
const anchor = pickString(eventId) ?? `ts-${Date.now()}-${Math.random()}`;
|
|
11877
|
+
return deriveIdempotencyKey(["telemetry", anchor, chatId]);
|
|
11878
|
+
}
|
|
11879
|
+
function buildLarkSendArgs(input) {
|
|
11880
|
+
const { chatId, text, profile, idempotencyKey } = input;
|
|
11881
|
+
const args = [
|
|
11882
|
+
"im",
|
|
11883
|
+
"+messages-send",
|
|
11884
|
+
"--chat-id",
|
|
11885
|
+
chatId,
|
|
11886
|
+
"--markdown",
|
|
11887
|
+
normalizeLarkAtMentions(text),
|
|
11888
|
+
"--as",
|
|
11889
|
+
"bot"
|
|
11890
|
+
];
|
|
11891
|
+
if (idempotencyKey) {
|
|
11892
|
+
args.push("--idempotency-key", idempotencyKey.slice(0, MAX_IDEMPOTENCY_KEY_LEN));
|
|
11893
|
+
}
|
|
11894
|
+
if (profile)
|
|
11895
|
+
args.unshift("--profile", profile);
|
|
11896
|
+
return args;
|
|
11897
|
+
}
|
|
11898
|
+
function sendLarkChatMarkdown(options) {
|
|
11899
|
+
const { chatId, text, profile, idempotencyKey } = options;
|
|
11900
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_SEND_TIMEOUT_MS;
|
|
11901
|
+
if (!chatId) {
|
|
11902
|
+
return Promise.reject(new Error("sendLarkChatMarkdown: empty chatId"));
|
|
11903
|
+
}
|
|
11904
|
+
return new Promise((resolve, reject) => {
|
|
11905
|
+
let settled = false;
|
|
11906
|
+
let timer;
|
|
11907
|
+
const finish = (err) => {
|
|
11908
|
+
if (settled)
|
|
11909
|
+
return;
|
|
11910
|
+
settled = true;
|
|
11911
|
+
if (timer)
|
|
11912
|
+
clearTimeout(timer);
|
|
11913
|
+
if (err)
|
|
11914
|
+
reject(err);
|
|
11915
|
+
else
|
|
11916
|
+
resolve();
|
|
11917
|
+
};
|
|
11918
|
+
const args = buildLarkSendArgs({ chatId, text, profile, idempotencyKey });
|
|
11919
|
+
let proc;
|
|
11920
|
+
try {
|
|
11921
|
+
proc = spawn("lark-cli", args, {
|
|
11922
|
+
shell: false,
|
|
11923
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
11924
|
+
});
|
|
11925
|
+
} catch (err) {
|
|
11926
|
+
finish(err instanceof Error ? err : new Error(String(err)));
|
|
11927
|
+
return;
|
|
11928
|
+
}
|
|
11929
|
+
let stderr = "";
|
|
11930
|
+
proc.stderr?.on("data", (chunk) => {
|
|
11931
|
+
stderr += chunk.toString();
|
|
11932
|
+
});
|
|
11933
|
+
timer = setTimeout(() => {
|
|
11934
|
+
try {
|
|
11935
|
+
proc.kill("SIGKILL");
|
|
11936
|
+
} catch {}
|
|
11937
|
+
finish(new Error(`lark-cli timed out after ${timeoutMs}ms`));
|
|
11938
|
+
}, timeoutMs);
|
|
11939
|
+
timer.unref?.();
|
|
11940
|
+
proc.on("close", (code) => {
|
|
11941
|
+
if (code === 0)
|
|
11942
|
+
finish();
|
|
11943
|
+
else
|
|
11944
|
+
finish(new Error(`lark-cli exited with code ${code}: ${stderr}`));
|
|
11945
|
+
});
|
|
11946
|
+
proc.on("error", (err) => finish(err));
|
|
11947
|
+
});
|
|
11948
|
+
}
|
|
11949
|
+
function targetFromEventMetadata(metadata) {
|
|
11950
|
+
if (!metadata)
|
|
11951
|
+
return;
|
|
11952
|
+
const replyChannel = metadata.replyChannel;
|
|
11953
|
+
const chatId = pickString(replyChannel?.chatId) ?? pickString(metadata.chatId);
|
|
11954
|
+
if (!chatId)
|
|
11955
|
+
return;
|
|
11956
|
+
const profile = pickString(replyChannel?.profile) ?? pickString(metadata.profile);
|
|
11957
|
+
return profile ? { chatId, profile } : { chatId };
|
|
11958
|
+
}
|
|
11959
|
+
async function targetFromTriggerEvent(eventStore, triggerEventId) {
|
|
11960
|
+
if (!eventStore || !triggerEventId)
|
|
11961
|
+
return;
|
|
11962
|
+
let persisted;
|
|
11963
|
+
try {
|
|
11964
|
+
persisted = await eventStore.getEventById(triggerEventId);
|
|
11965
|
+
} catch {
|
|
11966
|
+
return;
|
|
11967
|
+
}
|
|
11968
|
+
if (!persisted || typeof persisted !== "object")
|
|
11969
|
+
return;
|
|
11970
|
+
const metadata = persisted.metadata;
|
|
11971
|
+
if (!metadata || typeof metadata !== "object")
|
|
11972
|
+
return;
|
|
11973
|
+
return targetFromEventMetadata(metadata);
|
|
11974
|
+
}
|
|
11975
|
+
|
|
11976
|
+
// src/commands/shared/self-echo-filter.ts
|
|
11977
|
+
var BOT_SENDER_TYPES = new Set(["bot", "app"]);
|
|
11978
|
+
function pickString2(v) {
|
|
11979
|
+
return typeof v === "string" && v.length > 0 ? v : undefined;
|
|
11980
|
+
}
|
|
11981
|
+
function extractSenderIdentity(event) {
|
|
11982
|
+
if (!event)
|
|
11983
|
+
return {};
|
|
11984
|
+
const metadata = event.metadata;
|
|
11985
|
+
const payload = event.payload;
|
|
11986
|
+
const payloadMeta = payload?.metadata;
|
|
11987
|
+
const rawEvent = payload?.rawEvent;
|
|
11988
|
+
const innerEvent = rawEvent?.event;
|
|
11989
|
+
const innerSender = innerEvent?.sender;
|
|
11990
|
+
const topSender = rawEvent?.sender;
|
|
11991
|
+
const senderType = pickString2(metadata?.senderType) ?? pickString2(payloadMeta?.senderType) ?? pickString2(rawEvent?.sender_type) ?? pickString2(innerSender?.sender_type) ?? pickString2(topSender?.sender_type) ?? pickString2(payload?.senderType);
|
|
11992
|
+
const nestedSenderId = innerSender?.sender_id ?? topSender?.sender_id;
|
|
11993
|
+
const senderId = pickString2(metadata?.senderId) ?? pickString2(payloadMeta?.senderId) ?? pickString2(payload?.senderId) ?? pickString2(rawEvent?.sender_id) ?? (typeof nestedSenderId === "string" ? pickString2(nestedSenderId) : pickString2(nestedSenderId?.open_id) ?? pickString2(nestedSenderId?.user_id) ?? pickString2(nestedSenderId?.union_id));
|
|
11994
|
+
return {
|
|
11995
|
+
...senderType ? { senderType } : {},
|
|
11996
|
+
...senderId ? { senderId } : {}
|
|
11997
|
+
};
|
|
11998
|
+
}
|
|
11999
|
+
function isSelfEchoEvent(event, options = {}) {
|
|
12000
|
+
const { senderType, senderId } = extractSenderIdentity(event);
|
|
12001
|
+
if (options.enabled === false) {
|
|
12002
|
+
return {
|
|
12003
|
+
skip: false,
|
|
12004
|
+
reason: "disabled",
|
|
12005
|
+
...senderType ? { senderType } : {},
|
|
12006
|
+
...senderId ? { senderId } : {}
|
|
12007
|
+
};
|
|
12008
|
+
}
|
|
12009
|
+
if (senderType && BOT_SENDER_TYPES.has(senderType.toLowerCase())) {
|
|
12010
|
+
return {
|
|
12011
|
+
skip: true,
|
|
12012
|
+
reason: "bot-sender",
|
|
12013
|
+
...senderType ? { senderType } : {},
|
|
12014
|
+
...senderId ? { senderId } : {}
|
|
12015
|
+
};
|
|
12016
|
+
}
|
|
12017
|
+
if (senderId && options.selfBotIds && options.selfBotIds.length > 0) {
|
|
12018
|
+
if (options.selfBotIds.includes(senderId)) {
|
|
12019
|
+
return {
|
|
12020
|
+
skip: true,
|
|
12021
|
+
reason: "self-bot-id",
|
|
12022
|
+
...senderType ? { senderType } : {},
|
|
12023
|
+
senderId
|
|
12024
|
+
};
|
|
12025
|
+
}
|
|
12026
|
+
}
|
|
12027
|
+
return {
|
|
12028
|
+
skip: false,
|
|
12029
|
+
...senderType ? { senderType } : {},
|
|
12030
|
+
...senderId ? { senderId } : {}
|
|
12031
|
+
};
|
|
12032
|
+
}
|
|
12033
|
+
var SELF_ECHO_FILTER_ENABLED_ENV = "ROY_AGENT_SELF_ECHO_FILTER";
|
|
12034
|
+
function readSelfEchoFilterEnabled(env = process.env) {
|
|
12035
|
+
const raw = env[SELF_ECHO_FILTER_ENABLED_ENV];
|
|
12036
|
+
if (raw === undefined)
|
|
12037
|
+
return true;
|
|
12038
|
+
const v = raw.trim().toLowerCase();
|
|
12039
|
+
return !(v === "0" || v === "false" || v === "off" || v === "no");
|
|
12040
|
+
}
|
|
12041
|
+
|
|
12042
|
+
// src/commands/shared/event-handler.ts
|
|
11700
12043
|
function parseLarkPerTaskChatId(contextJson) {
|
|
11701
12044
|
if (!contextJson)
|
|
11702
12045
|
return;
|
|
@@ -11716,6 +12059,8 @@ var NOTIFY_V2_TERMINAL_TYPES = new Set([
|
|
|
11716
12059
|
]);
|
|
11717
12060
|
|
|
11718
12061
|
class EventHandler {
|
|
12062
|
+
static DEFAULT_LANE_KEY = "__default__";
|
|
12063
|
+
static DEFAULT_MAX_CONCURRENT_SESSIONS = 4;
|
|
11719
12064
|
env;
|
|
11720
12065
|
eventTypes;
|
|
11721
12066
|
onEvent;
|
|
@@ -11723,15 +12068,39 @@ class EventHandler {
|
|
|
11723
12068
|
formatter;
|
|
11724
12069
|
isIdle;
|
|
11725
12070
|
idleCheckInterval;
|
|
11726
|
-
|
|
11727
|
-
|
|
12071
|
+
isSessionIdleFn = null;
|
|
12072
|
+
maxConcurrentSessions;
|
|
12073
|
+
lanes = new Map;
|
|
12074
|
+
runningLanes = new Set;
|
|
12075
|
+
laneTails = new Map;
|
|
12076
|
+
get isProcessing() {
|
|
12077
|
+
return this.runningLanes.size > 0;
|
|
12078
|
+
}
|
|
12079
|
+
chatSessionCache = new Map;
|
|
12080
|
+
inFlightCount = 0;
|
|
12081
|
+
legacyQueue = [];
|
|
12082
|
+
get queue() {
|
|
12083
|
+
return this.legacyQueue;
|
|
12084
|
+
}
|
|
11728
12085
|
isStopped = false;
|
|
11729
12086
|
unsubscribe = null;
|
|
12087
|
+
activeSlots = 0;
|
|
12088
|
+
slotWaiters = [];
|
|
12089
|
+
sessionChains = new Map;
|
|
11730
12090
|
sessionComponent = null;
|
|
11731
12091
|
activeEventSessionId = null;
|
|
11732
12092
|
resolvedSessionByTrigger = new Map;
|
|
11733
12093
|
eventStore = null;
|
|
11734
12094
|
getHandlerForEsType = null;
|
|
12095
|
+
telemetrySender = (notice) => sendLarkChatMarkdown(notice);
|
|
12096
|
+
selfEchoFilter = {
|
|
12097
|
+
enabled: true,
|
|
12098
|
+
selfBotIds: []
|
|
12099
|
+
};
|
|
12100
|
+
selfEchoDroppedCount = 0;
|
|
12101
|
+
getSelfEchoDroppedCount() {
|
|
12102
|
+
return this.selfEchoDroppedCount;
|
|
12103
|
+
}
|
|
11735
12104
|
constructor(options) {
|
|
11736
12105
|
this.env = options.env;
|
|
11737
12106
|
this.eventTypes = options.eventTypes;
|
|
@@ -11739,10 +12108,18 @@ class EventHandler {
|
|
|
11739
12108
|
this.onEventWithEnv = options.onEventWithEnv;
|
|
11740
12109
|
this.formatter = options.formatter ?? new EventMessageFormatter;
|
|
11741
12110
|
this.isIdle = options.isIdle ?? (() => true);
|
|
12111
|
+
this.isSessionIdleFn = options.isSessionIdle ?? null;
|
|
12112
|
+
const maxSessions = options.maxConcurrentSessions;
|
|
12113
|
+
this.maxConcurrentSessions = typeof maxSessions === "number" && Number.isFinite(maxSessions) && maxSessions >= 1 ? Math.floor(maxSessions) : EventHandler.DEFAULT_MAX_CONCURRENT_SESSIONS;
|
|
11742
12114
|
this.idleCheckInterval = options.idleCheckInterval ?? 100;
|
|
11743
12115
|
this.sessionComponent = options.sessionComponent ?? null;
|
|
11744
12116
|
this.eventStore = options.eventStore ?? null;
|
|
11745
12117
|
this.getHandlerForEsType = options.getHandlerForEsType ?? null;
|
|
12118
|
+
this.telemetrySender = options.telemetrySender ?? ((notice) => sendLarkChatMarkdown(notice));
|
|
12119
|
+
this.selfEchoFilter = {
|
|
12120
|
+
enabled: options.selfEchoFilter?.enabled ?? readSelfEchoFilterEnabled(),
|
|
12121
|
+
selfBotIds: options.selfEchoFilter?.selfBotIds ?? []
|
|
12122
|
+
};
|
|
11746
12123
|
}
|
|
11747
12124
|
start() {
|
|
11748
12125
|
this.isStopped = false;
|
|
@@ -11776,17 +12153,58 @@ class EventHandler {
|
|
|
11776
12153
|
this.unsubscribe();
|
|
11777
12154
|
this.unsubscribe = null;
|
|
11778
12155
|
}
|
|
11779
|
-
this.
|
|
11780
|
-
this.
|
|
12156
|
+
this.lanes.clear();
|
|
12157
|
+
this.legacyQueue = [];
|
|
12158
|
+
this.laneTails.clear();
|
|
12159
|
+
const waiters = this.slotWaiters.splice(0, this.slotWaiters.length);
|
|
12160
|
+
for (const w of waiters)
|
|
12161
|
+
w();
|
|
12162
|
+
this.activeSlots = 0;
|
|
11781
12163
|
this.clearActiveSession();
|
|
11782
12164
|
}
|
|
11783
12165
|
async handleEvent(event) {
|
|
11784
12166
|
if (this.isStopped) {
|
|
11785
12167
|
return;
|
|
11786
12168
|
}
|
|
12169
|
+
if (this.selfEchoFilter.enabled) {
|
|
12170
|
+
const verdict = isSelfEchoEvent(event, {
|
|
12171
|
+
selfBotIds: this.selfEchoFilter.selfBotIds
|
|
12172
|
+
});
|
|
12173
|
+
if (verdict.skip) {
|
|
12174
|
+
this.selfEchoDroppedCount += 1;
|
|
12175
|
+
console.error(`[EventHandler] self-echo event dropped (reason=${verdict.reason}` + `, senderType=${verdict.senderType ?? "-"}` + `, senderId=${verdict.senderId ?? "-"}` + `, type=${event.type})`);
|
|
12176
|
+
return;
|
|
12177
|
+
}
|
|
12178
|
+
}
|
|
12179
|
+
if (isTelemetryEvent(event.type)) {
|
|
12180
|
+
this.sendTelemetryNotice(event);
|
|
12181
|
+
return;
|
|
12182
|
+
}
|
|
11787
12183
|
const formatted = await this.formatEvent(event);
|
|
11788
12184
|
this.enqueue(formatted);
|
|
11789
12185
|
}
|
|
12186
|
+
async sendTelemetryNotice(event) {
|
|
12187
|
+
try {
|
|
12188
|
+
const metadata = event.metadata;
|
|
12189
|
+
let target = targetFromEventMetadata(metadata);
|
|
12190
|
+
if (!target) {
|
|
12191
|
+
const triggerEventId = typeof metadata?.triggerEventId === "string" ? metadata.triggerEventId : undefined;
|
|
12192
|
+
target = await targetFromTriggerEvent(this.eventStore, triggerEventId);
|
|
12193
|
+
}
|
|
12194
|
+
if (!target) {
|
|
12195
|
+
return;
|
|
12196
|
+
}
|
|
12197
|
+
const text = buildTelemetryNoticeText(event.type, event.payload);
|
|
12198
|
+
await this.telemetrySender({
|
|
12199
|
+
chatId: target.chatId,
|
|
12200
|
+
...target.profile ? { profile: target.profile } : {},
|
|
12201
|
+
text,
|
|
12202
|
+
idempotencyKey: deriveTelemetryIdempotencyKey(event.id, target.chatId)
|
|
12203
|
+
});
|
|
12204
|
+
} catch (err) {
|
|
12205
|
+
console.error(`[EventHandler] telemetry notice failed (swallowed) type=${event.type}`, err);
|
|
12206
|
+
}
|
|
12207
|
+
}
|
|
11790
12208
|
async formatEvent(event) {
|
|
11791
12209
|
if (NOTIFY_V2_TERMINAL_TYPES.has(event.type) && event.metadata?.triggerEventId && this.eventStore && this.getHandlerForEsType) {
|
|
11792
12210
|
try {
|
|
@@ -11899,77 +12317,218 @@ class EventHandler {
|
|
|
11899
12317
|
await this.onEvent(formatted.message);
|
|
11900
12318
|
}
|
|
11901
12319
|
}
|
|
12320
|
+
laneKeyFor(item) {
|
|
12321
|
+
if (item.chatId)
|
|
12322
|
+
return item.chatId;
|
|
12323
|
+
if (item.triggerSessionId)
|
|
12324
|
+
return `trigger:${item.triggerSessionId}`;
|
|
12325
|
+
return EventHandler.DEFAULT_LANE_KEY;
|
|
12326
|
+
}
|
|
11902
12327
|
enqueue(formattedEvent) {
|
|
11903
12328
|
if (this.isStopped) {
|
|
11904
12329
|
return;
|
|
11905
12330
|
}
|
|
11906
|
-
|
|
11907
|
-
if (!
|
|
11908
|
-
|
|
12331
|
+
const item = { ...formattedEvent };
|
|
12332
|
+
if (!item.envContext) {
|
|
12333
|
+
item.envContext = getEnvContext();
|
|
11909
12334
|
}
|
|
12335
|
+
const laneKey = this.laneKeyFor(item);
|
|
12336
|
+
const lane = this.lanes.get(laneKey);
|
|
12337
|
+
if (lane) {
|
|
12338
|
+
lane.push(item);
|
|
12339
|
+
} else {
|
|
12340
|
+
this.lanes.set(laneKey, [item]);
|
|
12341
|
+
}
|
|
12342
|
+
this.scheduleLane(laneKey);
|
|
11910
12343
|
}
|
|
11911
12344
|
getQueueLength() {
|
|
11912
|
-
|
|
12345
|
+
let total = this.legacyQueue.length + this.inFlightCount;
|
|
12346
|
+
for (const lane of this.lanes.values()) {
|
|
12347
|
+
total += lane.length;
|
|
12348
|
+
}
|
|
12349
|
+
return total;
|
|
11913
12350
|
}
|
|
11914
12351
|
isQueueEmpty() {
|
|
11915
|
-
return this.
|
|
12352
|
+
return this.getQueueLength() === 0;
|
|
11916
12353
|
}
|
|
11917
|
-
|
|
11918
|
-
this.
|
|
11919
|
-
|
|
11920
|
-
|
|
11921
|
-
|
|
11922
|
-
|
|
11923
|
-
|
|
12354
|
+
isSessionIdle(laneKey) {
|
|
12355
|
+
return !this.runningLanes.has(laneKey);
|
|
12356
|
+
}
|
|
12357
|
+
getRunningLaneKeys() {
|
|
12358
|
+
return Array.from(this.runningLanes);
|
|
12359
|
+
}
|
|
12360
|
+
scheduleLane(laneKey) {
|
|
12361
|
+
if (this.isStopped)
|
|
12362
|
+
return;
|
|
12363
|
+
if (this.runningLanes.has(laneKey))
|
|
12364
|
+
return;
|
|
12365
|
+
this.runningLanes.add(laneKey);
|
|
12366
|
+
const tail = this.runLane(laneKey).catch((err) => {
|
|
12367
|
+
console.error(`[EventHandler] lane ${laneKey} 处理异常:`, err);
|
|
12368
|
+
}).finally(() => {
|
|
12369
|
+
this.runningLanes.delete(laneKey);
|
|
12370
|
+
this.laneTails.delete(laneKey);
|
|
12371
|
+
const rest = this.lanes.get(laneKey);
|
|
12372
|
+
if (rest && rest.length > 0) {
|
|
12373
|
+
this.scheduleLane(laneKey);
|
|
11924
12374
|
}
|
|
11925
|
-
|
|
11926
|
-
|
|
12375
|
+
});
|
|
12376
|
+
this.laneTails.set(laneKey, tail);
|
|
12377
|
+
}
|
|
12378
|
+
async runLane(laneKey) {
|
|
12379
|
+
while (!this.isStopped) {
|
|
12380
|
+
const lane = this.lanes.get(laneKey);
|
|
12381
|
+
if (!lane || lane.length === 0) {
|
|
11927
12382
|
break;
|
|
11928
12383
|
}
|
|
11929
|
-
|
|
11930
|
-
|
|
11931
|
-
|
|
11932
|
-
|
|
11933
|
-
|
|
11934
|
-
|
|
11935
|
-
|
|
11936
|
-
|
|
11937
|
-
|
|
12384
|
+
const head = lane[0];
|
|
12385
|
+
const sessionId = await runWithEnvContextAsync(head.envContext, () => this.resolveSessionForItem(laneKey, head));
|
|
12386
|
+
if (this.isStopped)
|
|
12387
|
+
break;
|
|
12388
|
+
const canonicalKey = sessionId ?? laneKey;
|
|
12389
|
+
if (canonicalKey !== laneKey) {
|
|
12390
|
+
const mine = this.lanes.get(laneKey) ?? [];
|
|
12391
|
+
if (mine.length > 0) {
|
|
12392
|
+
const target = this.lanes.get(canonicalKey);
|
|
12393
|
+
if (target) {
|
|
12394
|
+
target.push(...mine);
|
|
12395
|
+
} else {
|
|
12396
|
+
this.lanes.set(canonicalKey, mine);
|
|
11938
12397
|
}
|
|
12398
|
+
this.lanes.delete(laneKey);
|
|
12399
|
+
this.scheduleLane(canonicalKey);
|
|
11939
12400
|
}
|
|
11940
|
-
|
|
11941
|
-
console.warn(`[EventHandler] Failed to ensure chat-keyed session (chatId=${item.chatId}), ` + `falling back to trigger_session_id path`);
|
|
11942
|
-
sessionId = await this.ensureActiveSession(item.triggerSessionId);
|
|
11943
|
-
}
|
|
11944
|
-
} else {
|
|
11945
|
-
sessionId = await this.ensureActiveSession(item.triggerSessionId);
|
|
12401
|
+
return;
|
|
11946
12402
|
}
|
|
12403
|
+
await this.waitForIdle(sessionId ?? laneKey);
|
|
12404
|
+
if (this.isStopped)
|
|
12405
|
+
break;
|
|
12406
|
+
const claimKey = sessionId ?? laneKey;
|
|
12407
|
+
const releaseClaim = await this.claimSession(claimKey);
|
|
11947
12408
|
if (this.isStopped) {
|
|
12409
|
+
releaseClaim();
|
|
11948
12410
|
break;
|
|
11949
12411
|
}
|
|
11950
|
-
|
|
11951
|
-
|
|
12412
|
+
await this.acquireSlot();
|
|
12413
|
+
if (this.isStopped) {
|
|
12414
|
+
releaseClaim();
|
|
12415
|
+
this.releaseSlot();
|
|
12416
|
+
break;
|
|
11952
12417
|
}
|
|
11953
12418
|
try {
|
|
12419
|
+
const item = lane.shift();
|
|
12420
|
+
if (!item)
|
|
12421
|
+
break;
|
|
12422
|
+
this.inFlightCount++;
|
|
12423
|
+
try {
|
|
12424
|
+
await this.processItem(item, sessionId);
|
|
12425
|
+
} finally {
|
|
12426
|
+
this.inFlightCount--;
|
|
12427
|
+
}
|
|
12428
|
+
} finally {
|
|
12429
|
+
releaseClaim();
|
|
12430
|
+
this.releaseSlot();
|
|
12431
|
+
}
|
|
12432
|
+
}
|
|
12433
|
+
const rest = this.lanes.get(laneKey);
|
|
12434
|
+
if (!rest || rest.length === 0) {
|
|
12435
|
+
this.lanes.delete(laneKey);
|
|
12436
|
+
}
|
|
12437
|
+
}
|
|
12438
|
+
async resolveSessionForItem(laneKey, item) {
|
|
12439
|
+
if (item.sessionResolved) {
|
|
12440
|
+
return item.resolvedSessionId ?? null;
|
|
12441
|
+
}
|
|
12442
|
+
const resolved = await this.resolveSessionForItemUncached(laneKey, item);
|
|
12443
|
+
item.sessionResolved = true;
|
|
12444
|
+
item.resolvedSessionId = resolved;
|
|
12445
|
+
return resolved;
|
|
12446
|
+
}
|
|
12447
|
+
async resolveSessionForItemUncached(laneKey, item) {
|
|
12448
|
+
if (item.chatId && this.sessionComponent) {
|
|
12449
|
+
const cached = this.chatSessionCache.get(item.chatId);
|
|
12450
|
+
if (cached)
|
|
12451
|
+
return cached;
|
|
12452
|
+
let resolved = await this.ensureChatSession(item.chatId);
|
|
12453
|
+
if (!resolved) {
|
|
12454
|
+
console.warn(`[EventHandler] Failed to ensure chat-keyed session (chatId=${item.chatId}), ` + `falling back to trigger_session_id path`);
|
|
12455
|
+
resolved = await this.ensureActiveSession(item.triggerSessionId);
|
|
12456
|
+
} else {
|
|
12457
|
+
this.chatSessionCache.set(item.chatId, resolved);
|
|
12458
|
+
}
|
|
12459
|
+
return resolved;
|
|
12460
|
+
}
|
|
12461
|
+
return this.ensureActiveSession(item.triggerSessionId);
|
|
12462
|
+
}
|
|
12463
|
+
async processItem(item, sessionId) {
|
|
12464
|
+
if (sessionId) {
|
|
12465
|
+
item.eventSessionId = sessionId;
|
|
12466
|
+
}
|
|
12467
|
+
try {
|
|
12468
|
+
await runWithEnvContextAsync(item.envContext, async () => {
|
|
11954
12469
|
if (this.onEventWithEnv) {
|
|
11955
12470
|
await this.onEventWithEnv(item);
|
|
11956
|
-
|
|
12471
|
+
return;
|
|
11957
12472
|
}
|
|
11958
12473
|
await this.onEvent(item.message);
|
|
11959
|
-
}
|
|
11960
|
-
|
|
11961
|
-
|
|
11962
|
-
|
|
11963
|
-
|
|
11964
|
-
|
|
11965
|
-
|
|
11966
|
-
|
|
11967
|
-
}
|
|
11968
|
-
|
|
11969
|
-
|
|
12474
|
+
});
|
|
12475
|
+
} catch (error) {
|
|
12476
|
+
console.error(`[EventHandler] 处理事件失败:`, error);
|
|
12477
|
+
try {
|
|
12478
|
+
await notifyReactFailure2({
|
|
12479
|
+
error,
|
|
12480
|
+
envEvent: item.envEvent,
|
|
12481
|
+
sessionId: sessionId ?? undefined
|
|
12482
|
+
});
|
|
12483
|
+
} catch (notifyErr) {
|
|
12484
|
+
console.error(`[EventHandler] 失败说明回飞书异常:`, notifyErr);
|
|
11970
12485
|
}
|
|
11971
12486
|
}
|
|
11972
|
-
|
|
12487
|
+
}
|
|
12488
|
+
async processQueue() {
|
|
12489
|
+
if (this.isStopped)
|
|
12490
|
+
return;
|
|
12491
|
+
if (this.legacyQueue.length > 0) {
|
|
12492
|
+
const pending = this.legacyQueue.splice(0, this.legacyQueue.length);
|
|
12493
|
+
for (const item of pending) {
|
|
12494
|
+
if (!item.envContext) {
|
|
12495
|
+
item.envContext = getEnvContext();
|
|
12496
|
+
}
|
|
12497
|
+
const laneKey = this.laneKeyFor(item);
|
|
12498
|
+
const lane = this.lanes.get(laneKey);
|
|
12499
|
+
if (lane)
|
|
12500
|
+
lane.push(item);
|
|
12501
|
+
else
|
|
12502
|
+
this.lanes.set(laneKey, [item]);
|
|
12503
|
+
}
|
|
12504
|
+
}
|
|
12505
|
+
for (const [laneKey, lane] of Array.from(this.lanes.entries())) {
|
|
12506
|
+
if (lane.length > 0)
|
|
12507
|
+
this.scheduleLane(laneKey);
|
|
12508
|
+
}
|
|
12509
|
+
const tails = Array.from(this.laneTails.values());
|
|
12510
|
+
if (tails.length > 0) {
|
|
12511
|
+
await Promise.all(tails.map((t) => t.catch(() => {
|
|
12512
|
+
return;
|
|
12513
|
+
})));
|
|
12514
|
+
}
|
|
12515
|
+
}
|
|
12516
|
+
async acquireSlot() {
|
|
12517
|
+
if (this.activeSlots < this.maxConcurrentSessions) {
|
|
12518
|
+
this.activeSlots++;
|
|
12519
|
+
return;
|
|
12520
|
+
}
|
|
12521
|
+
await new Promise((resolve) => {
|
|
12522
|
+
this.slotWaiters.push(resolve);
|
|
12523
|
+
});
|
|
12524
|
+
this.activeSlots++;
|
|
12525
|
+
}
|
|
12526
|
+
releaseSlot() {
|
|
12527
|
+
if (this.activeSlots > 0)
|
|
12528
|
+
this.activeSlots--;
|
|
12529
|
+
const next = this.slotWaiters.shift();
|
|
12530
|
+
if (next)
|
|
12531
|
+
next();
|
|
11973
12532
|
}
|
|
11974
12533
|
async ensureActiveSession(triggerSessionIdOverride) {
|
|
11975
12534
|
if (!this.sessionComponent)
|
|
@@ -12079,6 +12638,7 @@ class EventHandler {
|
|
|
12079
12638
|
clearActiveSession() {
|
|
12080
12639
|
this.activeEventSessionId = null;
|
|
12081
12640
|
this.resolvedSessionByTrigger.clear();
|
|
12641
|
+
this.chatSessionCache.clear();
|
|
12082
12642
|
}
|
|
12083
12643
|
cacheResolvedSession(triggerSessionIdOverride, sessionId) {
|
|
12084
12644
|
if (triggerSessionIdOverride && sessionId) {
|
|
@@ -12088,11 +12648,38 @@ class EventHandler {
|
|
|
12088
12648
|
getActiveEventSessionId() {
|
|
12089
12649
|
return this.activeEventSessionId;
|
|
12090
12650
|
}
|
|
12091
|
-
async waitForIdle() {
|
|
12092
|
-
while (!this.isStopped && !this.
|
|
12651
|
+
async waitForIdle(sessionId) {
|
|
12652
|
+
while (!this.isStopped && !this.isLaneIdle(sessionId)) {
|
|
12093
12653
|
await this.sleep(this.idleCheckInterval);
|
|
12094
12654
|
}
|
|
12095
12655
|
}
|
|
12656
|
+
isLaneIdle(sessionId) {
|
|
12657
|
+
if (this.isSessionIdleFn && sessionId) {
|
|
12658
|
+
return this.isSessionIdleFn(sessionId);
|
|
12659
|
+
}
|
|
12660
|
+
return this.isIdle();
|
|
12661
|
+
}
|
|
12662
|
+
claimSession(sessionKey) {
|
|
12663
|
+
const prev = this.sessionChains.get(sessionKey) ?? Promise.resolve();
|
|
12664
|
+
let releaseFn;
|
|
12665
|
+
const current = new Promise((resolve) => {
|
|
12666
|
+
releaseFn = resolve;
|
|
12667
|
+
});
|
|
12668
|
+
const tail = prev.then(() => current);
|
|
12669
|
+
this.sessionChains.set(sessionKey, tail);
|
|
12670
|
+
return prev.then(() => {
|
|
12671
|
+
let released = false;
|
|
12672
|
+
return () => {
|
|
12673
|
+
if (released)
|
|
12674
|
+
return;
|
|
12675
|
+
released = true;
|
|
12676
|
+
releaseFn();
|
|
12677
|
+
if (this.sessionChains.get(sessionKey) === tail) {
|
|
12678
|
+
this.sessionChains.delete(sessionKey);
|
|
12679
|
+
}
|
|
12680
|
+
};
|
|
12681
|
+
});
|
|
12682
|
+
}
|
|
12096
12683
|
sleep(ms) {
|
|
12097
12684
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
12098
12685
|
}
|
|
@@ -12105,6 +12692,14 @@ __legacyDecorateClassTS([
|
|
|
12105
12692
|
]),
|
|
12106
12693
|
__legacyMetadataTS("design:returntype", typeof Promise === "undefined" ? Object : Promise)
|
|
12107
12694
|
], EventHandler.prototype, "handleEvent", null);
|
|
12695
|
+
__legacyDecorateClassTS([
|
|
12696
|
+
TracedAs5("event_handler.telemetry_notice", { recordParams: true, recordResult: false }),
|
|
12697
|
+
__legacyMetadataTS("design:type", Function),
|
|
12698
|
+
__legacyMetadataTS("design:paramtypes", [
|
|
12699
|
+
typeof EnvEvent === "undefined" ? Object : EnvEvent
|
|
12700
|
+
]),
|
|
12701
|
+
__legacyMetadataTS("design:returntype", typeof Promise === "undefined" ? Object : Promise)
|
|
12702
|
+
], EventHandler.prototype, "sendTelemetryNotice", null);
|
|
12108
12703
|
__legacyDecorateClassTS([
|
|
12109
12704
|
TracedAs5("cli.event-handler.formatEvent", { recordParams: true, recordResult: false }),
|
|
12110
12705
|
__legacyMetadataTS("design:type", Function),
|
|
@@ -12187,12 +12782,24 @@ function createEventHandlerForInteractive(options) {
|
|
|
12187
12782
|
const dbPath = options.dbPath ?? createDefaultEventStoreDbPath();
|
|
12188
12783
|
const eventStore = getOrCreateEventStore(dbPath);
|
|
12189
12784
|
const getHandlerForEsType = getHandlerForEsTypeForEnv(options.env);
|
|
12785
|
+
const maxConcurrentSessions = options.maxConcurrentSessions ?? readMaxConcurrentSessionsFromEnv();
|
|
12190
12786
|
return new EventHandler({
|
|
12191
12787
|
...options,
|
|
12788
|
+
...maxConcurrentSessions !== undefined ? { maxConcurrentSessions } : {},
|
|
12192
12789
|
eventStore,
|
|
12193
12790
|
getHandlerForEsType
|
|
12194
12791
|
});
|
|
12195
12792
|
}
|
|
12793
|
+
var MAX_CONCURRENT_SESSIONS_ENV = "ROY_AGENT_MAX_CONCURRENT_SESSIONS";
|
|
12794
|
+
function readMaxConcurrentSessionsFromEnv(env = process.env) {
|
|
12795
|
+
const raw = env[MAX_CONCURRENT_SESSIONS_ENV];
|
|
12796
|
+
if (raw === undefined || raw.trim() === "")
|
|
12797
|
+
return;
|
|
12798
|
+
const parsed = Number(raw);
|
|
12799
|
+
if (!Number.isFinite(parsed) || parsed < 1)
|
|
12800
|
+
return;
|
|
12801
|
+
return Math.max(1, Math.floor(parsed));
|
|
12802
|
+
}
|
|
12196
12803
|
|
|
12197
12804
|
// src/commands/shared/esc-active-descendant.ts
|
|
12198
12805
|
function hasActiveDescendants(env, parentSessionId) {
|
|
@@ -12865,7 +13472,8 @@ var USER_PROMPT = COLORS.accent("❯ ");
|
|
|
12865
13472
|
class REPL {
|
|
12866
13473
|
rl;
|
|
12867
13474
|
options;
|
|
12868
|
-
|
|
13475
|
+
executingSessions = new Map;
|
|
13476
|
+
static LEGACY_SESSION_KEY = "__legacy_isExecuting__";
|
|
12869
13477
|
replMode = "ready";
|
|
12870
13478
|
statusBarCtx = {};
|
|
12871
13479
|
isAltEnterPending = false;
|
|
@@ -13058,7 +13666,10 @@ ${COLORS.system("[正在中断...]")}`);
|
|
|
13058
13666
|
}
|
|
13059
13667
|
}
|
|
13060
13668
|
abortStream();
|
|
13061
|
-
this.
|
|
13669
|
+
for (const sid of this.getExecutingSessionIds()) {
|
|
13670
|
+
abortStream(sid);
|
|
13671
|
+
}
|
|
13672
|
+
this.abortAllExecutingSessions();
|
|
13062
13673
|
console.log(`${COLORS.system("[已中断,可以继续输入]")}`);
|
|
13063
13674
|
} else {
|
|
13064
13675
|
console.log(`
|
|
@@ -13143,7 +13754,8 @@ ${COLORS.system("[没有正在执行的请求]")}`);
|
|
|
13143
13754
|
this.inkApi = api;
|
|
13144
13755
|
},
|
|
13145
13756
|
onSubmit: async (input) => {
|
|
13146
|
-
|
|
13757
|
+
const inkSessionId = this.options.sessionId;
|
|
13758
|
+
this.markSessionExecuting(inkSessionId, true);
|
|
13147
13759
|
inkApiRef?.setMode("executing");
|
|
13148
13760
|
try {
|
|
13149
13761
|
await this.options.onExecute(input);
|
|
@@ -13161,7 +13773,7 @@ ${COLORS.system("[没有正在执行的请求]")}`);
|
|
|
13161
13773
|
inkApiRef?.appendMessage({ role: "system", content: `[Error] ${msg}` });
|
|
13162
13774
|
throw err;
|
|
13163
13775
|
} finally {
|
|
13164
|
-
this.
|
|
13776
|
+
this.markSessionExecuting(inkSessionId, false);
|
|
13165
13777
|
}
|
|
13166
13778
|
},
|
|
13167
13779
|
onCommand: async (cmd) => {
|
|
@@ -13314,7 +13926,8 @@ ${COLORS.error("❓ 未知命令: /" + cmd + "}")}`);
|
|
|
13314
13926
|
}
|
|
13315
13927
|
}
|
|
13316
13928
|
async handleMessage(message) {
|
|
13317
|
-
|
|
13929
|
+
const inputSessionId = this.options.sessionId;
|
|
13930
|
+
if (!this.isSessionIdle(inputSessionId)) {
|
|
13318
13931
|
console.log(`
|
|
13319
13932
|
${COLORS.system("⏳ 上一次请求尚未完成,请稍候...")}
|
|
13320
13933
|
`);
|
|
@@ -13381,7 +13994,7 @@ ${COLORS.system("[通知2] ❯ " + message.replace(/\n/g, `
|
|
|
13381
13994
|
};
|
|
13382
13995
|
}
|
|
13383
13996
|
}
|
|
13384
|
-
|
|
13997
|
+
const agentContext = {
|
|
13385
13998
|
agentType: agentFromEvent,
|
|
13386
13999
|
pluginEnabled,
|
|
13387
14000
|
envEvent: envEventForAgent,
|
|
@@ -13389,9 +14002,12 @@ ${COLORS.system("[通知2] ❯ " + message.replace(/\n/g, `
|
|
|
13389
14002
|
eventSessionId,
|
|
13390
14003
|
systemPrompt: envEvent.metadata?.systemPrompt
|
|
13391
14004
|
};
|
|
13392
|
-
await this.executeInternal(message, {
|
|
14005
|
+
await this.executeInternal(message, {
|
|
14006
|
+
showPrompt: true,
|
|
14007
|
+
sessionId: eventSessionId,
|
|
14008
|
+
agentContext
|
|
14009
|
+
});
|
|
13393
14010
|
}
|
|
13394
|
-
currentAgentContext = undefined;
|
|
13395
14011
|
lastReplyChannel = undefined;
|
|
13396
14012
|
lastReplyChannelByChat = new Map;
|
|
13397
14013
|
static REPLY_CHANNEL_CHAT_CACHE_MAX = 100;
|
|
@@ -13410,7 +14026,56 @@ ${COLORS.system("[通知2] ❯ " + message.replace(/\n/g, `
|
|
|
13410
14026
|
}
|
|
13411
14027
|
}
|
|
13412
14028
|
isIdle() {
|
|
13413
|
-
return !this.
|
|
14029
|
+
return !this.anySessionBusy();
|
|
14030
|
+
}
|
|
14031
|
+
anySessionBusy() {
|
|
14032
|
+
for (const count of this.execSet().values()) {
|
|
14033
|
+
if (count > 0)
|
|
14034
|
+
return true;
|
|
14035
|
+
}
|
|
14036
|
+
return false;
|
|
14037
|
+
}
|
|
14038
|
+
execSet() {
|
|
14039
|
+
if (!this.executingSessions)
|
|
14040
|
+
this.executingSessions = new Map;
|
|
14041
|
+
return this.executingSessions;
|
|
14042
|
+
}
|
|
14043
|
+
get isExecuting() {
|
|
14044
|
+
return this.anySessionBusy();
|
|
14045
|
+
}
|
|
14046
|
+
set isExecuting(executing) {
|
|
14047
|
+
if (!executing) {
|
|
14048
|
+
this.execSet().clear();
|
|
14049
|
+
return;
|
|
14050
|
+
}
|
|
14051
|
+
this.execSet().set(REPL.LEGACY_SESSION_KEY, 1);
|
|
14052
|
+
}
|
|
14053
|
+
markSessionExecuting(sessionId, executing) {
|
|
14054
|
+
const counts = this.execSet();
|
|
14055
|
+
if (executing) {
|
|
14056
|
+
counts.set(sessionId, (counts.get(sessionId) ?? 0) + 1);
|
|
14057
|
+
return;
|
|
14058
|
+
}
|
|
14059
|
+
const current = counts.get(sessionId) ?? 0;
|
|
14060
|
+
if (current <= 1) {
|
|
14061
|
+
counts.delete(sessionId);
|
|
14062
|
+
} else {
|
|
14063
|
+
counts.set(sessionId, current - 1);
|
|
14064
|
+
}
|
|
14065
|
+
}
|
|
14066
|
+
isSessionIdle(sessionId) {
|
|
14067
|
+
return (this.execSet().get(sessionId) ?? 0) <= 0;
|
|
14068
|
+
}
|
|
14069
|
+
getExecutingSessionIds() {
|
|
14070
|
+
const ids = [];
|
|
14071
|
+
for (const [sid, count] of this.execSet().entries()) {
|
|
14072
|
+
if (count > 0)
|
|
14073
|
+
ids.push(sid);
|
|
14074
|
+
}
|
|
14075
|
+
return ids;
|
|
14076
|
+
}
|
|
14077
|
+
abortAllExecutingSessions() {
|
|
14078
|
+
this.execSet().clear();
|
|
13414
14079
|
}
|
|
13415
14080
|
setMode(mode, detail) {
|
|
13416
14081
|
this.replMode = mode;
|
|
@@ -13433,30 +14098,37 @@ ${COLORS.system("[通知2] ❯ " + message.replace(/\n/g, `
|
|
|
13433
14098
|
}));
|
|
13434
14099
|
}
|
|
13435
14100
|
async executeInternal(message, options) {
|
|
13436
|
-
|
|
13437
|
-
|
|
13438
|
-
|
|
13439
|
-
|
|
14101
|
+
const execSessionId = options.sessionId ?? this.options.sessionId;
|
|
14102
|
+
const agentContext = {
|
|
14103
|
+
...options.agentContext,
|
|
14104
|
+
eventSessionId: options.agentContext?.eventSessionId ?? execSessionId
|
|
14105
|
+
};
|
|
13440
14106
|
resetStreamAbort();
|
|
13441
14107
|
const provider = getTracerProvider3();
|
|
13442
14108
|
const tracer = provider.getTracer("roy-tracer");
|
|
13443
|
-
const
|
|
14109
|
+
const payloadTraceContext = agentContext?.envEvent?.metadata?.traceContext;
|
|
14110
|
+
const existingContext = payloadTraceContext ?? provider.getGlobalContext();
|
|
13444
14111
|
let rootSpan;
|
|
13445
14112
|
let traceId;
|
|
13446
|
-
|
|
13447
|
-
rootSpan = tracer.startSpan("interactive.execute", {
|
|
13448
|
-
parent: existingContext
|
|
13449
|
-
});
|
|
13450
|
-
traceId = existingContext.traceId;
|
|
13451
|
-
} else {
|
|
13452
|
-
rootSpan = tracer.startSpan("interactive.execute");
|
|
13453
|
-
traceId = rootSpan.spanContext.traceId;
|
|
13454
|
-
provider.setGlobalContext(rootSpan.spanContext);
|
|
13455
|
-
}
|
|
13456
|
-
console.log(`${COLORS.system("[Trace] " + traceId)}`);
|
|
13457
|
-
console.log(`${COLORS.progress("[thinking...]")}`);
|
|
14113
|
+
let runTraceContext = existingContext;
|
|
13458
14114
|
try {
|
|
13459
|
-
|
|
14115
|
+
this.markSessionExecuting(execSessionId, true);
|
|
14116
|
+
this.setMode("executing");
|
|
14117
|
+
await provider.withGlobalContext(runTraceContext, async () => {
|
|
14118
|
+
if (existingContext) {
|
|
14119
|
+
rootSpan = tracer.startSpan("interactive.execute", {
|
|
14120
|
+
parent: existingContext
|
|
14121
|
+
});
|
|
14122
|
+
traceId = existingContext.traceId;
|
|
14123
|
+
} else {
|
|
14124
|
+
rootSpan = tracer.startSpan("interactive.execute");
|
|
14125
|
+
traceId = rootSpan.spanContext.traceId;
|
|
14126
|
+
runTraceContext = rootSpan.spanContext;
|
|
14127
|
+
}
|
|
14128
|
+
console.log(`${COLORS.system("[Trace] " + traceId)}`);
|
|
14129
|
+
console.log(`${COLORS.progress("[thinking...]")}`);
|
|
14130
|
+
await this.options.onExecute(message, traceId, agentContext);
|
|
14131
|
+
});
|
|
13460
14132
|
if (this.options.onAfterExecute) {
|
|
13461
14133
|
try {
|
|
13462
14134
|
await this.options.onAfterExecute(this.lastUsage);
|
|
@@ -13472,7 +14144,7 @@ ${COLORS.system("[通知2] ❯ " + message.replace(/\n/g, `
|
|
|
13472
14144
|
console.error(`
|
|
13473
14145
|
${COLORS.error("❌ 执行失败: " + error)}
|
|
13474
14146
|
`);
|
|
13475
|
-
rootSpan
|
|
14147
|
+
rootSpan?.setAttribute("error", String(error));
|
|
13476
14148
|
try {
|
|
13477
14149
|
await notifyReactFailure3({
|
|
13478
14150
|
error,
|
|
@@ -13484,14 +14156,15 @@ ${COLORS.error("❌ 执行失败: " + error)}
|
|
|
13484
14156
|
}
|
|
13485
14157
|
}
|
|
13486
14158
|
} finally {
|
|
13487
|
-
|
|
13488
|
-
|
|
13489
|
-
|
|
13490
|
-
|
|
13491
|
-
|
|
14159
|
+
try {
|
|
14160
|
+
provider.runInGlobalContextSync(runTraceContext, () => rootSpan?.end());
|
|
14161
|
+
} catch (endErr) {
|
|
14162
|
+
logger6.warn("root span end failed (ignored)", { error: String(endErr) });
|
|
14163
|
+
}
|
|
14164
|
+
this.markSessionExecuting(execSessionId, false);
|
|
14165
|
+
if (this.isIdle()) {
|
|
14166
|
+
this.setMode("ready");
|
|
13492
14167
|
}
|
|
13493
|
-
this.isExecuting = false;
|
|
13494
|
-
this.setMode("ready");
|
|
13495
14168
|
if (options.showPrompt) {
|
|
13496
14169
|
this.redrawInputArea();
|
|
13497
14170
|
if (this.rl) {
|
|
@@ -13661,6 +14334,9 @@ ${COLORS.error("❌ 执行失败: " + error)}
|
|
|
13661
14334
|
}
|
|
13662
14335
|
}
|
|
13663
14336
|
abortStream();
|
|
14337
|
+
for (const sid of this.getExecutingSessionIds()) {
|
|
14338
|
+
abortStream(sid);
|
|
14339
|
+
}
|
|
13664
14340
|
if (this.inkApi && typeof this.inkApi.finishAssistantStream === "function") {
|
|
13665
14341
|
try {
|
|
13666
14342
|
this.inkApi.finishAssistantStream();
|
|
@@ -13687,7 +14363,7 @@ ${COLORS.error("❌ 执行失败: " + error)}
|
|
|
13687
14363
|
}
|
|
13688
14364
|
}
|
|
13689
14365
|
if (isExecuting) {
|
|
13690
|
-
this.
|
|
14366
|
+
this.abortAllExecutingSessions();
|
|
13691
14367
|
}
|
|
13692
14368
|
this.setMode("ready");
|
|
13693
14369
|
if (this.rl) {
|
|
@@ -13890,6 +14566,57 @@ function createInteractiveCommand(externalEnvService) {
|
|
|
13890
14566
|
quiet: true,
|
|
13891
14567
|
silent: useInk
|
|
13892
14568
|
});
|
|
14569
|
+
const MAX_SESSION_EXECUTORS = 16;
|
|
14570
|
+
const sessionExecutors = new Map;
|
|
14571
|
+
const runningTurns = new Set;
|
|
14572
|
+
let sessionChunkCallback = undefined;
|
|
14573
|
+
const getSessionExecutor = (sid) => {
|
|
14574
|
+
if (!sid)
|
|
14575
|
+
return queryExecutor;
|
|
14576
|
+
const cached = sessionExecutors.get(sid);
|
|
14577
|
+
if (cached) {
|
|
14578
|
+
sessionExecutors.delete(sid);
|
|
14579
|
+
sessionExecutors.set(sid, cached);
|
|
14580
|
+
return cached;
|
|
14581
|
+
}
|
|
14582
|
+
const created = new QueryExecutor({
|
|
14583
|
+
env,
|
|
14584
|
+
sessionComponent,
|
|
14585
|
+
output,
|
|
14586
|
+
quiet: true,
|
|
14587
|
+
silent: true
|
|
14588
|
+
});
|
|
14589
|
+
created.initStreamOutput(llmComponent);
|
|
14590
|
+
created.setSessionScope(sid);
|
|
14591
|
+
created.setAcceptsSidelessEvents(false);
|
|
14592
|
+
created.setChunkCallback(sessionChunkCallback);
|
|
14593
|
+
sessionExecutors.set(sid, created);
|
|
14594
|
+
while (sessionExecutors.size > MAX_SESSION_EXECUTORS) {
|
|
14595
|
+
let victim;
|
|
14596
|
+
for (const key of sessionExecutors.keys()) {
|
|
14597
|
+
if (!runningTurns.has(key)) {
|
|
14598
|
+
victim = key;
|
|
14599
|
+
break;
|
|
14600
|
+
}
|
|
14601
|
+
}
|
|
14602
|
+
if (victim === undefined)
|
|
14603
|
+
break;
|
|
14604
|
+
const evicted = sessionExecutors.get(victim);
|
|
14605
|
+
sessionExecutors.delete(victim);
|
|
14606
|
+
try {
|
|
14607
|
+
evicted?.dispose();
|
|
14608
|
+
} catch {}
|
|
14609
|
+
}
|
|
14610
|
+
return created;
|
|
14611
|
+
};
|
|
14612
|
+
const disposeSessionExecutors = () => {
|
|
14613
|
+
for (const ex of sessionExecutors.values()) {
|
|
14614
|
+
try {
|
|
14615
|
+
ex.dispose();
|
|
14616
|
+
} catch {}
|
|
14617
|
+
}
|
|
14618
|
+
sessionExecutors.clear();
|
|
14619
|
+
};
|
|
13893
14620
|
let currentAgentContext = undefined;
|
|
13894
14621
|
if (args.agent && args.agent !== "default") {
|
|
13895
14622
|
const agentComponent = env.getComponent("agent");
|
|
@@ -13992,7 +14719,8 @@ function createInteractiveCommand(externalEnvService) {
|
|
|
13992
14719
|
version: getPackageVersion(),
|
|
13993
14720
|
useInk,
|
|
13994
14721
|
onExecute: async (message, traceId, agentContext) => {
|
|
13995
|
-
|
|
14722
|
+
const runSessionId = agentContext?.eventSessionId;
|
|
14723
|
+
resetStreamAbort(runSessionId);
|
|
13996
14724
|
const preloadedPrompts = eventSourceSystemPrompts;
|
|
13997
14725
|
const eventSourceSystemPrompt = preloadedPrompts.length > 0 ? joinResolvedSystemPrompts(preloadedPrompts) : undefined;
|
|
13998
14726
|
const mergedContext = {
|
|
@@ -14007,16 +14735,27 @@ function createInteractiveCommand(externalEnvService) {
|
|
|
14007
14735
|
}
|
|
14008
14736
|
};
|
|
14009
14737
|
const effectiveSessionId = mergedContext.eventSessionId ?? sessionId;
|
|
14010
|
-
const
|
|
14011
|
-
|
|
14012
|
-
|
|
14013
|
-
|
|
14014
|
-
|
|
14015
|
-
|
|
14016
|
-
|
|
14738
|
+
const isEventDrivenTurn = !!runSessionId && runSessionId !== sessionId;
|
|
14739
|
+
const exec2 = isEventDrivenTurn ? getSessionExecutor(effectiveSessionId) : queryExecutor;
|
|
14740
|
+
runningTurns.add(effectiveSessionId);
|
|
14741
|
+
try {
|
|
14742
|
+
const result = await exec2.execute(message, effectiveSessionId, {
|
|
14743
|
+
showReasoning: args.reasoning,
|
|
14744
|
+
showToolCalls: args.toolCalls,
|
|
14745
|
+
showToolResults: args.toolResults
|
|
14746
|
+
}, traceId, mergedContext);
|
|
14747
|
+
if (result && !exec2.getFullText()) {
|
|
14748
|
+
console.log(result);
|
|
14749
|
+
} else if (isEventDrivenTurn) {
|
|
14750
|
+
const full = exec2.getFullText();
|
|
14751
|
+
if (full)
|
|
14752
|
+
console.log(full);
|
|
14753
|
+
}
|
|
14754
|
+
repl.setLastUsage(exec2.getLastUsage());
|
|
14755
|
+
return result;
|
|
14756
|
+
} finally {
|
|
14757
|
+
runningTurns.delete(effectiveSessionId);
|
|
14017
14758
|
}
|
|
14018
|
-
repl.setLastUsage(queryExecutor.getLastUsage());
|
|
14019
|
-
return result;
|
|
14020
14759
|
},
|
|
14021
14760
|
onAfterExecute: (usage) => {
|
|
14022
14761
|
if (useInk)
|
|
@@ -14041,6 +14780,7 @@ function createInteractiveCommand(externalEnvService) {
|
|
|
14041
14780
|
onSwitchSession: async (newSessionId) => {
|
|
14042
14781
|
const result = await sessionManager.switchSession(newSessionId);
|
|
14043
14782
|
queryExecutor.dispose();
|
|
14783
|
+
disposeSessionExecutors();
|
|
14044
14784
|
return result;
|
|
14045
14785
|
},
|
|
14046
14786
|
onCompact: async () => {
|
|
@@ -14090,6 +14830,7 @@ function createInteractiveCommand(externalEnvService) {
|
|
|
14090
14830
|
eventTypes: ["task.background.*", "event-source.event.*"],
|
|
14091
14831
|
formatter: new EventMessageFormatter({ prefix: "[通知]" }),
|
|
14092
14832
|
isIdle: () => repl.isIdle(),
|
|
14833
|
+
isSessionIdle: (sid) => repl.isSessionIdle(sid),
|
|
14093
14834
|
sessionComponent,
|
|
14094
14835
|
onEvent: async (_message) => {},
|
|
14095
14836
|
onEventWithEnv: async (formattedEvent) => {
|
|
@@ -14123,6 +14864,20 @@ function createInteractiveCommand(externalEnvService) {
|
|
|
14123
14864
|
repl.sessionManager = sessionManager;
|
|
14124
14865
|
repl.sessionComponent = sessionComponent;
|
|
14125
14866
|
repl._queryExecutor = queryExecutor;
|
|
14867
|
+
{
|
|
14868
|
+
let inkCb = null;
|
|
14869
|
+
Object.defineProperty(repl, "inkChunkCallback", {
|
|
14870
|
+
configurable: true,
|
|
14871
|
+
get: () => inkCb,
|
|
14872
|
+
set: (cb) => {
|
|
14873
|
+
inkCb = cb;
|
|
14874
|
+
sessionChunkCallback = cb ?? undefined;
|
|
14875
|
+
for (const ex of sessionExecutors.values()) {
|
|
14876
|
+
ex.setChunkCallback(sessionChunkCallback);
|
|
14877
|
+
}
|
|
14878
|
+
}
|
|
14879
|
+
});
|
|
14880
|
+
}
|
|
14126
14881
|
await repl.start();
|
|
14127
14882
|
process.removeListener("SIGINT", sigintHandler);
|
|
14128
14883
|
console.log("正在清理资源...");
|
|
@@ -14134,6 +14889,7 @@ function createInteractiveCommand(externalEnvService) {
|
|
|
14134
14889
|
}
|
|
14135
14890
|
eventHandler.stop();
|
|
14136
14891
|
queryExecutor.dispose();
|
|
14892
|
+
disposeSessionExecutors();
|
|
14137
14893
|
const esComponent = env.getComponent("event-source");
|
|
14138
14894
|
if (esComponent) {
|
|
14139
14895
|
const sources = esComponent.list?.();
|
|
@@ -15501,6 +16257,7 @@ async function loadHandleQuery(options, hooks) {
|
|
|
15501
16257
|
const llmComponent = envService.getLLM();
|
|
15502
16258
|
queryExecutor.initStreamOutput(llmComponent ?? null);
|
|
15503
16259
|
const handleQuery = async (message, envEvent) => {
|
|
16260
|
+
const eventTraceContext = envEvent?.metadata?.traceContext;
|
|
15504
16261
|
const mergedContext = {
|
|
15505
16262
|
...agentContext,
|
|
15506
16263
|
model: options.model,
|
|
@@ -15515,7 +16272,7 @@ async function loadHandleQuery(options, hooks) {
|
|
|
15515
16272
|
showReasoning: options.reasoning ?? true,
|
|
15516
16273
|
showToolCalls: options.toolCalls ?? true,
|
|
15517
16274
|
showToolResults: options.toolResults ?? false
|
|
15518
|
-
},
|
|
16275
|
+
}, eventTraceContext?.traceId, mergedContext);
|
|
15519
16276
|
return String(result ?? "");
|
|
15520
16277
|
};
|
|
15521
16278
|
const taskEventHandler = new TaskEventHandler({
|
|
@@ -15592,6 +16349,7 @@ function createStreamHandleQuery(queryExecutor, sessionId, options, agentContext
|
|
|
15592
16349
|
break;
|
|
15593
16350
|
}
|
|
15594
16351
|
});
|
|
16352
|
+
const eventTraceContext = envEvent?.metadata?.traceContext;
|
|
15595
16353
|
const mergedContext = {
|
|
15596
16354
|
...agentContext,
|
|
15597
16355
|
model: options.model,
|
|
@@ -15606,7 +16364,7 @@ function createStreamHandleQuery(queryExecutor, sessionId, options, agentContext
|
|
|
15606
16364
|
showReasoning: options.reasoning ?? true,
|
|
15607
16365
|
showToolCalls: true,
|
|
15608
16366
|
showToolResults: true
|
|
15609
|
-
},
|
|
16367
|
+
}, eventTraceContext?.traceId, mergedContext);
|
|
15610
16368
|
return String(result ?? "");
|
|
15611
16369
|
};
|
|
15612
16370
|
}
|