@omercnet/paseo-omp 0.4.0-next.114.1 → 0.4.0-next.119.1
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/package.json +3 -1
- package/server/package-version.ts +1 -1
- package/server/provider/connection.ts +28 -1
- package/server/provider/omp-rpc.ts +792 -178
- package/server/provider/session-descriptors.ts +52 -18
- package/server/provider/session.ts +12 -1
- package/server/provider/subsessions.ts +28 -6
- package/server/provider/timeline-projector.ts +94 -24
|
@@ -2,7 +2,7 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import { constants, type Dir } from "node:fs";
|
|
3
3
|
import { type FileHandle, lstat, open, opendir, realpath } from "node:fs/promises";
|
|
4
4
|
import { homedir } from "node:os";
|
|
5
|
-
import { basename,
|
|
5
|
+
import { basename, isAbsolute, join, relative, resolve } from "node:path";
|
|
6
6
|
import { ompSessionDir } from "../paths";
|
|
7
7
|
import { isValidImagePayload } from "./image";
|
|
8
8
|
|
|
@@ -510,16 +510,19 @@ interface PersistedTranscriptNode {
|
|
|
510
510
|
message?: unknown;
|
|
511
511
|
}
|
|
512
512
|
|
|
513
|
-
function persistedTranscriptMessage(record: Record<string, unknown>, entryId
|
|
513
|
+
function persistedTranscriptMessage(record: Record<string, unknown>, entryId?: string): unknown {
|
|
514
514
|
if (record.type === "message") {
|
|
515
515
|
if (!record.message || typeof record.message !== "object" || Array.isArray(record.message))
|
|
516
516
|
return;
|
|
517
|
-
return {
|
|
517
|
+
return {
|
|
518
|
+
...(record.message as Record<string, unknown>),
|
|
519
|
+
...(entryId ? { entryId } : {}),
|
|
520
|
+
};
|
|
518
521
|
}
|
|
519
522
|
if (record.type !== "custom_message") return;
|
|
520
523
|
return {
|
|
521
524
|
role: "custom",
|
|
522
|
-
entryId,
|
|
525
|
+
...(entryId ? { entryId } : {}),
|
|
523
526
|
customType: record.customType,
|
|
524
527
|
content: record.content,
|
|
525
528
|
display: record.display,
|
|
@@ -680,6 +683,7 @@ export async function readOmpPersistedSubagentTranscript(
|
|
|
680
683
|
childTranscriptId: string,
|
|
681
684
|
cwd: string,
|
|
682
685
|
signal?: AbortSignal,
|
|
686
|
+
childSessionFile?: string,
|
|
683
687
|
): Promise<OmpPersistedSubagentTranscript> {
|
|
684
688
|
signal?.throwIfAborted();
|
|
685
689
|
if (
|
|
@@ -687,7 +691,12 @@ export async function readOmpPersistedSubagentTranscript(
|
|
|
687
691
|
!parentSessionFile.endsWith(".jsonl") ||
|
|
688
692
|
parentSessionFile.includes("\0") ||
|
|
689
693
|
!CHILD_TRANSCRIPT_ID.test(childTranscriptId) ||
|
|
690
|
-
basename(childTranscriptId) !== childTranscriptId
|
|
694
|
+
basename(childTranscriptId) !== childTranscriptId ||
|
|
695
|
+
(childSessionFile !== undefined &&
|
|
696
|
+
(!isAbsolute(childSessionFile) ||
|
|
697
|
+
!childSessionFile.endsWith(".jsonl") ||
|
|
698
|
+
childSessionFile.includes("\0") ||
|
|
699
|
+
basename(childSessionFile) !== `${childTranscriptId}.jsonl`))
|
|
691
700
|
) {
|
|
692
701
|
throw new Error("Invalid OMP child transcript descriptor");
|
|
693
702
|
}
|
|
@@ -707,34 +716,53 @@ export async function readOmpPersistedSubagentTranscript(
|
|
|
707
716
|
await parentHandle.close().catch(() => undefined);
|
|
708
717
|
}
|
|
709
718
|
const canonicalParent = await realpath(parentSessionFile);
|
|
710
|
-
const
|
|
711
|
-
const expectedDirectory = canonicalParent.slice(0, -parentExtension.length);
|
|
719
|
+
const expectedDirectory = canonicalParent.slice(0, -".jsonl".length);
|
|
712
720
|
const canonicalDirectory = await realpath(expectedDirectory).catch(() => undefined);
|
|
713
721
|
if (!canonicalDirectory || canonicalDirectory !== expectedDirectory) {
|
|
714
722
|
throw new Error("OMP child transcript directory is not canonically owned by its parent");
|
|
715
723
|
}
|
|
716
|
-
const
|
|
724
|
+
const requestedFile = resolve(
|
|
725
|
+
childSessionFile ?? join(canonicalDirectory, `${childTranscriptId}.jsonl`),
|
|
726
|
+
);
|
|
717
727
|
let handle: FileHandle;
|
|
718
728
|
try {
|
|
719
729
|
handle = await open(
|
|
720
|
-
|
|
730
|
+
requestedFile,
|
|
721
731
|
constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0) | (constants.O_NONBLOCK ?? 0),
|
|
722
732
|
);
|
|
723
733
|
} catch {
|
|
724
734
|
throw new Error("OMP child transcript could not be opened");
|
|
725
735
|
}
|
|
726
736
|
try {
|
|
727
|
-
const [stat, canonicalChild] = await Promise.all([
|
|
737
|
+
const [stat, pathStat, canonicalChild] = await Promise.all([
|
|
738
|
+
handle.stat(),
|
|
739
|
+
lstat(requestedFile),
|
|
740
|
+
realpath(requestedFile),
|
|
741
|
+
]);
|
|
728
742
|
if (
|
|
729
743
|
!stat.isFile() ||
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
744
|
+
!pathStat.isFile() ||
|
|
745
|
+
pathStat.isSymbolicLink() ||
|
|
746
|
+
stat.dev !== pathStat.dev ||
|
|
747
|
+
stat.ino !== pathStat.ino ||
|
|
748
|
+
stat.size > MAX_CHILD_TRANSCRIPT_BYTES
|
|
733
749
|
) {
|
|
734
750
|
throw new Error("OMP child transcript failed ownership validation");
|
|
735
751
|
}
|
|
736
|
-
const
|
|
737
|
-
|
|
752
|
+
const canonicalRelativeChild = relative(canonicalDirectory, canonicalChild);
|
|
753
|
+
if (
|
|
754
|
+
!canonicalRelativeChild ||
|
|
755
|
+
canonicalRelativeChild.startsWith("..") ||
|
|
756
|
+
isAbsolute(canonicalRelativeChild)
|
|
757
|
+
) {
|
|
758
|
+
throw new Error("OMP child transcript failed ownership validation");
|
|
759
|
+
}
|
|
760
|
+
const bytes = await readStableFile(
|
|
761
|
+
handle,
|
|
762
|
+
stat.size,
|
|
763
|
+
signal,
|
|
764
|
+
"OMP child transcript changed while reading",
|
|
765
|
+
);
|
|
738
766
|
const text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
739
767
|
const messages: unknown[] = [];
|
|
740
768
|
let nativeSessionId: string | undefined;
|
|
@@ -752,15 +780,21 @@ export async function readOmpPersistedSubagentTranscript(
|
|
|
752
780
|
nativeSessionId ??= candidateId;
|
|
753
781
|
if (nativeSessionId !== candidateId)
|
|
754
782
|
throw new Error("OMP child transcript identity changed");
|
|
755
|
-
} else
|
|
783
|
+
} else {
|
|
784
|
+
const entryId =
|
|
785
|
+
typeof record.id === "string" && CHILD_TRANSCRIPT_ID.test(record.id)
|
|
786
|
+
? record.id
|
|
787
|
+
: undefined;
|
|
788
|
+
const message = persistedTranscriptMessage(record, entryId);
|
|
789
|
+
if (message === undefined) continue;
|
|
756
790
|
if (messages.length >= MAX_CHILD_TRANSCRIPT_MESSAGES) {
|
|
757
791
|
throw new Error("OMP child transcript exceeds message limits");
|
|
758
792
|
}
|
|
759
|
-
messages.push(
|
|
793
|
+
messages.push(message);
|
|
760
794
|
}
|
|
761
795
|
}
|
|
762
796
|
if (!nativeSessionId) throw new Error("OMP child transcript is missing session identity");
|
|
763
|
-
return { sessionFile, nativeSessionId, byteLength: bytes.byteLength, messages };
|
|
797
|
+
return { sessionFile: canonicalChild, nativeSessionId, byteLength: bytes.byteLength, messages };
|
|
764
798
|
} catch (error) {
|
|
765
799
|
if (error instanceof Error) throw error;
|
|
766
800
|
throw new Error("OMP child transcript could not be decoded");
|
|
@@ -1685,7 +1685,7 @@ export class OmpProviderSession {
|
|
|
1685
1685
|
});
|
|
1686
1686
|
}
|
|
1687
1687
|
}
|
|
1688
|
-
messages ??= await waitForReplay(this.runtime.getMessages(), replay.signal);
|
|
1688
|
+
messages ??= await waitForReplay(this.runtime.getMessages(replay.signal), replay.signal);
|
|
1689
1689
|
this.quarantineBranchEntries();
|
|
1690
1690
|
for (const message of messages) {
|
|
1691
1691
|
replay.signal.throwIfAborted();
|
|
@@ -3234,6 +3234,17 @@ export class OmpProviderSession {
|
|
|
3234
3234
|
this.handleRuntimeFailure();
|
|
3235
3235
|
return;
|
|
3236
3236
|
}
|
|
3237
|
+
if (
|
|
3238
|
+
event.type === "config_warnings_changed" ||
|
|
3239
|
+
event.type === "advisor_cost_changed" ||
|
|
3240
|
+
event.type === "ttsr_triggered"
|
|
3241
|
+
) {
|
|
3242
|
+
return;
|
|
3243
|
+
}
|
|
3244
|
+
if (event.type === "irc_message") {
|
|
3245
|
+
this.projector.projectPassive(event);
|
|
3246
|
+
return;
|
|
3247
|
+
}
|
|
3237
3248
|
if (
|
|
3238
3249
|
event.type === "notice" ||
|
|
3239
3250
|
event.type === "todo_reminder" ||
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import { basename, extname } from "node:path";
|
|
2
|
+
import { basename, extname, isAbsolute } from "node:path";
|
|
3
3
|
import type { ProviderEvent } from "@getpaseo/plugin/server/provider";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import type {
|
|
@@ -882,10 +882,32 @@ export class OmpSubsessionProjector {
|
|
|
882
882
|
signal.throwIfAborted();
|
|
883
883
|
if (this.sessionIdByNativeId.has(snapshot.id)) continue;
|
|
884
884
|
try {
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
885
|
+
let history: ReplayHistory;
|
|
886
|
+
if (snapshot.sessionFile && isAbsolute(snapshot.sessionFile) && this.rootSessionFile) {
|
|
887
|
+
try {
|
|
888
|
+
history = await waitForReplay(
|
|
889
|
+
runtime.readPersistedSubagentTranscript({
|
|
890
|
+
parentSessionFile: this.rootSessionFile,
|
|
891
|
+
childTranscriptId: snapshot.id,
|
|
892
|
+
sessionFile: snapshot.sessionFile,
|
|
893
|
+
cwd: this.cwd,
|
|
894
|
+
signal,
|
|
895
|
+
}),
|
|
896
|
+
signal,
|
|
897
|
+
);
|
|
898
|
+
} catch (error) {
|
|
899
|
+
if (signal.aborted) throw error;
|
|
900
|
+
history = await waitForReplay(
|
|
901
|
+
runtimeSession.getSubagentMessages({ subagentId: snapshot.id }),
|
|
902
|
+
signal,
|
|
903
|
+
);
|
|
904
|
+
}
|
|
905
|
+
} else {
|
|
906
|
+
history = await waitForReplay(
|
|
907
|
+
runtimeSession.getSubagentMessages({ subagentId: snapshot.id }),
|
|
908
|
+
signal,
|
|
909
|
+
);
|
|
910
|
+
}
|
|
889
911
|
try {
|
|
890
912
|
this.accountReplay(history.messages, budget, signal);
|
|
891
913
|
collected.push({
|
|
@@ -899,7 +921,7 @@ export class OmpSubsessionProjector {
|
|
|
899
921
|
}
|
|
900
922
|
} catch (error) {
|
|
901
923
|
if (signal.aborted) throw error;
|
|
902
|
-
collected.push({ snapshot });
|
|
924
|
+
collected.push({ snapshot, sessionFile: snapshot.sessionFile });
|
|
903
925
|
}
|
|
904
926
|
}
|
|
905
927
|
collected.sort((left, right) => {
|
|
@@ -6,7 +6,12 @@ import type {
|
|
|
6
6
|
} from "@getpaseo/plugin/server/provider";
|
|
7
7
|
import { OMP_MCP_AUTH_TIMELINE_KIND } from "../../shared/mcp";
|
|
8
8
|
import { isOmpImageMimeType, isValidImagePayload, type OmpImageMimeType } from "./image";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
OMP_MAX_CONTENT_PARTS,
|
|
11
|
+
OMP_MESSAGE_REPLAY_POLICIES,
|
|
12
|
+
type OmpMessage,
|
|
13
|
+
type OmpRpcEvent,
|
|
14
|
+
} from "./omp-rpc";
|
|
10
15
|
import {
|
|
11
16
|
boundedJsonBytes,
|
|
12
17
|
type JsonValue,
|
|
@@ -134,6 +139,10 @@ function imageBlock(data: string, mimeType: string): StreamBlockSnapshot | undef
|
|
|
134
139
|
}
|
|
135
140
|
|
|
136
141
|
type OmpAssistantMessage = Extract<OmpMessage, { role: "assistant" }>;
|
|
142
|
+
type OmpCustomDisplayMessage = Extract<
|
|
143
|
+
OmpMessage,
|
|
144
|
+
{ role: "bashExecution" | "pythonExecution" | "custom" | "hookMessage" }
|
|
145
|
+
>;
|
|
137
146
|
|
|
138
147
|
function blockText(
|
|
139
148
|
message: OmpAssistantMessage,
|
|
@@ -417,16 +426,35 @@ export class OmpTimelineProjector {
|
|
|
417
426
|
return;
|
|
418
427
|
}
|
|
419
428
|
}
|
|
429
|
+
if (
|
|
430
|
+
(event.type === "message_start" ||
|
|
431
|
+
event.type === "message_update" ||
|
|
432
|
+
event.type === "message_end") &&
|
|
433
|
+
OMP_MESSAGE_REPLAY_POLICIES[event.message.role] === "ignore"
|
|
434
|
+
) {
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
420
437
|
if (
|
|
421
438
|
event.type === "todo_reminder" ||
|
|
422
439
|
event.type === "todo_auto_clear" ||
|
|
440
|
+
event.type === "goal_updated" ||
|
|
441
|
+
event.type === "auto_retry_start" ||
|
|
442
|
+
event.type === "auto_retry_end" ||
|
|
443
|
+
event.type === "retry_fallback_applied" ||
|
|
444
|
+
event.type === "retry_fallback_succeeded" ||
|
|
423
445
|
event.type === "notice" ||
|
|
424
446
|
event.type === "extension_ui_request" ||
|
|
425
447
|
event.type === "auto_compaction_start" ||
|
|
426
448
|
event.type === "auto_compaction_end" ||
|
|
427
449
|
event.type === "compaction_start" ||
|
|
428
450
|
event.type === "compaction_end" ||
|
|
429
|
-
event.type === "advisor_yielded"
|
|
451
|
+
event.type === "advisor_yielded" ||
|
|
452
|
+
event.type === "config_warnings_changed" ||
|
|
453
|
+
event.type === "advisor_cost_changed" ||
|
|
454
|
+
event.type === "ttsr_triggered" ||
|
|
455
|
+
event.type === "irc_message" ||
|
|
456
|
+
event.type === "model_changed" ||
|
|
457
|
+
event.type === "thinking_level_changed"
|
|
430
458
|
) {
|
|
431
459
|
this.projectPassive(event);
|
|
432
460
|
return;
|
|
@@ -449,7 +477,12 @@ export class OmpTimelineProjector {
|
|
|
449
477
|
this.scheduleFlush();
|
|
450
478
|
return;
|
|
451
479
|
case "message_end":
|
|
452
|
-
if (
|
|
480
|
+
if (
|
|
481
|
+
event.message.role === "custom" ||
|
|
482
|
+
event.message.role === "hookMessage" ||
|
|
483
|
+
event.message.role === "bashExecution" ||
|
|
484
|
+
event.message.role === "pythonExecution"
|
|
485
|
+
) {
|
|
453
486
|
this.publishCustomMessage(event.message);
|
|
454
487
|
return;
|
|
455
488
|
}
|
|
@@ -499,12 +532,13 @@ export class OmpTimelineProjector {
|
|
|
499
532
|
if (!snapshot.silent) this.publishTool(snapshot, "running");
|
|
500
533
|
return;
|
|
501
534
|
}
|
|
502
|
-
case "tool_execution_update":
|
|
535
|
+
case "tool_execution_update":
|
|
536
|
+
case "tool_stream_update": {
|
|
503
537
|
const previous = this.tools.get(event.toolCallId);
|
|
504
538
|
if (!previous) return;
|
|
505
539
|
if (previous.turnId !== turnId || previous.generation !== this.runtimeGeneration) return;
|
|
506
540
|
const output = this.dataFilter.json(
|
|
507
|
-
event.partialResult,
|
|
541
|
+
event.type === "tool_execution_update" ? event.partialResult : event.update,
|
|
508
542
|
MAX_PUBLIC_TOOL_PAYLOAD_BYTES,
|
|
509
543
|
MAX_PUBLIC_TOOL_PAYLOAD_BYTES,
|
|
510
544
|
);
|
|
@@ -600,6 +634,10 @@ export class OmpTimelineProjector {
|
|
|
600
634
|
this.publishRetryFallback(event);
|
|
601
635
|
return;
|
|
602
636
|
}
|
|
637
|
+
if (event.type === "irc_message") {
|
|
638
|
+
this.publishCustomMessage(event.message as OmpCustomDisplayMessage);
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
603
641
|
if (event.type === "notice") {
|
|
604
642
|
this.noticeSequence += 1;
|
|
605
643
|
this.publish({
|
|
@@ -839,8 +877,9 @@ export class OmpTimelineProjector {
|
|
|
839
877
|
|
|
840
878
|
projectReplayMessage(message: OmpMessage): void {
|
|
841
879
|
if (this.closed) return;
|
|
842
|
-
const nativeIdentity = assistantIdentity(message);
|
|
843
880
|
this.replaySequence += 1;
|
|
881
|
+
if (OMP_MESSAGE_REPLAY_POLICIES[message.role] === "ignore") return;
|
|
882
|
+
|
|
844
883
|
if (message.role === "user") {
|
|
845
884
|
this.replayToolCalls.clear();
|
|
846
885
|
if (this.replayTurnId) this.finishTurn(this.replayTurnId);
|
|
@@ -861,7 +900,9 @@ export class OmpTimelineProjector {
|
|
|
861
900
|
}
|
|
862
901
|
return;
|
|
863
902
|
}
|
|
903
|
+
|
|
864
904
|
if (message.role === "assistant") {
|
|
905
|
+
const nativeIdentity = assistantIdentity(message);
|
|
865
906
|
this.replayTurnId ??= `omp:replay-turn:${this.replaySequence}`;
|
|
866
907
|
this.projectingReplay = true;
|
|
867
908
|
try {
|
|
@@ -880,6 +921,7 @@ export class OmpTimelineProjector {
|
|
|
880
921
|
if (nativeIdentity) this.rememberReplayOccurrence(nativeIdentity, message);
|
|
881
922
|
return;
|
|
882
923
|
}
|
|
924
|
+
|
|
883
925
|
this.replayTurnId ??= `omp:replay-turn:${this.replaySequence}`;
|
|
884
926
|
if (message.role === "toolResult") {
|
|
885
927
|
const replayCall = this.replayToolCalls.get(message.toolCallId);
|
|
@@ -910,10 +952,18 @@ export class OmpTimelineProjector {
|
|
|
910
952
|
);
|
|
911
953
|
return;
|
|
912
954
|
}
|
|
913
|
-
|
|
955
|
+
|
|
956
|
+
if (
|
|
957
|
+
message.role === "bashExecution" ||
|
|
958
|
+
message.role === "pythonExecution" ||
|
|
959
|
+
message.role === "custom" ||
|
|
960
|
+
message.role === "hookMessage"
|
|
961
|
+
) {
|
|
914
962
|
this.publishCustomMessage(message);
|
|
915
|
-
|
|
916
|
-
|
|
963
|
+
if (message.role === "bashExecution" || message.role === "pythonExecution") {
|
|
964
|
+
this.finishTurn(this.replayTurnId);
|
|
965
|
+
this.replayTurnId = null;
|
|
966
|
+
}
|
|
917
967
|
}
|
|
918
968
|
}
|
|
919
969
|
|
|
@@ -1350,9 +1400,17 @@ export class OmpTimelineProjector {
|
|
|
1350
1400
|
return undefined;
|
|
1351
1401
|
}
|
|
1352
1402
|
|
|
1353
|
-
private publishCustomMessage(message:
|
|
1354
|
-
if (
|
|
1355
|
-
|
|
1403
|
+
private publishCustomMessage(message: OmpCustomDisplayMessage): void {
|
|
1404
|
+
if (
|
|
1405
|
+
(message.role === "custom" || message.role === "hookMessage") &&
|
|
1406
|
+
message.display === false
|
|
1407
|
+
) {
|
|
1408
|
+
return;
|
|
1409
|
+
}
|
|
1410
|
+
const rawType =
|
|
1411
|
+
message.role === "custom" || message.role === "hookMessage"
|
|
1412
|
+
? (message.customType ?? message.role)
|
|
1413
|
+
: message.role;
|
|
1356
1414
|
const publicType = this.dataFilter.text(rawType, 256);
|
|
1357
1415
|
const lowerType = rawType.toLowerCase();
|
|
1358
1416
|
const details = jsonRecord(this.dataFilter.json(message.details ?? null));
|
|
@@ -1361,7 +1419,9 @@ export class OmpTimelineProjector {
|
|
|
1361
1419
|
const id = nativeIdentity
|
|
1362
1420
|
? `omp:custom:${createHash("sha256").update(nativeIdentity).digest("base64url").slice(0, 12)}`
|
|
1363
1421
|
: `omp:custom:${this.customSequence}`;
|
|
1364
|
-
const
|
|
1422
|
+
const messageContent =
|
|
1423
|
+
message.role === "custom" || message.role === "hookMessage" ? message.content : undefined;
|
|
1424
|
+
const contentParts = Array.isArray(messageContent) ? messageContent : [];
|
|
1365
1425
|
const imageResult = nativeImageResult(
|
|
1366
1426
|
{
|
|
1367
1427
|
content:
|
|
@@ -1373,16 +1433,26 @@ export class OmpTimelineProjector {
|
|
|
1373
1433
|
this.dataFilter,
|
|
1374
1434
|
);
|
|
1375
1435
|
const content =
|
|
1376
|
-
typeof
|
|
1377
|
-
?
|
|
1436
|
+
typeof messageContent === "string"
|
|
1437
|
+
? messageContent
|
|
1378
1438
|
: contentParts
|
|
1379
1439
|
.flatMap((part) => (part.type === "text" && part.text ? [part.text] : []))
|
|
1380
1440
|
.join("\n\n");
|
|
1381
|
-
|
|
1441
|
+
const execution = message.role === "bashExecution" || message.role === "pythonExecution";
|
|
1442
|
+
if (execution || /bash|shell|python/u.test(lowerType)) {
|
|
1443
|
+
const nativeCommand =
|
|
1444
|
+
message.role === "bashExecution"
|
|
1445
|
+
? message.command
|
|
1446
|
+
: message.role === "pythonExecution"
|
|
1447
|
+
? message.code
|
|
1448
|
+
: undefined;
|
|
1382
1449
|
const command = this.dataFilter.text(
|
|
1383
|
-
|
|
1450
|
+
nativeCommand ?? firstString(details, "command", "input") ?? publicType,
|
|
1384
1451
|
);
|
|
1385
|
-
const output = message.output ?? content;
|
|
1452
|
+
const output = execution ? (message.output ?? content) : content;
|
|
1453
|
+
const exitCode = execution ? message.exitCode : undefined;
|
|
1454
|
+
const cancelled = execution ? message.cancelled : undefined;
|
|
1455
|
+
const truncated = execution ? message.truncated : undefined;
|
|
1386
1456
|
this.publish({
|
|
1387
1457
|
type: "tool_call",
|
|
1388
1458
|
id,
|
|
@@ -1393,21 +1463,21 @@ export class OmpTimelineProjector {
|
|
|
1393
1463
|
command,
|
|
1394
1464
|
...(firstString(details, "cwd") ? { cwd: firstString(details, "cwd") } : {}),
|
|
1395
1465
|
...(output ? { output: this.dataFilter.text(output, MAX_STREAM_TEXT_LENGTH) } : {}),
|
|
1396
|
-
...(typeof
|
|
1397
|
-
? { exitCode
|
|
1466
|
+
...(typeof exitCode === "number" || exitCode === null
|
|
1467
|
+
? { exitCode }
|
|
1398
1468
|
: typeof details?.exitCode === "number"
|
|
1399
1469
|
? { exitCode: details.exitCode }
|
|
1400
1470
|
: {}),
|
|
1401
1471
|
},
|
|
1402
|
-
...(
|
|
1472
|
+
...(cancelled !== undefined || truncated !== undefined
|
|
1403
1473
|
? {
|
|
1404
1474
|
metadata: {
|
|
1405
|
-
...(
|
|
1406
|
-
...(
|
|
1475
|
+
...(cancelled !== undefined ? { cancelled } : {}),
|
|
1476
|
+
...(truncated !== undefined ? { truncated } : {}),
|
|
1407
1477
|
},
|
|
1408
1478
|
}
|
|
1409
1479
|
: {}),
|
|
1410
|
-
status:
|
|
1480
|
+
status: cancelled ? "canceled" : "completed",
|
|
1411
1481
|
error: null,
|
|
1412
1482
|
});
|
|
1413
1483
|
if (imageResult) this.publishImages(id, publicType, imageResult.image);
|