({ agentPubkey }: { agentPubkey: string })
| 93 | } |
| 94 | |
| 95 | function MemorySectionForOwner({ agentPubkey }: { agentPubkey: string }) { |
| 96 | const { query, graph } = useAgentMemoryGraph(agentPubkey); |
| 97 | |
| 98 | // Order matters here. We want: |
| 99 | // - first paint, no cache → skeleton |
| 100 | // - error with no cache → error state (with retry) |
| 101 | // - error WITH cache → keep the data, show a non-blocking "refetch failed" |
| 102 | // banner; user can retry without losing what they had |
| 103 | // - data, but empty → empty state ("This agent has no memories yet") |
| 104 | // - data, non-empty → render |
| 105 | const showInitialSkeleton = query.isLoading && !query.data; |
| 106 | const showInitialError = query.isError && !query.data; |
| 107 | |
| 108 | return ( |
| 109 | <section data-testid="agent-memory-section"> |
| 110 | {showInitialSkeleton ? <MemorySkeleton /> : null} |
| 111 | |
| 112 | {showInitialError ? ( |
| 113 | <MemoryErrorState |
| 114 | error={query.error} |
| 115 | onRetry={() => query.refetch()} |
| 116 | retrying={query.isFetching} |
| 117 | /> |
| 118 | ) : null} |
| 119 | |
| 120 | {query.data && graph ? ( |
| 121 | <> |
| 122 | {/* Stale-cache error banner: shown when a refetch fails but we |
| 123 | still have prior data on screen. Distinct from the initial |
| 124 | error state above. */} |
| 125 | {query.isError && !query.isFetching ? ( |
| 126 | <MemoryStaleErrorBanner onRetry={() => query.refetch()} /> |
| 127 | ) : null} |
| 128 | |
| 129 | <MemoryGraphView graph={graph} truncated={query.data.truncated} /> |
| 130 | </> |
| 131 | ) : null} |
| 132 | </section> |
| 133 | ); |
| 134 | } |
| 135 | |
| 136 | // ── Subviews ──────────────────────────────────────────────────────────────── |
| 137 |
nothing calls this directly
no test coverage detected