@adelie/server 0.6.7 → 0.6.8

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/index.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-GO6G445C.js";
9
9
  import {
10
10
  TICKET_SLUG_PATTERN
11
- } from "./chunk-2NN3GRLL.js";
11
+ } from "./chunk-OYLSIVS7.js";
12
12
  import {
13
13
  MachinesRepo
14
14
  } from "./chunk-HMTT2PX4.js";
@@ -3828,7 +3828,7 @@ import { DEFAULT_PROJECT_ID as DEFAULT_PROJECT_ID3, DEFAULT_PROJECT_NAME as DEFA
3828
3828
 
3829
3829
  // src/ifaces.json
3830
3830
  var ifaces_default = {
3831
- hash: "bd8f0cb27b4ce1db502e9b13e9818933c2b572478fcb7917370d8e7ac36afbfe",
3831
+ hash: "d8d20ea5e3d2ed0efa41124541a9f94d5b894d7eb1e85d0f829977783976fb0c",
3832
3832
  ifaces: {
3833
3833
  "@adelie/server#Access": {
3834
3834
  name: "Access",
@@ -16653,6 +16653,14 @@ var ifaces_default = {
16653
16653
  }
16654
16654
  }
16655
16655
  },
16656
+ liveSessions: {
16657
+ params: [],
16658
+ returns: {
16659
+ data: {
16660
+ $ref: "typescript#Array<{ sessionId: string; projectId: string; agentId: string; status: SessionStatus; }>"
16661
+ }
16662
+ }
16663
+ },
16656
16664
  pendingApprovalCount: {
16657
16665
  params: [
16658
16666
  {
@@ -19937,6 +19945,27 @@ var ifaces_default = {
19937
19945
  }
19938
19946
  }
19939
19947
  },
19948
+ sessionDays: {
19949
+ params: [
19950
+ {
19951
+ data: "string"
19952
+ },
19953
+ {
19954
+ data: [
19955
+ {
19956
+ "days?": "number"
19957
+ },
19958
+ "|",
19959
+ "undefined"
19960
+ ]
19961
+ }
19962
+ ],
19963
+ returns: {
19964
+ data: {
19965
+ $ref: "typescript#Array<UsageSessionDay>"
19966
+ }
19967
+ }
19968
+ },
19940
19969
  queryErrors: {
19941
19970
  params: [
19942
19971
  {
@@ -20257,6 +20286,27 @@ var ifaces_default = {
20257
20286
  }
20258
20287
  }
20259
20288
  },
20289
+ sessionDayByModel: {
20290
+ params: [
20291
+ {
20292
+ data: "string"
20293
+ },
20294
+ {
20295
+ data: [
20296
+ {
20297
+ $ref: "@adelie/server#UsageFilter"
20298
+ },
20299
+ "|",
20300
+ "undefined"
20301
+ ]
20302
+ }
20303
+ ],
20304
+ returns: {
20305
+ data: {
20306
+ $ref: "typescript#Array<UsageSessionDaySums>"
20307
+ }
20308
+ }
20309
+ },
20260
20310
  seriesByModel: {
20261
20311
  params: [
20262
20312
  {
@@ -20500,6 +20550,27 @@ var ifaces_default = {
20500
20550
  }
20501
20551
  }
20502
20552
  },
20553
+ sessionDays: {
20554
+ params: [
20555
+ {
20556
+ data: "string"
20557
+ },
20558
+ {
20559
+ data: [
20560
+ {
20561
+ "days?": "number"
20562
+ },
20563
+ "|",
20564
+ "undefined"
20565
+ ]
20566
+ }
20567
+ ],
20568
+ returns: {
20569
+ data: {
20570
+ $ref: "typescript#Array<UsageSessionDay>"
20571
+ }
20572
+ }
20573
+ },
20503
20574
  lifetimeCost: {
20504
20575
  params: [
20505
20576
  {
@@ -20649,6 +20720,27 @@ var ifaces_default = {
20649
20720
  }
20650
20721
  }
20651
20722
  },
20723
+ sessionDayByModel: {
20724
+ params: [
20725
+ {
20726
+ data: "string"
20727
+ },
20728
+ {
20729
+ data: [
20730
+ {
20731
+ $ref: "@adelie/server#UsageFilter"
20732
+ },
20733
+ "|",
20734
+ "undefined"
20735
+ ]
20736
+ }
20737
+ ],
20738
+ returns: {
20739
+ data: {
20740
+ $ref: "typescript#Array<UsageSessionDaySums>"
20741
+ }
20742
+ }
20743
+ },
20652
20744
  agentSeries: {
20653
20745
  params: [
20654
20746
  {
@@ -25000,7 +25092,7 @@ var ifaces_default = {
25000
25092
  },
25001
25093
  "@adelie/server#ScheduleStatus": "'done'|'expired'|'active'|'missed'|'invalid'|'disabled'",
25002
25094
  "@adelie/server#SemanticIdKind": "'agent'|'org'|'channel'|'project'|'benchmark'",
25003
- "@adelie/server#SemanticIdSuggestReason": "'no_default_model'|'model_failed'|'unusable_answer'|'no_ascii'",
25095
+ "@adelie/server#SemanticIdSuggestReason": "'no_free_model'|'model_failed'|'unusable_answer'|'no_ascii'",
25004
25096
  "@adelie/server#SemanticIdSuggestRequest": {
25005
25097
  name: "string",
25006
25098
  kind: {
@@ -26125,6 +26217,45 @@ var ifaces_default = {
26125
26217
  completed: "number",
26126
26218
  denominator: "number"
26127
26219
  },
26220
+ "@adelie/server#UsageSessionDay": {
26221
+ date: "string",
26222
+ cacheRead: "number",
26223
+ cacheWrite: "number",
26224
+ output: "number",
26225
+ total: "number",
26226
+ requests: "number",
26227
+ cost: "null|number",
26228
+ hasUncosted: "boolean",
26229
+ sessions: {
26230
+ $ref: "typescript#Array<UsageSessionDayRow>"
26231
+ }
26232
+ },
26233
+ "@adelie/server#UsageSessionDayRow": {
26234
+ sessionId: "string",
26235
+ agentId: "string",
26236
+ "title?": "string",
26237
+ cacheRead: "number",
26238
+ cacheWrite: "number",
26239
+ output: "number",
26240
+ total: "number",
26241
+ requests: "number",
26242
+ cost: "null|number",
26243
+ hasUncosted: "boolean"
26244
+ },
26245
+ "@adelie/server#UsageSessionDaySums": {
26246
+ date: "string",
26247
+ sessionId: "string",
26248
+ agentId: "string",
26249
+ provider: "string",
26250
+ modelId: "string",
26251
+ cacheRead: "number",
26252
+ cacheWrite: "number",
26253
+ output: "number",
26254
+ total: "number",
26255
+ requests: "number",
26256
+ cost: "null|number",
26257
+ uncosted: "number"
26258
+ },
26128
26259
  "@adelie/server#UsageTrendPointInTrace": {
26129
26260
  ts: "string",
26130
26261
  requestTotal: "number",
@@ -27038,6 +27169,24 @@ var ifaces_default = {
27038
27169
  },
27039
27170
  "[]"
27040
27171
  ],
27172
+ "typescript#Array<UsageSessionDay>": [
27173
+ {
27174
+ $ref: "@adelie/server#UsageSessionDay"
27175
+ },
27176
+ "[]"
27177
+ ],
27178
+ "typescript#Array<UsageSessionDayRow>": [
27179
+ {
27180
+ $ref: "@adelie/server#UsageSessionDayRow"
27181
+ },
27182
+ "[]"
27183
+ ],
27184
+ "typescript#Array<UsageSessionDaySums>": [
27185
+ {
27186
+ $ref: "@adelie/server#UsageSessionDaySums"
27187
+ },
27188
+ "[]"
27189
+ ],
27041
27190
  "typescript#Array<UsageTrendPointInTrace>": [
27042
27191
  {
27043
27192
  $ref: "@adelie/server#UsageTrendPointInTrace"
@@ -27244,6 +27393,17 @@ var ifaces_default = {
27244
27393
  },
27245
27394
  "[]"
27246
27395
  ],
27396
+ "typescript#Array<{ sessionId: string; projectId: string; agentId: string; status: SessionStatus; }>": [
27397
+ {
27398
+ sessionId: "string",
27399
+ projectId: "string",
27400
+ agentId: "string",
27401
+ status: {
27402
+ $ref: "@adelie/server#SessionStatus"
27403
+ }
27404
+ },
27405
+ "[]"
27406
+ ],
27247
27407
  "typescript#Array<{ ticketId: string; sessionId: string; agentId: string; }>": [
27248
27408
  {
27249
27409
  ticketId: "string",
@@ -30634,6 +30794,12 @@ var ifaces_default = {
30634
30794
  auth: "user",
30635
30795
  order: 255
30636
30796
  },
30797
+ {
30798
+ id: "session-api.sessions-running",
30799
+ prefix: "/api/projects/:projectId/sessions/running",
30800
+ auth: "user",
30801
+ order: 256
30802
+ },
30637
30803
  {
30638
30804
  id: "session-api.usage",
30639
30805
  prefix: "/api/projects/:projectId/usage",
@@ -33245,12 +33411,14 @@ var LIST_MODELS_TIMEOUT_MS = 2e4;
33245
33411
  var SPEED_PROBE_PROMPT = "Count from 1 to 50 as a comma-separated list, and nothing else. Do not think or explain.\n<think></think>";
33246
33412
  var UTILITY_COMPLETION_BUDGET = 300;
33247
33413
  var UTILITY_COMPLETION_TIMEOUT_MS = 15e3;
33414
+ var UTILITY_COMPLETION_ATTEMPTS = 4;
33415
+ var UTILITY_COMPLETION_WALK_BUDGET_MS = 3e4;
33248
33416
  var MAX_FAILURE_DETAIL = 300;
33249
33417
  function outcomeDetail(outcome) {
33250
33418
  const detail = outcome.errorMessage ? outcome.errorMessage : outcome.status;
33251
33419
  return String(detail).slice(0, MAX_FAILURE_DETAIL);
33252
33420
  }
33253
- function utilityCompletionConfig(modelId, entry) {
33421
+ function utilityCompletionConfig(modelId, entry, requestTimeoutMs = UTILITY_COMPLETION_TIMEOUT_MS) {
33254
33422
  const clientType = canonicalClientType(optStr(entry.client_type));
33255
33423
  const credential = resolveModelCredential({
33256
33424
  provider: optStr(entry.provider) ?? "",
@@ -33266,9 +33434,26 @@ function utilityCompletionConfig(modelId, entry) {
33266
33434
  tools: [],
33267
33435
  thinkingLevel: "none",
33268
33436
  maxTokens: metaMaxTokens(UTILITY_COMPLETION_BUDGET, optNum(entry.max_tokens)),
33269
- requestTimeoutMs: UTILITY_COMPLETION_TIMEOUT_MS
33437
+ requestTimeoutMs
33270
33438
  };
33271
33439
  }
33440
+ function freeModelEntries(raw) {
33441
+ const out = [];
33442
+ const seen = /* @__PURE__ */ new Set();
33443
+ for (const entry of asArray(raw.models)) {
33444
+ const provider = optStr(entry.provider);
33445
+ const modelId = optStr(entry.model_id);
33446
+ if (provider === void 0 || modelId === void 0) continue;
33447
+ const pricing = pricingDtoOf(entry.pricing);
33448
+ if (pricing === void 0) continue;
33449
+ if (pricing.cacheRead !== 0 || pricing.cacheWrite !== 0 || pricing.output !== 0) continue;
33450
+ const key2 = `${provider}\0${modelId}`;
33451
+ if (seen.has(key2)) continue;
33452
+ seen.add(key2);
33453
+ out.push({ provider, modelId, entry });
33454
+ }
33455
+ return out;
33456
+ }
33272
33457
  async function collectUtilityCompletion(stream) {
33273
33458
  let text2 = "";
33274
33459
  for (; ; ) {
@@ -33706,15 +33891,21 @@ var ProjectConfigService = class {
33706
33891
  }
33707
33892
  }
33708
33893
  /**
33709
- * One short completion on the Project's **default** model, for utility asks that belong to
33710
- * no Session — today the English identifier a display name is translated into. Everything
33711
- * comes from the stored default entry (credential, base URL, pinned protocol), and the
33712
- * answer is the model's plain text. Nothing throws: no default model, no entry for it, a
33713
- * construction that throws on a missing credential, a refusal, a timeout, or an answer with
33714
- * no text all come back as `{ ok: false }` carrying the reason, which the caller records so
33715
- * the errors panel can say why the ask produced nothing. Callers must still have a result
33716
- * that works without it. The request is not metered — it carries no Session to attribute
33717
- * it to.
33894
+ * One short completion on a **free** model of the Project, for utility asks that belong to
33895
+ * no Session — today the English identifier a display name is translated into. A free model
33896
+ * is walked first, and several of them: free endpoints are throttled, delisted and retired
33897
+ * routinely, one dead endpoint says nothing about the next, and the ask must not cost
33898
+ * anything, so the Project's default model is deliberately not among the candidates. What
33899
+ * the caller gets when none of them answers is the reason, and its own fallback.
33900
+ *
33901
+ * The walk is bounded twice over: at most `UTILITY_COMPLETION_ATTEMPTS` requests are sent,
33902
+ * and together they get `UTILITY_COMPLETION_WALK_BUDGET_MS`. A candidate that cannot be built
33903
+ * at all — no credential, no routable id — costs neither an attempt nor a wait, so a config
33904
+ * full of unusable free rows does not eat the budget of the ones that work. Nothing throws:
33905
+ * no free entry, an entry with no credential, a refusal, a timeout, or an answer with no text
33906
+ * all come back as `{ ok: false }` carrying the reason, which the caller records so the
33907
+ * errors panel can say why the ask produced nothing. Callers must still have a result that
33908
+ * works without it. The request is not metered — it carries no Session to attribute it to.
33718
33909
  *
33719
33910
  * Thinking is off and the budget is the shared meta budget, for the same reason core's own
33720
33911
  * out-of-band requests set them that way: a reasoning model spends thinking out of
@@ -33723,33 +33914,51 @@ var ProjectConfigService = class {
33723
33914
  */
33724
33915
  async completeOnce(projectId, prompt) {
33725
33916
  const raw = await this.readRaw(projectId);
33726
- const ref = optRef(raw.default_model);
33727
- if (ref === void 0) {
33728
- return { ok: false, cause: "no_model", error: "the Project names no default model" };
33729
- }
33730
- const entry = asArray(raw.models).find((m) => entryMatches(m, ref.provider, ref.model_id));
33731
- if (entry === void 0) {
33732
- return {
33733
- ok: false,
33734
- cause: "no_model",
33735
- error: `the default model ${ref.provider}/${ref.model_id} has no entry in the Project config`
33736
- };
33737
- }
33738
- try {
33739
- const llm = new GenerativeModel({
33740
- ...utilityCompletionConfig(ref.model_id, entry),
33741
- ...this.requestApiKeyResolver(projectId, ref.provider, ref.model_id)
33742
- });
33743
- return await collectUtilityCompletion(
33917
+ const candidates = freeModelEntries(raw);
33918
+ const deadline = Date.now() + UTILITY_COMPLETION_WALK_BUDGET_MS;
33919
+ let failure;
33920
+ let sent = 0;
33921
+ for (const candidate of candidates) {
33922
+ if (sent >= UTILITY_COMPLETION_ATTEMPTS) break;
33923
+ const remaining = deadline - Date.now();
33924
+ if (remaining < 1e3) break;
33925
+ let llm;
33926
+ try {
33927
+ llm = new GenerativeModel({
33928
+ ...utilityCompletionConfig(
33929
+ candidate.modelId,
33930
+ candidate.entry,
33931
+ Math.min(UTILITY_COMPLETION_TIMEOUT_MS, remaining)
33932
+ ),
33933
+ ...this.requestApiKeyResolver(projectId, candidate.provider, candidate.modelId)
33934
+ });
33935
+ } catch (err) {
33936
+ failure = {
33937
+ ok: false,
33938
+ cause: "failed",
33939
+ error: (err instanceof Error ? err.message : String(err)).slice(0, MAX_FAILURE_DETAIL)
33940
+ };
33941
+ continue;
33942
+ }
33943
+ sent += 1;
33944
+ const res = await collectUtilityCompletion(
33744
33945
  llm.streamGenerate({ newMessages: [userText(prompt)] })
33745
33946
  );
33746
- } catch (err) {
33947
+ if (res.ok) return res;
33948
+ failure = res;
33949
+ }
33950
+ if (sent === 0) {
33747
33951
  return {
33748
33952
  ok: false,
33749
- cause: "failed",
33750
- error: (err instanceof Error ? err.message : String(err)).slice(0, MAX_FAILURE_DETAIL)
33953
+ cause: "no_model",
33954
+ error: failure?.error ?? "the Project has no free ($0-priced) model that can be run"
33751
33955
  };
33752
33956
  }
33957
+ return {
33958
+ ok: false,
33959
+ cause: "failed",
33960
+ error: failure?.error ?? "every free model of the Project gave no answer"
33961
+ };
33753
33962
  }
33754
33963
  async testModel(projectId, req) {
33755
33964
  const raw = await this.readRaw(projectId);
@@ -36901,6 +37110,25 @@ var SessionManager = class {
36901
37110
  statusOf(sessionId) {
36902
37111
  return this.entries.get(sessionId)?.status ?? "idle";
36903
37112
  }
37113
+ /**
37114
+ * Every Session this process holds in a live state — running or compacting — across all
37115
+ * Projects and Agents. `statusOf` answers one id at a time, and a Session nobody is looking
37116
+ * at has no row in any client's list; the account menu's "what is running right now" asks
37117
+ * the whole table instead, which is a walk over the entries this process already keeps.
37118
+ */
37119
+ liveSessions() {
37120
+ const out = [];
37121
+ for (const e of this.entries.values()) {
37122
+ if (e.status === "idle") continue;
37123
+ out.push({
37124
+ sessionId: e.sessionId,
37125
+ projectId: e.projectId,
37126
+ agentId: e.agentId,
37127
+ status: e.status
37128
+ });
37129
+ }
37130
+ return out;
37131
+ }
36904
37132
  pendingApprovalCount(sessionId) {
36905
37133
  return this.entries.get(sessionId)?.approvals.size ?? 0;
36906
37134
  }
@@ -46504,6 +46732,25 @@ var UsageRepo = class {
46504
46732
  ).all(params);
46505
46733
  return rows.map((r) => ({ key: r.key, ...toSums(r) }));
46506
46734
  }
46735
+ /**
46736
+ * Per-(calendar day, Session, Agent) x paired reference sums: the day-by-day
46737
+ * "which conversations spent the Tokens" view. Same filter and same `date`
46738
+ * column as `groupsByModel`, so a total here adds up to the cost center's.
46739
+ */
46740
+ sessionDayByModel(projectId, f = {}) {
46741
+ const { where, params } = this.conds(projectId, f);
46742
+ const rows = this.db.prepare(
46743
+ `SELECT date, session_id, agent_id, provider, model_id, ${SUM_COLUMNS}
46744
+ FROM usage_records WHERE ${where}
46745
+ GROUP BY date, session_id, agent_id, provider, model_id`
46746
+ ).all(params);
46747
+ return rows.map((r) => ({
46748
+ date: r.date,
46749
+ sessionId: r.session_id,
46750
+ agentId: r.agent_id,
46751
+ ...toSums(r)
46752
+ }));
46753
+ }
46507
46754
  /**
46508
46755
  * Time-series sums (bucket key x paired reference breakdown) with per-bucket
46509
46756
  * success-rate counts riding along: powers the cost center's time-series charts
@@ -48079,6 +48326,86 @@ var UsageService = class {
48079
48326
  }))
48080
48327
  };
48081
48328
  }
48329
+ /**
48330
+ * Usage by calendar day, each day split by Session — the account menu's "会话运行记录":
48331
+ * which conversations spent the Tokens, day by day. One grouped scan over the last `days`
48332
+ * calendar days (today included), folded here into days and Sessions; both levels sum the
48333
+ * same rows, so a day's figure is the sum of its Sessions' and the window's is the sum of
48334
+ * the days'.
48335
+ *
48336
+ * Days with no records are left out rather than drawn as zeros — a day nobody used the app
48337
+ * is not a row worth reading — but today is always answered, at zero when nothing has run,
48338
+ * because "今天花了多少" is the one figure the list is opened for. Within a day, Sessions
48339
+ * are ordered by Token total, descending.
48340
+ */
48341
+ sessionDays(projectId, opts = {}) {
48342
+ const days = Math.min(Math.max(opts.days ?? 7, 1), 90);
48343
+ const now = this.clock.now();
48344
+ const today = formatLocalDate(now);
48345
+ const rows = this.usage.sessionDayByModel(projectId, {
48346
+ from: localDateMinusDays(now, days - 1),
48347
+ to: today
48348
+ });
48349
+ const byDate = /* @__PURE__ */ new Map();
48350
+ for (const r of rows) {
48351
+ let day = byDate.get(r.date);
48352
+ if (!day) {
48353
+ day = {
48354
+ date: r.date,
48355
+ cacheRead: 0,
48356
+ cacheWrite: 0,
48357
+ output: 0,
48358
+ total: 0,
48359
+ requests: 0,
48360
+ cost: null,
48361
+ hasUncosted: false,
48362
+ sessions: []
48363
+ };
48364
+ byDate.set(r.date, day);
48365
+ }
48366
+ let session = day.sessions.find((s) => s.sessionId === r.sessionId);
48367
+ if (!session) {
48368
+ session = {
48369
+ sessionId: r.sessionId,
48370
+ agentId: r.agentId,
48371
+ cacheRead: 0,
48372
+ cacheWrite: 0,
48373
+ output: 0,
48374
+ total: 0,
48375
+ requests: 0,
48376
+ cost: null,
48377
+ hasUncosted: false
48378
+ };
48379
+ day.sessions.push(session);
48380
+ }
48381
+ for (const target of [day, session]) {
48382
+ target.cacheRead += r.cacheRead;
48383
+ target.cacheWrite += r.cacheWrite;
48384
+ target.output += r.output;
48385
+ target.total += r.total;
48386
+ target.requests += r.requests;
48387
+ if (r.cost !== null) target.cost = (target.cost ?? 0) + r.cost;
48388
+ if (r.uncosted > 0) target.hasUncosted = true;
48389
+ }
48390
+ }
48391
+ const out = [...byDate.values()];
48392
+ for (const day of out) day.sessions.sort((a, b) => b.total - a.total);
48393
+ out.sort((a, b) => b.date.localeCompare(a.date));
48394
+ if (!byDate.has(today)) {
48395
+ out.unshift({
48396
+ date: today,
48397
+ cacheRead: 0,
48398
+ cacheWrite: 0,
48399
+ output: 0,
48400
+ total: 0,
48401
+ requests: 0,
48402
+ cost: null,
48403
+ hasUncosted: false,
48404
+ sessions: []
48405
+ });
48406
+ }
48407
+ return out;
48408
+ }
48082
48409
  /**
48083
48410
  * The Project's lifetime cost — one unfiltered grouped scan, the same one `modelTotals` runs,
48084
48411
  * summing the costs fixed when the rows were written. Its consumer is a per-account figure
@@ -58750,6 +59077,27 @@ function usageRoutes(deps) {
58750
59077
  deps.access.requireProjectAccess(c.var.user.userId, projectId);
58751
59078
  return c.json(deps.usageService.modelTotals(projectId));
58752
59079
  });
59080
+ app.get("/session-days", (c) => {
59081
+ const projectId = requireValidId(c, "projectId");
59082
+ deps.access.requireProjectAccess(c.var.user.userId, projectId);
59083
+ const raw = c.req.query("days");
59084
+ const parsed = raw === void 0 || raw === "" ? 7 : /^\d{1,3}$/.test(raw) ? Number(raw) : NaN;
59085
+ if (!Number.isInteger(parsed) || parsed < 1 || parsed > 90) {
59086
+ throw badRequest("days must be a whole number between 1 and 90.");
59087
+ }
59088
+ const titles = /* @__PURE__ */ new Map();
59089
+ const days = deps.usageService.sessionDays(projectId, { days: parsed }).map((day) => ({
59090
+ ...day,
59091
+ sessions: day.sessions.map((row) => {
59092
+ if (!titles.has(row.sessionId)) {
59093
+ titles.set(row.sessionId, deps.sessionsRepo.findById(row.sessionId)?.title ?? void 0);
59094
+ }
59095
+ const title = titles.get(row.sessionId);
59096
+ return { ...row, ...title !== void 0 ? { title } : {} };
59097
+ })
59098
+ }));
59099
+ return c.json({ days });
59100
+ });
58753
59101
  app.get("/errors", (c) => {
58754
59102
  const projectId = requireValidId(c, "projectId");
58755
59103
  deps.access.requireProjectAccess(c.var.user.userId, projectId);
@@ -59710,6 +60058,22 @@ function agentSessionsRoutes(deps) {
59710
60058
  });
59711
60059
  return app;
59712
60060
  }
60061
+ function runningSessionsRoutes(deps) {
60062
+ const app = new Hono22();
60063
+ app.get("/", async (c) => {
60064
+ const projectId = requireValidId(c, "projectId");
60065
+ deps.access.requireProjectAccess(c.var.user.userId, projectId);
60066
+ const live = deps.manager.liveSessions().filter((e) => e.projectId === projectId).sort((a, b) => a.status === b.status ? 0 : a.status === "running" ? -1 : 1);
60067
+ const sessions2 = [];
60068
+ for (const entry of live) {
60069
+ const row = deps.sessionsRepo.findById(entry.sessionId);
60070
+ if (!row) continue;
60071
+ sessions2.push(await deps.sessionService.toInfo(row, await deps.sessionService.hasTrace(row)));
60072
+ }
60073
+ return c.json({ sessions: sessions2 });
60074
+ });
60075
+ return app;
60076
+ }
59713
60077
  function sessionsRoutes(deps) {
59714
60078
  const app = new Hono22();
59715
60079
  const resolveSession = (c) => {
@@ -60423,7 +60787,7 @@ function sessionsRoutes(deps) {
60423
60787
  });
60424
60788
  return app;
60425
60789
  }
60426
- var _sessionsRoutes_dec, _workspaceFilesRoutes_dec, _usageRoutes_dec, _sessionsBatchRoutes_dec, _agentSessionsRoutes_dec, _vaultRoutes_dec, _agentConfigRoutes_dec, _agentDeletionsRoutes_dec, _agentsRoutes_dec, _commandPolicyRoutes_dec, _chatDefaultsRoutes_dec, _modelScopeAuthRoutes_dec, _platformAuthRoutes_dec, _modelOauthRoutes_dec, _modelsRoutes_dec, _modelOauthCallbackRoutes_dec, _agentApi_dec2, _auth_dec5, _liveStreams_dec3, _usage_dec5, _errorsRepo_dec, _sources_dec4, _sessionsRepo_dec3, _settings_dec4, _previewTokens_dec, _desktop_dec2, _fileReveal_dec, _workspaceFiles_dec2, _traces_dec, _traceIndex_dec3, _modelScopeAuth_dec2, _platformAuth_dec, _modelOAuth_dec, _projectConfig_dec11, _projectEvents_dec2, _access_dec3, _schedulesRepo_dec, _messaging_dec2, _agents_dec3, _userVault_dec, _agentConfig_dec3, _sessionService_dec2, _machines_dec, _manager_dec3, _channels_dec8, _config_dec8, _SessionApiRoutes_decorators, _init110;
60790
+ var _sessionsRoutes_dec, _workspaceFilesRoutes_dec, _usageRoutes_dec, _runningSessionsRoutes_dec, _sessionsBatchRoutes_dec, _agentSessionsRoutes_dec, _vaultRoutes_dec, _agentConfigRoutes_dec, _agentDeletionsRoutes_dec, _agentsRoutes_dec, _commandPolicyRoutes_dec, _chatDefaultsRoutes_dec, _modelScopeAuthRoutes_dec, _platformAuthRoutes_dec, _modelOauthRoutes_dec, _modelsRoutes_dec, _modelOauthCallbackRoutes_dec, _agentApi_dec2, _auth_dec5, _liveStreams_dec3, _usage_dec5, _errorsRepo_dec, _sources_dec4, _sessionsRepo_dec3, _settings_dec4, _previewTokens_dec, _desktop_dec2, _fileReveal_dec, _workspaceFiles_dec2, _traces_dec, _traceIndex_dec3, _modelScopeAuth_dec2, _platformAuth_dec, _modelOAuth_dec, _projectConfig_dec11, _projectEvents_dec2, _access_dec3, _schedulesRepo_dec, _messaging_dec2, _agents_dec3, _userVault_dec, _agentConfig_dec3, _sessionService_dec2, _machines_dec, _manager_dec3, _channels_dec8, _config_dec8, _SessionApiRoutes_decorators, _init110;
60427
60791
  _SessionApiRoutes_decorators = [Component50({
60428
60792
  contributes: {
60429
60793
  "HttpModule.routes": [
@@ -60505,6 +60869,12 @@ _SessionApiRoutes_decorators = [Component50({
60505
60869
  auth: "user",
60506
60870
  order: 255
60507
60871
  },
60872
+ {
60873
+ id: "session-api.sessions-running",
60874
+ prefix: "/api/projects/:projectId/sessions/running",
60875
+ auth: "user",
60876
+ order: 256
60877
+ },
60508
60878
  {
60509
60879
  id: "session-api.usage",
60510
60880
  prefix: "/api/projects/:projectId/usage",
@@ -60525,7 +60895,7 @@ _SessionApiRoutes_decorators = [Component50({
60525
60895
  }
60526
60896
  ]
60527
60897
  }
60528
- })], _config_dec8 = [Use50()], _channels_dec8 = [Use50()], _manager_dec3 = [Use50()], _machines_dec = [Use50()], _sessionService_dec2 = [Use50()], _agentConfig_dec3 = [Use50()], _userVault_dec = [Use50()], _agents_dec3 = [Use50()], _messaging_dec2 = [Use50()], _schedulesRepo_dec = [Use50()], _access_dec3 = [Use50()], _projectEvents_dec2 = [Use50()], _projectConfig_dec11 = [Use50()], _modelOAuth_dec = [Use50()], _platformAuth_dec = [Use50()], _modelScopeAuth_dec2 = [Use50()], _traceIndex_dec3 = [Use50()], _traces_dec = [Use50()], _workspaceFiles_dec2 = [Use50()], _fileReveal_dec = [Use50()], _desktop_dec2 = [Use50()], _previewTokens_dec = [Use50()], _settings_dec4 = [Use50()], _sessionsRepo_dec3 = [Use50()], _sources_dec4 = [Use50()], _errorsRepo_dec = [Use50()], _usage_dec5 = [Use50()], _liveStreams_dec3 = [Use50()], _auth_dec5 = [Use50()], _agentApi_dec2 = [Use50()], _modelOauthCallbackRoutes_dec = [Bind11("session-api.model-oauth-callback")], _modelsRoutes_dec = [Bind11("session-api.models")], _modelOauthRoutes_dec = [Bind11("session-api.model-oauth")], _platformAuthRoutes_dec = [Bind11("session-api.platform-auth")], _modelScopeAuthRoutes_dec = [Bind11("session-api.modelscope-auth")], _chatDefaultsRoutes_dec = [Bind11("session-api.chat-defaults")], _commandPolicyRoutes_dec = [Bind11("session-api.command-policy")], _agentsRoutes_dec = [Bind11("session-api.agents")], _agentDeletionsRoutes_dec = [Bind11("session-api.agent-deletions")], _agentConfigRoutes_dec = [Bind11("session-api.agent-config")], _vaultRoutes_dec = [Bind11("session-api.vault")], _agentSessionsRoutes_dec = [Bind11("session-api.agent-sessions")], _sessionsBatchRoutes_dec = [Bind11("session-api.sessions-batch")], _usageRoutes_dec = [Bind11("session-api.usage")], _workspaceFilesRoutes_dec = [Bind11("session-api.workspace-files")], _sessionsRoutes_dec = [Bind11("session-api.sessions")];
60898
+ })], _config_dec8 = [Use50()], _channels_dec8 = [Use50()], _manager_dec3 = [Use50()], _machines_dec = [Use50()], _sessionService_dec2 = [Use50()], _agentConfig_dec3 = [Use50()], _userVault_dec = [Use50()], _agents_dec3 = [Use50()], _messaging_dec2 = [Use50()], _schedulesRepo_dec = [Use50()], _access_dec3 = [Use50()], _projectEvents_dec2 = [Use50()], _projectConfig_dec11 = [Use50()], _modelOAuth_dec = [Use50()], _platformAuth_dec = [Use50()], _modelScopeAuth_dec2 = [Use50()], _traceIndex_dec3 = [Use50()], _traces_dec = [Use50()], _workspaceFiles_dec2 = [Use50()], _fileReveal_dec = [Use50()], _desktop_dec2 = [Use50()], _previewTokens_dec = [Use50()], _settings_dec4 = [Use50()], _sessionsRepo_dec3 = [Use50()], _sources_dec4 = [Use50()], _errorsRepo_dec = [Use50()], _usage_dec5 = [Use50()], _liveStreams_dec3 = [Use50()], _auth_dec5 = [Use50()], _agentApi_dec2 = [Use50()], _modelOauthCallbackRoutes_dec = [Bind11("session-api.model-oauth-callback")], _modelsRoutes_dec = [Bind11("session-api.models")], _modelOauthRoutes_dec = [Bind11("session-api.model-oauth")], _platformAuthRoutes_dec = [Bind11("session-api.platform-auth")], _modelScopeAuthRoutes_dec = [Bind11("session-api.modelscope-auth")], _chatDefaultsRoutes_dec = [Bind11("session-api.chat-defaults")], _commandPolicyRoutes_dec = [Bind11("session-api.command-policy")], _agentsRoutes_dec = [Bind11("session-api.agents")], _agentDeletionsRoutes_dec = [Bind11("session-api.agent-deletions")], _agentConfigRoutes_dec = [Bind11("session-api.agent-config")], _vaultRoutes_dec = [Bind11("session-api.vault")], _agentSessionsRoutes_dec = [Bind11("session-api.agent-sessions")], _sessionsBatchRoutes_dec = [Bind11("session-api.sessions-batch")], _runningSessionsRoutes_dec = [Bind11("session-api.sessions-running")], _usageRoutes_dec = [Bind11("session-api.usage")], _workspaceFilesRoutes_dec = [Bind11("session-api.workspace-files")], _sessionsRoutes_dec = [Bind11("session-api.sessions")];
60529
60899
  var SessionApiRoutes = class {
60530
60900
  constructor() {
60531
60901
  __publicField(this, "config", __runInitializers(_init110, 8, this)), __runInitializers(_init110, 11, this);
@@ -60571,9 +60941,10 @@ var SessionApiRoutes = class {
60571
60941
  __publicField(this, "vaultRoutes", __runInitializers(_init110, 168, this)), __runInitializers(_init110, 171, this);
60572
60942
  __publicField(this, "agentSessionsRoutes", __runInitializers(_init110, 172, this)), __runInitializers(_init110, 175, this);
60573
60943
  __publicField(this, "sessionsBatchRoutes", __runInitializers(_init110, 176, this)), __runInitializers(_init110, 179, this);
60574
- __publicField(this, "usageRoutes", __runInitializers(_init110, 180, this)), __runInitializers(_init110, 183, this);
60575
- __publicField(this, "workspaceFilesRoutes", __runInitializers(_init110, 184, this)), __runInitializers(_init110, 187, this);
60576
- __publicField(this, "sessionsRoutes", __runInitializers(_init110, 188, this)), __runInitializers(_init110, 191, this);
60944
+ __publicField(this, "runningSessionsRoutes", __runInitializers(_init110, 180, this)), __runInitializers(_init110, 183, this);
60945
+ __publicField(this, "usageRoutes", __runInitializers(_init110, 184, this)), __runInitializers(_init110, 187, this);
60946
+ __publicField(this, "workspaceFilesRoutes", __runInitializers(_init110, 188, this)), __runInitializers(_init110, 191, this);
60947
+ __publicField(this, "sessionsRoutes", __runInitializers(_init110, 192, this)), __runInitializers(_init110, 195, this);
60577
60948
  }
60578
60949
  setup() {
60579
60950
  const manager = this.manager;
@@ -60663,7 +61034,8 @@ var SessionApiRoutes = class {
60663
61034
  });
60664
61035
  this.agentSessionsRoutes = agentSessionsRoutes(sessionsDeps);
60665
61036
  this.sessionsBatchRoutes = sessionsBatchRoutes(sessionsDeps);
60666
- this.usageRoutes = usageRoutes({ access, usageService: this.usage });
61037
+ this.runningSessionsRoutes = runningSessionsRoutes(sessionsDeps);
61038
+ this.usageRoutes = usageRoutes({ access, usageService: this.usage, sessionsRepo });
60667
61039
  this.workspaceFilesRoutes = workspaceFilesRoutes({
60668
61040
  access,
60669
61041
  workspaceFiles: this.workspaceFiles,
@@ -60717,6 +61089,7 @@ __decorateElement(_init110, 5, "agentConfigRoutes", _agentConfigRoutes_dec, Sess
60717
61089
  __decorateElement(_init110, 5, "vaultRoutes", _vaultRoutes_dec, SessionApiRoutes);
60718
61090
  __decorateElement(_init110, 5, "agentSessionsRoutes", _agentSessionsRoutes_dec, SessionApiRoutes);
60719
61091
  __decorateElement(_init110, 5, "sessionsBatchRoutes", _sessionsBatchRoutes_dec, SessionApiRoutes);
61092
+ __decorateElement(_init110, 5, "runningSessionsRoutes", _runningSessionsRoutes_dec, SessionApiRoutes);
60720
61093
  __decorateElement(_init110, 5, "usageRoutes", _usageRoutes_dec, SessionApiRoutes);
60721
61094
  __decorateElement(_init110, 5, "workspaceFilesRoutes", _workspaceFilesRoutes_dec, SessionApiRoutes);
60722
61095
  __decorateElement(_init110, 5, "sessionsRoutes", _sessionsRoutes_dec, SessionApiRoutes);
@@ -67491,7 +67864,7 @@ async function modelSemanticId(deps, complete, projectId, input, avoid) {
67491
67864
  const res = await complete(projectId, prompt);
67492
67865
  if (!res.ok) {
67493
67866
  record(res.error);
67494
- return { reason: res.cause === "no_model" ? "no_default_model" : "model_failed" };
67867
+ return { reason: res.cause === "no_model" ? "no_free_model" : "model_failed" };
67495
67868
  }
67496
67869
  const id = sanitizeSuggestedId(res.text, input.rule, avoid);
67497
67870
  if (id !== null) return { id };