ework-daemon 0.4.53 → 0.4.55

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ework-daemon",
3
- "version": "0.4.53",
3
+ "version": "0.4.55",
4
4
  "description": "Issue-driven AI development daemon. Spawns opencode subprocesses to resolve Gitea issues.",
5
5
  "module": "src/index.ts",
6
6
  "type": "module",
package/src/opencode.ts CHANGED
@@ -1299,11 +1299,11 @@ export class Engine {
1299
1299
  const superseded = () => this.generation.get(k) !== gen;
1300
1300
 
1301
1301
  // running.delete deferred to dequeuePending
1302
- this.currentMessage.delete(k);
1303
- this.currentModel.delete(k);
1304
-
1305
1302
  const started = this.startedAt.get(k);
1306
1303
  this.startedAt.delete(k);
1304
+ const usedModel = this.currentModel.get(k) ?? "";
1305
+ this.currentMessage.delete(k);
1306
+ this.currentModel.delete(k);
1307
1307
 
1308
1308
  const progressId = this.progressCommentId.get(k);
1309
1309
  const ref = this.sessionToRef(session, issue);
@@ -1361,11 +1361,15 @@ export class Engine {
1361
1361
  const hasRecent = this.hasRecentBotReply(commentsNow, tracker, started ?? undefined);
1362
1362
 
1363
1363
  if (hasRecent) {
1364
- const matched = commentsNow.find(c => tracker.isBotUser(c.author) && !this.isSystemComment(c) && c.createdAt && new Date(c.createdAt).getTime() > (started ?? 0));
1364
+ // oldest-first comment lists would match a pre-run bot reply when started
1365
+ // is undefined; pick the LAST qualifying comment instead.
1366
+ const matched = [...commentsNow].reverse().find(c => tracker.isBotUser(c.author) && !this.isSystemComment(c) && c.createdAt && new Date(c.createdAt).getTime() > (started ?? 0));
1365
1367
  log.info(`engine: [bot] reply found for ${k} after prompt (comment ${matched?.id ?? "?"} createdAt ${matched?.createdAt ?? "?"}), marking done`);
1366
- const usedModel = this.currentModel.get(k) ?? "";
1367
- if (matched && usedModel) {
1368
- void tracker.setCommentModel(ref, matched.id, usedModel).catch(() => { /* display-only */ });
1368
+ if (matched && !usedModel) {
1369
+ const fromSession = await this.backend.lastSessionModel(session.opencodeSessionId).catch(() => ({ model: "" }));
1370
+ if (fromSession.model) {
1371
+ void tracker.setCommentModel(ref, matched.id, fromSession.model).catch(() => { /* display-only */ });
1372
+ }
1369
1373
  }
1370
1374
  this.nudgeRounds.delete(k);
1371
1375
  this.emptyResponseRounds.delete(k);
@@ -7,6 +7,7 @@ import type {
7
7
  RuntimeSpawnCallbacks,
8
8
  RuntimeHandle,
9
9
  SessionOutputResult,
10
+ LastModelResult,
10
11
  } from "./types";
11
12
 
12
13
  const ENV_DENY_ALWAYS = ["OPENCODE", "OPENCODE_PID", "OPENCODE_RUN_ID", "OPENCODE_PROCESS_ROLE"] as const;
@@ -105,6 +106,28 @@ export class OpencodeBackend implements RuntimeBackend {
105
106
  }
106
107
  }
107
108
 
109
+ async lastSessionModel(sessionId: string | undefined): Promise<LastModelResult> {
110
+ if (!sessionId) return { model: "" };
111
+ let db: Database;
112
+ try {
113
+ db = new Database(this.dbPath, { readonly: true });
114
+ } catch {
115
+ return { model: "" };
116
+ }
117
+ try {
118
+ const row = db.prepare(
119
+ "SELECT json_extract(data,'$.modelID') AS model FROM message " +
120
+ "WHERE session_id = ? AND json_extract(data,'$.modelID') IS NOT NULL AND json_extract(data,'$.modelID') != '' " +
121
+ "ORDER BY time_created DESC LIMIT 1"
122
+ ).get(sessionId) as { model: string | null } | null;
123
+ return { model: row?.model ?? "" };
124
+ } catch {
125
+ return { model: "" };
126
+ } finally {
127
+ db.close();
128
+ }
129
+ }
130
+
108
131
  async getSessionOutputTokens(sessionId: string | undefined): Promise<SessionOutputResult> {
109
132
  if (!sessionId) return { hasOutput: true, tokenCount: 0 };
110
133
  let db: Database;
@@ -8,6 +8,7 @@ import type {
8
8
  RuntimeSpawnCallbacks,
9
9
  RuntimeHandle,
10
10
  SessionOutputResult,
11
+ LastModelResult,
11
12
  } from "./types";
12
13
 
13
14
  export class PiBackend implements RuntimeBackend {
@@ -98,6 +99,10 @@ export class PiBackend implements RuntimeBackend {
98
99
  }
99
100
  }
100
101
 
102
+ async lastSessionModel(_sessionId: string | undefined): Promise<LastModelResult> {
103
+ return { model: "" };
104
+ }
105
+
101
106
  async sessionExists(sessionId: string): Promise<boolean> {
102
107
  if (!sessionId) return false;
103
108
  return this.findSessionFile(sessionId) !== null;
@@ -11,6 +11,10 @@ export interface RuntimeSpawnCallbacks {
11
11
  onSessionId: (id: string) => Promise<void> | void;
12
12
  }
13
13
 
14
+ export interface LastModelResult {
15
+ model: string;
16
+ }
17
+
14
18
  export interface RuntimeHandle {
15
19
  pid: number;
16
20
  exited: Promise<number>;
@@ -26,6 +30,7 @@ export interface RuntimeBackend {
26
30
  readonly name: string;
27
31
 
28
32
  spawn(opts: RuntimeSpawnOpts, callbacks: RuntimeSpawnCallbacks): Promise<RuntimeHandle>;
33
+ lastSessionModel(sessionId: string | undefined): Promise<LastModelResult>;
29
34
 
30
35
  sessionExists(sessionId: string): Promise<boolean>;
31
36