@jkwd/inbase 0.1.4 → 0.1.5

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.
@@ -1,6 +1,6 @@
1
1
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
2
2
  import { Canvas } from '@react-three/fiber'
3
- import { emptyIntent, fetchAgentIntent, inspectTargetFile, performAgentAction, persistSessionBlueprint } from './agentIntent'
3
+ import { emptyIntent, fetchAgentIntent, fetchAgentIntents, inspectTargetFile, performAgentAction, persistSessionBlueprint } from './agentIntent'
4
4
  import { fetchCodebase } from './codebase'
5
5
  import {
6
6
  layoutWorld,
@@ -100,7 +100,17 @@ function Explorer({
100
100
  graph: CodebaseGraph
101
101
  onRefreshGraph: () => Promise<void>
102
102
  }) {
103
- const [intent, setIntent] = useState<AgentIntent>(emptyIntent)
103
+ const [intents, setIntents] = useState<AgentIntent[]>([])
104
+ const [focusedSessionId, setFocusedSessionId] = useState<string | null>(null)
105
+ const intent =
106
+ intents.find((item) => item.sessionId === focusedSessionId) ??
107
+ intents[0] ??
108
+ emptyIntent
109
+ const creationIntent =
110
+ intents.find((item) => item.creationMode) ??
111
+ intents.find((item) => item.status === 'blueprint') ??
112
+ null
113
+ const creationMode = Boolean(creationIntent?.creationMode)
104
114
  const previewing = intent.preview || isPatchPreview(intent.status)
105
115
  const plannedCreates = previewing ? intent.creates : []
106
116
  const [userBlocks, setUserBlocks] = useState<UserCreatedBlock[]>([])
@@ -172,12 +182,30 @@ function Explorer({
172
182
  const [followLook, setFollowLook] = useState(false)
173
183
  const [importedBy, setImportedBy] = useState(false)
174
184
  const lastIntentSig = useRef<string | null>(null)
175
- const viewedDiffId = useRef<string | null>(null)
176
- const browsingHistory = useRef(false)
185
+ const viewedDiffId = useRef<Record<string, string | null>>({})
186
+ const browsingHistory = useRef<Record<string, boolean>>({})
177
187
 
178
- const applyIntent = useCallback((next: AgentIntent) => {
179
- setIntent(next)
180
- viewedDiffId.current = next.diffId
188
+ const applyIntent = useCallback((next: AgentIntent, sessionId?: string) => {
189
+ const targetId = next.sessionId ?? sessionId ?? null
190
+ setIntents((current) => {
191
+ const nextList =
192
+ !targetId || next.status === 'idle' || !next.sessionId
193
+ ? current.filter((item) => item.sessionId !== targetId)
194
+ : current.some((item) => item.sessionId === targetId)
195
+ ? current.map((item) => (item.sessionId === targetId ? next : item))
196
+ : [...current, next]
197
+ setFocusedSessionId((currentFocus) => {
198
+ if (
199
+ currentFocus &&
200
+ nextList.some((item) => item.sessionId === currentFocus)
201
+ ) {
202
+ return currentFocus
203
+ }
204
+ return nextList[0]?.sessionId ?? null
205
+ })
206
+ return nextList
207
+ })
208
+ if (targetId && next.sessionId) viewedDiffId.current[targetId] = next.diffId
181
209
  }, [])
182
210
 
183
211
  const rememberWalk = useCallback((x: number, z: number) => {
@@ -244,23 +272,25 @@ function Explorer({
244
272
 
245
273
  const runWorkflowAction = useCallback(
246
274
  async (
275
+ sessionId: string,
247
276
  action: WorkflowAction,
248
277
  options: { instruction?: string; step?: number } = {},
249
278
  ) => {
250
- if (!intent.sessionId) return
279
+ const current = intents.find((item) => item.sessionId === sessionId)
280
+ if (!current?.sessionId) return
251
281
  if (
252
282
  (action === 'continue' || action === 'instruct') &&
253
- (!intent.diffId || !intent.isActiveDiff)
283
+ (!current.diffId || !current.isActiveDiff)
254
284
  ) {
255
285
  return
256
286
  }
257
287
  try {
258
288
  const next = await performAgentAction(
259
289
  action,
260
- intent.sessionId,
290
+ current.sessionId,
261
291
  {
262
292
  ...options,
263
- diffId: intent.diffId ?? undefined,
293
+ diffId: current.diffId ?? undefined,
264
294
  ...(action === 'blueprint_send'
265
295
  ? {
266
296
  userCreatedBlocks: namedCreatedBlocks(userBlocks),
@@ -272,9 +302,9 @@ function Explorer({
272
302
  : {}),
273
303
  },
274
304
  )
275
- browsingHistory.current = false
276
- lastIntentSig.current = intentSignature(next)
277
- applyIntent(next)
305
+ browsingHistory.current[sessionId] = false
306
+ lastIntentSig.current = null
307
+ applyIntent(next, sessionId)
278
308
  if (action === 'invoke' || action === 'continue' || action === 'stop') {
279
309
  await onRefreshGraph()
280
310
  }
@@ -287,9 +317,7 @@ function Explorer({
287
317
  blueprintFunctions,
288
318
  blueprintImports,
289
319
  blueprintVariables,
290
- intent.diffId,
291
- intent.isActiveDiff,
292
- intent.sessionId,
320
+ intents,
293
321
  onRefreshGraph,
294
322
  userBlocks,
295
323
  userIslands,
@@ -297,28 +325,29 @@ function Explorer({
297
325
  )
298
326
 
299
327
  const navigateDiff = useCallback(
300
- async (diffId: string) => {
328
+ async (sessionId: string, diffId: string) => {
329
+ const current = intents.find((item) => item.sessionId === sessionId)
330
+ if (!current) return
301
331
  try {
302
- const latest = intent.chain.at(-1)?.id
303
- browsingHistory.current = diffId !== latest
304
- if (intent.sessionId) {
305
- try {
306
- await inspectTargetFile({
307
- sessionId: intent.sessionId,
308
- diffId,
309
- })
310
- } catch {
311
- // Still show the historical preview if disk replay failed.
312
- }
332
+ const latest = current.chain.at(-1)?.id
333
+ browsingHistory.current[sessionId] = diffId !== latest
334
+ try {
335
+ await inspectTargetFile({
336
+ sessionId,
337
+ diffId,
338
+ })
339
+ } catch {
340
+ // Still show the historical preview if disk replay failed.
313
341
  }
314
- const next = await fetchAgentIntent(diffId)
315
- lastIntentSig.current = intentSignature(next)
316
- applyIntent(next)
342
+ const next = await fetchAgentIntent(sessionId, diffId)
343
+ lastIntentSig.current = null
344
+ applyIntent(next, sessionId)
345
+ setFocusedSessionId(sessionId)
317
346
  } catch {
318
347
  // Keep the current chain position if navigation failed.
319
348
  }
320
349
  },
321
- [applyIntent, intent.chain, intent.sessionId],
350
+ [applyIntent, intents],
322
351
  )
323
352
 
324
353
  const inspectFile = useCallback(
@@ -370,7 +399,7 @@ function Explorer({
370
399
  }, [])
371
400
 
372
401
  useEffect(() => {
373
- if (!intent.sessionId) {
402
+ if (!creationIntent?.sessionId) {
374
403
  setUserBlocks([])
375
404
  setUserIslands([])
376
405
  setBlueprintFunctions([])
@@ -380,13 +409,13 @@ function Explorer({
380
409
  }
381
410
  const knownFiles = new Set(graph.files.map((file) => file.id))
382
411
  const knownFolders = new Set(graph.folders.map((folder) => folder.path))
383
- const nextBlocks = parseUserCreatedBlocks(intent.userCreatedBlocks).filter(
412
+ const nextBlocks = parseUserCreatedBlocks(creationIntent.userCreatedBlocks).filter(
384
413
  (block) => !knownFiles.has(block.id),
385
414
  )
386
- const nextIslands = parseUserCreatedIslands(intent.userCreatedIslands).filter(
415
+ const nextIslands = parseUserCreatedIslands(creationIntent.userCreatedIslands).filter(
387
416
  (island) => !knownFolders.has(island.path),
388
417
  )
389
- if (intent.creationMode) {
418
+ if (creationIntent.creationMode) {
390
419
  setUserBlocks((current) =>
391
420
  current.some((block) => block.naming) || current.length > 0
392
421
  ? current
@@ -398,28 +427,29 @@ function Explorer({
398
427
  : nextIslands,
399
428
  )
400
429
  setBlueprintFunctions((current) =>
401
- current.length > 0 ? current : intent.blueprintFunctions,
430
+ current.length > 0 ? current : creationIntent.blueprintFunctions,
402
431
  )
403
432
  setBlueprintVariables((current) =>
404
- current.length > 0 ? current : intent.blueprintVariables,
433
+ current.length > 0 ? current : creationIntent.blueprintVariables,
405
434
  )
406
435
  setBlueprintImports((current) =>
407
- current.length > 0 ? current : intent.blueprintImports,
436
+ current.length > 0 ? current : creationIntent.blueprintImports,
408
437
  )
409
438
  return
410
439
  }
411
440
  setUserBlocks(nextBlocks)
412
441
  setUserIslands(nextIslands)
413
- setBlueprintFunctions(intent.blueprintFunctions)
414
- setBlueprintVariables(intent.blueprintVariables)
415
- setBlueprintImports(intent.blueprintImports)
442
+ setBlueprintFunctions(creationIntent.blueprintFunctions)
443
+ setBlueprintVariables(creationIntent.blueprintVariables)
444
+ setBlueprintImports(creationIntent.blueprintImports)
416
445
  }, [
417
- intent.blueprintFunctions,
418
- intent.blueprintImports,
419
- intent.blueprintVariables,
420
- intent.creationMode,
421
- intent.userCreatedBlocks,
422
- intent.userCreatedIslands,
446
+ creationIntent?.blueprintFunctions,
447
+ creationIntent?.blueprintImports,
448
+ creationIntent?.blueprintVariables,
449
+ creationIntent?.creationMode,
450
+ creationIntent?.sessionId,
451
+ creationIntent?.userCreatedBlocks,
452
+ creationIntent?.userCreatedIslands,
423
453
  graph,
424
454
  ])
425
455
 
@@ -431,8 +461,8 @@ function Explorer({
431
461
  variables: PatchSymbolAddition[] = blueprintVariables,
432
462
  imports: PatchImportAddition[] = blueprintImports,
433
463
  ) => {
434
- if (!intent.sessionId || !intent.creationMode) return
435
- persistSessionBlueprint(intent.sessionId, {
464
+ if (!creationIntent?.sessionId || !creationIntent.creationMode) return
465
+ persistSessionBlueprint(creationIntent.sessionId, {
436
466
  userCreatedBlocks: namedCreatedBlocks(blocks),
437
467
  userCreatedIslands: namedCreatedIslands(islands),
438
468
  addedFunctions: functions,
@@ -444,8 +474,8 @@ function Explorer({
444
474
  blueprintFunctions,
445
475
  blueprintImports,
446
476
  blueprintVariables,
447
- intent.creationMode,
448
- intent.sessionId,
477
+ creationIntent?.creationMode,
478
+ creationIntent?.sessionId,
449
479
  userBlocks,
450
480
  userIslands,
451
481
  ],
@@ -453,7 +483,7 @@ function Explorer({
453
483
 
454
484
  const placeBlock = useCallback(
455
485
  (spot: { x: number; z: number; folder: string }) => {
456
- if (!intent.creationMode) return
486
+ if (!creationMode) return
457
487
  setUserBlocks((current) => {
458
488
  if (current.some((block) => block.naming)) return current
459
489
  return [
@@ -471,12 +501,12 @@ function Explorer({
471
501
  })
472
502
  document.exitPointerLock()
473
503
  },
474
- [intent.creationMode],
504
+ [creationMode],
475
505
  )
476
506
 
477
507
  const placeBlockOnFolder = useCallback(
478
508
  (folderPath: string) => {
479
- if (!intent.creationMode) return
509
+ if (!creationMode) return
480
510
  const fileCount = displayGraph.files.filter(
481
511
  (file) => file.folder === folderPath,
482
512
  ).length
@@ -484,7 +514,7 @@ function Explorer({
484
514
  if (!spot) return
485
515
  placeBlock(spot)
486
516
  },
487
- [displayGraph.files, intent.creationMode, layout, placeBlock],
517
+ [displayGraph.files, creationMode, layout, placeBlock],
488
518
  )
489
519
 
490
520
  const commitBlockName = useCallback(
@@ -521,7 +551,7 @@ function Explorer({
521
551
 
522
552
  const placeIsland = useCallback(
523
553
  (parent: string) => {
524
- if (!intent.creationMode) return
554
+ if (!creationMode) return
525
555
  setUserIslands((current) => {
526
556
  if (current.some((island) => island.naming)) return current
527
557
  return [
@@ -537,15 +567,15 @@ function Explorer({
537
567
  })
538
568
  document.exitPointerLock()
539
569
  },
540
- [intent.creationMode],
570
+ [creationMode],
541
571
  )
542
572
 
543
573
  const placeIslandOnFolder = useCallback(
544
574
  (parent: string) => {
545
- if (!intent.creationMode) return
575
+ if (!creationMode) return
546
576
  placeIsland(parent)
547
577
  },
548
- [intent.creationMode, placeIsland],
578
+ [creationMode, placeIsland],
549
579
  )
550
580
 
551
581
  const commitIslandName = useCallback(
@@ -579,7 +609,7 @@ function Explorer({
579
609
  }, [])
580
610
 
581
611
  const deleteSelectedCreatedBlock = useCallback(() => {
582
- if (!intent.creationMode || !selectedId) return false
612
+ if (!creationMode || !selectedId) return false
583
613
  const selected = userBlocks.find((block) => block.id === selectedId)
584
614
  if (!selected || selected.naming) return false
585
615
  const next = userBlocks.filter((block) => block.id !== selectedId)
@@ -587,7 +617,7 @@ function Explorer({
587
617
  persistBlueprint(next, userIslands)
588
618
  setSelectedId(null)
589
619
  return true
590
- }, [intent.creationMode, persistBlueprint, selectedId, userBlocks, userIslands])
620
+ }, [creationMode, persistBlueprint, selectedId, userBlocks, userIslands])
591
621
 
592
622
  const selectFile = useCallback(
593
623
  (fileId: string | null) => {
@@ -596,9 +626,9 @@ function Explorer({
596
626
  setSelectedFolder(null)
597
627
  setSelectedTick((tick) => tick + 1)
598
628
  }
599
- if (fileId && intent.creationMode) document.exitPointerLock()
629
+ if (fileId && creationMode) document.exitPointerLock()
600
630
  },
601
- [intent.creationMode],
631
+ [creationMode],
602
632
  )
603
633
 
604
634
  const selectFolder = useCallback((folderPath: string | null) => {
@@ -608,7 +638,7 @@ function Explorer({
608
638
 
609
639
  const addBlueprintFunction = useCallback(
610
640
  (fileId: string, rawName: string) => {
611
- if (!intent.creationMode || fileId.startsWith('draft:')) return false
641
+ if (!creationMode || fileId.startsWith('draft:')) return false
612
642
  const name = rawName.trim()
613
643
  if (!isBlueprintSymbolName(name)) return false
614
644
  const exists =
@@ -631,7 +661,7 @@ function Explorer({
631
661
  blueprintImports,
632
662
  blueprintVariables,
633
663
  displayGraph.files,
634
- intent.creationMode,
664
+ creationMode,
635
665
  persistBlueprint,
636
666
  userBlocks,
637
667
  userIslands,
@@ -640,7 +670,7 @@ function Explorer({
640
670
 
641
671
  const addBlueprintVariable = useCallback(
642
672
  (fileId: string, rawName: string) => {
643
- if (!intent.creationMode || fileId.startsWith('draft:')) return false
673
+ if (!creationMode || fileId.startsWith('draft:')) return false
644
674
  const name = rawName.trim()
645
675
  if (!isBlueprintSymbolName(name)) return false
646
676
  const exists =
@@ -663,7 +693,7 @@ function Explorer({
663
693
  blueprintImports,
664
694
  blueprintVariables,
665
695
  displayGraph.files,
666
- intent.creationMode,
696
+ creationMode,
667
697
  persistBlueprint,
668
698
  userBlocks,
669
699
  userIslands,
@@ -672,7 +702,7 @@ function Explorer({
672
702
 
673
703
  const addBlueprintImport = useCallback(
674
704
  (fileId: string, raw: string) => {
675
- if (!intent.creationMode || fileId.startsWith('draft:')) return false
705
+ if (!creationMode || fileId.startsWith('draft:')) return false
676
706
  const parsed = parseBlueprintImport(
677
707
  raw,
678
708
  fileId,
@@ -702,7 +732,7 @@ function Explorer({
702
732
  blueprintImports,
703
733
  blueprintVariables,
704
734
  displayGraph.files,
705
- intent.creationMode,
735
+ creationMode,
706
736
  persistBlueprint,
707
737
  userBlocks,
708
738
  userIslands,
@@ -711,7 +741,7 @@ function Explorer({
711
741
 
712
742
  const removeBlueprintFunction = useCallback(
713
743
  (fileId: string, name: string) => {
714
- if (!intent.creationMode) return
744
+ if (!creationMode) return
715
745
  const next = blueprintFunctions.filter(
716
746
  (item) => !(item.file === fileId && item.name === name),
717
747
  )
@@ -722,7 +752,7 @@ function Explorer({
722
752
  blueprintFunctions,
723
753
  blueprintImports,
724
754
  blueprintVariables,
725
- intent.creationMode,
755
+ creationMode,
726
756
  persistBlueprint,
727
757
  userBlocks,
728
758
  userIslands,
@@ -731,7 +761,7 @@ function Explorer({
731
761
 
732
762
  const removeBlueprintVariable = useCallback(
733
763
  (fileId: string, name: string) => {
734
- if (!intent.creationMode) return
764
+ if (!creationMode) return
735
765
  const next = blueprintVariables.filter(
736
766
  (item) => !(item.file === fileId && item.name === name),
737
767
  )
@@ -742,7 +772,7 @@ function Explorer({
742
772
  blueprintFunctions,
743
773
  blueprintImports,
744
774
  blueprintVariables,
745
- intent.creationMode,
775
+ creationMode,
746
776
  persistBlueprint,
747
777
  userBlocks,
748
778
  userIslands,
@@ -751,7 +781,7 @@ function Explorer({
751
781
 
752
782
  const removeBlueprintImport = useCallback(
753
783
  (fileId: string, name: string, from: string) => {
754
- if (!intent.creationMode) return
784
+ if (!creationMode) return
755
785
  const next = blueprintImports.filter(
756
786
  (item) =>
757
787
  !(item.file === fileId && item.name === name && item.from === from),
@@ -769,7 +799,7 @@ function Explorer({
769
799
  blueprintFunctions,
770
800
  blueprintImports,
771
801
  blueprintVariables,
772
- intent.creationMode,
802
+ creationMode,
773
803
  persistBlueprint,
774
804
  userBlocks,
775
805
  userIslands,
@@ -844,15 +874,45 @@ function Explorer({
844
874
  let cancelled = false
845
875
  const poll = async () => {
846
876
  try {
847
- const next = await fetchAgentIntent(
848
- browsingHistory.current ? viewedDiffId.current ?? undefined : undefined,
849
- )
850
- const signature = intentSignature(next)
877
+ const bundle = await fetchAgentIntents()
878
+ const merged: AgentIntent[] = []
879
+ for (const next of bundle.intents) {
880
+ const sessionId = next.sessionId
881
+ if (
882
+ sessionId &&
883
+ browsingHistory.current[sessionId] &&
884
+ viewedDiffId.current[sessionId]
885
+ ) {
886
+ merged.push(
887
+ await fetchAgentIntent(sessionId, viewedDiffId.current[sessionId] ?? undefined),
888
+ )
889
+ } else {
890
+ merged.push(next)
891
+ }
892
+ }
893
+ const signature = JSON.stringify(merged.map(intentSignature))
851
894
  if (cancelled || signature === lastIntentSig.current) {
852
895
  return
853
896
  }
854
897
  lastIntentSig.current = signature
855
- applyIntent(next)
898
+ setIntents(merged)
899
+ for (const next of merged) {
900
+ if (next.sessionId && !browsingHistory.current[next.sessionId]) {
901
+ viewedDiffId.current[next.sessionId] = next.diffId
902
+ }
903
+ }
904
+ setFocusedSessionId((current) => {
905
+ if (current && merged.some((item) => item.sessionId === current)) {
906
+ return current
907
+ }
908
+ if (
909
+ bundle.focusedSessionId &&
910
+ merged.some((item) => item.sessionId === bundle.focusedSessionId)
911
+ ) {
912
+ return bundle.focusedSessionId
913
+ }
914
+ return merged[0]?.sessionId ?? null
915
+ })
856
916
  } catch {
857
917
  // Explorer may be running without the intent endpoint yet.
858
918
  }
@@ -865,7 +925,7 @@ function Explorer({
865
925
  cancelled = true
866
926
  window.clearInterval(timer)
867
927
  }
868
- }, [applyIntent])
928
+ }, [])
869
929
 
870
930
  const plannedIds = previewing ? [...intent.files, ...intent.creates] : []
871
931
  const blueprintImportEdges = blueprintImports.flatMap((item) => {
@@ -883,6 +943,7 @@ function Explorer({
883
943
  <div className="stage">
884
944
  <Canvas
885
945
  shadows={false}
946
+ dpr={[1, 1.5]}
886
947
  gl={{ antialias: true, toneMappingExposure: 1.25 }}
887
948
  camera={{
888
949
  position: layout.spawn,
@@ -919,8 +980,8 @@ function Explorer({
919
980
  importedBy={importedBy}
920
981
  namingId={namingId}
921
982
  namingIslandId={namingIslandId}
922
- onPlaceBlock={intent.creationMode ? placeBlock : undefined}
923
- onPlaceIsland={intent.creationMode ? placeIsland : undefined}
983
+ onPlaceBlock={creationMode ? placeBlock : undefined}
984
+ onPlaceIsland={creationMode ? placeIsland : undefined}
924
985
  onCommitName={commitBlockName}
925
986
  onCancelName={cancelBlockName}
926
987
  userCreatedBlocks={userBlocks}
@@ -930,14 +991,19 @@ function Explorer({
930
991
  </div>
931
992
  <HUD
932
993
  graph={displayGraph}
994
+ layout={layout}
933
995
  mode={mode}
934
996
  locked={locked}
935
997
  selectedId={selectedId}
936
998
  selectedTick={selectedTick}
937
999
  selectedFolder={selectedFolder}
1000
+ landAt={landAt}
938
1001
  aimedRelation={aimedRelation}
939
1002
  currentFolder={currentFolder}
940
1003
  intent={intent}
1004
+ intents={intents}
1005
+ focusedSessionId={focusedSessionId}
1006
+ onFocusSession={setFocusedSessionId}
941
1007
  onWorkflowAction={runWorkflowAction}
942
1008
  onNavigateDiff={navigateDiff}
943
1009
  onOpenMap={openMap}
@@ -966,6 +1032,9 @@ function Explorer({
966
1032
  onMapAddFile={placeBlockOnFolder}
967
1033
  onMapAddFolder={placeIslandOnFolder}
968
1034
  onInspectFile={inspectFile}
1035
+ plannedIds={plannedIds}
1036
+ createdIds={plannedCreates}
1037
+ deletedIds={deletedIds}
969
1038
  />
970
1039
  </>
971
1040
  )
@@ -1,5 +1,6 @@
1
1
  import type {
2
2
  AgentIntent,
3
+ AgentIntentBundle,
3
4
  PatchImport,
4
5
  PatchImportAddition,
5
6
  PatchSymbolAddition,
@@ -124,8 +125,39 @@ function normalize(data: Partial<AgentIntent> | null | undefined): AgentIntent {
124
125
  }
125
126
  }
126
127
 
127
- export async function fetchAgentIntent(diffId?: string): Promise<AgentIntent> {
128
+ export async function fetchAgentIntents(): Promise<AgentIntentBundle> {
128
129
  const query = new URLSearchParams({ t: String(Date.now()) })
130
+ const response = await fetch(`/api/agent-intent?${query}`)
131
+ if (!response.ok) return { focusedSessionId: null, intents: [] }
132
+ const data = (await response.json()) as {
133
+ focusedSessionId?: string | null
134
+ intents?: unknown
135
+ sessionId?: string | null
136
+ } & Partial<AgentIntent>
137
+ if (Array.isArray(data.intents)) {
138
+ return {
139
+ focusedSessionId:
140
+ typeof data.focusedSessionId === 'string' ? data.focusedSessionId : null,
141
+ intents: data.intents
142
+ .map((intent) => normalize(intent as Partial<AgentIntent>))
143
+ .filter((intent) => Boolean(intent.sessionId)),
144
+ }
145
+ }
146
+ const intent = normalize(data)
147
+ return {
148
+ focusedSessionId: intent.sessionId,
149
+ intents: intent.sessionId ? [intent] : [],
150
+ }
151
+ }
152
+
153
+ export async function fetchAgentIntent(
154
+ sessionId: string,
155
+ diffId?: string,
156
+ ): Promise<AgentIntent> {
157
+ const query = new URLSearchParams({
158
+ t: String(Date.now()),
159
+ sessionId,
160
+ })
129
161
  if (diffId) query.set('diffId', diffId)
130
162
  const response = await fetch(`/api/agent-intent?${query}`)
131
163
  if (!response.ok) return emptyIntent