@tmustier/pi-agent-teams 0.2.0 → 0.3.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/README.md +15 -3
- package/docs/claude-parity.md +7 -5
- package/docs/smoke-test-plan.md +20 -4
- package/eslint.config.js +74 -0
- package/extensions/teams/activity-tracker.ts +2 -2
- package/extensions/teams/leader-lifecycle-commands.ts +151 -14
- package/extensions/teams/leader-messaging-commands.ts +0 -1
- package/extensions/teams/leader-plan-commands.ts +1 -1
- package/extensions/teams/leader-spawn-command.ts +3 -19
- package/extensions/teams/leader-task-commands.ts +11 -7
- package/extensions/teams/leader-team-command.ts +329 -0
- package/extensions/teams/leader-teams-tool.ts +5 -16
- package/extensions/teams/leader.ts +34 -310
- package/extensions/teams/protocol.ts +20 -0
- package/extensions/teams/spawn-types.ts +21 -0
- package/extensions/teams/task-store.ts +4 -0
- package/extensions/teams/teammate-rpc.ts +26 -2
- package/extensions/teams/teams-panel.ts +41 -95
- package/extensions/teams/teams-ui-shared.ts +89 -0
- package/extensions/teams/teams-widget.ts +15 -68
- package/extensions/teams/worker.ts +1 -1
- package/package.json +9 -4
- package/scripts/integration-claim-test.mts +16 -86
- package/scripts/integration-todo-test.mts +14 -65
- package/scripts/lib/pi-workers.ts +105 -0
- package/skills/agent-teams/SKILL.md +8 -4
- package/.github/workflows/ci.yml +0 -32
- package/scripts/smoke-test.mjs +0 -199
|
@@ -9,36 +9,16 @@ import { TEAM_MAILBOX_NS } from "./protocol.js";
|
|
|
9
9
|
import { listTasks, unassignTasksForAgent, type TeamTask } from "./task-store.js";
|
|
10
10
|
import { TeammateRpc } from "./teammate-rpc.js";
|
|
11
11
|
import { ensureTeamConfig, loadTeamConfig, setMemberStatus, upsertMember, type TeamConfig } from "./team-config.js";
|
|
12
|
-
import { getTeamDir
|
|
12
|
+
import { getTeamDir } from "./paths.js";
|
|
13
13
|
import { ensureWorktreeCwd } from "./worktree.js";
|
|
14
14
|
import { ActivityTracker, TranscriptTracker } from "./activity-tracker.js";
|
|
15
15
|
import { openInteractiveWidget } from "./teams-panel.js";
|
|
16
16
|
import { createTeamsWidget } from "./teams-widget.js";
|
|
17
17
|
import { getTeamsStyleFromEnv, type TeamsStyle, formatMemberDisplayName, getTeamsStrings } from "./teams-style.js";
|
|
18
18
|
import { pollLeaderInbox as pollLeaderInboxImpl } from "./leader-inbox.js";
|
|
19
|
-
import {
|
|
20
|
-
import { handleTeamPlanCommand } from "./leader-plan-commands.js";
|
|
21
|
-
import { handleTeamSpawnCommand } from "./leader-spawn-command.js";
|
|
19
|
+
import { handleTeamCommand } from "./leader-team-command.js";
|
|
22
20
|
import { registerTeamsTool } from "./leader-teams-tool.js";
|
|
23
|
-
import {
|
|
24
|
-
handleTeamBroadcastCommand,
|
|
25
|
-
handleTeamDmCommand,
|
|
26
|
-
handleTeamSendCommand,
|
|
27
|
-
handleTeamSteerCommand,
|
|
28
|
-
} from "./leader-messaging-commands.js";
|
|
29
|
-
import { handleTeamEnvCommand, handleTeamIdCommand, handleTeamListCommand } from "./leader-info-commands.js";
|
|
30
|
-
import {
|
|
31
|
-
handleTeamCleanupCommand,
|
|
32
|
-
handleTeamDelegateCommand,
|
|
33
|
-
handleTeamKillCommand,
|
|
34
|
-
handleTeamShutdownCommand,
|
|
35
|
-
handleTeamStopCommand,
|
|
36
|
-
handleTeamStyleCommand,
|
|
37
|
-
} from "./leader-lifecycle-commands.js";
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
type ContextMode = "fresh" | "branch";
|
|
41
|
-
type WorkspaceMode = "shared" | "worktree";
|
|
21
|
+
import type { ContextMode, SpawnTeammateFn, SpawnTeammateResult, WorkspaceMode } from "./spawn-types.js";
|
|
42
22
|
|
|
43
23
|
function getTeamsExtensionEntryPath(): string | null {
|
|
44
24
|
// In dev, teammates won't automatically have this extension unless it is installed or discoverable.
|
|
@@ -59,15 +39,6 @@ function shellQuote(v: string): string {
|
|
|
59
39
|
return "'" + v.replace(/'/g, `"'"'"'`) + "'";
|
|
60
40
|
}
|
|
61
41
|
|
|
62
|
-
function parseAssigneePrefix(text: string): { assignee?: string; text: string } {
|
|
63
|
-
const m = text.match(/^([a-zA-Z0-9_-]+):\s*(.+)$/);
|
|
64
|
-
if (!m) return { text };
|
|
65
|
-
const assignee = m[1];
|
|
66
|
-
const rest = m[2];
|
|
67
|
-
if (!assignee || !rest) return { text };
|
|
68
|
-
return { assignee, text: rest };
|
|
69
|
-
}
|
|
70
|
-
|
|
71
42
|
function getTeamSessionsDir(teamDir: string): string {
|
|
72
43
|
return path.join(teamDir, "sessions");
|
|
73
44
|
}
|
|
@@ -121,17 +92,6 @@ async function createSessionForTeammate(
|
|
|
121
92
|
}
|
|
122
93
|
}
|
|
123
94
|
|
|
124
|
-
function taskAssignmentPayload(task: TeamTask, assignedBy: string) {
|
|
125
|
-
return {
|
|
126
|
-
type: "task_assignment",
|
|
127
|
-
taskId: task.id,
|
|
128
|
-
subject: task.subject,
|
|
129
|
-
description: task.description,
|
|
130
|
-
assignedBy,
|
|
131
|
-
timestamp: new Date().toISOString(),
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
|
|
135
95
|
// Message parsers are shared with the worker implementation.
|
|
136
96
|
export function runLeader(pi: ExtensionAPI): void {
|
|
137
97
|
const teammates = new Map<string, TeammateRpc>();
|
|
@@ -226,22 +186,7 @@ export function runLeader(pi: ExtensionAPI): void {
|
|
|
226
186
|
currentCtx.ui.setWidget("pi-teams", widgetFactory);
|
|
227
187
|
};
|
|
228
188
|
|
|
229
|
-
|
|
230
|
-
| {
|
|
231
|
-
ok: true;
|
|
232
|
-
name: string;
|
|
233
|
-
mode: ContextMode;
|
|
234
|
-
workspaceMode: WorkspaceMode;
|
|
235
|
-
childCwd: string;
|
|
236
|
-
note?: string;
|
|
237
|
-
warnings: string[];
|
|
238
|
-
}
|
|
239
|
-
| { ok: false; error: string };
|
|
240
|
-
|
|
241
|
-
const spawnTeammate = async (
|
|
242
|
-
ctx: ExtensionContext,
|
|
243
|
-
opts: { name: string; mode?: ContextMode; workspaceMode?: WorkspaceMode; planRequired?: boolean },
|
|
244
|
-
): Promise<SpawnTeammateResult> => {
|
|
189
|
+
const spawnTeammate: SpawnTeammateFn = async (ctx, opts): Promise<SpawnTeammateResult> => {
|
|
245
190
|
const warnings: string[] = [];
|
|
246
191
|
const mode: ContextMode = opts.mode ?? "fresh";
|
|
247
192
|
let workspaceMode: WorkspaceMode = opts.workspaceMode ?? "shared";
|
|
@@ -516,7 +461,6 @@ export function runLeader(pi: ExtensionAPI): void {
|
|
|
516
461
|
teammates,
|
|
517
462
|
spawnTeammate,
|
|
518
463
|
getTaskListId: () => taskListId,
|
|
519
|
-
taskAssignmentPayload,
|
|
520
464
|
refreshTasks,
|
|
521
465
|
renderWidget,
|
|
522
466
|
});
|
|
@@ -550,11 +494,11 @@ export function runLeader(pi: ExtensionAPI): void {
|
|
|
550
494
|
timestamp: new Date().toISOString(),
|
|
551
495
|
});
|
|
552
496
|
},
|
|
553
|
-
|
|
497
|
+
abortMember(name: string) {
|
|
554
498
|
const rpc = teammates.get(name);
|
|
555
499
|
if (rpc) void rpc.abort();
|
|
556
500
|
},
|
|
557
|
-
|
|
501
|
+
killMember(name: string) {
|
|
558
502
|
const rpc = teammates.get(name);
|
|
559
503
|
if (!rpc) return;
|
|
560
504
|
|
|
@@ -613,254 +557,34 @@ export function runLeader(pi: ExtensionAPI): void {
|
|
|
613
557
|
currentCtx = ctx;
|
|
614
558
|
currentTeamId = ctx.sessionManager.getSessionId();
|
|
615
559
|
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
ctx
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
" /team task dep rm <id> <depId>",
|
|
645
|
-
" /team task dep ls <id>",
|
|
646
|
-
" /team task use <taskListId>",
|
|
647
|
-
].join("\n"),
|
|
648
|
-
"info",
|
|
649
|
-
);
|
|
650
|
-
return;
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
switch (sub) {
|
|
654
|
-
case "list": {
|
|
655
|
-
await handleTeamListCommand({
|
|
656
|
-
ctx,
|
|
657
|
-
teammates,
|
|
658
|
-
getTeamConfig: () => teamConfig,
|
|
659
|
-
style,
|
|
660
|
-
refreshTasks,
|
|
661
|
-
renderWidget,
|
|
662
|
-
});
|
|
663
|
-
return;
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
case "id": {
|
|
667
|
-
await handleTeamIdCommand({
|
|
668
|
-
ctx,
|
|
669
|
-
taskListId,
|
|
670
|
-
leadName: teamConfig?.leadName ?? "team-lead",
|
|
671
|
-
style,
|
|
672
|
-
});
|
|
673
|
-
return;
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
case "env": {
|
|
677
|
-
await handleTeamEnvCommand({
|
|
678
|
-
ctx,
|
|
679
|
-
rest,
|
|
680
|
-
taskListId,
|
|
681
|
-
leadName: teamConfig?.leadName ?? "team-lead",
|
|
682
|
-
style,
|
|
683
|
-
getTeamsExtensionEntryPath,
|
|
684
|
-
shellQuote,
|
|
685
|
-
});
|
|
686
|
-
return;
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
case "cleanup": {
|
|
690
|
-
await handleTeamCleanupCommand({
|
|
691
|
-
ctx,
|
|
692
|
-
rest,
|
|
693
|
-
teammates,
|
|
694
|
-
refreshTasks,
|
|
695
|
-
getTasks: () => tasks,
|
|
696
|
-
renderWidget,
|
|
697
|
-
style,
|
|
698
|
-
});
|
|
699
|
-
return;
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
case "delegate": {
|
|
703
|
-
await handleTeamDelegateCommand({
|
|
704
|
-
ctx,
|
|
705
|
-
rest,
|
|
706
|
-
getDelegateMode: () => delegateMode,
|
|
707
|
-
setDelegateMode: (next) => {
|
|
708
|
-
delegateMode = next;
|
|
709
|
-
},
|
|
710
|
-
renderWidget,
|
|
711
|
-
});
|
|
712
|
-
return;
|
|
713
|
-
}
|
|
714
|
-
|
|
715
|
-
case "shutdown": {
|
|
716
|
-
await handleTeamShutdownCommand({
|
|
717
|
-
ctx,
|
|
718
|
-
rest,
|
|
719
|
-
teammates,
|
|
720
|
-
leadName: teamConfig?.leadName ?? "team-lead",
|
|
721
|
-
style,
|
|
722
|
-
getCurrentCtx: () => currentCtx,
|
|
723
|
-
});
|
|
724
|
-
return;
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
case "spawn": {
|
|
728
|
-
await handleTeamSpawnCommand({ ctx, rest, teammates, style, spawnTeammate });
|
|
729
|
-
return;
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
case "style": {
|
|
733
|
-
const teamId = ctx.sessionManager.getSessionId();
|
|
734
|
-
const teamDir = getTeamDir(teamId);
|
|
735
|
-
await handleTeamStyleCommand({
|
|
736
|
-
ctx,
|
|
737
|
-
rest,
|
|
738
|
-
teamDir,
|
|
739
|
-
getStyle: () => style,
|
|
740
|
-
setStyle: (next) => {
|
|
741
|
-
style = next;
|
|
742
|
-
},
|
|
743
|
-
refreshTasks,
|
|
744
|
-
renderWidget,
|
|
745
|
-
});
|
|
746
|
-
return;
|
|
747
|
-
}
|
|
748
|
-
|
|
749
|
-
case "panel":
|
|
750
|
-
case "widget": {
|
|
751
|
-
await openWidget(ctx);
|
|
752
|
-
return;
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
case "send": {
|
|
756
|
-
await handleTeamSendCommand({
|
|
757
|
-
ctx,
|
|
758
|
-
rest,
|
|
759
|
-
teammates,
|
|
760
|
-
style,
|
|
761
|
-
renderWidget,
|
|
762
|
-
});
|
|
763
|
-
return;
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
case "steer": {
|
|
767
|
-
await handleTeamSteerCommand({
|
|
768
|
-
ctx,
|
|
769
|
-
rest,
|
|
770
|
-
teammates,
|
|
771
|
-
style,
|
|
772
|
-
renderWidget,
|
|
773
|
-
});
|
|
774
|
-
return;
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
case "stop": {
|
|
778
|
-
await handleTeamStopCommand({
|
|
779
|
-
ctx,
|
|
780
|
-
rest,
|
|
781
|
-
teammates,
|
|
782
|
-
leadName: teamConfig?.leadName ?? "team-lead",
|
|
783
|
-
style,
|
|
784
|
-
refreshTasks,
|
|
785
|
-
getTasks: () => tasks,
|
|
786
|
-
renderWidget,
|
|
787
|
-
});
|
|
788
|
-
return;
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
case "kill": {
|
|
792
|
-
await handleTeamKillCommand({
|
|
793
|
-
ctx,
|
|
794
|
-
rest,
|
|
795
|
-
teammates,
|
|
796
|
-
leadName: teamConfig?.leadName ?? "team-lead",
|
|
797
|
-
style,
|
|
798
|
-
taskListId,
|
|
799
|
-
refreshTasks,
|
|
800
|
-
renderWidget,
|
|
801
|
-
});
|
|
802
|
-
return;
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
case "dm": {
|
|
806
|
-
await handleTeamDmCommand({
|
|
807
|
-
ctx,
|
|
808
|
-
rest,
|
|
809
|
-
leadName: teamConfig?.leadName ?? "team-lead",
|
|
810
|
-
style,
|
|
811
|
-
});
|
|
812
|
-
return;
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
case "broadcast": {
|
|
816
|
-
await handleTeamBroadcastCommand({
|
|
817
|
-
ctx,
|
|
818
|
-
rest,
|
|
819
|
-
teammates,
|
|
820
|
-
leadName: teamConfig?.leadName ?? "team-lead",
|
|
821
|
-
style,
|
|
822
|
-
refreshTasks,
|
|
823
|
-
getTasks: () => tasks,
|
|
824
|
-
getTaskListId: () => taskListId,
|
|
825
|
-
});
|
|
826
|
-
return;
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
case "task": {
|
|
830
|
-
await handleTeamTaskCommand({
|
|
831
|
-
ctx,
|
|
832
|
-
rest,
|
|
833
|
-
leadName: teamConfig?.leadName ?? "team-lead",
|
|
834
|
-
style,
|
|
835
|
-
getTaskListId: () => taskListId,
|
|
836
|
-
setTaskListId: (id) => {
|
|
837
|
-
taskListId = id;
|
|
838
|
-
},
|
|
839
|
-
getTasks: () => tasks,
|
|
840
|
-
refreshTasks,
|
|
841
|
-
renderWidget,
|
|
842
|
-
parseAssigneePrefix,
|
|
843
|
-
taskAssignmentPayload,
|
|
844
|
-
});
|
|
845
|
-
return;
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
case "plan": {
|
|
849
|
-
await handleTeamPlanCommand({
|
|
850
|
-
ctx,
|
|
851
|
-
rest,
|
|
852
|
-
leadName: teamConfig?.leadName ?? "team-lead",
|
|
853
|
-
style,
|
|
854
|
-
pendingPlanApprovals,
|
|
855
|
-
});
|
|
856
|
-
return;
|
|
857
|
-
}
|
|
858
|
-
|
|
859
|
-
default: {
|
|
860
|
-
ctx.ui.notify(`Unknown subcommand: ${sub}`, "error");
|
|
861
|
-
return;
|
|
862
|
-
}
|
|
863
|
-
}
|
|
560
|
+
await handleTeamCommand({
|
|
561
|
+
args,
|
|
562
|
+
ctx,
|
|
563
|
+
teammates,
|
|
564
|
+
getTeamConfig: () => teamConfig,
|
|
565
|
+
getTasks: () => tasks,
|
|
566
|
+
refreshTasks,
|
|
567
|
+
renderWidget,
|
|
568
|
+
getTaskListId: () => taskListId,
|
|
569
|
+
setTaskListId: (id) => {
|
|
570
|
+
taskListId = id;
|
|
571
|
+
},
|
|
572
|
+
pendingPlanApprovals,
|
|
573
|
+
getDelegateMode: () => delegateMode,
|
|
574
|
+
setDelegateMode: (next) => {
|
|
575
|
+
delegateMode = next;
|
|
576
|
+
},
|
|
577
|
+
getStyle: () => style,
|
|
578
|
+
setStyle: (next) => {
|
|
579
|
+
style = next;
|
|
580
|
+
},
|
|
581
|
+
spawnTeammate,
|
|
582
|
+
openWidget,
|
|
583
|
+
getTeamsExtensionEntryPath,
|
|
584
|
+
shellQuote,
|
|
585
|
+
getCurrentCtx: () => currentCtx,
|
|
586
|
+
stopAllTeammates,
|
|
587
|
+
});
|
|
864
588
|
},
|
|
865
589
|
});
|
|
866
590
|
}
|
|
@@ -1,5 +1,25 @@
|
|
|
1
|
+
import type { TeamTask } from "./task-store.js";
|
|
2
|
+
|
|
1
3
|
export const TEAM_MAILBOX_NS = "team";
|
|
2
4
|
|
|
5
|
+
export function taskAssignmentPayload(task: TeamTask, assignedBy: string): {
|
|
6
|
+
type: "task_assignment";
|
|
7
|
+
taskId: string;
|
|
8
|
+
subject: string;
|
|
9
|
+
description: string;
|
|
10
|
+
assignedBy: string;
|
|
11
|
+
timestamp: string;
|
|
12
|
+
} {
|
|
13
|
+
return {
|
|
14
|
+
type: "task_assignment",
|
|
15
|
+
taskId: task.id,
|
|
16
|
+
subject: task.subject,
|
|
17
|
+
description: task.description,
|
|
18
|
+
assignedBy,
|
|
19
|
+
timestamp: new Date().toISOString(),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
3
23
|
function safeParseJson(text: string): unknown | null {
|
|
4
24
|
try {
|
|
5
25
|
const parsed: unknown = JSON.parse(text);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ExtensionContext } from "@mariozechner/pi-coding-agent";
|
|
2
|
+
|
|
3
|
+
export type ContextMode = "fresh" | "branch";
|
|
4
|
+
export type WorkspaceMode = "shared" | "worktree";
|
|
5
|
+
|
|
6
|
+
export type SpawnTeammateResult =
|
|
7
|
+
| {
|
|
8
|
+
ok: true;
|
|
9
|
+
name: string;
|
|
10
|
+
mode: ContextMode;
|
|
11
|
+
workspaceMode: WorkspaceMode;
|
|
12
|
+
childCwd?: string;
|
|
13
|
+
note?: string;
|
|
14
|
+
warnings: string[];
|
|
15
|
+
}
|
|
16
|
+
| { ok: false; error: string };
|
|
17
|
+
|
|
18
|
+
export type SpawnTeammateFn = (
|
|
19
|
+
ctx: ExtensionContext,
|
|
20
|
+
opts: { name: string; mode?: ContextMode; workspaceMode?: WorkspaceMode; planRequired?: boolean },
|
|
21
|
+
) => Promise<SpawnTeammateResult>;
|
|
@@ -328,6 +328,10 @@ export async function unassignTasksForAgent(
|
|
|
328
328
|
if (t.owner !== agentName) continue;
|
|
329
329
|
if (t.status === "completed") continue;
|
|
330
330
|
const updated = await updateTask(teamDir, taskListId, t.id, (cur) => {
|
|
331
|
+
// Re-check ownership under the per-task lock to avoid races with other claimers.
|
|
332
|
+
if (cur.owner !== agentName) return cur;
|
|
333
|
+
if (cur.status === "completed") return cur;
|
|
334
|
+
|
|
331
335
|
const metadata = { ...(cur.metadata ?? {}) };
|
|
332
336
|
if (reason) metadata.unassignedReason = reason;
|
|
333
337
|
metadata.unassignedAt = new Date().toISOString();
|
|
@@ -4,7 +4,7 @@ import type { AgentEvent } from "@mariozechner/pi-agent-core";
|
|
|
4
4
|
export type TeammateStatus = "starting" | "idle" | "streaming" | "stopped" | "error";
|
|
5
5
|
|
|
6
6
|
type RpcCommand =
|
|
7
|
-
| { id: string; type: "prompt"; message: string
|
|
7
|
+
| { id: string; type: "prompt"; message: string }
|
|
8
8
|
| { id: string; type: "steer"; message: string }
|
|
9
9
|
| { id: string; type: "follow_up"; message: string }
|
|
10
10
|
| { id: string; type: "abort" }
|
|
@@ -48,7 +48,31 @@ function isRpcResponse(v: unknown): v is RpcResponse {
|
|
|
48
48
|
|
|
49
49
|
function isAgentEvent(v: unknown): v is AgentEvent {
|
|
50
50
|
if (!isRecord(v)) return false;
|
|
51
|
-
|
|
51
|
+
if (typeof v.type !== "string") return false;
|
|
52
|
+
|
|
53
|
+
// Validate the minimal shapes we actually dereference below.
|
|
54
|
+
if (v.type === "message_update") {
|
|
55
|
+
const ame = v.assistantMessageEvent;
|
|
56
|
+
if (!isRecord(ame)) return false;
|
|
57
|
+
if (typeof ame.type !== "string") return false;
|
|
58
|
+
if (ame.type === "text_delta" && typeof ame.delta !== "string") return false;
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (v.type === "tool_execution_start" || v.type === "tool_execution_update" || v.type === "tool_execution_end") {
|
|
63
|
+
if (typeof v.toolCallId !== "string") return false;
|
|
64
|
+
if (typeof v.toolName !== "string") return false;
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
v.type === "agent_start" ||
|
|
70
|
+
v.type === "agent_end" ||
|
|
71
|
+
v.type === "turn_start" ||
|
|
72
|
+
v.type === "turn_end" ||
|
|
73
|
+
v.type === "message_start" ||
|
|
74
|
+
v.type === "message_end"
|
|
75
|
+
);
|
|
52
76
|
}
|
|
53
77
|
|
|
54
78
|
export class TeammateRpc {
|