modelstat 0.0.18 → 0.0.20

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/dist/cli.mjs CHANGED
@@ -32291,6 +32291,70 @@ var init_config = __esm({
32291
32291
  }
32292
32292
  });
32293
32293
 
32294
+ // ../../packages/companion-core/src/logger.ts
32295
+ function defaultLevel() {
32296
+ const env2 = globalThis.process?.env ?? {};
32297
+ const raw = (env2.LOG_LEVEL ?? "").toLowerCase();
32298
+ if (raw === "debug" || raw === "info" || raw === "warn" || raw === "error") return raw;
32299
+ return env2.NODE_ENV === "production" ? "info" : "debug";
32300
+ }
32301
+ function consoleLogger(opts = {}) {
32302
+ const scope = opts.scope ?? "main";
32303
+ const level = opts.level ?? defaultLevel();
32304
+ const threshold = LEVEL_RANK[level];
32305
+ const emit = (lvl, msg, fields) => {
32306
+ if (LEVEL_RANK[lvl] < threshold) return;
32307
+ const prefix = `[modelstat:${scope}]`;
32308
+ const args = fields !== void 0 ? [prefix, msg, fields] : [prefix, msg];
32309
+ const fn = lvl === "warn" ? "warn" : lvl === "error" ? "error" : "log";
32310
+ console[fn](...args);
32311
+ };
32312
+ return {
32313
+ debug: (msg, fields) => emit("debug", msg, fields),
32314
+ info: (msg, fields) => emit("info", msg, fields),
32315
+ warn: (msg, fields) => emit("warn", msg, fields),
32316
+ error: (msg, fields) => emit("error", msg, fields),
32317
+ child: (childScope) => consoleLogger({ scope: `${scope}:${childScope}`, level })
32318
+ };
32319
+ }
32320
+ function createLogger(scope, opts = {}) {
32321
+ return consoleLogger({ scope, ...opts });
32322
+ }
32323
+ function describeErrorWithCause(err, depth = 4) {
32324
+ if (!err) return "unknown";
32325
+ if (!(err instanceof Error)) return String(err);
32326
+ const parts = [err.message || err.name];
32327
+ let cur = err.cause;
32328
+ let left = depth;
32329
+ while (cur && left-- > 0) {
32330
+ if (cur instanceof AggregateError && Array.isArray(cur.errors) && cur.errors[0]) {
32331
+ cur = cur.errors[0];
32332
+ continue;
32333
+ }
32334
+ if (cur instanceof Error) {
32335
+ const code = cur.code;
32336
+ parts.push(`${code ? `code=${code} ` : ""}msg=${cur.message || cur.name}`);
32337
+ cur = cur.cause;
32338
+ continue;
32339
+ }
32340
+ parts.push(String(cur));
32341
+ break;
32342
+ }
32343
+ return parts.join(" \u2192 ");
32344
+ }
32345
+ var LEVEL_RANK;
32346
+ var init_logger = __esm({
32347
+ "../../packages/companion-core/src/logger.ts"() {
32348
+ "use strict";
32349
+ LEVEL_RANK = {
32350
+ debug: 10,
32351
+ info: 20,
32352
+ warn: 30,
32353
+ error: 40
32354
+ };
32355
+ }
32356
+ });
32357
+
32294
32358
  // ../../packages/companion-core/src/http/index.ts
32295
32359
  function classifyStatus(status2, attempt) {
32296
32360
  if (status2 >= 200 && status2 < 300) return { type: "commit" };
@@ -32311,6 +32375,7 @@ var init_http = __esm({
32311
32375
  "../../packages/companion-core/src/http/index.ts"() {
32312
32376
  "use strict";
32313
32377
  init_config();
32378
+ init_logger();
32314
32379
  IngestClient = class {
32315
32380
  constructor(opts) {
32316
32381
  this.opts = opts;
@@ -32322,6 +32387,7 @@ var init_http = __esm({
32322
32387
  maxAttempts;
32323
32388
  async upload(batch) {
32324
32389
  const url = `${this.opts.apiUrl.replace(/\/+$/, "")}/v1/ingest`;
32390
+ let lastFetchError = null;
32325
32391
  for (let attempt = 0; attempt < this.maxAttempts; attempt++) {
32326
32392
  const token = await this.opts.auth.getToken();
32327
32393
  if (!token) {
@@ -32340,7 +32406,13 @@ var init_http = __esm({
32340
32406
  body: JSON.stringify(batch)
32341
32407
  });
32342
32408
  } catch (err) {
32343
- this.opts.logger.warn("ingest fetch failed", { err: String(err), attempt });
32409
+ const detail = describeErrorWithCause(err);
32410
+ lastFetchError = detail;
32411
+ this.opts.logger.warn("ingest fetch failed", {
32412
+ err: detail,
32413
+ url,
32414
+ attempt
32415
+ });
32344
32416
  await sleep(expBackoff(attempt));
32345
32417
  continue;
32346
32418
  }
@@ -32370,54 +32442,13 @@ var init_http = __esm({
32370
32442
  });
32371
32443
  await sleep(decision.delayMs);
32372
32444
  }
32373
- return { kind: "drop", reason: "max_attempts_exceeded" };
32445
+ const reason = lastFetchError ? `network: ${lastFetchError}` : "max_attempts_exceeded";
32446
+ return { kind: "drop", reason };
32374
32447
  }
32375
32448
  };
32376
32449
  }
32377
32450
  });
32378
32451
 
32379
- // ../../packages/companion-core/src/logger.ts
32380
- function defaultLevel() {
32381
- const env2 = globalThis.process?.env ?? {};
32382
- const raw = (env2.LOG_LEVEL ?? "").toLowerCase();
32383
- if (raw === "debug" || raw === "info" || raw === "warn" || raw === "error") return raw;
32384
- return env2.NODE_ENV === "production" ? "info" : "debug";
32385
- }
32386
- function consoleLogger(opts = {}) {
32387
- const scope = opts.scope ?? "main";
32388
- const level = opts.level ?? defaultLevel();
32389
- const threshold = LEVEL_RANK[level];
32390
- const emit = (lvl, msg, fields) => {
32391
- if (LEVEL_RANK[lvl] < threshold) return;
32392
- const prefix = `[modelstat:${scope}]`;
32393
- const args = fields !== void 0 ? [prefix, msg, fields] : [prefix, msg];
32394
- const fn = lvl === "warn" ? "warn" : lvl === "error" ? "error" : "log";
32395
- console[fn](...args);
32396
- };
32397
- return {
32398
- debug: (msg, fields) => emit("debug", msg, fields),
32399
- info: (msg, fields) => emit("info", msg, fields),
32400
- warn: (msg, fields) => emit("warn", msg, fields),
32401
- error: (msg, fields) => emit("error", msg, fields),
32402
- child: (childScope) => consoleLogger({ scope: `${scope}:${childScope}`, level })
32403
- };
32404
- }
32405
- function createLogger(scope, opts = {}) {
32406
- return consoleLogger({ scope, ...opts });
32407
- }
32408
- var LEVEL_RANK;
32409
- var init_logger = __esm({
32410
- "../../packages/companion-core/src/logger.ts"() {
32411
- "use strict";
32412
- LEVEL_RANK = {
32413
- debug: 10,
32414
- info: 20,
32415
- warn: 30,
32416
- error: 40
32417
- };
32418
- }
32419
- });
32420
-
32421
32452
  // ../../node_modules/.pnpm/dotenv@16.6.1/node_modules/dotenv/package.json
32422
32453
  var require_package = __commonJS({
32423
32454
  "../../node_modules/.pnpm/dotenv@16.6.1/node_modules/dotenv/package.json"(exports, module) {
@@ -44018,7 +44049,15 @@ async function buildForOneSession(sessionId, events, adapters2) {
44018
44049
  const turnSurfaces = sorted.map((e) => turnSurface(e));
44019
44050
  const turnEmbeddings = [];
44020
44051
  for (const s of turnSurfaces) {
44021
- turnEmbeddings.push(s.length > 0 ? await adapters2.embed(s) : []);
44052
+ if (s.length === 0) {
44053
+ turnEmbeddings.push([]);
44054
+ continue;
44055
+ }
44056
+ try {
44057
+ turnEmbeddings.push(await adapters2.embed(s));
44058
+ } catch {
44059
+ turnEmbeddings.push([]);
44060
+ }
44022
44061
  }
44023
44062
  const boundaries = [];
44024
44063
  let runStart = 0;
@@ -44289,27 +44328,62 @@ var init_node2 = __esm({
44289
44328
  });
44290
44329
 
44291
44330
  // src/pipeline.ts
44292
- function getAdapters() {
44293
- if (!adapters) {
44294
- const cfg = defaultOllamaConfig();
44331
+ async function probeOllama(baseUrl) {
44332
+ try {
44333
+ const ctrl = new AbortController();
44334
+ const t = setTimeout(() => ctrl.abort(), 500);
44335
+ const res = await fetch(`${baseUrl.replace(/\/+$/, "")}/api/tags`, {
44336
+ method: "GET",
44337
+ signal: ctrl.signal
44338
+ });
44339
+ clearTimeout(t);
44340
+ return res.ok;
44341
+ } catch {
44342
+ return false;
44343
+ }
44344
+ }
44345
+ function fallbackAdapters() {
44346
+ return {
44347
+ embed: async () => [],
44348
+ // Throw → companion-core/summariseSlice's try/catch falls back to
44349
+ // the `promptFacts` string which is what we want here.
44350
+ summarize: async () => {
44351
+ throw new Error("ollama_unavailable");
44352
+ },
44353
+ tokenize: (text) => Math.max(1, Math.ceil(text.length / 4))
44354
+ };
44355
+ }
44356
+ async function getAdapters() {
44357
+ if (adapters && probed) return adapters;
44358
+ const cfg = defaultOllamaConfig();
44359
+ const up = await probeOllama(cfg.baseUrl);
44360
+ probed = true;
44361
+ if (up) {
44362
+ console.log(`[modelstat] ollama up at ${cfg.baseUrl} \u2014 using LLM pipeline`);
44295
44363
  adapters = {
44296
44364
  embed: ollamaEmbed(cfg),
44297
44365
  summarize: ollamaSummarize(cfg),
44298
44366
  tokenize: ollamaTokenize()
44299
44367
  };
44368
+ } else {
44369
+ console.log(
44370
+ `[modelstat] ollama not reachable at ${cfg.baseUrl} \u2014 using fallback pipeline (server does classification)`
44371
+ );
44372
+ adapters = fallbackAdapters();
44300
44373
  }
44301
44374
  return adapters;
44302
44375
  }
44303
44376
  async function buildSegments(events) {
44304
- return buildSegmentsForSession(events, getAdapters());
44377
+ return buildSegmentsForSession(events, await getAdapters());
44305
44378
  }
44306
- var adapters;
44379
+ var adapters, probed;
44307
44380
  var init_pipeline2 = __esm({
44308
44381
  "src/pipeline.ts"() {
44309
44382
  "use strict";
44310
44383
  init_pipeline();
44311
44384
  init_node2();
44312
44385
  adapters = null;
44386
+ probed = false;
44313
44387
  }
44314
44388
  });
44315
44389
 
@@ -44375,6 +44449,7 @@ async function scanAll(cb = {}) {
44375
44449
  let batchesUploaded = 0;
44376
44450
  let eventsUploaded = 0;
44377
44451
  let buffer = [];
44452
+ let pendingCursors = [];
44378
44453
  async function flushBatch() {
44379
44454
  if (!buffer.length) return;
44380
44455
  cb.onUpload?.(buffer.length);
@@ -44389,6 +44464,8 @@ async function scanAll(cb = {}) {
44389
44464
  const res = await uploadBatch(batch);
44390
44465
  batchesUploaded += 1;
44391
44466
  eventsUploaded += res.accepted;
44467
+ for (const pc of pendingCursors) state.setCursor(pc.path, pc.cs);
44468
+ pendingCursors = [];
44392
44469
  buffer = [];
44393
44470
  }
44394
44471
  for (let i = 0; i < jobs.length; i++) {
@@ -44409,7 +44486,7 @@ async function scanAll(cb = {}) {
44409
44486
  if (buffer.length >= BATCH_MAX_EVENTS) await flushBatch();
44410
44487
  }
44411
44488
  }
44412
- if (cs) state.setCursor(job.path, cs);
44489
+ if (cs) pendingCursors.push({ path: job.path, cs });
44413
44490
  } catch (e) {
44414
44491
  console.warn(` ! parse failed for ${job.path}:`, e.message);
44415
44492
  }
@@ -44426,7 +44503,7 @@ var init_scan = __esm({
44426
44503
  init_pipeline2();
44427
44504
  init_config2();
44428
44505
  init_api();
44429
- AGENT_VERSION = "agent-dev-0.0.1";
44506
+ AGENT_VERSION = "agent-dev-0.0.20";
44430
44507
  BATCH_MAX_EVENTS = 2e3;
44431
44508
  }
44432
44509
  });
@@ -46219,7 +46296,7 @@ async function runDiscovery() {
46219
46296
  status.stats["installations_detected"] = d.installations.length;
46220
46297
  status.stats["identities_detected"] = d.identities.length;
46221
46298
  } catch (e) {
46222
- setPhase("error", `discovery failed: ${e.message}`);
46299
+ setPhase("error", `discovery failed: ${describeErrorWithCause(e)}`);
46223
46300
  }
46224
46301
  }
46225
46302
  async function runScanCycle(reason) {
@@ -46243,7 +46320,7 @@ async function runScanCycle(reason) {
46243
46320
  setPhase("watching", "Waiting for new events");
46244
46321
  setProgress(0, 0);
46245
46322
  } catch (e) {
46246
- setPhase("offline", `Upload failed: ${e.message}`);
46323
+ setPhase("offline", `Upload failed: ${describeErrorWithCause(e)}`);
46247
46324
  }
46248
46325
  }
46249
46326
  function basename3(p) {
@@ -46315,11 +46392,12 @@ var init_daemon = __esm({
46315
46392
  "src/daemon.ts"() {
46316
46393
  "use strict";
46317
46394
  import_undici2 = __toESM(require_undici(), 1);
46395
+ init_logger();
46318
46396
  init_src2();
46319
46397
  init_api();
46320
46398
  init_config2();
46321
46399
  init_scan();
46322
- AGENT_VERSION2 = "agent-dev-0.0.1";
46400
+ AGENT_VERSION2 = "agent-dev-0.0.20";
46323
46401
  HEARTBEAT_INTERVAL_MS = 1e4;
46324
46402
  SCAN_INTERVAL_MS = 5 * 60 * 1e3;
46325
46403
  status = {