personal-bot 0.2.4 → 0.2.6
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/CONTEXT.md +9 -7
- package/README.md +15 -8
- package/README.zh-CN.md +15 -8
- package/docs/README.md +3 -1
- package/docs/agent-collaboration.md +27 -13
- package/docs/architecture-guidelines.md +2 -2
- package/docs/capability-design.md +6 -4
- package/docs/dsh-implementation-plan.md +158 -0
- package/docs/dsh-support-proposal.md +314 -0
- package/docs/dsh.md +103 -0
- package/docs/file-storage.md +14 -9
- package/docs/history.md +29 -18
- package/docs/installation-design.md +3 -1
- package/docs/interaction-design.md +13 -0
- package/docs/release.md +3 -3
- package/docs/subagent-upgrade-proposal.md +3 -3
- package/docs/technical-design.md +29 -15
- package/docs/validation.md +49 -3
- package/lib/client.js +1071 -0
- package/lib/common/files.d.ts +2 -0
- package/lib/common/files.js +44 -0
- package/lib/common/json.d.ts +6 -0
- package/lib/common/json.js +16 -0
- package/lib/common/markdown.d.ts +5 -0
- package/lib/common/markdown.js +26 -0
- package/lib/common/paths.d.ts +1 -0
- package/lib/common/paths.js +2 -0
- package/lib/common/validation.d.ts +3 -0
- package/lib/common/validation.js +14 -0
- package/lib/common/version.d.ts +3 -0
- package/lib/common/version.js +13 -0
- package/lib/dsh.d.ts +4 -0
- package/lib/dsh.js +22 -0
- package/lib/extension/dsh/agent-events.d.ts +24 -0
- package/lib/extension/dsh/agent-events.js +242 -0
- package/lib/extension/dsh/agent-runtime.d.ts +49 -0
- package/lib/extension/dsh/agent-runtime.js +348 -0
- package/lib/extension/dsh/command.d.ts +4 -0
- package/lib/extension/dsh/command.js +83 -0
- package/lib/extension/dsh/files.d.ts +5 -0
- package/lib/extension/dsh/files.js +67 -0
- package/lib/extension/dsh/history.d.ts +15 -0
- package/lib/extension/dsh/history.js +88 -0
- package/lib/extension/dsh/management.d.ts +21 -0
- package/lib/extension/dsh/management.js +217 -0
- package/lib/extension/dsh/workspace.d.ts +48 -0
- package/lib/extension/dsh/workspace.js +290 -0
- package/lib/integrations/agent-resources.d.ts +1 -0
- package/lib/integrations/agent-resources.js +18 -0
- package/lib/integrations/dsh/dsh-agents.d.ts +30 -0
- package/lib/integrations/dsh/dsh-agents.js +104 -0
- package/lib/integrations/dsh/history-summary.d.ts +11 -0
- package/lib/integrations/dsh/history-summary.js +40 -0
- package/lib/integrations/dsh/history.d.ts +16 -0
- package/lib/integrations/dsh/history.js +156 -0
- package/lib/integrations/dsh/input.d.ts +21 -0
- package/lib/integrations/dsh/input.js +62 -0
- package/lib/integrations/dsh/messages.d.ts +36 -0
- package/lib/integrations/dsh/messages.js +11 -0
- package/lib/integrations/dsh/notifications.d.ts +8 -0
- package/lib/integrations/dsh/notifications.js +55 -0
- package/lib/integrations/dsh/resources.d.ts +10 -0
- package/lib/integrations/dsh/resources.js +41 -0
- package/lib/integrations/dsh/schema.d.ts +7 -0
- package/lib/integrations/dsh/schema.js +28 -0
- package/lib/integrations/dsh/session.d.ts +14 -0
- package/lib/integrations/dsh/session.js +59 -0
- package/lib/integrations/history-summary.d.ts +2 -0
- package/lib/integrations/history-summary.js +21 -0
- package/lib/integrations/process.d.ts +14 -0
- package/lib/integrations/process.js +48 -0
- package/lib/integrations/python-activation.d.ts +2 -0
- package/lib/integrations/python-activation.js +29 -0
- package/lib/integrations/team-context.d.ts +18 -0
- package/lib/integrations/team-context.js +57 -0
- package/lib/model/agent.d.ts +92 -0
- package/lib/model/agent.js +1 -0
- package/lib/model/history.d.ts +43 -0
- package/lib/model/history.js +1 -0
- package/lib/model/team.d.ts +85 -0
- package/lib/model/team.js +1 -0
- package/lib/services/agents/agent-notices.d.ts +13 -0
- package/lib/services/agents/agent-notices.js +25 -0
- package/lib/services/agents/agent-run.d.ts +39 -0
- package/lib/services/agents/agent-run.js +138 -0
- package/lib/services/agents/agent-service.d.ts +166 -0
- package/lib/services/agents/agent-service.js +325 -0
- package/lib/services/agents/team-service.d.ts +168 -0
- package/lib/services/agents/team-service.js +343 -0
- package/lib/services/history/history-service.d.ts +103 -0
- package/lib/services/history/history-service.js +269 -0
- package/lib/services/workspace/python-environment-service.d.ts +15 -0
- package/lib/services/workspace/python-environment-service.js +50 -0
- package/lib/services/workspace/workspace-files.d.ts +2 -0
- package/lib/services/workspace/workspace-files.js +17 -0
- package/lib/services/workspace/workspace-preparation.d.ts +2 -0
- package/lib/services/workspace/workspace-preparation.js +18 -0
- package/lib/storage/agent-files.d.ts +30 -0
- package/lib/storage/agent-files.js +166 -0
- package/lib/storage/atomic-json.d.ts +11 -0
- package/lib/storage/atomic-json.js +101 -0
- package/lib/storage/file-access.d.ts +2 -0
- package/lib/storage/file-access.js +26 -0
- package/lib/storage/history-files.d.ts +10 -0
- package/lib/storage/history-files.js +63 -0
- package/lib/storage/team-files.d.ts +16 -0
- package/lib/storage/team-files.js +111 -0
- package/lib/tools/agents/actions.d.ts +52 -0
- package/lib/tools/agents/actions.js +49 -0
- package/lib/tools/agents/contract.d.ts +163 -0
- package/lib/tools/agents/contract.js +56 -0
- package/lib/tools/agents/dsh-contract.d.ts +52 -0
- package/lib/tools/agents/dsh-contract.js +15 -0
- package/lib/tools/agents/dsh-tool.d.ts +5 -0
- package/lib/tools/agents/dsh-tool.js +38 -0
- package/lib/tools/history/actions.d.ts +70 -0
- package/lib/tools/history/actions.js +7 -0
- package/lib/tools/history/contract.d.ts +81 -0
- package/lib/tools/history/contract.js +32 -0
- package/lib/tools/history/dsh-tool.d.ts +4 -0
- package/lib/tools/history/dsh-tool.js +22 -0
- package/lib/tools/result.d.ts +18 -0
- package/lib/tools/result.js +10 -0
- package/lib/tools/teams/actions.d.ts +24 -0
- package/lib/tools/teams/actions.js +38 -0
- package/lib/tools/teams/contract.d.ts +232 -0
- package/lib/tools/teams/contract.js +67 -0
- package/lib/tools/teams/dsh-tool.d.ts +8 -0
- package/lib/tools/teams/dsh-tool.js +49 -0
- package/lib/ui/dsh/attachments.d.ts +5 -0
- package/lib/ui/dsh/attachments.js +39 -0
- package/lib/ui/dsh/elements.d.ts +17 -0
- package/lib/ui/dsh/elements.js +79 -0
- package/lib/ui/dsh/index.d.ts +4 -0
- package/lib/ui/dsh/index.js +13 -0
- package/lib/ui/dsh/management.d.ts +4 -0
- package/lib/ui/dsh/management.js +711 -0
- package/lib/ui/dsh/remote.d.ts +15 -0
- package/lib/ui/dsh/remote.js +11 -0
- package/lib/ui/dsh/styles.d.ts +1 -0
- package/lib/ui/dsh/styles.js +132 -0
- package/lib/ui/presentation.d.ts +3 -0
- package/lib/ui/presentation.js +12 -0
- package/npm-shrinkwrap.json +11123 -793
- package/package.json +94 -11
- package/python/README.md +6 -6
- package/resources/agents/coordinator.md +1 -1
- package/resources/dsh/cordis.patch.yml +3 -0
- package/resources/prompts/workspace.md +1 -1
- package/resources/references/compute.md +1 -1
- package/resources/references/task-conductor.md +6 -4
- package/resources/skills/provider-connections/SKILL.md +10 -0
- package/scripts/README.md +9 -1
- package/src/dsh.ts +22 -0
- package/src/extension/agent-events.ts +51 -46
- package/src/extension/agents-command.ts +48 -34
- package/src/extension/command.ts +42 -23
- package/src/extension/dsh/agent-events.ts +148 -0
- package/src/extension/dsh/agent-runtime.ts +251 -0
- package/src/extension/dsh/command.ts +78 -0
- package/src/extension/dsh/files.ts +61 -0
- package/src/extension/dsh/history.ts +69 -0
- package/src/extension/dsh/management.ts +108 -0
- package/src/extension/dsh/workspace.ts +206 -0
- package/src/extension/events.ts +6 -4
- package/src/extension/history.ts +15 -12
- package/src/extension/subagent-entry.ts +34 -63
- package/src/extension/teams-command.ts +53 -46
- package/src/integrations/{pi/agent-resources.ts → agent-resources.ts} +2 -2
- package/src/integrations/dsh/dsh-agents.ts +97 -0
- package/src/integrations/dsh/history-summary.ts +43 -0
- package/src/integrations/dsh/history.ts +76 -0
- package/src/integrations/dsh/input.ts +66 -0
- package/src/integrations/dsh/messages.ts +22 -0
- package/src/integrations/dsh/notifications.ts +46 -0
- package/src/integrations/dsh/resources.ts +44 -0
- package/src/integrations/dsh/schema.ts +26 -0
- package/src/integrations/dsh/session.ts +67 -0
- package/src/integrations/history-summary.ts +20 -0
- package/src/integrations/pi/history.ts +4 -14
- package/src/integrations/pi/pi-agents.ts +17 -6
- package/src/integrations/pi/team-context.ts +6 -58
- package/src/integrations/team-context.ts +60 -0
- package/src/model/agent.ts +2 -0
- package/src/model/history.ts +3 -1
- package/src/pbot.ts +1 -1
- package/src/services/agents/agent-notices.ts +28 -0
- package/src/services/agents/agent-run.ts +114 -0
- package/src/services/agents/agent-service.ts +127 -64
- package/src/services/history/history-service.ts +120 -59
- package/src/storage/agent-files.ts +17 -4
- package/src/storage/history-files.ts +30 -5
- package/src/tools/agents/actions.ts +47 -0
- package/src/tools/agents/contract.ts +8 -5
- package/src/tools/agents/dsh-contract.ts +16 -0
- package/src/tools/agents/dsh-tool.ts +41 -0
- package/src/tools/agents/tool.ts +7 -43
- package/src/tools/history/actions.ts +9 -0
- package/src/tools/history/contract.ts +34 -0
- package/src/tools/history/dsh-tool.ts +22 -0
- package/src/tools/history/tool.ts +7 -30
- package/src/tools/teams/actions.ts +38 -0
- package/src/tools/teams/contract.ts +7 -3
- package/src/tools/teams/dsh-tool.ts +55 -0
- package/src/tools/teams/tool.ts +6 -31
- package/src/ui/agent-display.ts +7 -4
- package/src/ui/dsh/attachments.ts +42 -0
- package/src/ui/dsh/elements.ts +50 -0
- package/src/ui/dsh/index.ts +18 -0
- package/src/ui/dsh/management.ts +412 -0
- package/src/ui/dsh/remote.ts +20 -0
- package/src/ui/dsh/styles.ts +132 -0
- package/src/ui/pi/menu.ts +37 -0
- package/src/ui/pi/reader.ts +46 -0
- package/src/ui/presentation.ts +12 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { AgentFiles } from "../../storage/agent-files.js";
|
|
2
|
+
import { TeamFiles } from "../../storage/team-files.js";
|
|
3
|
+
import type { AgentCompletion, AgentOwner } from "../../model/agent.js";
|
|
4
|
+
import type { TeamActor, TeamAgent, TeamInput, TeamLink, TeamMessage, TeamRecord, TeamRunOptions } from "../../model/team.js";
|
|
5
|
+
/** Team decisions only. The parent dispatches returned inputs through AgentService. */
|
|
6
|
+
export declare class TeamService {
|
|
7
|
+
#private;
|
|
8
|
+
readonly root: string;
|
|
9
|
+
readonly agents: AgentFiles;
|
|
10
|
+
readonly files: TeamFiles;
|
|
11
|
+
constructor(root: string, agents: AgentFiles, files: TeamFiles);
|
|
12
|
+
check(): void;
|
|
13
|
+
fail(error: unknown): void;
|
|
14
|
+
dispose(): void;
|
|
15
|
+
private owned;
|
|
16
|
+
private records;
|
|
17
|
+
private get;
|
|
18
|
+
private member;
|
|
19
|
+
private requests;
|
|
20
|
+
private active;
|
|
21
|
+
private available;
|
|
22
|
+
create(owner: AgentOwner, input: Pick<TeamRecord, "name" | "brief" | "members">, views: TeamAgent[]): TeamRecord;
|
|
23
|
+
run(id: string, owner: AgentOwner, options: TeamRunOptions, views: TeamAgent[]): {
|
|
24
|
+
runId: `${string}-${string}-${string}-${string}-${string}`;
|
|
25
|
+
instruction: string;
|
|
26
|
+
mode: "roundRobin" | "parallel";
|
|
27
|
+
rounds: number;
|
|
28
|
+
maxConcurrent: number;
|
|
29
|
+
deadlineAt: number;
|
|
30
|
+
generations: {
|
|
31
|
+
[k: string]: string;
|
|
32
|
+
};
|
|
33
|
+
state: "running";
|
|
34
|
+
issued: never[];
|
|
35
|
+
};
|
|
36
|
+
pause(id: string, owner: AgentOwner, reason?: string): void;
|
|
37
|
+
private pauseRecord;
|
|
38
|
+
pauseAll(owner: AgentOwner, reason: string): void;
|
|
39
|
+
recover(owner: AgentOwner): void;
|
|
40
|
+
pauseMember(agentId: string, reason: string): void;
|
|
41
|
+
close(id: string, owner: AgentOwner, views: TeamAgent[]): void;
|
|
42
|
+
post(id: string, actor: TeamActor, operationId: string, text: string, replyTo?: number): TeamMessage;
|
|
43
|
+
read(id: string, actor: TeamActor, page?: {
|
|
44
|
+
afterSeq?: number;
|
|
45
|
+
seq?: number;
|
|
46
|
+
offset?: number;
|
|
47
|
+
limit?: number;
|
|
48
|
+
}): {
|
|
49
|
+
teamId: string;
|
|
50
|
+
messages: {
|
|
51
|
+
text: string;
|
|
52
|
+
offset: number;
|
|
53
|
+
totalLength: number;
|
|
54
|
+
nextOffset: number | null;
|
|
55
|
+
seq: number;
|
|
56
|
+
operationId: string;
|
|
57
|
+
author: {
|
|
58
|
+
kind: "user" | "coordinator" | "member";
|
|
59
|
+
agentId?: string;
|
|
60
|
+
name: string;
|
|
61
|
+
};
|
|
62
|
+
replyTo?: number;
|
|
63
|
+
runId?: string;
|
|
64
|
+
source?: {
|
|
65
|
+
requestId: string;
|
|
66
|
+
cycleId: string;
|
|
67
|
+
};
|
|
68
|
+
}[];
|
|
69
|
+
lastSeq: number;
|
|
70
|
+
nextAfterSeq: number | null;
|
|
71
|
+
};
|
|
72
|
+
status(id: string, owner: AgentOwner, views: TeamAgent[]): {
|
|
73
|
+
owned: false;
|
|
74
|
+
teamId: string;
|
|
75
|
+
name: string;
|
|
76
|
+
closed: boolean;
|
|
77
|
+
} | {
|
|
78
|
+
run?: {
|
|
79
|
+
reason?: string;
|
|
80
|
+
runId: string;
|
|
81
|
+
instruction: string;
|
|
82
|
+
mode: "roundRobin" | "parallel";
|
|
83
|
+
state: "running" | "paused" | "finished";
|
|
84
|
+
rounds: number;
|
|
85
|
+
maxConcurrent: number;
|
|
86
|
+
deadlineAt: number;
|
|
87
|
+
scheduled: number;
|
|
88
|
+
published: number;
|
|
89
|
+
};
|
|
90
|
+
brief: string;
|
|
91
|
+
owned: true;
|
|
92
|
+
members: {
|
|
93
|
+
name: string;
|
|
94
|
+
state: "starting" | "busy" | "idle" | "stopping" | "stopped" | "error";
|
|
95
|
+
agentId: string;
|
|
96
|
+
role: string;
|
|
97
|
+
}[];
|
|
98
|
+
lastSeq: number;
|
|
99
|
+
activeCount: number;
|
|
100
|
+
unresolved: {
|
|
101
|
+
cycleId?: string;
|
|
102
|
+
requestId: string;
|
|
103
|
+
agentId: string;
|
|
104
|
+
runId: string;
|
|
105
|
+
round: number;
|
|
106
|
+
active: boolean;
|
|
107
|
+
state: string;
|
|
108
|
+
}[];
|
|
109
|
+
teamId: string;
|
|
110
|
+
name: string;
|
|
111
|
+
closed: boolean;
|
|
112
|
+
};
|
|
113
|
+
list(owner: AgentOwner, views: TeamAgent[]): ({
|
|
114
|
+
owned: false;
|
|
115
|
+
teamId: string;
|
|
116
|
+
name: string;
|
|
117
|
+
closed: boolean;
|
|
118
|
+
} | {
|
|
119
|
+
run?: {
|
|
120
|
+
reason?: string;
|
|
121
|
+
runId: string;
|
|
122
|
+
instruction: string;
|
|
123
|
+
mode: "roundRobin" | "parallel";
|
|
124
|
+
state: "running" | "paused" | "finished";
|
|
125
|
+
rounds: number;
|
|
126
|
+
maxConcurrent: number;
|
|
127
|
+
deadlineAt: number;
|
|
128
|
+
scheduled: number;
|
|
129
|
+
published: number;
|
|
130
|
+
};
|
|
131
|
+
brief: string;
|
|
132
|
+
owned: true;
|
|
133
|
+
members: {
|
|
134
|
+
name: string;
|
|
135
|
+
state: "starting" | "busy" | "idle" | "stopping" | "stopped" | "error";
|
|
136
|
+
agentId: string;
|
|
137
|
+
role: string;
|
|
138
|
+
}[];
|
|
139
|
+
lastSeq: number;
|
|
140
|
+
activeCount: number;
|
|
141
|
+
unresolved: {
|
|
142
|
+
cycleId?: string;
|
|
143
|
+
requestId: string;
|
|
144
|
+
agentId: string;
|
|
145
|
+
runId: string;
|
|
146
|
+
round: number;
|
|
147
|
+
active: boolean;
|
|
148
|
+
state: string;
|
|
149
|
+
}[];
|
|
150
|
+
teamId: string;
|
|
151
|
+
name: string;
|
|
152
|
+
closed: boolean;
|
|
153
|
+
})[];
|
|
154
|
+
private summary;
|
|
155
|
+
links(): Map<string, TeamLink>;
|
|
156
|
+
/** The callback persists the existing child receipt while the shared control lock is held. */
|
|
157
|
+
claim(agentId: string, generation: string, requestId: string, commit: () => void): TeamLink | undefined;
|
|
158
|
+
advance(owner: AgentOwner, views: TeamAgent[], completions: AgentCompletion[]): TeamInput[];
|
|
159
|
+
notifications(owner: AgentOwner, views: TeamAgent[]): {
|
|
160
|
+
reason?: string;
|
|
161
|
+
key: string;
|
|
162
|
+
teamId: string;
|
|
163
|
+
name: string;
|
|
164
|
+
runId: string;
|
|
165
|
+
state: "running" | "paused" | "finished";
|
|
166
|
+
activeCount: number;
|
|
167
|
+
}[];
|
|
168
|
+
}
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { requireThat } from "../../common/validation.js";
|
|
3
|
+
import { packageVersion, releaseLine } from "../../common/version.js";
|
|
4
|
+
import { AgentFiles, descriptor, launch, status, message } from "../../storage/agent-files.js";
|
|
5
|
+
import { TeamFiles } from "../../storage/team-files.js";
|
|
6
|
+
/** Team decisions only. The parent dispatches returned inputs through AgentService. */
|
|
7
|
+
export class TeamService {
|
|
8
|
+
root;
|
|
9
|
+
agents;
|
|
10
|
+
files;
|
|
11
|
+
#failure;
|
|
12
|
+
#disposed = false;
|
|
13
|
+
#recovered = new Set();
|
|
14
|
+
constructor(root, agents, files) {
|
|
15
|
+
this.root = root;
|
|
16
|
+
this.agents = agents;
|
|
17
|
+
this.files = files;
|
|
18
|
+
}
|
|
19
|
+
check() { requireThat(!this.#disposed, "团队服务已关闭。"); this.files.check(); if (this.#failure)
|
|
20
|
+
throw this.#failure; }
|
|
21
|
+
fail(error) { this.#failure = error; }
|
|
22
|
+
dispose() { this.#disposed = true; }
|
|
23
|
+
owned(team, owner) {
|
|
24
|
+
return team.workspace === this.root && team.parentSessionId === owner.sessionId && (team.parentLeaf === null || owner.branch.includes(team.parentLeaf));
|
|
25
|
+
}
|
|
26
|
+
records(sessionId) {
|
|
27
|
+
this.check();
|
|
28
|
+
return this.files.list().filter(t => t.workspace === this.root && releaseLine(t.release) === releaseLine(packageVersion) &&
|
|
29
|
+
(!sessionId || t.parentSessionId === sessionId));
|
|
30
|
+
}
|
|
31
|
+
get(id, actor) {
|
|
32
|
+
this.check();
|
|
33
|
+
const team = this.files.read(id);
|
|
34
|
+
requireThat(team.workspace === this.root && releaseLine(team.release) === releaseLine(packageVersion), "团队工作区或版本不匹配。");
|
|
35
|
+
if (actor.kind === "member") {
|
|
36
|
+
const d = this.agents.read(actor.agentId, "descriptor.json", descriptor), run = this.agents.read(actor.agentId, "launch.json", launch);
|
|
37
|
+
requireThat(d.workspace === this.root && d.parentSessionId === team.parentSessionId && team.members.some(m => m.agentId === actor.agentId) &&
|
|
38
|
+
run.generation === actor.generation && !run.stop, "团队成员身份已失效。");
|
|
39
|
+
}
|
|
40
|
+
else
|
|
41
|
+
requireThat(this.owned(team, actor.owner), "团队不属于当前会话分支。");
|
|
42
|
+
return team;
|
|
43
|
+
}
|
|
44
|
+
member(id, owner, views) {
|
|
45
|
+
const v = views.find(v => v.agentId === id), d = this.agents.read(id, "descriptor.json", descriptor);
|
|
46
|
+
requireThat(v && v.owned && d.workspace === this.root && d.parentSessionId === owner.sessionId &&
|
|
47
|
+
(d.parentLeaf === null || owner.branch.includes(d.parentLeaf)), "成员不属于当前分支:" + id);
|
|
48
|
+
requireThat(releaseLine(d.release) === releaseLine(packageVersion), "成员版本不兼容:" + id);
|
|
49
|
+
return v;
|
|
50
|
+
}
|
|
51
|
+
requests(team, views) {
|
|
52
|
+
const states = new Map(team.members.map(m => [m.agentId, { view: views.find(v => v.agentId === m.agentId),
|
|
53
|
+
saved: this.agents.optional(m.agentId, "status.json", status),
|
|
54
|
+
cycles: new Map(this.agents.completions(m.agentId).flatMap(c => c.requestIds.map(id => [c.generation + ":" + id, c]))) }]));
|
|
55
|
+
return team.runs.flatMap(run => run.issued.map(q => {
|
|
56
|
+
const s = states.get(q.agentId), ended = s.cycles.get(q.generation + ":" + q.requestId);
|
|
57
|
+
const accepted = s.saved?.generation === q.generation && !!s.saved.accepted?.includes(q.requestId);
|
|
58
|
+
const active = !ended && accepted && !!s.view?.alive && s.view.generation === q.generation;
|
|
59
|
+
let outcome = ended?.state;
|
|
60
|
+
if (ended && ended.source !== "parent")
|
|
61
|
+
outcome = ended.source;
|
|
62
|
+
else if (outcome === "completed" && !team.messages.some(m => m.source?.requestId === q.requestId))
|
|
63
|
+
outcome = "unpublished";
|
|
64
|
+
return { requestId: q.requestId, agentId: q.agentId, runId: run.runId, round: q.round, active,
|
|
65
|
+
state: outcome ?? (active ? "accepted" : accepted ? "uncertain" : run.state === "running" ? "queued" : "cancelled"),
|
|
66
|
+
...(ended ? { cycleId: ended.cycleId } : {}) };
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
active(team, views) { return this.requests(team, views).filter(q => q.active); }
|
|
70
|
+
available(id, owner, views, links) {
|
|
71
|
+
const v = this.member(id, owner, views), run = this.agents.read(id, "launch.json", launch);
|
|
72
|
+
const saved = this.agents.optional(id, "status.json", status), ready = this.files.ready(id);
|
|
73
|
+
const available = (condition, message) => {
|
|
74
|
+
if (!condition)
|
|
75
|
+
throw Object.assign(new Error(message), { code: "TEAM_NOT_READY" });
|
|
76
|
+
};
|
|
77
|
+
available(v.alive && v.state === "idle" && !run.stop && v.generation === run.generation && saved?.generation === run.generation && saved.state === "idle", "成员尚未空闲:" + id);
|
|
78
|
+
available(ready?.ready && ready.generation === run.generation, "成员需加载新版子入口:" + id);
|
|
79
|
+
available(!this.agents.messages(id).some(q => q.generation === run.generation && !saved?.accepted?.includes(q.requestId) && !links.has(q.requestId)), "成员有待处理私人输入:" + id);
|
|
80
|
+
return v;
|
|
81
|
+
}
|
|
82
|
+
create(owner, input, views) {
|
|
83
|
+
this.check();
|
|
84
|
+
return this.agents.control(() => {
|
|
85
|
+
const records = this.records();
|
|
86
|
+
for (const m of input.members) {
|
|
87
|
+
this.member(m.agentId, owner, views);
|
|
88
|
+
requireThat(!records.some(t => !t.closed && t.members.some(v => v.agentId === m.agentId)), "成员已属于未关闭团队:" + m.agentId);
|
|
89
|
+
}
|
|
90
|
+
const team = { ...input, members: structuredClone(input.members), teamId: randomUUID(), release: packageVersion,
|
|
91
|
+
workspace: this.root, parentSessionId: owner.sessionId, parentLeaf: owner.leaf, closed: false, runs: [], messages: [] };
|
|
92
|
+
this.files.save(team, true);
|
|
93
|
+
return team;
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
run(id, owner, options, views) {
|
|
97
|
+
this.check();
|
|
98
|
+
return this.agents.control(() => {
|
|
99
|
+
const team = this.get(id, { kind: "coordinator", owner }), links = this.files.links(this.records());
|
|
100
|
+
requireThat(!team.closed && !team.runs.some(r => r.state === "running") && !this.active(team, views).length, "团队仍在工作或已关闭。");
|
|
101
|
+
const members = team.members.map(m => this.available(m.agentId, owner, views, links));
|
|
102
|
+
requireThat(options.mode !== "roundRobin" || options.maxConcurrent === undefined || options.maxConcurrent === 1, "轮流讨论并发须为 1。");
|
|
103
|
+
const rounds = options.rounds ?? 2, maxConcurrent = options.mode === "roundRobin" ? 1 : options.maxConcurrent ?? Math.min(2, members.length);
|
|
104
|
+
requireThat(Number.isInteger(rounds) && rounds >= 1 && rounds <= 10 && Number.isInteger(maxConcurrent) && maxConcurrent >= 1 && maxConcurrent <= members.length, "轮次或并发无效。");
|
|
105
|
+
const seconds = options.timeoutSeconds ?? 900;
|
|
106
|
+
requireThat(Number.isInteger(seconds) && seconds >= 1 && seconds <= 86400, "期限须为 1–86400 秒。");
|
|
107
|
+
requireThat(options.instruction.trim().length > 0, "新批次需要新的明确要求。");
|
|
108
|
+
const run = { runId: randomUUID(), instruction: options.instruction, mode: options.mode, rounds, maxConcurrent,
|
|
109
|
+
deadlineAt: Date.now() + seconds * 1000, generations: Object.fromEntries(members.map(v => [v.agentId, v.generation])),
|
|
110
|
+
state: "running", issued: [] };
|
|
111
|
+
team.runs.push(run);
|
|
112
|
+
this.files.save(team);
|
|
113
|
+
return run;
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
pause(id, owner, reason = "主会话暂停") {
|
|
117
|
+
this.check();
|
|
118
|
+
this.agents.control(() => { const team = this.get(id, { kind: "coordinator", owner }); this.pauseRecord(team, reason); });
|
|
119
|
+
}
|
|
120
|
+
pauseRecord(team, reason) {
|
|
121
|
+
let changed = false;
|
|
122
|
+
for (const run of team.runs)
|
|
123
|
+
if (run.state === "running") {
|
|
124
|
+
run.state = "paused";
|
|
125
|
+
run.reason = reason;
|
|
126
|
+
changed = true;
|
|
127
|
+
}
|
|
128
|
+
if (changed)
|
|
129
|
+
this.files.save(team);
|
|
130
|
+
}
|
|
131
|
+
pauseAll(owner, reason) {
|
|
132
|
+
this.check();
|
|
133
|
+
this.agents.control(() => { for (const team of this.records(owner.sessionId))
|
|
134
|
+
this.pauseRecord(team, reason); });
|
|
135
|
+
}
|
|
136
|
+
recover(owner) {
|
|
137
|
+
if (this.#recovered.has(owner.sessionId))
|
|
138
|
+
return;
|
|
139
|
+
this.pauseAll(owner, "主会话恢复:未自动续排旧批次");
|
|
140
|
+
this.#recovered.add(owner.sessionId);
|
|
141
|
+
}
|
|
142
|
+
pauseMember(agentId, reason) {
|
|
143
|
+
this.check();
|
|
144
|
+
this.agents.control(() => { for (const team of this.records())
|
|
145
|
+
if (team.members.some(m => m.agentId === agentId))
|
|
146
|
+
this.pauseRecord(team, reason); });
|
|
147
|
+
}
|
|
148
|
+
close(id, owner, views) {
|
|
149
|
+
this.check();
|
|
150
|
+
this.agents.control(() => {
|
|
151
|
+
const team = this.get(id, { kind: "coordinator", owner });
|
|
152
|
+
requireThat(!team.runs.some(r => r.state === "running") && !this.active(team, views).length, "先暂停团队并等待在途工作结束。");
|
|
153
|
+
if (!team.closed) {
|
|
154
|
+
team.closed = true;
|
|
155
|
+
this.files.save(team);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
post(id, actor, operationId, text, replyTo) {
|
|
160
|
+
this.check();
|
|
161
|
+
requireThat(text.trim().length > 0 && text.length <= 24000 && operationId.length > 0, "消息须为 1–24000 字符。");
|
|
162
|
+
operationId = actor.kind === "member" ? "post:" + actor.agentId + ":" + actor.generation + ":" + operationId : "post:" + actor.kind + ":" + actor.owner.sessionId + ":" + operationId;
|
|
163
|
+
return this.agents.control(() => {
|
|
164
|
+
const team = this.get(id, actor);
|
|
165
|
+
const prior = team.messages.find(m => m.operationId === operationId);
|
|
166
|
+
if (prior) {
|
|
167
|
+
requireThat(prior.text === text && prior.replyTo === replyTo && prior.author.kind === actor.kind &&
|
|
168
|
+
(actor.kind !== "member" || prior.author.agentId === actor.agentId), "发布操作 ID 冲突。");
|
|
169
|
+
return prior;
|
|
170
|
+
}
|
|
171
|
+
requireThat(!team.closed, "团队已关闭。");
|
|
172
|
+
requireThat(replyTo === undefined || team.messages.some(m => m.seq === replyTo), "回复目标不存在。");
|
|
173
|
+
let runId;
|
|
174
|
+
if (actor.kind === "member") {
|
|
175
|
+
const run = team.runs.find(r => r.issued.some(q => q.requestId === actor.requestId && q.agentId === actor.agentId && q.generation === actor.generation));
|
|
176
|
+
const saved = this.agents.optional(actor.agentId, "status.json", status);
|
|
177
|
+
requireThat(run && saved?.generation === actor.generation && saved.cycle?.state === "running" && saved.cycle.source === "parent" &&
|
|
178
|
+
!!actor.requestId && saved.cycle.requestIds.includes(actor.requestId), "只能在自己的团队工作中发言。");
|
|
179
|
+
runId = run.runId;
|
|
180
|
+
}
|
|
181
|
+
const value = { seq: team.messages.length + 1, operationId, text,
|
|
182
|
+
author: actor.kind === "member" ? { kind: "member", agentId: actor.agentId, name: this.agents.read(actor.agentId, "launch.json", launch).name }
|
|
183
|
+
: { kind: actor.kind, name: actor.kind === "user" ? "用户" : "主会话" },
|
|
184
|
+
...(replyTo === undefined ? {} : { replyTo }), ...(runId ? { runId } : {}) };
|
|
185
|
+
team.messages.push(value);
|
|
186
|
+
this.files.save(team);
|
|
187
|
+
return value;
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
read(id, actor, page = {}) {
|
|
191
|
+
const team = this.get(id, actor), limit = page.limit ?? 16000, after = page.afterSeq ?? 0, offset = page.offset ?? 0;
|
|
192
|
+
requireThat(Number.isInteger(limit) && limit >= 1 && limit <= 16000 && Number.isInteger(after) && after >= 0 && after <= team.messages.length &&
|
|
193
|
+
Number.isInteger(offset) && offset >= 0 && (page.seq !== undefined || offset === 0), "分页参数无效。");
|
|
194
|
+
const values = page.seq === undefined ? team.messages.filter(m => m.seq > after) : team.messages.filter(m => m.seq === page.seq);
|
|
195
|
+
requireThat(page.seq === undefined || values.length === 1, "消息不存在。");
|
|
196
|
+
let left = limit;
|
|
197
|
+
const messages = [];
|
|
198
|
+
for (const m of values) {
|
|
199
|
+
const at = page.seq === undefined ? 0 : offset;
|
|
200
|
+
requireThat(at <= m.text.length, "消息分页位置超出范围。");
|
|
201
|
+
const text = m.text.slice(at, at + left);
|
|
202
|
+
left -= Math.max(1, text.length);
|
|
203
|
+
messages.push({ ...m, text, offset: at, totalLength: m.text.length, nextOffset: at + text.length < m.text.length ? at + text.length : null });
|
|
204
|
+
if (left <= 0)
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
const last = messages.at(-1)?.seq ?? after;
|
|
208
|
+
return { teamId: id, messages, lastSeq: team.messages.length, nextAfterSeq: page.seq === undefined && last < team.messages.length ? last : null };
|
|
209
|
+
}
|
|
210
|
+
status(id, owner, views) {
|
|
211
|
+
return this.summary(this.get(id, { kind: "coordinator", owner }), owner, views);
|
|
212
|
+
}
|
|
213
|
+
list(owner, views) { return this.records(owner.sessionId).map(t => this.summary(t, owner, views)); }
|
|
214
|
+
summary(team, owner, views) {
|
|
215
|
+
const identity = { teamId: team.teamId, name: team.name, closed: team.closed };
|
|
216
|
+
if (!this.owned(team, owner))
|
|
217
|
+
return { ...identity, owned: false };
|
|
218
|
+
const run = team.runs.at(-1), requests = this.requests(team, views), activeCount = requests.filter(q => q.active).length;
|
|
219
|
+
return { ...identity, brief: team.brief, owned: true,
|
|
220
|
+
members: team.members.map(m => { const v = views.find(v => v.agentId === m.agentId); return { ...m, name: v?.name ?? m.agentId, state: v?.state ?? "stopped" }; }),
|
|
221
|
+
lastSeq: team.messages.length, activeCount, unresolved: requests.filter(q => q.state !== "completed"),
|
|
222
|
+
...(run ? { run: { runId: run.runId, instruction: run.instruction, mode: run.mode, state: run.state, rounds: run.rounds,
|
|
223
|
+
maxConcurrent: run.maxConcurrent, deadlineAt: run.deadlineAt, scheduled: run.issued.length,
|
|
224
|
+
published: team.messages.filter(m => m.runId === run.runId && m.source).length, ...(run.reason ? { reason: run.reason } : {}) } } : {}) };
|
|
225
|
+
}
|
|
226
|
+
links() { return this.files.links(this.records()); }
|
|
227
|
+
/** The callback persists the existing child receipt while the shared control lock is held. */
|
|
228
|
+
claim(agentId, generation, requestId, commit) {
|
|
229
|
+
this.check();
|
|
230
|
+
return this.agents.control(() => {
|
|
231
|
+
const link = this.links().get(requestId), run = this.agents.read(agentId, "launch.json", launch), ready = this.files.ready(agentId);
|
|
232
|
+
const saved = this.agents.optional(agentId, "status.json", status), input = this.agents.optional(agentId, "inbox/" + requestId + ".json", message);
|
|
233
|
+
if (!link || link.request.agentId !== agentId || link.request.generation !== generation || run.generation !== generation || run.stop ||
|
|
234
|
+
!ready?.ready || ready.generation !== generation || saved?.generation !== generation || saved.state !== "idle" ||
|
|
235
|
+
saved.accepted?.includes(requestId) || input?.generation !== generation || link.team.closed || link.run.state !== "running" || link.run.deadlineAt <= Date.now())
|
|
236
|
+
return;
|
|
237
|
+
for (const member of link.team.members) {
|
|
238
|
+
const memberRun = this.agents.read(member.agentId, "launch.json", launch), memberReady = this.files.ready(member.agentId);
|
|
239
|
+
if (memberRun.stop || memberRun.generation !== link.run.generations[member.agentId] || !memberReady?.ready || memberReady.generation !== memberRun.generation)
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
commit();
|
|
243
|
+
return link;
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
advance(owner, views, completions) {
|
|
247
|
+
this.check();
|
|
248
|
+
return this.agents.control(() => {
|
|
249
|
+
const inputs = [], records = this.records(owner.sessionId), links = this.files.links(records);
|
|
250
|
+
for (const team of records) {
|
|
251
|
+
let changed = false;
|
|
252
|
+
for (const run of team.runs) {
|
|
253
|
+
for (const q of run.issued) {
|
|
254
|
+
const done = completions.find(v => v.agentId === q.agentId && v.cycle.generation === q.generation && v.cycle.requestIds.includes(q.requestId));
|
|
255
|
+
if (!done)
|
|
256
|
+
continue;
|
|
257
|
+
if (done.cycle.state !== "completed" || done.cycle.source !== "parent" || done.cycle.requestIds.length !== 1 || !done.report.trim()) {
|
|
258
|
+
if (run.state === "running") {
|
|
259
|
+
run.state = "paused";
|
|
260
|
+
run.reason = "成员失败或人工接管:" + q.agentId;
|
|
261
|
+
changed = true;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
else if (!team.messages.some(m => m.source?.requestId === q.requestId)) {
|
|
265
|
+
team.messages.push({ seq: team.messages.length + 1, operationId: "result:" + q.requestId,
|
|
266
|
+
author: { kind: "member", agentId: q.agentId, name: done.name }, text: done.report, runId: run.runId,
|
|
267
|
+
source: { requestId: q.requestId, cycleId: done.cycle.cycleId } });
|
|
268
|
+
changed = true;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
if (run.state !== "running")
|
|
272
|
+
continue;
|
|
273
|
+
const unavailable = team.members.find(m => {
|
|
274
|
+
const v = views.find(v => v.agentId === m.agentId), ready = this.files.ready(m.agentId);
|
|
275
|
+
return !v?.alive || !v.owned || v.generation !== run.generations[m.agentId] || !ready?.ready || ready.generation !== v.generation ||
|
|
276
|
+
["stopping", "stopped", "error"].includes(v.state) || (v.cycle?.state === "running" && v.cycle.source !== "parent");
|
|
277
|
+
});
|
|
278
|
+
if (!this.owned(team, owner) || unavailable || Date.now() >= run.deadlineAt) {
|
|
279
|
+
run.state = "paused";
|
|
280
|
+
run.reason = !this.owned(team, owner) ? "当前分支无团队归属" : unavailable ? "成员不可用:" + unavailable.agentId : "已到期限";
|
|
281
|
+
changed = true;
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
const finished = new Set(team.messages.filter(m => m.runId === run.runId && m.source).map(m => m.source.requestId));
|
|
285
|
+
const outstanding = run.issued.filter(q => !finished.has(q.requestId));
|
|
286
|
+
const round = Math.max(1, ...run.issued.map(q => q.round));
|
|
287
|
+
const thisRound = run.issued.filter(q => q.round === round);
|
|
288
|
+
const nextRound = thisRound.length === team.members.length && thisRound.every(q => finished.has(q.requestId)) ? round + 1 : round;
|
|
289
|
+
if (nextRound > run.rounds) {
|
|
290
|
+
run.state = "finished";
|
|
291
|
+
changed = true;
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
let slots = run.maxConcurrent - outstanding.length;
|
|
295
|
+
for (const m of team.members) {
|
|
296
|
+
if (slots <= 0)
|
|
297
|
+
break;
|
|
298
|
+
if (run.issued.some(q => q.round === nextRound && q.agentId === m.agentId))
|
|
299
|
+
continue;
|
|
300
|
+
// Waiting here does not create a second work queue. Unexpected private work pauses the batch.
|
|
301
|
+
const view = views.find(v => v.agentId === m.agentId);
|
|
302
|
+
if (view?.state === "busy" && view.cycle?.requestIds.some(id => run.issued.some(q => q.requestId === id)))
|
|
303
|
+
break;
|
|
304
|
+
try {
|
|
305
|
+
this.available(m.agentId, owner, views, links);
|
|
306
|
+
}
|
|
307
|
+
catch (error) {
|
|
308
|
+
if (error.code !== "TEAM_NOT_READY")
|
|
309
|
+
throw error;
|
|
310
|
+
run.state = "paused";
|
|
311
|
+
run.reason = String(error);
|
|
312
|
+
changed = true;
|
|
313
|
+
break;
|
|
314
|
+
}
|
|
315
|
+
const q = { requestId: randomUUID(), agentId: m.agentId, generation: run.generations[m.agentId], round: nextRound, throughSeq: team.messages.length };
|
|
316
|
+
run.issued.push(q);
|
|
317
|
+
slots--;
|
|
318
|
+
changed = true;
|
|
319
|
+
inputs.push({ ...q, teamId: team.teamId, runId: run.runId,
|
|
320
|
+
message: ["# 团队发言任务", "", "执行本次团队发言安排。最终答复将公开给全体成员;这不扩大原任务授权。", "",
|
|
321
|
+
"- `teamId`: `" + team.teamId + "`", "- `runId`: `" + run.runId + "`", "- 轮次:" + q.round,
|
|
322
|
+
"", "## 本批次要求", "", run.instruction].join("\n") });
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
if (changed)
|
|
326
|
+
this.files.save(team);
|
|
327
|
+
}
|
|
328
|
+
return inputs.filter(input => records.find(t => t.teamId === input.teamId)?.runs.find(r => r.runId === input.runId)?.state === "running");
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
notifications(owner, views) {
|
|
332
|
+
return this.records(owner.sessionId).filter(t => this.owned(t, owner) && t.members.every(m => views.some(v => v.agentId === m.agentId && v.owned)))
|
|
333
|
+
.flatMap(team => {
|
|
334
|
+
const requests = this.requests(team, views);
|
|
335
|
+
return team.runs.filter(r => r.state !== "running").map(run => {
|
|
336
|
+
const activeCount = requests.filter(q => q.runId === run.runId && q.active).length;
|
|
337
|
+
return { key: team.teamId + ":" + run.runId + ":" + run.state + (activeCount ? ":draining" : ":settled"),
|
|
338
|
+
teamId: team.teamId, name: team.name, runId: run.runId, state: run.state, activeCount,
|
|
339
|
+
...(run.reason ? { reason: run.reason } : {}) };
|
|
340
|
+
});
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { HistoryHost, HistoryLocation, HistoryNode, HistoryRecord, HistorySession, HistorySource, HistorySummarizer } from "../../model/history.js";
|
|
2
|
+
import type { HistoryFiles } from "../../storage/history-files.js";
|
|
3
|
+
/** Shared prefixes reuse nodes; only consecutive exchanges on one native branch can merge. */
|
|
4
|
+
export declare function indexHistory(session: HistorySession, previous?: HistoryRecord, host?: HistoryHost): HistoryRecord;
|
|
5
|
+
export interface HistoryQuery {
|
|
6
|
+
host?: HistoryHost;
|
|
7
|
+
query?: string;
|
|
8
|
+
sessionId?: string;
|
|
9
|
+
from?: string;
|
|
10
|
+
to?: string;
|
|
11
|
+
offset?: number;
|
|
12
|
+
limit?: number;
|
|
13
|
+
}
|
|
14
|
+
/** Validate the exact inputs again under the source lock; another writer's ready summary wins. */
|
|
15
|
+
export declare function completeHistorySummary(record: HistoryRecord, id: string, children: HistoryNode[], text: string): boolean;
|
|
16
|
+
export declare class HistoryService {
|
|
17
|
+
#private;
|
|
18
|
+
readonly root: string;
|
|
19
|
+
private readonly files;
|
|
20
|
+
private readonly source;
|
|
21
|
+
private previousFiles?;
|
|
22
|
+
private readonly otherFiles?;
|
|
23
|
+
constructor(root: string, files: HistoryFiles, source: HistorySource, previousFiles?: HistoryFiles | undefined, otherFiles?: HistoryFiles | undefined);
|
|
24
|
+
check(): void;
|
|
25
|
+
get warnings(): string[];
|
|
26
|
+
get status(): {
|
|
27
|
+
loaded: boolean;
|
|
28
|
+
organizing: boolean;
|
|
29
|
+
pending: number | null;
|
|
30
|
+
warnings: string[];
|
|
31
|
+
};
|
|
32
|
+
refresh(location: HistoryLocation, signal?: AbortSignal): Promise<void>;
|
|
33
|
+
private load;
|
|
34
|
+
search({ host, query, sessionId, from, to, offset, limit }?: HistoryQuery): {
|
|
35
|
+
matches: {
|
|
36
|
+
parents: string[];
|
|
37
|
+
snippet: string;
|
|
38
|
+
host: HistoryHost;
|
|
39
|
+
id: string;
|
|
40
|
+
kind: "session" | "exchange" | "summary";
|
|
41
|
+
sessionId: string;
|
|
42
|
+
name: string;
|
|
43
|
+
preview: string;
|
|
44
|
+
from: string;
|
|
45
|
+
to: string;
|
|
46
|
+
ready: boolean;
|
|
47
|
+
completed: boolean;
|
|
48
|
+
}[];
|
|
49
|
+
total: number;
|
|
50
|
+
nextOffset: number | null;
|
|
51
|
+
warnings: string[];
|
|
52
|
+
};
|
|
53
|
+
private find;
|
|
54
|
+
read(id: string, offset?: number, limit?: number, childrenOffset?: number, host?: HistoryHost): {
|
|
55
|
+
text: string;
|
|
56
|
+
totalLength: number;
|
|
57
|
+
nextOffset: number | null;
|
|
58
|
+
parents: {
|
|
59
|
+
host: HistoryHost;
|
|
60
|
+
id: string;
|
|
61
|
+
kind: "session" | "exchange" | "summary";
|
|
62
|
+
sessionId: string;
|
|
63
|
+
name: string;
|
|
64
|
+
preview: string;
|
|
65
|
+
from: string;
|
|
66
|
+
to: string;
|
|
67
|
+
ready: boolean;
|
|
68
|
+
completed: boolean;
|
|
69
|
+
}[];
|
|
70
|
+
children: {
|
|
71
|
+
host: HistoryHost;
|
|
72
|
+
id: string;
|
|
73
|
+
kind: "session" | "exchange" | "summary";
|
|
74
|
+
sessionId: string;
|
|
75
|
+
name: string;
|
|
76
|
+
preview: string;
|
|
77
|
+
from: string;
|
|
78
|
+
to: string;
|
|
79
|
+
ready: boolean;
|
|
80
|
+
completed: boolean;
|
|
81
|
+
}[];
|
|
82
|
+
nextChildrenOffset: number | null;
|
|
83
|
+
source: {
|
|
84
|
+
host: HistoryHost;
|
|
85
|
+
sessionId: string;
|
|
86
|
+
entryIds: string[];
|
|
87
|
+
};
|
|
88
|
+
warnings: string[];
|
|
89
|
+
host: HistoryHost;
|
|
90
|
+
id: string;
|
|
91
|
+
kind: "session" | "exchange" | "summary";
|
|
92
|
+
sessionId: string;
|
|
93
|
+
name: string;
|
|
94
|
+
preview: string;
|
|
95
|
+
from: string;
|
|
96
|
+
to: string;
|
|
97
|
+
ready: boolean;
|
|
98
|
+
completed: boolean;
|
|
99
|
+
};
|
|
100
|
+
/** Only this source is organized. Model calls run outside the write lock. */
|
|
101
|
+
organize(summarize: HistorySummarizer, signal: AbortSignal): Promise<void>;
|
|
102
|
+
close(): Promise<void>;
|
|
103
|
+
}
|