agl 40.5.1 → 41.0.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 (137) hide show
  1. package/changelog.md +43 -0
  2. package/dist_serve/bundle.js +3514 -3357
  3. package/dist_serve/bundle.js.map +2 -2
  4. package/dist_serve/bundle.js.third-party-notices.json +58 -32
  5. package/dist_serve/bundle.js.third-party-notices.txt +108 -33
  6. package/dist_ts/00_commitinfo_data.js +1 -1
  7. package/dist_ts/aglapi/aglapisurface.document.js +64 -37
  8. package/dist_ts/classes.aglhome.d.ts +5 -0
  9. package/dist_ts/classes.aglhome.js +2 -1
  10. package/dist_ts/classes.authstore.js +5 -1
  11. package/dist_ts/classes.controller.d.ts +8 -0
  12. package/dist_ts/classes.controller.js +119 -22
  13. package/dist_ts/classes.controllereventdelivery.d.ts +72 -0
  14. package/dist_ts/classes.controllereventdelivery.js +233 -0
  15. package/dist_ts/classes.flexmodels.public.js +4 -1
  16. package/dist_ts/classes.flexprojectionreader.d.ts +6 -0
  17. package/dist_ts/classes.flexprojectionreader.js +29 -5
  18. package/dist_ts/classes.flexservice.d.ts +2 -1
  19. package/dist_ts/classes.flexservice.js +34 -6
  20. package/dist_ts/classes.flexstore.d.ts +41 -4
  21. package/dist_ts/classes.flexstore.js +266 -203
  22. package/dist_ts/classes.inferencegateway.d.ts +35 -1
  23. package/dist_ts/classes.inferencegateway.js +86 -26
  24. package/dist_ts/classes.inferenceservice.d.ts +4 -2
  25. package/dist_ts/classes.inferenceservice.js +5 -4
  26. package/dist_ts/classes.proxycontrol.d.ts +58 -4
  27. package/dist_ts/classes.proxycontrol.js +23 -44
  28. package/dist_ts/classes.proxycontrolclient.d.ts +15 -5
  29. package/dist_ts/classes.proxycontrolclient.js +67 -17
  30. package/dist_ts/classes.proxydaemon.d.ts +22 -3
  31. package/dist_ts/classes.proxydaemon.js +73 -12
  32. package/dist_ts/classes.proxyleaseholder.d.ts +43 -14
  33. package/dist_ts/classes.proxyleaseholder.js +66 -22
  34. package/dist_ts/classes.proxystore.d.ts +9 -0
  35. package/dist_ts/classes.proxystore.js +15 -7
  36. package/dist_ts/classes.ticketnotifier.js +4 -2
  37. package/dist_ts/classes.ticketstore.d.ts +50 -2
  38. package/dist_ts/classes.ticketstore.js +195 -78
  39. package/dist_ts/classes.workercallerbindings.d.ts +66 -0
  40. package/dist_ts/classes.workercallerbindings.js +211 -0
  41. package/dist_ts/classes.workercallers.d.ts +63 -2
  42. package/dist_ts/classes.workercallers.js +430 -65
  43. package/dist_ts/driver/classes.drivereventrelay.d.ts +13 -1
  44. package/dist_ts/driver/classes.drivereventrelay.js +99 -6
  45. package/dist_ts/driver/functions.driverinstructions.d.ts +1 -1
  46. package/dist_ts/driver/functions.driverinstructions.js +1 -1
  47. package/dist_ts/driver/functions.drivertools.d.ts +11 -2
  48. package/dist_ts/driver/functions.drivertools.js +19 -9
  49. package/dist_ts/fleet/classes.boardpump.d.ts +8 -2
  50. package/dist_ts/fleet/classes.boardpump.js +38 -20
  51. package/dist_ts/fleet/classes.ticketeffects.d.ts +17 -2
  52. package/dist_ts/fleet/classes.ticketeffects.js +16 -10
  53. package/dist_ts/fleet/classes.workerlaunches.d.ts +12 -5
  54. package/dist_ts/fleet/classes.workerlaunches.js +25 -19
  55. package/dist_ts/fleet/classes.workers.d.ts +21 -0
  56. package/dist_ts/fleet/classes.workers.js +110 -17
  57. package/dist_ts/fleet/functions.workervalidation.js +2 -2
  58. package/dist_ts/functions.flexprivatesnapshot.d.ts +102 -0
  59. package/dist_ts/functions.flexprivatesnapshot.js +461 -0
  60. package/dist_ts/functions.inferencecli.d.ts +3 -2
  61. package/dist_ts/functions.inferencecli.js +67 -5
  62. package/dist_ts/functions.inferencecliarguments.d.ts +6 -2
  63. package/dist_ts/functions.inferencecliarguments.js +29 -2
  64. package/dist_ts/functions.inferencelaunch.d.ts +24 -0
  65. package/dist_ts/functions.inferencelaunch.js +42 -2
  66. package/dist_ts/functions.mcptickettools.d.ts +3 -0
  67. package/dist_ts/functions.mcptickettools.js +2 -2
  68. package/dist_ts/functions.proxycontract.d.ts +11 -0
  69. package/dist_ts/functions.proxycontract.js +12 -1
  70. package/dist_ts/functions.proxysocket.d.ts +6 -0
  71. package/dist_ts/functions.proxysocket.js +46 -0
  72. package/dist_ts/functions.ticketcli.d.ts +1 -1
  73. package/dist_ts/functions.ticketcli.js +8 -4
  74. package/dist_ts/functions.ticketvalidation.d.ts +3 -0
  75. package/dist_ts/functions.ticketvalidation.js +7 -4
  76. package/dist_ts/functions.workerprocessproof.d.ts +6 -0
  77. package/dist_ts/functions.workerprocessproof.js +28 -4
  78. package/dist_ts/interfaces.flexipc.d.ts +21 -2
  79. package/dist_ts/interfaces.flexipc.js +33 -16
  80. package/dist_ts_interfaces/fleetworkers.d.ts +6 -0
  81. package/dist_ts_interfaces/interfaces.d.ts +1 -1
  82. package/dist_ts_interfaces/interfaces.js +1 -1
  83. package/dist_ts_interfaces/requests.tickets.d.ts +8 -12
  84. package/dist_ts_interfaces/tickets.d.ts +37 -9
  85. package/dist_ts_interfaces/tickets.js +7 -1
  86. package/dist_ts_interfaces/workercallers.d.ts +43 -4
  87. package/package.json +7 -7
  88. package/readme.md +156 -23
  89. package/ts/00_commitinfo_data.ts +1 -1
  90. package/ts/aglapi/aglapisurface.document.ts +63 -36
  91. package/ts/classes.aglhome.ts +6 -0
  92. package/ts/classes.authstore.ts +4 -0
  93. package/ts/classes.controller.ts +141 -32
  94. package/ts/classes.controllereventdelivery.ts +289 -0
  95. package/ts/classes.flexmodels.public.ts +10 -0
  96. package/ts/classes.flexprojectionreader.ts +30 -3
  97. package/ts/classes.flexservice.ts +33 -5
  98. package/ts/classes.flexstore.ts +381 -246
  99. package/ts/classes.inferencegateway.ts +104 -23
  100. package/ts/classes.inferenceservice.ts +6 -3
  101. package/ts/classes.proxycontrol.ts +76 -39
  102. package/ts/classes.proxycontrolclient.ts +72 -20
  103. package/ts/classes.proxydaemon.ts +85 -15
  104. package/ts/classes.proxyleaseholder.ts +84 -28
  105. package/ts/classes.proxystore.ts +16 -5
  106. package/ts/classes.ticketnotifier.ts +3 -1
  107. package/ts/classes.ticketstore.ts +201 -75
  108. package/ts/classes.workercallerbindings.ts +147 -0
  109. package/ts/classes.workercallers.ts +410 -59
  110. package/ts/driver/classes.drivereventrelay.ts +89 -4
  111. package/ts/driver/functions.driverinstructions.ts +1 -1
  112. package/ts/driver/functions.drivertools.ts +22 -8
  113. package/ts/fleet/classes.boardpump.ts +51 -19
  114. package/ts/fleet/classes.ticketeffects.ts +25 -11
  115. package/ts/fleet/classes.workerlaunches.ts +23 -15
  116. package/ts/fleet/classes.workers.ts +79 -17
  117. package/ts/fleet/functions.workervalidation.ts +1 -1
  118. package/ts/functions.flexprivatesnapshot.ts +601 -0
  119. package/ts/functions.inferencecli.ts +61 -7
  120. package/ts/functions.inferencecliarguments.ts +32 -1
  121. package/ts/functions.inferencelaunch.ts +49 -2
  122. package/ts/functions.mcptickettools.ts +1 -1
  123. package/ts/functions.proxycontract.ts +12 -0
  124. package/ts/functions.proxysocket.ts +39 -0
  125. package/ts/functions.ticketcli.ts +7 -3
  126. package/ts/functions.ticketvalidation.ts +7 -3
  127. package/ts/functions.workerprocessproof.ts +27 -4
  128. package/ts/interfaces.flexipc.ts +50 -21
  129. package/ts_interfaces/fleetworkers.ts +6 -0
  130. package/ts_interfaces/interfaces.ts +1 -1
  131. package/ts_interfaces/requests.tickets.ts +9 -6
  132. package/ts_interfaces/tickets.ts +32 -1
  133. package/ts_interfaces/workercallers.ts +32 -4
  134. package/ts_web/00_commitinfo_data.ts +1 -1
  135. package/ts_web/elements.harnesscontrollerapp.ts +19 -8
  136. package/ts_web/elements.ticketboard.ts +16 -4
  137. package/ts_web/settings.general.ts +10 -4
@@ -1,7 +1,7 @@
1
1
  import type * as plugins from './plugins.js';
2
2
  import type {
3
- ITicket, ITicketActivity, ITicketAnswer, ITicketAsk, ITicketBoard, ITicketChanges, ITicketComment, ITicketCreate,
4
- ITicketFilters, ITicketMove, ITicketQuestion, TTicketLink, TTicketOperation, TTicketReferenceContent, TTicketRequest,
3
+ ITicket, ITicketAnswer, ITicketAsk, ITicketBoard, ITicketChanges, ITicketComment, ITicketCreate,
4
+ ITicketDetail, ITicketFilters, ITicketGet, ITicketMove, ITicketQuestion, TTicketLink, TTicketOperation, TTicketReferenceContent, TTicketRequest,
5
5
  TTicketResponse,
6
6
  } from './tickets.js';
7
7
 
@@ -61,15 +61,18 @@ export interface IReq_ControllerMcpTicketSearch extends plugins.typedrequestInte
61
61
  response: { tickets: ITicket[] };
62
62
  }
63
63
  /**
64
- * Reads a ticket by its `AGL-<n>` key, with its Markdown comments, source, links, questions and
65
- * their answers, and its complete activity log.
64
+ * Reads a ticket by its `AGL-<n>` key with its source, links, all its questions and their answers,
65
+ * and the newest page of its history (up to `limit` entries, default 50, at most 500, within 256 KiB), oldest first: the
66
+ * activity entries and the Markdown comments they name, a `commented` entry naming its comment by
67
+ * id. `historyBefore` is present while older history exists; pass it as `before` for the next page.
68
+ * `commentId` reads that one comment instead (`comments: [it]`, `activity: []`), without `before` or `limit`.
66
69
  */
67
70
  export interface IReq_ControllerMcpTicketGet extends plugins.typedrequestInterfaces.implementsTR<
68
71
  TControllerMcpTicketRequest<'get'>, IReq_ControllerMcpTicketGet
69
72
  > {
70
73
  method: 'agl.mcp.ticket.get';
71
- request: { ticketId: string } & { ownerToken?: string };
72
- response: { ticket: ITicket; comments: ITicketComment[]; activity: ITicketActivity[]; questions: ITicketQuestion[] };
74
+ request: ITicketGet & { ownerToken?: string };
75
+ response: ITicketDetail;
73
76
  }
74
77
  /** Reads a ticket's comments. */
75
78
  export interface IReq_ControllerMcpTicketComments extends plugins.typedrequestInterfaces.implementsTR<
@@ -200,6 +200,36 @@ export interface ITicketCreate {
200
200
  attachments?: ITicketAttachment[];
201
201
  }
202
202
  export interface ITicketMove { ticketId: string; columnId: TTicketColumn; beforeTicketId?: string; }
203
+ /**
204
+ * How many history entries one `get` returns unless it names `limit`, the most it may name, and the bytes a page holds
205
+ * at most (its entries plus the comments they name, serialized; a page holds at least one entry). The budget wins over `limit`.
206
+ */
207
+ export const ticketHistoryPage = { default: 50, maximum: 500, bytes: 256 * 1024 } as const;
208
+ /** A ticket and one page of its history: the newest entries, or those older than the entry `before` names, within `ticketHistoryPage`. */
209
+ export interface ITicketGet {
210
+ ticketId: string;
211
+ /** An activity id, as `historyBefore` returned it: the page holds only older entries. */
212
+ before?: string;
213
+ /** Entries on the page, 1 to 500 (`ticketHistoryPage.maximum`); 50 (`ticketHistoryPage.default`) when absent. */
214
+ limit?: number;
215
+ /**
216
+ * One comment of this ticket, by the id an activity entry or a fleet event names: the response holds the ticket, its
217
+ * questions and that comment alone (`comments: [it]`, `activity: []`, no `historyBefore`). Excludes `before` and `limit`.
218
+ */
219
+ commentId?: string;
220
+ }
221
+ /**
222
+ * A ticket, all its questions and one page of its history, oldest first. `activity` is the page; `comments` are the
223
+ * comments its `commented` entries name, whose `changes.comment` holds only `{ after: { id } }` here (the stored
224
+ * entry keeps the whole comment). `historyBefore` is present while older entries exist: pass it as `before`.
225
+ */
226
+ export interface ITicketDetail {
227
+ ticket: ITicket;
228
+ comments: ITicketComment[];
229
+ activity: ITicketActivity[];
230
+ questions: ITicketQuestion[];
231
+ historyBefore?: string;
232
+ }
203
233
  export interface ITicketBoard {
204
234
  revision: number;
205
235
  columns: { id: TTicketColumn; title: string; done?: boolean }[];
@@ -211,7 +241,7 @@ export interface ITicketOperations {
211
241
  list: { request: ITicketFilters; response: { tickets: ITicket[] } };
212
242
  board: { request: ITicketFilters; response: ITicketBoard };
213
243
  search: { request: { query: string; label?: string }; response: { tickets: ITicket[] } };
214
- get: { request: { ticketId: string }; response: { ticket: ITicket; comments: ITicketComment[]; activity: ITicketActivity[]; questions: ITicketQuestion[] } };
244
+ get: { request: ITicketGet; response: ITicketDetail };
215
245
  comments: { request: { ticketId: string }; response: { comments: ITicketComment[] } };
216
246
  create: { request: ITicketCreate; response: { ticket: ITicket } };
217
247
  update: { request: { ticketId: string; expectedRevision: number; changes: ITicketChanges }; response: { ticket: ITicket } };
@@ -259,6 +289,7 @@ export const ticketErrorMessages = {
259
289
  ticket_ask_forbidden: 'Workers may ask questions only on tickets assigned to their verified session.',
260
290
  ticket_answer_forbidden: 'Only the owner or the driver may answer ticket questions.',
261
291
  ticket_question_not_found: 'The requested question does not exist on this ticket.',
292
+ ticket_comment_not_found: 'The requested comment does not exist on this ticket.',
262
293
  ticket_question_answered: 'The question already has a different answer; a second answer is refused. Ask a new question instead.',
263
294
  ticket_answer_invalid: 'An answer chooses existing option ids (one unless multiSelect) and/or gives free text where the question allows it.',
264
295
  } as const;
@@ -6,6 +6,8 @@ export const workerCallerLaunchGenerationEnvironmentVariable = 'AGL_MCP_LAUNCH_G
6
6
  export interface IFleetWorkerCallerLaunchBase {
7
7
  launchId: string;
8
8
  projectId: string;
9
+ /** The fleet worker the launch identifies, `${projectId}:${name}`: a worker holds one current launch. */
10
+ workerId: string;
9
11
  }
10
12
 
11
13
  /**
@@ -27,11 +29,15 @@ export interface IFleetClaudeProcess {
27
29
  startTicks: string;
28
30
  }
29
31
 
30
- export type TFleetWorkerCallerBinding = IFleetWorkerCallerLaunchBase & {
32
+ export type TFleetWorkerCallerBinding = Omit<IFleetWorkerCallerLaunchBase, 'workerId'> & {
31
33
  nativeSessionId: string;
32
34
  expectedBindingRevision: number;
33
35
  } & (
34
- | { harnessId: 'claude'; claudeProcess: IFleetClaudeProcess }
36
+ /**
37
+ * A Claude launch binds to its background job and to the job's current process; a job whose process already exited
38
+ * binds without one, and the next process of the same job proves itself when its bridge enrolls.
39
+ */
40
+ | { harnessId: 'claude'; claudeJobId: string; claudeProcess?: IFleetClaudeProcess }
35
41
  | { harnessId: 'codex' }
36
42
  );
37
43
 
@@ -53,12 +59,34 @@ export interface IFleetWorkerCallerHooks {
53
59
  ticketSessionId: string;
54
60
  }>;
55
61
  getWorkerCallerStatus(launchId: string): IWorkerCallerReadiness;
56
- revokeWorkerCaller(request: {
57
- launchId: string;
62
+ /**
63
+ * Revokes one launch, or the current launch of a worker, also one the controller kept from before a restart. Every
64
+ * reason but `generation_change` revokes it for good: its kept binding is deleted with it.
65
+ */
66
+ revokeWorkerCaller(request: ({ launchId: string } | { workerId: string }) & {
58
67
  reason: 'failure' | 'stop' | 'replacement' | 'generation_change' | 'cancelled';
59
68
  }): Promise<void>;
60
69
  }
61
70
 
71
+ /** The background job a Claude worker's launch is bound to, as the controller asks the fleet about it. */
72
+ export interface IWorkerClaudeJobRequest {
73
+ workerId: string;
74
+ projectId: string;
75
+ nativeSessionId: string;
76
+ jobId: string;
77
+ }
78
+
79
+ /**
80
+ * What a fresh Claude inventory shows of that job: `running` in one process, `settled` without a process, `ended` for
81
+ * this worker (the worker is gone or archived, continues in another session, or the session continues as another job),
82
+ * or `unproven` when the registry or the inventory could not be read or did not list the session once.
83
+ */
84
+ export type TWorkerClaudeJobObservation =
85
+ | { state: 'running'; process: IFleetClaudeProcess }
86
+ | { state: 'settled' }
87
+ | { state: 'ended'; reason: string }
88
+ | { state: 'unproven'; reason: string };
89
+
62
90
  export interface IWorkerCallerSubject {
63
91
  kind: 'worker_launch';
64
92
  launchId: string;
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: 'agl',
6
- version: '40.5.1',
6
+ version: '41.0.0',
7
7
  description: 'Agent Gateway Layer for OpenCode, FlexHarness, and Codex sessions'
8
8
  }
@@ -941,10 +941,13 @@ const modelHarnessId = (choiceArg: interfaces.TControllerModelChoice): TBrowserS
941
941
  /** How long after asking for a restart this page expects its connection to drop; still connected, AGL did not restart. */
942
942
  const restartCheckMs = 20_000;
943
943
 
944
+ /** A model as a harness's own row names it, without the harness: "openai/gpt-5.6-sol". */
945
+ const modelChoiceName = (choiceArg: interfaces.TControllerModelChoice): string => `${choiceArg.providerID}/${choiceArg.modelID}`;
946
+
944
947
  const modelOptionLabel = (choiceArg: interfaces.TControllerModelChoice): string => {
945
948
  return [
946
949
  sessionHarnessLabel(modelHarnessId(choiceArg)),
947
- `${choiceArg.providerID}/${choiceArg.modelID}`,
950
+ modelChoiceName(choiceArg),
948
951
  ].join(' · ');
949
952
  };
950
953
 
@@ -18816,16 +18819,23 @@ ${entry.detail.stack}`}</pre>`}
18816
18819
 
18817
18820
  /** General as the controller's confirmed settings and this browser's own choices have it. */
18818
18821
  private generalSettingsView(): IGeneralSettingsView {
18822
+ // Each row belongs to one harness, so it names a model without the harness.
18823
+ const modelName = (modelStringArg: string): string => {
18824
+ const choice = this.modelChoicesByString.get(modelStringArg);
18825
+ return choice ? modelChoiceName(choice) : modelStringArg;
18826
+ };
18819
18827
  return {
18820
18828
  defaults: (['opencode', 'flex', 'codex', 'claude'] as const).map((harnessIdArg) => {
18821
18829
  const name = sessionHarnessLabel(harnessIdArg);
18822
18830
  const model = this.defaultModelStrings[harnessIdArg];
18823
18831
  const unavailable = this.unavailableDefaultModels[harnessIdArg];
18824
18832
  // Flex has no default of its own: without one AGL can name, its composer asks for a model.
18825
- const runningDefault = this.composerDefaultModelStrings[harnessIdArg]
18826
- || (harnessIdArg === 'flex' ? '' : `${name}'s own default`);
18833
+ const composerDefault = this.composerDefaultModelStrings[harnessIdArg];
18834
+ const runningDefault = composerDefault
18835
+ ? modelName(composerDefault)
18836
+ : harnessIdArg === 'flex' ? '' : `${name}'s own default`;
18827
18837
  const note = unavailable
18828
- ? `The saved default ${modelOptionLabel(unavailable)} is no longer offered. ${runningDefault
18838
+ ? `The saved default ${modelChoiceName(unavailable)} is no longer offered. ${runningDefault
18829
18839
  ? `New conversations run on ${runningDefault}.`
18830
18840
  : 'New Flex conversations need an account and model chosen in the composer.'}`
18831
18841
  : harnessIdArg === 'flex' && !model ? 'Without a default, Flex\'s composer asks for an account and a model.' : '';
@@ -18834,7 +18844,7 @@ ${entry.detail.stack}`}</pre>`}
18834
18844
  name,
18835
18845
  models: [
18836
18846
  { key: '', label: harnessIdArg === 'flex' ? 'Ask in the composer' : `${name}'s own default` },
18837
- ...this.modelOptionsForHarness(harnessIdArg).map((optionArg) => ({ key: optionArg, label: optionArg })),
18847
+ ...this.modelOptionsForHarness(harnessIdArg).map((optionArg) => ({ key: optionArg, label: modelName(optionArg) })),
18838
18848
  ],
18839
18849
  model,
18840
18850
  efforts: this.settingsEffortDropdownOptions(model)
@@ -18854,9 +18864,10 @@ ${entry.detail.stack}`}</pre>`}
18854
18864
  gpu: this.browserGpu,
18855
18865
  activeGpu: this.activeBrowserGpu,
18856
18866
  presentation: this.browserPresentation,
18857
- paintState: this.activeBrowserPaint
18858
- ? describeBrowserPaintAvailability(this.activeBrowserPaint)
18859
- : 'No browser runtime is running.',
18867
+ // Said only while Paint cannot be used: an available Paint needs no sentence.
18868
+ paintState: !this.activeBrowserPaint
18869
+ ? 'No browser runtime is running.'
18870
+ : this.activeBrowserPaint.state === 'available' ? '' : describeBrowserPaintAvailability(this.activeBrowserPaint),
18860
18871
  paintRearm: this.activeBrowserPaint?.state === 'unavailable'
18861
18872
  && this.activeBrowserPaint.reason !== 'descriptor-missing'
18862
18873
  && this.activeBrowserPaint.reason !== 'unsupported-platform'
@@ -250,6 +250,20 @@ export class AglTicketBoard extends plugins.deesElement.DeesElement {
250
250
  ?? { id: personArg.id, name: personArg.name };
251
251
  }
252
252
 
253
+ /** A ticket's whole history: `get` returns it a page at a time, newest first, so this reads back to the first entry. */
254
+ private async history(ticketIdArg: string, signalArg?: AbortSignal): Promise<Omit<interfaces.ITicketDetail, 'historyBefore'>> {
255
+ const pages: interfaces.ITicketDetail[] = [];
256
+ let before: string | undefined;
257
+ do {
258
+ const page = await this.fire('get', { ticketId: ticketIdArg, limit: interfaces.ticketHistoryPage.maximum,
259
+ ...(before === undefined ? {} : { before }) }, signalArg);
260
+ pages.unshift(page);
261
+ before = page.historyBefore;
262
+ } while (before !== undefined);
263
+ const { ticket, questions } = pages.at(-1)!;
264
+ return { ticket, questions, comments: pages.flatMap((pageArg) => pageArg.comments), activity: pages.flatMap((pageArg) => pageArg.activity) };
265
+ }
266
+
253
267
  /** Tickets as the kanban shows them, remembering whom they name. */
254
268
  private shown(ticketsArg: interfaces.ITicket[]): IKanbanTicket[] {
255
269
  for (const ticket of ticketsArg) {
@@ -274,12 +288,10 @@ export class AglTicketBoard extends plugins.deesElement.DeesElement {
274
288
  searchTickets: async (queryArg, signalArg) => this.shown((await this.fire('search', { query: queryArg }, signalArg)).tickets),
275
289
  // The discussion is the comments and the questions; the kanban orders them by when they were written.
276
290
  loadComments: async (ticketIdArg, signalArg) => {
277
- const { comments, questions } = await this.fire('get', { ticketId: ticketIdArg }, signalArg);
291
+ const { comments, questions } = await this.history(ticketIdArg, signalArg);
278
292
  return [...comments.map(kanbanComment), ...questions.map(kanbanQuestion)];
279
293
  },
280
- loadActivity: async (ticketIdArg, signalArg) => (
281
- (await this.fire('get', { ticketId: ticketIdArg }, signalArg)).activity.map(kanbanActivity)
282
- ),
294
+ loadActivity: async (ticketIdArg, signalArg) => (await this.history(ticketIdArg, signalArg)).activity.map(kanbanActivity),
283
295
  addComment: async (inputArg) => this.change(async () => (
284
296
  kanbanComment((await this.fire('comment', { ticketId: inputArg.ticketId, body: inputArg.body })).comment)
285
297
  )),
@@ -36,7 +36,7 @@ export interface IGeneralSettingsView {
36
36
  gpu: 'enabled' | 'disabled';
37
37
  activeGpu: 'enabled' | 'disabled';
38
38
  presentation: interfaces.TControllerBrowserPresentation;
39
- /** What the runtime says of Paint, or that no browser runtime runs. */
39
+ /** Why Paint cannot be used now, or that no browser runtime runs; empty while Paint is available. */
40
40
  paintState: string;
41
41
  /** Paint's integrity retries stopped and can be started again. */
42
42
  paintRearm: boolean;
@@ -90,10 +90,15 @@ export const renderGeneralSettings = (
90
90
  leading: html`<mp-harness-mark .harness=${rowArg.harnessId}></mp-harness-mark>`,
91
91
  label: rowArg.name,
92
92
  ...(rowArg.note ? { description: rowArg.note } : {}),
93
- control: html`<mp-model-picker class="settingsDefault" data-harness=${rowArg.harnessId} style="width: min(340px, 100%);"
93
+ // One folded button per row (model · effort), as wide as it says and at most a share of a narrow screen;
94
+ // it opens the model and the effort in a speech bubble. A saved default no longer offered gives it the
95
+ // warning tone.
96
+ control: html`<mp-model-picker class="settingsDefault" data-harness=${rowArg.harnessId} fold="always"
97
+ style="max-width: min(360px, 45vw);" .label=${`Default model for ${rowArg.name}`}
98
+ .warning=${rowArg.noteIsWarning ? rowArg.note : ''}
94
99
  .models=${rowArg.models} .model=${rowArg.model} .efforts=${rowArg.efforts} .effort=${rowArg.effort}
95
100
  .effortDisabledReason=${rowArg.effortDisabledReason} .modelPlaceholder=${'Choose a model'}
96
- .modelLabel=${`${rowArg.name} default model`} .effortLabel=${`${rowArg.name} reasoning effort`}
101
+ .modelLabel=${'Model'} .effortLabel=${'Reasoning effort'}
97
102
  @mp-model-change=${(eventArg: CustomEvent<TMpModelChoice>) => actionsArg.setDefault(rowArg.harnessId, eventArg.detail)}
98
103
  ></mp-model-picker>`,
99
104
  })),
@@ -161,7 +166,8 @@ export const renderGeneralSettings = (
161
166
  {
162
167
  key: 'presentation',
163
168
  label: 'New browser views show',
164
- description: `Paint draws the page as vector scenes in this tab; Video streams it. Each view can switch on its own. ${viewArg.paintState}`,
169
+ description: `Paint draws the page as vector scenes in this tab; Video streams it. Each view can switch on its own.${
170
+ viewArg.paintState ? ` ${viewArg.paintState}` : ''}`,
165
171
  control: html`
166
172
  ${viewArg.paintRearm
167
173
  ? html`<dees-button class="settingsBrowserPaintRearm" size="sm" text="Retry Paint" @clicked=${() => actionsArg.rearmPaint()}></dees-button>`