niahere 0.2.48 → 0.2.50
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 +1 -1
- package/src/chat/engine.ts +1 -1
- package/src/cli/index.ts +3 -3
- package/src/core/scheduler.ts +12 -5
- package/src/db/models/session.ts +32 -18
package/package.json
CHANGED
package/src/chat/engine.ts
CHANGED
|
@@ -367,7 +367,7 @@ export async function createChatEngine(opts: EngineOptions): Promise<ChatEngine>
|
|
|
367
367
|
messageId = await Message.save({ ...saveParams, metadata: undefined });
|
|
368
368
|
}
|
|
369
369
|
await Session.touch(sessionId);
|
|
370
|
-
|
|
370
|
+
Session.accumulateMetadata(sessionId, { ...metadata, channel }).catch(() => {});
|
|
371
371
|
}
|
|
372
372
|
|
|
373
373
|
await ActiveEngine.unregister(room);
|
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/core/scheduler.ts
CHANGED
|
@@ -79,10 +79,10 @@ async function tick(): Promise<void> {
|
|
|
79
79
|
|
|
80
80
|
for (const job of dueJobs) {
|
|
81
81
|
if (!job.always && !isWithinActiveHours()) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
await Job.markRun(job.name, nextRun).catch(() => {});
|
|
85
|
-
}
|
|
82
|
+
try {
|
|
83
|
+
const nextRun = computeNextRun(job.scheduleType, job.schedule, config.timezone, new Date());
|
|
84
|
+
if (nextRun) await Job.markRun(job.name, nextRun).catch(() => {});
|
|
85
|
+
} catch {}
|
|
86
86
|
log.info({ job: job.name }, "scheduler: skipping — outside active hours");
|
|
87
87
|
continue;
|
|
88
88
|
}
|
|
@@ -95,7 +95,14 @@ async function tick(): Promise<void> {
|
|
|
95
95
|
log.error({ err, job: job.name }, "scheduler: job failed");
|
|
96
96
|
});
|
|
97
97
|
|
|
98
|
-
|
|
98
|
+
let nextRun: Date | null = null;
|
|
99
|
+
try {
|
|
100
|
+
nextRun = computeNextRun(job.scheduleType, job.schedule, config.timezone, new Date());
|
|
101
|
+
} catch (err) {
|
|
102
|
+
log.error({ err, job: job.name, schedule: job.schedule }, "scheduler: invalid schedule, disabling job");
|
|
103
|
+
await Job.update(job.name, { enabled: false }).catch(() => {});
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
99
106
|
await Job.markRun(job.name, nextRun).catch((err) => {
|
|
100
107
|
log.error({ err, job: job.name }, "scheduler: failed to update next_run_at");
|
|
101
108
|
});
|
package/src/db/models/session.ts
CHANGED
|
@@ -115,18 +115,16 @@ export async function getRecentSummaries(room: string, limit = 3): Promise<Array
|
|
|
115
115
|
|
|
116
116
|
export async function accumulateMetadata(id: string, resultMeta: Record<string, unknown>): Promise<void> {
|
|
117
117
|
const sql = getSql();
|
|
118
|
-
const rows = await sql`SELECT metadata FROM sessions WHERE id = ${id}`;
|
|
119
|
-
const existing = (rows[0]?.metadata as Record<string, unknown>) || {};
|
|
120
118
|
|
|
121
119
|
const modelUsage = resultMeta.model_usage as Record<string, Record<string, number>> | undefined;
|
|
122
|
-
const modelsUsed = new Set<string>((existing.models_used as string[]) || []);
|
|
123
120
|
let inputTokens = 0;
|
|
124
121
|
let outputTokens = 0;
|
|
125
122
|
let cacheReadTokens = 0;
|
|
126
123
|
let cacheCreationTokens = 0;
|
|
124
|
+
const newModels: string[] = [];
|
|
127
125
|
if (modelUsage) {
|
|
128
126
|
for (const [model, usage] of Object.entries(modelUsage)) {
|
|
129
|
-
|
|
127
|
+
newModels.push(model);
|
|
130
128
|
inputTokens += usage.inputTokens || 0;
|
|
131
129
|
outputTokens += usage.outputTokens || 0;
|
|
132
130
|
cacheReadTokens += usage.cacheReadInputTokens || 0;
|
|
@@ -134,21 +132,37 @@ export async function accumulateMetadata(id: string, resultMeta: Record<string,
|
|
|
134
132
|
}
|
|
135
133
|
}
|
|
136
134
|
|
|
137
|
-
const
|
|
138
|
-
total_cost_usd: (
|
|
139
|
-
total_turns: (
|
|
140
|
-
total_duration_ms: (
|
|
141
|
-
total_duration_api_ms: (
|
|
142
|
-
total_input_tokens:
|
|
143
|
-
total_output_tokens:
|
|
144
|
-
total_cache_read_tokens:
|
|
145
|
-
total_cache_creation_tokens:
|
|
146
|
-
message_count:
|
|
147
|
-
models_used:
|
|
148
|
-
channel:
|
|
149
|
-
};
|
|
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
|
+
});
|
|
150
148
|
|
|
151
|
-
|
|
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
|
+
`;
|
|
152
166
|
}
|
|
153
167
|
|
|
154
168
|
export async function getLatestRoomIndex(prefix: string): Promise<number> {
|