niahere 0.2.47 → 0.2.49
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.
package/package.json
CHANGED
package/src/chat/engine.ts
CHANGED
|
@@ -332,22 +332,42 @@ export async function createChatEngine(opts: EngineOptions): Promise<ChatEngine>
|
|
|
332
332
|
}
|
|
333
333
|
|
|
334
334
|
if (message.type === "result" && pending) {
|
|
335
|
+
const msg = message as any;
|
|
335
336
|
if (!message.is_error) {
|
|
336
|
-
const resultText =
|
|
337
|
-
const costUsd =
|
|
338
|
-
const turns =
|
|
337
|
+
const resultText = msg.result as string;
|
|
338
|
+
const costUsd = msg.total_cost_usd as number;
|
|
339
|
+
const turns = msg.num_turns as number;
|
|
340
|
+
|
|
341
|
+
const metadata: Record<string, unknown> = {
|
|
342
|
+
cost_usd: costUsd,
|
|
343
|
+
turns,
|
|
344
|
+
duration_ms: msg.duration_ms,
|
|
345
|
+
duration_api_ms: msg.duration_api_ms,
|
|
346
|
+
stop_reason: msg.stop_reason,
|
|
347
|
+
session_id: msg.session_id,
|
|
348
|
+
subtype: msg.subtype,
|
|
349
|
+
usage: msg.usage,
|
|
350
|
+
model_usage: msg.modelUsage,
|
|
351
|
+
};
|
|
339
352
|
|
|
340
353
|
let messageId: number | undefined;
|
|
341
354
|
if (sessionId && resultText) {
|
|
342
|
-
|
|
355
|
+
const saveParams = {
|
|
343
356
|
sessionId,
|
|
344
357
|
room,
|
|
345
358
|
sender: "nia",
|
|
346
359
|
content: resultText,
|
|
347
360
|
isFromAgent: true,
|
|
348
|
-
deliveryStatus: "pending",
|
|
349
|
-
|
|
361
|
+
deliveryStatus: "pending" as const,
|
|
362
|
+
metadata,
|
|
363
|
+
};
|
|
364
|
+
try {
|
|
365
|
+
messageId = await Message.save(saveParams);
|
|
366
|
+
} catch {
|
|
367
|
+
messageId = await Message.save({ ...saveParams, metadata: undefined });
|
|
368
|
+
}
|
|
350
369
|
await Session.touch(sessionId);
|
|
370
|
+
Session.accumulateMetadata(sessionId, { ...metadata, channel }).catch(() => {});
|
|
351
371
|
}
|
|
352
372
|
|
|
353
373
|
await ActiveEngine.unregister(room);
|
|
@@ -356,7 +376,7 @@ export async function createChatEngine(opts: EngineOptions): Promise<ChatEngine>
|
|
|
356
376
|
pending = null;
|
|
357
377
|
resetIdleTimer();
|
|
358
378
|
} else {
|
|
359
|
-
const errors =
|
|
379
|
+
const errors = msg.errors;
|
|
360
380
|
const errorText = `[error] ${errors?.join(", ") || "unknown error"}`;
|
|
361
381
|
await ActiveEngine.unregister(room);
|
|
362
382
|
clearLongRunningTimer();
|
package/src/cli/index.ts
CHANGED
|
@@ -276,11 +276,11 @@ switch (command) {
|
|
|
276
276
|
|
|
277
277
|
case "chat": {
|
|
278
278
|
const chatArgs = process.argv.slice(3);
|
|
279
|
-
const mode = (chatArgs.includes("--
|
|
280
|
-
? "
|
|
279
|
+
const mode = (chatArgs.includes("--continue") || chatArgs.includes("-c"))
|
|
280
|
+
? "continue" as const
|
|
281
281
|
: (chatArgs.includes("--resume") || chatArgs.includes("-r"))
|
|
282
282
|
? "pick" as const
|
|
283
|
-
: "
|
|
283
|
+
: "new" as const;
|
|
284
284
|
const chIdx = chatArgs.indexOf("--channel");
|
|
285
285
|
const simChannel = chIdx !== -1 && chatArgs[chIdx + 1] ? chatArgs[chIdx + 1] : undefined;
|
|
286
286
|
await startRepl(mode, simChannel);
|
package/src/db/models/message.ts
CHANGED
|
@@ -3,12 +3,13 @@ import type { SaveMessageParams, RoomStats, RecentMessage, SearchResult, Session
|
|
|
3
3
|
|
|
4
4
|
export type DeliveryStatus = "pending" | "sent" | "failed";
|
|
5
5
|
|
|
6
|
-
export async function save(params: SaveMessageParams & { deliveryStatus?: DeliveryStatus }): Promise<number> {
|
|
6
|
+
export async function save(params: SaveMessageParams & { deliveryStatus?: DeliveryStatus; metadata?: Record<string, unknown> }): Promise<number> {
|
|
7
7
|
const sql = getSql();
|
|
8
8
|
const status = params.deliveryStatus || "sent";
|
|
9
|
+
const meta = params.metadata ? JSON.stringify(params.metadata) : null;
|
|
9
10
|
const rows = await sql`
|
|
10
|
-
INSERT INTO messages (session_id, room, sender, content, is_from_agent, delivery_status)
|
|
11
|
-
VALUES (${params.sessionId}, ${params.room}, ${params.sender}, ${params.content}, ${params.isFromAgent}, ${status})
|
|
11
|
+
INSERT INTO messages (session_id, room, sender, content, is_from_agent, delivery_status, metadata)
|
|
12
|
+
VALUES (${params.sessionId}, ${params.room}, ${params.sender}, ${params.content}, ${params.isFromAgent}, ${status}, ${meta})
|
|
12
13
|
RETURNING id
|
|
13
14
|
`;
|
|
14
15
|
return rows[0].id;
|
package/src/db/models/session.ts
CHANGED
|
@@ -113,6 +113,58 @@ export async function getRecentSummaries(room: string, limit = 3): Promise<Array
|
|
|
113
113
|
}));
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
export async function accumulateMetadata(id: string, resultMeta: Record<string, unknown>): Promise<void> {
|
|
117
|
+
const sql = getSql();
|
|
118
|
+
|
|
119
|
+
const modelUsage = resultMeta.model_usage as Record<string, Record<string, number>> | undefined;
|
|
120
|
+
let inputTokens = 0;
|
|
121
|
+
let outputTokens = 0;
|
|
122
|
+
let cacheReadTokens = 0;
|
|
123
|
+
let cacheCreationTokens = 0;
|
|
124
|
+
const newModels: string[] = [];
|
|
125
|
+
if (modelUsage) {
|
|
126
|
+
for (const [model, usage] of Object.entries(modelUsage)) {
|
|
127
|
+
newModels.push(model);
|
|
128
|
+
inputTokens += usage.inputTokens || 0;
|
|
129
|
+
outputTokens += usage.outputTokens || 0;
|
|
130
|
+
cacheReadTokens += usage.cacheReadInputTokens || 0;
|
|
131
|
+
cacheCreationTokens += usage.cacheCreationInputTokens || 0;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const delta = JSON.stringify({
|
|
136
|
+
total_cost_usd: (resultMeta.cost_usd as number) || 0,
|
|
137
|
+
total_turns: (resultMeta.turns as number) || 0,
|
|
138
|
+
total_duration_ms: (resultMeta.duration_ms as number) || 0,
|
|
139
|
+
total_duration_api_ms: (resultMeta.duration_api_ms as number) || 0,
|
|
140
|
+
total_input_tokens: inputTokens,
|
|
141
|
+
total_output_tokens: outputTokens,
|
|
142
|
+
total_cache_read_tokens: cacheReadTokens,
|
|
143
|
+
total_cache_creation_tokens: cacheCreationTokens,
|
|
144
|
+
message_count: 1,
|
|
145
|
+
models_used: newModels,
|
|
146
|
+
channel: resultMeta.channel || null,
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// Atomic accumulate — no read-then-write race
|
|
150
|
+
await sql`
|
|
151
|
+
UPDATE sessions SET metadata = jsonb_build_object(
|
|
152
|
+
'total_cost_usd', COALESCE((metadata->>'total_cost_usd')::real, 0) + (${delta}::jsonb->>'total_cost_usd')::real,
|
|
153
|
+
'total_turns', COALESCE((metadata->>'total_turns')::int, 0) + (${delta}::jsonb->>'total_turns')::int,
|
|
154
|
+
'total_duration_ms', COALESCE((metadata->>'total_duration_ms')::real, 0) + (${delta}::jsonb->>'total_duration_ms')::real,
|
|
155
|
+
'total_duration_api_ms', COALESCE((metadata->>'total_duration_api_ms')::real, 0) + (${delta}::jsonb->>'total_duration_api_ms')::real,
|
|
156
|
+
'total_input_tokens', COALESCE((metadata->>'total_input_tokens')::int, 0) + (${delta}::jsonb->>'total_input_tokens')::int,
|
|
157
|
+
'total_output_tokens', COALESCE((metadata->>'total_output_tokens')::int, 0) + (${delta}::jsonb->>'total_output_tokens')::int,
|
|
158
|
+
'total_cache_read_tokens', COALESCE((metadata->>'total_cache_read_tokens')::int, 0) + (${delta}::jsonb->>'total_cache_read_tokens')::int,
|
|
159
|
+
'total_cache_creation_tokens', COALESCE((metadata->>'total_cache_creation_tokens')::int, 0) + (${delta}::jsonb->>'total_cache_creation_tokens')::int,
|
|
160
|
+
'message_count', COALESCE((metadata->>'message_count')::int, 0) + 1,
|
|
161
|
+
'models_used', COALESCE(metadata->'models_used', '[]'::jsonb) || ${JSON.stringify(newModels)}::jsonb,
|
|
162
|
+
'channel', COALESCE(metadata->>'channel', ${(resultMeta.channel as string) || null})
|
|
163
|
+
)
|
|
164
|
+
WHERE id = ${id}
|
|
165
|
+
`;
|
|
166
|
+
}
|
|
167
|
+
|
|
116
168
|
export async function getLatestRoomIndex(prefix: string): Promise<number> {
|
|
117
169
|
const sql = getSql();
|
|
118
170
|
const rows = await sql`
|