241
* commands so clients see the simplified form.
242
*/
244
>
session: URI,
245
>
db: ISessionDatabase | undefined,
246
>
events: readonly SessionEvent[],
247
>
options: URI | IMapSessionEventsOptions | undefined = undefined,
248
>
): Promise<{ turns: Turn[]; subagentTurnsByToolCallId: ReadonlyMap<string, Turn[]> }> {
249
>
const workingDirectory = options instanceof URI ? options : options?.workingDirectory;
250
>
let currentModel = options instanceof URI ? undefined : options?.model;
251
>
let currentAgent = options instanceof URI ? undefined : options?.agent;
252
>
// First pass: collect tool-arg info and identify edit tool calls so we
253
>
// can batch-load their stored file edits before the second pass needs
254
>
// them at `tool.execution_complete` time. We also build the
255
>
// `agentId` -> parent tool call id map here so the second pass can route
256
>
// sub-agent events without depending on event ordering.
257
>
const toolInfoByCallId = new Map<string, IToolStartInfo>();
258
>
const editToolCallIds: string[] = [];
259
>
const completionsByCallId = new Map<string, ToolExecutionCompleteData>();
260
>
261
>
// The SDK tags events that originate from a sub-agent with an
262
>
// envelope-level `agentId` (the deprecated `data.parentToolCallId` is no
263
>
// longer populated). `subagent.started` carries both the sub-agent's
264
>
// `agentId` and the parent tool call id it was spawned from, so we map
265
>
// one to the other and resolve every later sub-agent event through it.
266
>
const parentToolCallIdByAgentId = new Map<string, string>();
267
>
const resolveParentToolCallId = (agentId: string | undefined, deprecatedParentToolCallId: string | undefined): string | undefined => {
268
const mapped = agentId ? parentToolCallIdByAgentId.get(agentId) : undefined;
269
return mapped ?? deprecatedParentToolCallId;
270
};
272
>
for (const e of events) {
273
if (e.type === 'subagent.started') {
274
if (e.agentId) {