@codori/client 0.0.4 → 0.0.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.
@@ -57,6 +57,7 @@ import {
57
57
  normalizeThreadTokenUsage,
58
58
  resolveContextWindowState,
59
59
  resolveEffortOptions,
60
+ shouldShowContextWindowIndicator,
60
61
  visibleModelOptions,
61
62
  type ReasoningEffort
62
63
  } from '~~/shared/chat-prompt-controls'
@@ -174,7 +175,6 @@ const starterPrompts = computed(() => {
174
175
  ]
175
176
  })
176
177
 
177
- const hasKnownThreadUsage = computed(() => !activeThreadId.value || tokenUsage.value !== null)
178
178
  const effectiveModelList = computed(() => {
179
179
  const withSelected = ensureModelOption(
180
180
  availableModels.value.length > 0 ? availableModels.value : FALLBACK_MODELS,
@@ -202,8 +202,9 @@ const effortSelectItems = computed(() =>
202
202
  }))
203
203
  )
204
204
  const contextWindowState = computed(() =>
205
- resolveContextWindowState(tokenUsage.value, modelContextWindow.value, hasKnownThreadUsage.value)
205
+ resolveContextWindowState(tokenUsage.value, modelContextWindow.value)
206
206
  )
207
+ const showContextIndicator = computed(() => shouldShowContextWindowIndicator(contextWindowState.value))
207
208
  const contextUsedPercent = computed(() => contextWindowState.value.usedPercent ?? 0)
208
209
  const contextIndicatorLabel = computed(() => {
209
210
  const remainingPercent = contextWindowState.value.remainingPercent
@@ -1708,6 +1709,7 @@ const sendMessage = async () => {
1708
1709
  input: buildTurnStartInput(text, uploadedAttachments),
1709
1710
  ...buildTurnOverrides(selectedModel.value, selectedEffort.value)
1710
1711
  })
1712
+ tokenUsage.value = null
1711
1713
  return
1712
1714
  }
1713
1715
 
@@ -1725,6 +1727,7 @@ const sendMessage = async () => {
1725
1727
  ...buildTurnOverrides(selectedModel.value, selectedEffort.value)
1726
1728
  })
1727
1729
 
1730
+ tokenUsage.value = null
1728
1731
  setLiveStreamTurnId(liveStream, turnStart.turn.id)
1729
1732
 
1730
1733
  for (const notification of liveStream.bufferedNotifications.splice(0, liveStream.bufferedNotifications.length)) {
@@ -2089,6 +2092,7 @@ watch([selectedModel, availableModels], () => {
2089
2092
 
2090
2093
  <div class="ml-auto flex shrink-0 items-center">
2091
2094
  <UPopover
2095
+ v-if="showContextIndicator"
2092
2096
  :content="{ side: 'top', align: 'end' }"
2093
2097
  arrow
2094
2098
  >
@@ -2128,8 +2132,6 @@ watch([selectedModel, availableModels], () => {
2128
2132
  {{ contextIndicatorLabel }}
2129
2133
  </span>
2130
2134
  </span>
2131
-
2132
- <span class="text-[11px] leading-none text-muted">context window</span>
2133
2135
  </button>
2134
2136
 
2135
2137
  <template #content>
@@ -2143,10 +2145,7 @@ watch([selectedModel, availableModels], () => {
2143
2145
  </div>
2144
2146
  </div>
2145
2147
 
2146
- <div
2147
- v-if="contextWindowState.contextWindow && contextWindowState.usedTokens !== null"
2148
- class="grid grid-cols-2 gap-3 text-sm"
2149
- >
2148
+ <div class="grid grid-cols-2 gap-3 text-sm">
2150
2149
  <div class="rounded-2xl border border-default bg-elevated/35 px-3 py-2">
2151
2150
  <div class="text-[11px] uppercase tracking-[0.18em] text-muted">
2152
2151
  Remaining
@@ -2166,23 +2165,11 @@ watch([selectedModel, availableModels], () => {
2166
2165
  {{ formatCompactTokenCount(contextWindowState.usedTokens ?? 0) }}
2167
2166
  </div>
2168
2167
  <div class="text-xs text-muted">
2169
- of {{ formatCompactTokenCount(contextWindowState.contextWindow) }}
2168
+ of {{ formatCompactTokenCount(contextWindowState.contextWindow ?? 0) }}
2170
2169
  </div>
2171
2170
  </div>
2172
2171
  </div>
2173
2172
 
2174
- <div
2175
- v-else
2176
- class="rounded-2xl border border-default bg-elevated/35 px-3 py-2 text-sm text-muted"
2177
- >
2178
- <div v-if="contextWindowState.contextWindow">
2179
- Live token usage will appear after the next turn completes.
2180
- </div>
2181
- <div v-else>
2182
- Context window details are not available from the runtime yet.
2183
- </div>
2184
- </div>
2185
-
2186
2173
  <div class="grid grid-cols-2 gap-3 text-sm">
2187
2174
  <div class="rounded-2xl border border-default bg-elevated/35 px-3 py-2">
2188
2175
  <div class="text-[11px] uppercase tracking-[0.18em] text-muted">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codori/client",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "private": false,
5
5
  "description": "Codori Nuxt dashboard for project browsing, Codex chat, and thread resume.",
6
6
  "type": "module",
@@ -20,15 +20,26 @@ export type ModelOption = {
20
20
  }
21
21
 
22
22
  export type TokenUsageSnapshot = {
23
+ totalTokens: number | null
23
24
  totalInputTokens: number
24
25
  totalCachedInputTokens: number
25
26
  totalOutputTokens: number
27
+ lastUsageKnown: boolean
28
+ lastTotalTokens: number | null
26
29
  lastInputTokens: number
27
30
  lastCachedInputTokens: number
28
31
  lastOutputTokens: number
29
32
  modelContextWindow: number | null
30
33
  }
31
34
 
35
+ export type ContextWindowState = {
36
+ contextWindow: number | null
37
+ usedTokens: number | null
38
+ remainingTokens: number | null
39
+ usedPercent: number | null
40
+ remainingPercent: number | null
41
+ }
42
+
32
43
  type ReasoningEffortOptionRecord = {
33
44
  reasoningEffort?: unknown
34
45
  }
@@ -250,15 +261,18 @@ export const normalizeThreadTokenUsage = (value: unknown): TokenUsageSnapshot |
250
261
  }
251
262
 
252
263
  const total = isObjectRecord(tokenUsage.total) ? tokenUsage.total : {}
253
- const last = isObjectRecord(tokenUsage.last) ? tokenUsage.last : {}
264
+ const last = isObjectRecord(tokenUsage.last) ? tokenUsage.last : null
254
265
 
255
266
  return {
267
+ totalTokens: toFiniteNumber(total.totalTokens),
256
268
  totalInputTokens: toFiniteNumber(total.inputTokens) ?? 0,
257
269
  totalCachedInputTokens: toFiniteNumber(total.cachedInputTokens) ?? 0,
258
270
  totalOutputTokens: toFiniteNumber(total.outputTokens) ?? 0,
259
- lastInputTokens: toFiniteNumber(last.inputTokens) ?? 0,
260
- lastCachedInputTokens: toFiniteNumber(last.cachedInputTokens) ?? 0,
261
- lastOutputTokens: toFiniteNumber(last.outputTokens) ?? 0,
271
+ lastUsageKnown: last !== null,
272
+ lastTotalTokens: toFiniteNumber(last?.totalTokens),
273
+ lastInputTokens: toFiniteNumber(last?.inputTokens) ?? 0,
274
+ lastCachedInputTokens: toFiniteNumber(last?.cachedInputTokens) ?? 0,
275
+ lastOutputTokens: toFiniteNumber(last?.outputTokens) ?? 0,
262
276
  modelContextWindow: toFiniteNumber(tokenUsage.modelContextWindow)
263
277
  }
264
278
  }
@@ -306,15 +320,16 @@ export const formatCompactTokenCount = (value: number) => {
306
320
 
307
321
  export const resolveContextWindowState = (
308
322
  tokenUsage: TokenUsageSnapshot | null,
309
- fallbackContextWindow: number | null,
310
- usageKnown = true
311
- ) => {
323
+ fallbackContextWindow: number | null
324
+ ): ContextWindowState => {
312
325
  const contextWindow = tokenUsage?.modelContextWindow ?? fallbackContextWindow
326
+ // App-server exposes cumulative thread totals separately; the latest turn total
327
+ // is the closest match to current context occupancy.
313
328
  const usedTokens = tokenUsage
314
- ? tokenUsage.totalInputTokens + tokenUsage.totalOutputTokens
315
- : usageKnown
316
- ? 0
317
- : null
329
+ ? tokenUsage.lastTotalTokens ?? (tokenUsage.lastUsageKnown
330
+ ? tokenUsage.lastInputTokens + tokenUsage.lastOutputTokens
331
+ : null)
332
+ : null
318
333
 
319
334
  if (!contextWindow || usedTokens == null) {
320
335
  return {
@@ -337,3 +352,6 @@ export const resolveContextWindowState = (
337
352
  remainingPercent: Math.max(0, 100 - usedPercent)
338
353
  }
339
354
  }
355
+
356
+ export const shouldShowContextWindowIndicator = (state: ContextWindowState) =>
357
+ state.contextWindow !== null && state.usedTokens !== null
package/shared/codori.ts CHANGED
@@ -7,6 +7,10 @@ export type ProjectRecord = {
7
7
  pid: number | null
8
8
  port: number | null
9
9
  startedAt: number | null
10
+ lastActivityAt: number | null
11
+ activeSessionCount: number
12
+ idleTimeoutMs: number | null
13
+ idleDeadlineAt: number | null
10
14
  error: string | null
11
15
  }
12
16