| 586 | return last.time.completed ? "idle" : "working" |
| 587 | }, |
| 588 | async sync(sessionID: string) { |
| 589 | if (fullSyncedSessions.has(sessionID)) return |
| 590 | const syncing = syncingSessions.get(sessionID) |
| 591 | if (syncing) return syncing |
| 592 | const tracker = { messages: new Set<string>(), parts: new Set<string>() } |
| 593 | hydratingSessions.set(sessionID, tracker) |
| 594 | const task = (async () => { |
| 595 | const [session, messages, todo, diff] = await Promise.all([ |
| 596 | sdk.client.session.get({ sessionID }, { throwOnError: true }), |
| 597 | sdk.client.session.messages({ sessionID, limit: 100 }), |
| 598 | sdk.client.session.todo({ sessionID }), |
| 599 | sdk.client.session.diff({ sessionID }), |
| 600 | ]) |
| 601 | setStore( |
| 602 | produce((draft) => { |
| 603 | const match = search(draft.session, sessionID, (s) => s.id) |
| 604 | if (match.found) draft.session[match.index] = session.data! |
| 605 | if (!match.found) draft.session.splice(match.index, 0, session.data!) |
| 606 | draft.todo[sessionID] = todo.data ?? [] |
| 607 | const currentMessages = draft.message[sessionID] ?? [] |
| 608 | const infos = (messages.data ?? []).flatMap((message) => { |
| 609 | if (!tracker.messages.has(message.info.id)) return [message.info] |
| 610 | const current = currentMessages.find((item) => item.id === message.info.id) |
| 611 | return current ? [current] : [] |
| 612 | }) |
| 613 | infos.push( |
| 614 | ...currentMessages.filter( |
| 615 | (message) => tracker.messages.has(message.id) && !infos.some((item) => item.id === message.id), |
| 616 | ), |
| 617 | ) |
| 618 | const removed = infos.slice(0, -100) |
| 619 | const visible = infos.slice(-100) |
| 620 | const visibleIDs = new Set(visible.map((message) => message.id)) |
| 621 | for (const message of messages.data ?? []) { |
| 622 | if (!visibleIDs.has(message.info.id)) { |
| 623 | delete draft.part[message.info.id] |
| 624 | continue |
| 625 | } |
| 626 | const currentParts = draft.part[message.info.id] ?? [] |
| 627 | const parts = message.parts.flatMap((part) => { |
| 628 | const current = currentParts.find((item) => item.id === part.id) |
| 629 | if (tracker.parts.has(part.id)) return current ? [current] : [] |
| 630 | if ( |
| 631 | current && |
| 632 | (part.type === "text" || part.type === "reasoning") && |
| 633 | (current.type === "text" || current.type === "reasoning") && |
| 634 | part.text.length === 0 && |
| 635 | current.text.length > 0 |
| 636 | ) { |
| 637 | return [current] |
| 638 | } |
| 639 | return [part] |
| 640 | }) |
| 641 | parts.push( |
| 642 | ...currentParts.filter( |
| 643 | (part) => tracker.parts.has(part.id) && !parts.some((item) => item.id === part.id), |
| 644 | ), |
| 645 | ) |