Phase 1: OpenAI API Token Extraction
- Add stream_options: { include_usage: true } to all streaming API calls
- Capture chunk.usage from final streaming chunks and response.usage from non-streaming
- Extend OpenAiChatIterationResult with optional usage field
- Update buildStats() to accept and return real token counts from usage data
- Wire iteration.usage through chat() to both buildStats() call sites
Phase 2: Agent Loop Stats Propagation
- Rename inputTokens/outputTokens to masterInputTokens/masterOutputTokens, add masterThinkingTokens
- Accumulate response.stats.tokenCounts after each master AI call
- Delete all Math.ceil(length/4) crude approximations (master and subagent loops)
- Track startTime/durationMs and emit IWorkOrderCompleteStats with workOrderComplete
- Subagent loop uses response.stats?.tokenCounts instead of Math.ceil
Phase 3: Database Model Changes
- Add contextWindowUsage field to IChatSession, ChatSessionSchema, and frontend ChatSession
- Initialize contextWindowUsage: 0 on session creation
Phase 4: Persist Stats on Turn Completion
- drone-session: accept IWorkOrderCompleteStats, persist turn stats, walk subagent records for aggregate
- drone-session: $inc session stats and contextWindowUsage, add formatDurationLabel() helper
- code-session: accept and forward stats, update in-memory session stats
- message-queue: Redis replay handles 4th stats arg
- Update WorkOrderCompleteMessage type in @gadget/api to accept stats parameter
Phase 5: UI — Context Window Fuel Gauge
- Add contextWindowUsage prop to SessionPanel
- Add fuel gauge bar with E→F labels, green/yellow/red zones, token count display
- Visible for ALL provider types (not gated by apiType)
Phase 6: Frontend Streaming State
- Add IWorkOrderCompleteStats interface to frontend api.ts
- handleWorkOrderComplete accepts stats, updates turn stats and session contextWindowUsage
- Pass contextWindowUsage prop to SessionPanel
50 lines
1.7 KiB
TypeScript
50 lines
1.7 KiB
TypeScript
// src/models/chat-session.ts
|
|
// Copyright (C) 2026 Robert Colbert <rob.colbert@openplatform.us>
|
|
// All Rights Reserved
|
|
|
|
import { Schema, model } from "mongoose";
|
|
import { ChatSessionMode, IChatSession, IChatSessionPin } from "@gadget/api";
|
|
import { nanoid } from "nanoid";
|
|
|
|
export const ChatSessionPinSchema = new Schema<IChatSessionPin>({
|
|
content: { type: String, required: true },
|
|
});
|
|
|
|
export const ChatSessionSchema = new Schema<IChatSession>({
|
|
_id: { type: String, default: () => nanoid() },
|
|
createdAt: { type: Date, default: Date.now, required: true },
|
|
lastMessageAt: { type: Date },
|
|
user: { type: String, required: true, index: 1, ref: "User" },
|
|
project: { type: String, required: false, index: 1, ref: "Project" },
|
|
name: { type: String, default: "New Session", required: true },
|
|
mode: {
|
|
type: String,
|
|
enum: ChatSessionMode,
|
|
default: ChatSessionMode.Build,
|
|
required: true,
|
|
},
|
|
provider: { type: String, required: true, ref: "AiProvider" },
|
|
selectedModel: { type: String, required: true },
|
|
reasoningEffort: {
|
|
type: String,
|
|
enum: ["off", "low", "medium", "high"],
|
|
default: "off",
|
|
},
|
|
numCtx: { type: Number },
|
|
contextWindowUsage: { type: Number, default: 0, required: true },
|
|
stats: {
|
|
turnCount: { type: Number, default: 0, required: true },
|
|
toolCallCount: { type: Number, default: 0, required: true },
|
|
inputTokens: { type: Number, default: 0, required: true },
|
|
outputTokens: { type: Number, default: 0, required: true },
|
|
},
|
|
pins: { type: [ChatSessionPinSchema], default: [], required: true },
|
|
});
|
|
|
|
export const ChatSession = model<IChatSession>(
|
|
"ChatSession",
|
|
ChatSessionSchema,
|
|
);
|
|
|
|
export default ChatSession;
|