pinomad 0.12.0 → 0.13.0

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.
Files changed (38) hide show
  1. package/dist/{chunk-np4jd070.js → chunk-4fferbxw.js} +97 -29
  2. package/dist/{chunk-ksfxqd8s.js → chunk-53xv3fny.js} +241 -48
  3. package/dist/{chunk-nppgxh6c.js → chunk-563fnad9.js} +1 -1
  4. package/dist/{chunk-41q0saz0.js → chunk-6th9xv39.js} +4 -4
  5. package/dist/{chunk-aqj9wfmb.js → chunk-90g1cg9n.js} +1 -1
  6. package/dist/{chunk-mnmqyq7d.js → chunk-aapsc9g0.js} +42 -48
  7. package/dist/{chunk-5qf1grkk.js → chunk-d4tq62yr.js} +46 -11
  8. package/dist/{chunk-gg2dcqbg.js → chunk-d9mq5d46.js} +22 -7
  9. package/dist/{chunk-47ff1d1t.js → chunk-kmzzjv53.js} +51 -4
  10. package/dist/{chunk-agq4tn9r.js → chunk-m51mq8vh.js} +4 -4
  11. package/dist/{chunk-vqkb70d7.js → chunk-maqv34cs.js} +2 -2
  12. package/dist/{chunk-vx7dy07y.js → chunk-ra86wjp5.js} +4 -4
  13. package/dist/{chunk-7wj0jh3t.js → chunk-s0h7c7da.js} +1 -1
  14. package/dist/{chunk-42nqtx5r.js → chunk-sd640dt7.js} +6 -6
  15. package/dist/{chunk-jeqsdcj1.js → chunk-t6fw0wa9.js} +4 -4
  16. package/dist/{chunk-t5abqsva.js → chunk-wd7aracm.js} +17 -5
  17. package/dist/pinomad.js +12 -12
  18. package/package.json +12 -11
  19. package/web/assets/{core-DnpzcQzs.js → core-BHm2gdHL.js} +1 -1
  20. package/web/assets/geist-mono-cyrillic-ext-wght-normal-X_5orZeX.woff2 +0 -0
  21. package/web/assets/geist-mono-cyrillic-wght-normal-DiZS0aHC.woff2 +0 -0
  22. package/web/assets/geist-mono-latin-ext-wght-normal-Bwz-egvJ.woff2 +0 -0
  23. package/web/assets/geist-mono-latin-wght-normal-XN7g48iV.woff2 +0 -0
  24. package/web/assets/geist-mono-symbols2-wght-normal-CO5SzqOn.woff2 +0 -0
  25. package/web/assets/geist-mono-vietnamese-wght-normal-DadHysG0.woff2 +0 -0
  26. package/web/assets/{highlighted-diff-Dn5ifsvK.js → highlighted-diff-DrHvSLK9.js} +2 -2
  27. package/web/assets/{highlights-DnHv6NBM.js → highlights-1aLwssz-.js} +1 -1
  28. package/web/assets/{highlights-themes-CUdrlZk3.js → highlights-themes-C1p4pFYS.js} +1 -1
  29. package/web/assets/index-A_AUJoO6.css +1 -0
  30. package/web/assets/index-BafYMKiN.js +396 -0
  31. package/web/assets/{shiki-BuPP5HCg.js → shiki-BwyCm3kZ.js} +2 -2
  32. package/web/assets/{shiki-langs-FJk0v0Ga.js → shiki-langs-CMlALLSg.js} +1 -1
  33. package/web/assets/{stream-tokenizer-Bl6bisIa.js → stream-tokenizer-BlgIhw0y.js} +1 -1
  34. package/web/assets/{theming-themes-BL_CC-Mm.js → theming-themes-DDvoqEqT.js} +1 -1
  35. package/web/assets/{xterm-view-ZsuzJb2C.js → xterm-view-BnKOnF3C.js} +1 -1
  36. package/web/index.html +2 -2
  37. package/web/assets/index-BV0ecolo.css +0 -1
  38. package/web/assets/index-DNsTTgPE.js +0 -396
@@ -5,7 +5,7 @@ import {
5
5
  openHostSettings,
6
6
  sameList,
7
7
  settingsDefaults
8
- } from "./chunk-nppgxh6c.js";
8
+ } from "./chunk-563fnad9.js";
9
9
  import {
10
10
  DevicesDoc,
11
11
  RevocationsDoc,
@@ -38,6 +38,7 @@ import {
38
38
  MAX_ATTACHMENT_NAME_LENGTH,
39
39
  MAX_PENDING_ATTACHMENTS,
40
40
  MAX_PENDING_ATTACHMENT_BYTES,
41
+ MAX_TRANSCRIPT_PAGE,
41
42
  PROTOCOL,
42
43
  RTC_DATA_CHANNEL_LABEL,
43
44
  RTC_DEFAULT_STUN,
@@ -56,7 +57,7 @@ import {
56
57
  rtcCandidateType,
57
58
  sdpCandidates,
58
59
  withRtcCandidates
59
- } from "./chunk-47ff1d1t.js";
60
+ } from "./chunk-kmzzjv53.js";
60
61
  import {
61
62
  ENDPOINT_SET_SCHEMA_VERSION,
62
63
  MAX_HOST_ENDPOINT_URL_LENGTH,
@@ -79,7 +80,7 @@ import {
79
80
  import {
80
81
  packagedVersion,
81
82
  webRoot
82
- } from "./chunk-7wj0jh3t.js";
83
+ } from "./chunk-s0h7c7da.js";
83
84
  import {
84
85
  __require
85
86
  } from "./chunk-df32avw6.js";
@@ -178,8 +179,10 @@ var QuestionWait = defineTask({
178
179
  resolve(initial);
179
180
  return;
180
181
  }
181
- watch.start(async (value) => {
182
- const found = resolutionOf(value, task.input.requestId);
182
+ watch.start(async (call) => {
183
+ if (call.kind !== "value")
184
+ return;
185
+ const found = resolutionOf(call.value, task.input.requestId);
183
186
  if (found !== undefined)
184
187
  resolve(found);
185
188
  });
@@ -3529,24 +3532,29 @@ async function attachPushSender(options) {
3529
3532
  }
3530
3533
  };
3531
3534
  const unsubscribeConversations = conversations.subscribe(() => update());
3532
- const unsubscribeCommits = harness.subscribeCommits((publication) => {
3533
- for (const change of publication.changes) {
3534
- if (change.type !== "document" || change.record.kind !== TitleDoc.definition.kind)
3535
- continue;
3536
- const id = change.conversationId;
3537
- if (id === undefined)
3538
- continue;
3539
- const title = change.value?.title;
3540
- if (typeof title !== "string" || title === "")
3541
- continue;
3542
- const waiters = titleWaiters.get(id);
3543
- titleWaiters.delete(id);
3544
- for (const settle of waiters ?? [])
3545
- settle(title);
3546
- }
3535
+ const commits = harness.observeCommits({
3536
+ advance: (publication) => {
3537
+ for (const change of publication.changes) {
3538
+ if (change.type !== "document" || change.kind !== "change" || change.record.kind !== TitleDoc.definition.kind)
3539
+ continue;
3540
+ const id = change.conversationId;
3541
+ if (id === undefined)
3542
+ continue;
3543
+ const title = change.value.title;
3544
+ if (typeof title !== "string" || title === "")
3545
+ continue;
3546
+ const waiters = titleWaiters.get(id);
3547
+ titleWaiters.delete(id);
3548
+ for (const settle of waiters ?? [])
3549
+ settle(title);
3550
+ }
3551
+ },
3552
+ end: () => {}
3547
3553
  });
3548
- indexWatch?.start(async (value) => {
3549
- index = value ?? undefined;
3554
+ indexWatch?.start(async (call) => {
3555
+ if (call.kind !== "value")
3556
+ return;
3557
+ index = call.value;
3550
3558
  update();
3551
3559
  });
3552
3560
  update();
@@ -3555,7 +3563,7 @@ async function attachPushSender(options) {
3555
3563
  async close() {
3556
3564
  disposed = true;
3557
3565
  unsubscribeConversations();
3558
- unsubscribeCommits();
3566
+ commits.detach();
3559
3567
  await indexWatch?.stop();
3560
3568
  for (const item of pending)
3561
3569
  drop(item);
@@ -4271,12 +4279,16 @@ class ConversationList {
4271
4279
  #list = [];
4272
4280
  #unsubscribe = () => {};
4273
4281
  #notifying = false;
4282
+ #harness;
4283
+ #live = new Map;
4284
+ #disposed = false;
4274
4285
  constructor(docs) {
4275
4286
  this.#questionTokens = (docs ?? []).filter((doc) => doc.presentation === "pinomad.question").map((doc) => doc.token);
4276
4287
  this.#questionKinds = new Set(this.#questionTokens.map((token) => token.definition.kind));
4277
4288
  }
4278
4289
  static async open(harness, docs) {
4279
4290
  const list = new ConversationList(docs);
4291
+ list.#harness = harness;
4280
4292
  const summaries = [];
4281
4293
  let cursor;
4282
4294
  const records = [];
@@ -4295,10 +4307,13 @@ class ConversationList {
4295
4307
  summaries.push(list.#summaryOf(record));
4296
4308
  }
4297
4309
  list.#list = summaries;
4298
- list.#unsubscribe = harness.subscribeCommits((publication) => list.#observe(publication));
4310
+ const observation = harness.observeCommits({ advance: (publication) => list.#observe(publication), end: () => {} });
4311
+ list.#unsubscribe = () => observation.detach();
4299
4312
  const touched = new Set;
4300
4313
  list.#reindex(await harness.snapshot(IndexDoc, context3), touched);
4301
4314
  list.#refreshSummaries(touched);
4315
+ for (const [id, facts] of list.#facts)
4316
+ list.#followLive(id, facts.running === true);
4302
4317
  return list;
4303
4318
  }
4304
4319
  async#load(harness, record) {
@@ -4354,22 +4369,23 @@ class ConversationList {
4354
4369
  facts.calls = entry.kind === "pi.assistant" ? callsOf(message) : undefined;
4355
4370
  } else if (change.type === "document") {
4356
4371
  const id = change.conversationId;
4372
+ const value = change.kind === "change" ? change.value : null;
4357
4373
  if (id === undefined) {
4358
4374
  if (change.record.kind === IndexDoc.definition.kind)
4359
- this.#reindex(change.value, touched);
4375
+ this.#reindex(value, touched);
4360
4376
  continue;
4361
4377
  }
4362
4378
  const facts = this.#fact(id);
4363
4379
  if (change.record.kind === "pi.live") {
4364
- const live = change.value;
4380
+ const live = value;
4365
4381
  const wasRunning = facts.running === true;
4366
4382
  facts.running = live?.run !== undefined;
4367
4383
  facts.tools = live?.tools;
4368
4384
  touched.add(id);
4385
+ this.#followLive(id, facts.running);
4369
4386
  if (wasRunning && !facts.running && this.#records.get(id)?.owner === undefined)
4370
4387
  ended.add(id);
4371
4388
  } else if (this.#questionKinds.has(change.record.kind)) {
4372
- const value = change.value;
4373
4389
  const pending = Value2.Check(QuestionSchema, value) && value.requests.some((request) => request.resolution === undefined);
4374
4390
  const next = new Set(facts.pending);
4375
4391
  if (pending)
@@ -4379,16 +4395,16 @@ class ConversationList {
4379
4395
  facts.pending = next;
4380
4396
  touched.add(id);
4381
4397
  } else if (change.record.kind === RoleDoc.definition.kind) {
4382
- facts.agent = roleNameOf(change.value);
4398
+ facts.agent = roleNameOf(value);
4383
4399
  touched.add(id);
4384
4400
  } else if (change.record.kind === SubagentDoc.definition.kind) {
4385
- const value = change.value;
4386
- facts.label = typeof value?.label === "string" && value.label !== "" ? value.label : undefined;
4387
- facts.role = typeof value?.role === "string" && value.role !== "" ? value.role : undefined;
4388
- facts.model = modelRefOf(value?.model);
4401
+ const subagent = value;
4402
+ facts.label = typeof subagent?.label === "string" && subagent.label !== "" ? subagent.label : undefined;
4403
+ facts.role = typeof subagent?.role === "string" && subagent.role !== "" ? subagent.role : undefined;
4404
+ facts.model = modelRefOf(subagent?.model);
4389
4405
  touched.add(id);
4390
4406
  } else if (change.record.kind === TitleDoc.definition.kind) {
4391
- const named = change.value?.title;
4407
+ const named = value?.title;
4392
4408
  facts.named = typeof named === "string" && named !== "" ? named : undefined;
4393
4409
  touched.add(id);
4394
4410
  }
@@ -4463,9 +4479,51 @@ class ConversationList {
4463
4479
  listener(this.#list);
4464
4480
  });
4465
4481
  }
4482
+ #followLive(id, running) {
4483
+ if (!running || this.#disposed) {
4484
+ const watch = this.#live.get(id);
4485
+ this.#live.delete(id);
4486
+ watch?.stop();
4487
+ return;
4488
+ }
4489
+ if (this.#live.has(id))
4490
+ return;
4491
+ this.#live.set(id, undefined);
4492
+ setImmediate(() => {
4493
+ this.#harness.watchDoc(LiveDoc, id, context3).then(async (watch) => {
4494
+ if (watch === undefined)
4495
+ return;
4496
+ if (this.#live.get(id) !== undefined || !this.#live.has(id)) {
4497
+ await watch.stop();
4498
+ return;
4499
+ }
4500
+ this.#live.set(id, watch);
4501
+ const apply = (live) => {
4502
+ const facts = this.#fact(id);
4503
+ if (live.run === undefined)
4504
+ return;
4505
+ facts.tools = live.tools;
4506
+ this.#refreshSummaries(new Set([id]));
4507
+ };
4508
+ apply(watch.value);
4509
+ watch.start(async (call) => {
4510
+ if (call.kind === "value")
4511
+ apply(call.value);
4512
+ });
4513
+ }, (error) => {
4514
+ if (this.#live.get(id) === undefined)
4515
+ this.#live.delete(id);
4516
+ console.error(`conversation ${id}: could not follow pi.live: ${error instanceof Error ? error.message : String(error)}`);
4517
+ });
4518
+ });
4519
+ }
4466
4520
  dispose() {
4521
+ this.#disposed = true;
4467
4522
  this.#unsubscribe();
4468
4523
  this.#listeners.clear();
4524
+ for (const watch of this.#live.values())
4525
+ watch?.stop();
4526
+ this.#live.clear();
4469
4527
  }
4470
4528
  }
4471
4529
  function roleNameOf(value) {
@@ -4534,6 +4592,38 @@ function titleOf(entry) {
4534
4592
  const title = stripUserBlocks(message.content).text.replace(/\s+/g, " ").trim();
4535
4593
  return title === "" ? {} : { title };
4536
4594
  }
4595
+ var WHOLE_TRANSCRIPT = { min: Number.MAX_SAFE_INTEGER, max: Number.MAX_SAFE_INTEGER };
4596
+ var TURN_STARTS = new Set(["pi.user", "pi.compaction", "pi.reset"]);
4597
+ async function turnPage(conversation, before, limit) {
4598
+ const want = Math.min(limit, MAX_TRANSCRIPT_PAGE);
4599
+ const done = (taken2) => taken2.length >= MAX_TRANSCRIPT_PAGE || taken2.length >= want && TURN_STARTS.has(taken2.at(-1).kind);
4600
+ const query = { order: "descending", ...before === undefined ? {} : { maxEntryId: before } };
4601
+ const taken = [];
4602
+ let cursor;
4603
+ for (;; ) {
4604
+ const page = await conversation.entries(query, Math.max(want + 1 - taken.length, 64), cursor, context3);
4605
+ for (const entry of page.items) {
4606
+ if (done(taken))
4607
+ return { entries: taken.reverse(), before: entry.id };
4608
+ taken.push(entry);
4609
+ }
4610
+ if (page.next === undefined)
4611
+ return { entries: taken.reverse() };
4612
+ cursor = page.next;
4613
+ }
4614
+ }
4615
+ async function viewWindow(conversation, window) {
4616
+ if (window === undefined)
4617
+ return WHOLE_TRANSCRIPT;
4618
+ const from = window.from ?? await startOf(conversation, window.limit);
4619
+ return from === undefined ? WHOLE_TRANSCRIPT : { ...WHOLE_TRANSCRIPT, from };
4620
+ }
4621
+ async function startOf(conversation, limit) {
4622
+ const page = await turnPage(conversation, undefined, limit);
4623
+ return page.before === undefined ? undefined : page.entries[0].id;
4624
+ }
4625
+ var shownOps = (call) => isGone(call) ? [["r", null]] : call.ops;
4626
+ var isGone = (call) => call.retired && !call.ops.some((op) => op[0] === "r");
4537
4627
  async function historyFacts(harness, id) {
4538
4628
  const conversation = await harness.conversation(id, context3);
4539
4629
  let first;
@@ -4745,15 +4835,19 @@ class GatewayClient {
4745
4835
  }
4746
4836
  async#receive(frame) {
4747
4837
  if (frame.type === "subscribe")
4748
- await this.#subscribe(frame.stream, frame.images === "ref", frame.since);
4838
+ await this.#subscribe(frame.stream, frame.images === "ref", frame.since, frame.window);
4749
4839
  else if (frame.type === "unsubscribe")
4750
4840
  await this.#unsubscribe(frame.stream);
4751
4841
  else
4752
4842
  await this.#answer(frame.id, frame.method, frame.args);
4753
4843
  }
4754
- async#subscribe(stream, imageRefs, since) {
4844
+ async#subscribe(stream, imageRefs, since, window) {
4755
4845
  const previous = this.#subscriptions.get(stream);
4756
- const state = imageRefs && stream.startsWith("conversation:") ? { images: new ImageRefs } : since === undefined ? {} : { since };
4846
+ const state = {
4847
+ ...imageRefs && stream.startsWith("conversation:") ? { images: new ImageRefs } : {},
4848
+ ...since === undefined ? {} : { since },
4849
+ ...window === undefined ? {} : { window }
4850
+ };
4757
4851
  this.#subscriptions.set(stream, state);
4758
4852
  const current = () => !this.#disposed && this.#subscriptions.get(stream) === state;
4759
4853
  const send = (frame) => current() ? this.send(frame) : Promise.resolve();
@@ -4820,7 +4914,7 @@ class GatewayClient {
4820
4914
  return this.#openDoc(stream, stream.slice("doc:".length, at), Number(stream.slice(at + 1)), send);
4821
4915
  }
4822
4916
  const conversation = await this.#conversation(Number(stream.slice("conversation:".length)));
4823
- return this.#forward(stream, await conversation.watch(context3), send, state);
4917
+ return this.#forward(stream, await conversation.watch(context3, await viewWindow(conversation, state?.window)), send, state);
4824
4918
  }
4825
4919
  #hostValue(stream) {
4826
4920
  return Object.hasOwn(this.#hostValues, stream) ? this.#hostValues[stream] : undefined;
@@ -4838,13 +4932,17 @@ class GatewayClient {
4838
4932
  });
4839
4933
  let inner;
4840
4934
  let stopped = false;
4841
- const unsubscribe = harness.subscribeCommits((publication) => {
4842
- const matches = publication.changes.some((change) => (change.type === "document" || change.type === "document.copy") && change.record.kind === kind && change.conversationId === id);
4843
- if (!matches)
4844
- return;
4845
- unsubscribe();
4846
- setImmediate(() => signalCreation());
4935
+ const observation = harness.observeCommits({
4936
+ advance: (publication) => {
4937
+ const matches = publication.changes.some((change) => (change.type === "document" || change.type === "document.copy") && change.record.kind === kind && change.conversationId === id);
4938
+ if (!matches)
4939
+ return;
4940
+ unsubscribe();
4941
+ setImmediate(() => signalCreation());
4942
+ },
4943
+ end: () => {}
4847
4944
  });
4945
+ const unsubscribe = () => observation.detach();
4848
4946
  try {
4849
4947
  const existing = await harness.watchDoc(token, id, context3);
4850
4948
  if (existing !== undefined) {
@@ -4885,16 +4983,19 @@ class GatewayClient {
4885
4983
  async#forward(stream, watch, send, state) {
4886
4984
  if (state?.images === undefined) {
4887
4985
  await send({ type: "snapshot", stream, value: watch.value });
4888
- watch.start((_value, ops) => send({ type: "ops", stream, ops }));
4986
+ watch.start((call) => call.kind === "value" ? send({ type: "ops", stream, ops: shownOps(call) }) : Promise.resolve());
4889
4987
  return watch;
4890
4988
  }
4891
4989
  const images = state.images;
4892
4990
  let before = watch.value;
4893
4991
  state.view = before;
4894
4992
  await send({ type: "snapshot", stream, value: await images.value(before) });
4895
- watch.start(async (value, ops) => {
4993
+ watch.start(async (call) => {
4994
+ if (call.kind !== "value")
4995
+ return;
4996
+ const ops = shownOps(call);
4896
4997
  const sent = await images.ops(ops, before);
4897
- before = value;
4998
+ before = isGone(call) ? null : call.value;
4898
4999
  state.view = before;
4899
5000
  return send({ type: "ops", stream, ops: sent });
4900
5001
  });
@@ -4904,7 +5005,7 @@ class GatewayClient {
4904
5005
  for (const state of this.#subscriptions.values()) {
4905
5006
  if (state.images === undefined || state.view === undefined)
4906
5007
  continue;
4907
- const image = state.images.image(state.view, ref);
5008
+ const image = state.images.image(state.view, ref) ?? (state.earlier === undefined ? undefined : state.images.image({ entries: state.earlier }, ref));
4908
5009
  if (image !== undefined)
4909
5010
  return image;
4910
5011
  }
@@ -5168,6 +5269,26 @@ class GatewayClient {
5168
5269
  const input = args;
5169
5270
  return listSkills(this.#options.harness, this.#skills, input.scope, context3);
5170
5271
  }
5272
+ case "earlierEntries": {
5273
+ const { conversationId, before, limit } = args;
5274
+ const stream = `conversation:${conversationId}`;
5275
+ const state = this.#subscriptions.get(stream);
5276
+ if (state === undefined)
5277
+ throw new Error(`Not subscribed to conversation ${conversationId}`);
5278
+ const replaced = () => this.#subscriptions.get(stream) !== state;
5279
+ const resubscribed = () => new Error(`Conversation ${conversationId} was resubscribed while its page loaded`);
5280
+ const page = await turnPage(await this.#conversation(conversationId), before, limit);
5281
+ if (replaced())
5282
+ throw resubscribed();
5283
+ if (state.images === undefined)
5284
+ return page;
5285
+ const raw = page.entries;
5286
+ const { entries } = await state.images.value({ entries: raw });
5287
+ if (replaced())
5288
+ throw resubscribed();
5289
+ state.earlier = [...state.earlier ?? [], ...raw];
5290
+ return { ...page, entries };
5291
+ }
5171
5292
  case "image": {
5172
5293
  const input = args;
5173
5294
  const image = this.#shownImage(input.ref);
@@ -5229,6 +5350,37 @@ class GatewayClient {
5229
5350
  return { outcome: "steered" };
5230
5351
  }, context3);
5231
5352
  }
5353
+ case "reorderQueued": {
5354
+ const { conversationId, submissionId, before } = args;
5355
+ return await this.#options.harness.commit(async (tx) => {
5356
+ const queuedState = async (id) => {
5357
+ const record = await tx.submission(id);
5358
+ if (record === undefined)
5359
+ throw new Error(`Submission ${id} does not exist`);
5360
+ assertQueuedInput(record, conversationId);
5361
+ if (record.entry !== undefined)
5362
+ return "sent";
5363
+ return record.status === "queued" ? "queued" : "unavailable";
5364
+ };
5365
+ const moved = await queuedState(submissionId);
5366
+ if (moved !== "queued")
5367
+ return { outcome: moved };
5368
+ if (before !== undefined && await queuedState(before) !== "queued") {
5369
+ return { outcome: "unavailable" };
5370
+ }
5371
+ if (before === submissionId)
5372
+ return { outcome: "moved" };
5373
+ const items = (await tx.doc(InboxDoc, conversationId)).items;
5374
+ const from = items.findIndex((candidate) => candidate.id === submissionId);
5375
+ if (from < 0 || before !== undefined && !items.some((candidate) => candidate.id === before)) {
5376
+ return { outcome: "unavailable" };
5377
+ }
5378
+ const [item] = items.splice(from, 1);
5379
+ const to = before === undefined ? items.findLastIndex((candidate) => candidate.mode !== "write") + 1 : items.findIndex((candidate) => candidate.id === before);
5380
+ items.splice(to, 0, item);
5381
+ return { outcome: "moved" };
5382
+ }, context3);
5383
+ }
5232
5384
  case "renameConversation": {
5233
5385
  const { title } = args;
5234
5386
  const trimmed = title.trim();
@@ -6887,6 +7039,45 @@ async function openModelAuth(runtime, options) {
6887
7039
  tail = next.catch(() => {});
6888
7040
  return next;
6889
7041
  };
7042
+ const opened = await readModelsFile(options.modelsPath);
7043
+ Promise.all([...custom].flatMap(([id, endpoint]) => {
7044
+ const entries = opened.providers[id]?.models;
7045
+ if (!Array.isArray(entries) || !entries.some(lacksLimits))
7046
+ return [];
7047
+ return [
7048
+ (async () => {
7049
+ const key = (await runtime.getAuth(id))?.auth.apiKey;
7050
+ const listed = await fetchEndpointModels(endpoint.api, endpoint.baseUrl, key).catch(() => []);
7051
+ return { id, endpoint, listed: new Map(listed.map((model) => [model.id, model])) };
7052
+ })()
7053
+ ];
7054
+ })).then((answers) => serial(async () => {
7055
+ if (closed)
7056
+ return;
7057
+ const filled = new Set;
7058
+ const fill = (target) => {
7059
+ for (const { id, endpoint, listed } of answers) {
7060
+ const entry = target.providers[id];
7061
+ if (entry?.api !== endpoint.api || entry.baseUrl !== endpoint.baseUrl || !Array.isArray(entry.models))
7062
+ continue;
7063
+ for (const model of entry.models) {
7064
+ const limits = listed.get(model.id);
7065
+ for (const field of LIMITS) {
7066
+ if (field in model || limits?.[field] === undefined)
7067
+ continue;
7068
+ model[field] = limits[field];
7069
+ filled.add(id);
7070
+ }
7071
+ }
7072
+ }
7073
+ };
7074
+ fill(await readModelsFile(options.modelsPath));
7075
+ if (filled.size === 0)
7076
+ return;
7077
+ await updateModelsFile(fill);
7078
+ await runtime.refresh({ providers: [...filled], allowNetwork: false });
7079
+ await republish();
7080
+ }));
6890
7081
  return {
6891
7082
  models,
6892
7083
  auth,
@@ -7092,6 +7283,8 @@ async function fetchEndpointModels(api, baseUrl, key) {
7092
7283
  throw new Error(`${url.host} listed no models`);
7093
7284
  return models;
7094
7285
  }
7286
+ var LIMITS = ["contextWindow", "maxTokens"];
7287
+ var lacksLimits = (model) => typeof model === "object" && model !== null && LIMITS.some((field) => !(field in model));
7095
7288
  var positive = (value) => typeof value === "number" && Number.isFinite(value) && value > 0 ? value : undefined;
7096
7289
  function endpointModel(id, reported) {
7097
7290
  return {
@@ -7252,7 +7445,7 @@ async function main(argv) {
7252
7445
  process.on("SIGINT", stop);
7253
7446
  process.on("SIGTERM", stop);
7254
7447
  host.closed.then((end) => {
7255
- if (end.reason !== "failed" || stopping)
7448
+ if (end.kind !== "failed" || stopping)
7256
7449
  return;
7257
7450
  stopping = true;
7258
7451
  stopLogRotation();
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  RTC_DEFAULT_STUN
3
- } from "./chunk-47ff1d1t.js";
3
+ } from "./chunk-kmzzjv53.js";
4
4
  import {
5
5
  HOST_SETTING_KEYS,
6
6
  cleanHostName,
@@ -8,17 +8,17 @@ import {
8
8
  reachabilityLine,
9
9
  serviceManager,
10
10
  versionLine
11
- } from "./chunk-t5abqsva.js";
12
- import"./chunk-np4jd070.js";
11
+ } from "./chunk-wd7aracm.js";
12
+ import"./chunk-4fferbxw.js";
13
13
  import"./chunk-kzbzacz9.js";
14
- import"./chunk-47ff1d1t.js";
14
+ import"./chunk-kmzzjv53.js";
15
15
  import"./chunk-pqe7q1s7.js";
16
16
  import {
17
17
  DEFAULT_DATA_DIR
18
18
  } from "./chunk-ngf1zatm.js";
19
19
  import {
20
20
  commandHint
21
- } from "./chunk-7wj0jh3t.js";
21
+ } from "./chunk-s0h7c7da.js";
22
22
  import"./chunk-df32avw6.js";
23
23
 
24
24
  // apps/host/src/cli/status.ts
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-ngf1zatm.js";
4
4
  import {
5
5
  packagedVersion
6
- } from "./chunk-7wj0jh3t.js";
6
+ } from "./chunk-s0h7c7da.js";
7
7
  import"./chunk-df32avw6.js";
8
8
 
9
9
  // apps/host/src/cli/web-link.ts