@newheap/platform-ai-chat 0.16.0 → 0.18.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.
package/README.md CHANGED
@@ -148,7 +148,9 @@ caller may decide each one. `NhAssistantStore.approvalRights` turns that into a
148
148
  approval card, `decide(decision, reason, approvalId)` decides a run's proposal with its
149
149
  proposal hash through `POST approvals/{id}/decisions` and reloads the thread, and cards
150
150
  the caller may not decide say who does (`waitingFor`: an approver, or another approver
151
- under four-eyes). Messages a trigger wrote (`authorKind: 'trigger'`) read as an event.
151
+ under four-eyes). Messages a trigger wrote (`authorKind: 'trigger'`) read as an event, and
152
+ messages the application posted (`role: 'application'`) as the application's, with their sender,
153
+ title, Markdown text and a link within the application or to an `https` address.
152
154
  Custom layouts pass `[approvalRights]` to `nh-assistant-thread` and handle
153
155
  `(approvalChoice)`, which carries the approval id.
154
156
 
@@ -288,6 +290,19 @@ custom layouts. Opened in the panel, the thread offers its proposals to the same
288
290
  **Decided by** shows the name from the subject's member snapshot (`decidedByDisplayName`)
289
291
  and falls back to the actor id.
290
292
 
293
+ The inbox also gives an overview. `divisionId` and `runId` filter it like `agentId` and
294
+ `subjectType`; `[grouped]="true"` groups the proposals by the parent the server recorded for each
295
+ proposal's subject (such as a project for its tasks) and by subject, `[groupByRun]="true"` also by
296
+ run. A group says how many of its proposals the page shows and whether it continues on another page,
297
+ and "Select group" selects only the shown proposals the person may decide. Proposals made since the
298
+ person's last visit of the inbox are marked new, and showing the inbox records the visit (`markNew`
299
+ and `recordVisit`, both on by default; turn `recordVisit` off for an inbox that shows only part of
300
+ it). `nh-assistant-run-result` lets its reader decide the run's proposals together.
301
+
302
+ ```html
303
+ <nh-assistant-agent-inbox [grouped]="true" [groupByRun]="true" [divisionId]="activeDivisionId" />
304
+ ```
305
+
291
306
  Subjects show the name of their type (`subjectTypeName`, such as "Project") and link to where
292
307
  the application shows them (`subjectLink`, from the server's `AddSubjectType(...).OpenAt(...)`).
293
308
  A link within the application navigates through the router; an `https` link leaves it. Replace
@@ -315,6 +330,14 @@ run for the whole application instead of a set of objects (sent as `subjectSet:
315
330
  division for an agent that works per division); the trigger list names it, and subject links name the
316
331
  whole application (`nh-system`, `isSystem` in the run catalog) once.
317
332
 
333
+ An agent's run configuration lists its consultations: those in code read only, and those defined as
334
+ data, which administrators add, change and remove within the agent's `consultationCeiling`
335
+ (`saveDataConsultation`, `removeDataConsultation`), with only the routes, requests and limits that
336
+ ceiling and the agent allow. Each consultation names the agents that ask it, with a link to their
337
+ editors, and its problems; the route switches turn a route off for all consultations of the agent, and
338
+ the flow's "When it runs" step names them. The mock API plays them with the scenario's
339
+ `consultationsAsData`, an agent's `consultableAsData` and its `dataConsultations`.
340
+
318
341
  With live updates the inbox, the thread view and its tabs reload by themselves when the hub
319
342
  reports `AgentWorkChanged` for work they show, debounced, and after every reconnect. The
320
343
  update names the thread, its subject (`subjectType`, `subjectId`) and whether a run, a
package/admin/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as _angular_core from '@angular/core';
2
2
  import { OnInit } from '@angular/core';
3
3
  import * as _newheap_platform_ai_chat from '@newheap/platform-ai-chat';
4
- import { NhAssistantStore, NhAssistantError, ApplicationContext, ApplicationContextVersion, AdminAgent, ToolCatalogEntry, McpServer, RunCatalog, SetAgentStateRequest, AgentSkillState, AgentShadowMode, AgentShadowState, AssistantAutonomy, AssistantDataClassification, AgentEvaluation, AgentReplay, AgentEvaluationCost, AgentProposalFeedbackCategory, AgentFeedbackSummaryRow, AgentFeedbackItem, AgentFeedbackCategoryCount, StaleKind, AgentProposalFeedbackGroup, AgentSubjectType, AgentRunStatus, ɵnhAssistantCodeKeys as _nhAssistantCodeKeys, AgentRunHistoryItem, DataSkill, AgentRunConfiguration, DataTrigger, SkillComparison, DataSkillVersion, ɵNhAssistantPickerOption as _NhAssistantPickerOption, McpServerTestResult, McpConnectionsSummary, McpBuiltInAuthMode, McpCustomAuthMode, McpAuthMode, McpTransport, McpConnectionScope, McpHeadlessUse, McpDiscovery, McpTool, McpToolEffect } from '@newheap/platform-ai-chat';
4
+ import { NhAssistantStore, NhAssistantError, ApplicationContext, ApplicationContextVersion, AdminAgent, ToolCatalogEntry, McpServer, RunCatalog, SetAgentStateRequest, AgentSkillState, AgentShadowMode, AgentShadowState, AssistantAutonomy, AssistantDataClassification, AgentEvaluation, AgentReplay, AgentEvaluationCost, AgentProposalFeedbackCategory, AgentFeedbackSummaryRow, AgentFeedbackItem, AgentFeedbackCategoryCount, StaleKind, AgentProposalFeedbackGroup, AgentSubjectType, AgentRunStatus, ɵnhAssistantCodeKeys as _nhAssistantCodeKeys, AgentRunHistoryItem, NhAssistantConsultationRoute, DataConsultation, CodeConsultation, DataSkill, AgentRunConfiguration, DataTrigger, SkillComparison, DataSkillVersion, ɵNhAssistantPickerOption as _NhAssistantPickerOption, McpServerTestResult, McpConnectionsSummary, McpBuiltInAuthMode, McpCustomAuthMode, McpAuthMode, McpTransport, McpConnectionScope, McpHeadlessUse, McpDiscovery, McpTool, McpToolEffect } from '@newheap/platform-ai-chat';
5
5
  import { ɵNhAssistantRunNowAgent as _NhAssistantRunNowAgent } from '@newheap/platform-ai-chat/agent-runs';
6
6
 
7
7
  type NhAssistantAdminTab = 'context' | 'agents' | 'mcp-servers';
@@ -317,6 +317,12 @@ declare class NhAssistantAdminAgentsComponent {
317
317
  onWorkRequested(agent: AdminAgent): void;
318
318
  /** The flow of the agent's run configuration opens the editor; saving or cancelling returns there. */
319
319
  editFromRunConfiguration(agent: AdminAgent): void;
320
+ /**
321
+ * A consultation of the agent's run configuration opens the editor of an agent that asks it, whose
322
+ * tool selectors are the consultation's second key; saving or cancelling returns to the run
323
+ * configuration it came from.
324
+ */
325
+ askerFromRunConfiguration(agent: AdminAgent, askerId: string): void;
320
326
  /** The flow of the agent's run configuration opens its runs; going back returns there. */
321
327
  runsFromRunConfiguration(agent: AdminAgent): void;
322
328
  /** The flow of an agent in code opens the form that replaces its technical account on its card. */
@@ -325,7 +331,11 @@ declare class NhAssistantAdminAgentsComponent {
325
331
  onEditorSaved(agent: AdminAgent): void;
326
332
  /** The editor closed without saving: back to the run configuration that opened it, or to the list. */
327
333
  onEditorCancelled(): void;
328
- /** Opens the run configuration again when its flow opened what closes now; `false` otherwise. */
334
+ /**
335
+ * Opens the run configuration again when its flow, or one of its consultations, opened what closes
336
+ * now; `false` otherwise. The editor of an agent that asks a consultation returns to the consulted
337
+ * agent's run configuration.
338
+ */
329
339
  private returnToRunConfiguration;
330
340
  /** What the agent works on, with its object types named as the run catalog names them. */
331
341
  worksOn(agent: AdminAgent): WorksOnSummary & {
@@ -787,6 +797,35 @@ declare class NhAssistantAgentRunHistoryComponent {
787
797
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<NhAssistantAgentRunHistoryComponent, "nh-assistant-agent-run-history", never, { "agentId": { "alias": "agentId"; "required": true; "isSignal": true; }; "subjectTypes": { "alias": "subjectTypes"; "required": false; "isSignal": true; }; }, { "openConversation": "openConversation"; }, never, never, true, never>;
788
798
  }
789
799
 
800
+ /** One consultation as the section and the flow list it: in code or defined as data. */
801
+ interface ConsultationRow {
802
+ subjectType: string;
803
+ origin: 'code' | 'data';
804
+ description: string | null;
805
+ /** The routes in effect: those code allows, or those of the data that still fit. */
806
+ routes: NhAssistantConsultationRoute[];
807
+ /** It generates the request tool now. */
808
+ requests: boolean;
809
+ /** MCP clients see its tools. */
810
+ mcp: boolean;
811
+ consultToolId: string;
812
+ /** The agents whose tool selectors select its consult tool now. */
813
+ askingAgents: string[];
814
+ inEffect: boolean;
815
+ problems: string[];
816
+ /** The consultation defined as data; `null` for one in code. */
817
+ data: DataConsultation | null;
818
+ code: CodeConsultation | null;
819
+ }
820
+ /**
821
+ * Why administrators cannot add a consultation to the agent now, or `null` when they can:
822
+ * `application` when the application does not let them define consultations, `agent` when the agent
823
+ * is in code and not consultable as data, `needs-settings` while an agent created here has no run
824
+ * settings, `limit` when it has as many as the ceiling allows, and `no-types` when every kind of
825
+ * object it works on already has a consultation.
826
+ */
827
+ type ConsultationsClosed = 'application' | 'agent' | 'needs-settings' | 'limit' | 'no-types';
828
+
790
829
  /**
791
830
  * What an entry point of the flow opens: the run configuration opens its own forms; the agent editor,
792
831
  * the technical account, the runs view and the MCP servers belong to the page that hosts it.
@@ -805,6 +844,11 @@ type AgentFlowEntry = {
805
844
  } | {
806
845
  kind: 'edit-trigger';
807
846
  triggerId: string;
847
+ } | {
848
+ kind: 'add-consultation';
849
+ } | {
850
+ kind: 'edit-consultation';
851
+ subjectType: string;
808
852
  } | {
809
853
  kind: 'edit-agent';
810
854
  } | {
@@ -815,6 +859,12 @@ type AgentFlowEntry = {
815
859
  kind: 'mcp-servers';
816
860
  };
817
861
 
862
+ /** What a saved consultation form tells its host. */
863
+ interface ConsultationFormSaved {
864
+ consultation: DataConsultation;
865
+ added: boolean;
866
+ }
867
+
818
868
  /** What a saved skill form tells its host. */
819
869
  interface SkillFormSaved {
820
870
  skill: DataSkill;
@@ -823,10 +873,10 @@ interface SkillFormSaved {
823
873
  added: boolean;
824
874
  }
825
875
 
826
- type Form = 'setup' | 'settings' | 'skill' | 'trigger';
876
+ type Form = 'setup' | 'settings' | 'skill' | 'trigger' | 'consultation';
827
877
  /** A removal, promotion or discard that waits for its confirmation. */
828
878
  interface Confirmation {
829
- action: 'remove-settings' | 'remove-skill' | 'remove-trigger' | 'promote' | 'discard';
879
+ action: 'remove-settings' | 'remove-skill' | 'remove-trigger' | 'remove-consultation' | 'promote' | 'discard';
830
880
  id: string;
831
881
  }
832
882
  /**
@@ -841,7 +891,11 @@ interface Confirmation {
841
891
  * they compare with the live version and promote or discard; they add data triggers on the
842
892
  * application's events or on a schedule and put them live; a schedule without a subject set runs for
843
893
  * the whole application, or for every division of an agent that works per division. New skills and
844
- * triggers start in shadow; `changed` tells the agents page to reload the agent's skill states.
894
+ * triggers start in shadow; `changed` tells the agents page to reload the agent's skill states. Its
895
+ * consultations (AC20) show what other assistants may consult it about: those in code read only, and
896
+ * those defined as data, which administrators add, change and remove within the agent's ceiling in
897
+ * code, each with the agents that ask it (`openAgent` opens the editor of one) and its problems,
898
+ * followed by the switches that turn a route off for all of its consultations.
845
899
  */
846
900
  declare class NhAssistantAgentRunConfigurationComponent implements OnInit {
847
901
  private readonly admin;
@@ -863,6 +917,8 @@ declare class NhAssistantAgentRunConfigurationComponent implements OnInit {
863
917
  * `null` while unknown.
864
918
  */
865
919
  readonly servers: _angular_core.InputSignal<readonly McpServer[] | null>;
920
+ /** Every agent of the administration, to name the agents that ask the agent's consultations. */
921
+ readonly agents: _angular_core.InputSignal<readonly AdminAgent[]>;
866
922
  /** A change of the run configuration changed the agent's skills or state. */
867
923
  readonly changed: _angular_core.OutputEmitterRef<void>;
868
924
  /** The flow asks to open the agent editor: what it works on, its tools, MCP servers and groups. */
@@ -873,6 +929,8 @@ declare class NhAssistantAgentRunConfigurationComponent implements OnInit {
873
929
  readonly openRuns: _angular_core.OutputEmitterRef<void>;
874
930
  /** The flow asks to open the MCP servers, whose background use decides what runs without a person use. */
875
931
  readonly openMcpServers: _angular_core.OutputEmitterRef<void>;
932
+ /** Opens the editor of an agent that asks one of the agent's consultations, by its id. */
933
+ readonly openAgent: _angular_core.OutputEmitterRef<string>;
876
934
  readonly id: string;
877
935
  readonly maxReason: 500;
878
936
  readonly skillNameKeys: typeof skillNameKeys;
@@ -910,6 +968,10 @@ declare class NhAssistantAgentRunConfigurationComponent implements OnInit {
910
968
  readonly editingSkill: _angular_core.WritableSignal<DataSkill | null>;
911
969
  /** The trigger being changed; `null` with the trigger form open adds a new trigger. */
912
970
  readonly editingTrigger: _angular_core.WritableSignal<DataTrigger | null>;
971
+ /** The consultation being changed; `null` with the consultation form open adds a new one. */
972
+ readonly editingConsultation: _angular_core.WritableSignal<DataConsultation | null>;
973
+ /** Counts the loads, so the route switches read the agent's routes again after a change. */
974
+ readonly loads: _angular_core.WritableSignal<number>;
913
975
  readonly comparison: _angular_core.WritableSignal<{
914
976
  skillId: string;
915
977
  result: SkillComparison | null;
@@ -928,6 +990,18 @@ declare class NhAssistantAgentRunConfigurationComponent implements OnInit {
928
990
  readonly skillIds: _angular_core.Signal<string[]>;
929
991
  readonly triggerIds: _angular_core.Signal<string[]>;
930
992
  readonly problems: _angular_core.Signal<_newheap_platform_ai_chat.RunConfigurationProblem[]>;
993
+ /** The consultations in code and as data, by subject type. */
994
+ readonly consultationRows: _angular_core.Signal<ConsultationRow[]>;
995
+ readonly showConsultations: _angular_core.Signal<boolean>;
996
+ /** The ceiling within which administrators may define the agent's consultations; `null` for none. */
997
+ readonly consultationCeiling: _angular_core.Signal<_newheap_platform_ai_chat.ConsultationCeiling | null>;
998
+ /** Why administrators cannot add a consultation now, or `null` when they can. */
999
+ readonly consultationsClosed: _angular_core.Signal<ConsultationsClosed | null>;
1000
+ /** The subject types the agent already has a consultation about. */
1001
+ readonly consultationTypes: _angular_core.Signal<string[]>;
1002
+ /** Whom the agent answers to, which decides whether a consultation may lend its rights. */
1003
+ readonly accountability: _angular_core.Signal<_newheap_platform_ai_chat.AgentAccountability | null>;
1004
+ readonly approvalPolicy: _angular_core.Signal<string | null>;
931
1005
  /** What the run settings' approval policy means, in a sentence. */
932
1006
  readonly settingsPolicy: _angular_core.Signal<string | null>;
933
1007
  constructor();
@@ -949,6 +1023,18 @@ declare class NhAssistantAgentRunConfigurationComponent implements OnInit {
949
1023
  editTrigger(trigger: DataTrigger): void;
950
1024
  setTriggerShadow(trigger: DataTrigger, shadow: boolean): void;
951
1025
  removeTrigger(trigger: DataTrigger): void;
1026
+ addConsultation(): void;
1027
+ editConsultation(consultation: DataConsultation): void;
1028
+ removeConsultation(consultation: DataConsultation): void;
1029
+ onConsultationSaved(result: ConsultationFormSaved): void;
1030
+ /** The name of a subject type, as the run catalog names it in the reader's language. */
1031
+ typeName(subjectType: string): string;
1032
+ /** An agent's name: the translation of an agent in code, the administrator's text, or its id. */
1033
+ agentNameOf(agentId: string): string;
1034
+ /** Who may ask a consultation defined as data, in a sentence; `null` for one in code, whose code says it. */
1035
+ askSentence(row: ConsultationRow): string | null;
1036
+ /** What the consultation may do and who decides its proposals, by the routes in effect. */
1037
+ decideSentence(row: ConsultationRow): string;
952
1038
  /** A form saved: show what happened and reload, which every change may affect. */
953
1039
  onSetupCompleted(live: boolean): void;
954
1040
  onSettingsSaved(): void;
@@ -981,7 +1067,7 @@ declare class NhAssistantAgentRunConfigurationComponent implements OnInit {
981
1067
  /** Runs a change and reloads the configuration, which every change may affect. */
982
1068
  private run;
983
1069
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<NhAssistantAgentRunConfigurationComponent, never>;
984
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<NhAssistantAgentRunConfigurationComponent, "nh-assistant-agent-run-configuration", never, { "agent": { "alias": "agent"; "required": true; "isSignal": true; }; "startSetup": { "alias": "startSetup"; "required": false; "isSignal": true; }; "tools": { "alias": "tools"; "required": false; "isSignal": true; }; "servers": { "alias": "servers"; "required": false; "isSignal": true; }; }, { "changed": "changed"; "editAgent": "editAgent"; "changeAccount": "changeAccount"; "openRuns": "openRuns"; "openMcpServers": "openMcpServers"; }, never, never, true, never>;
1070
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<NhAssistantAgentRunConfigurationComponent, "nh-assistant-agent-run-configuration", never, { "agent": { "alias": "agent"; "required": true; "isSignal": true; }; "startSetup": { "alias": "startSetup"; "required": false; "isSignal": true; }; "tools": { "alias": "tools"; "required": false; "isSignal": true; }; "servers": { "alias": "servers"; "required": false; "isSignal": true; }; "agents": { "alias": "agents"; "required": false; "isSignal": true; }; }, { "changed": "changed"; "editAgent": "editAgent"; "changeAccount": "changeAccount"; "openRuns": "openRuns"; "openMcpServers": "openMcpServers"; "openAgent": "openAgent"; }, never, never, true, never>;
985
1071
  }
986
1072
 
987
1073
  /** Result of the latest connection test per server. */
@@ -1,6 +1,6 @@
1
1
  import * as _angular_core from '@angular/core';
2
2
  import * as _newheap_platform_ai_chat from '@newheap/platform-ai-chat';
3
- import { AgentProposal, AgentThreadLookup, AgentTriggerReceipt, NhAssistantError, AgentProposalDecisionRight, AgentProposalFeedback, AgentProposalOrigin, AgentProposalDecision, AgentExecutionResolution, AgentSubjectRole, AgentRun, ɵnhAssistantCodeKeys as _nhAssistantCodeKeys, AgentRunRetryMode, AgentThreadMemory, AgentArtifact, AgentConsultation, AgentSubjectWork, AgentSubjectWorkAgent, AgentSubjectType, ɵNhAssistantPickerOption as _NhAssistantPickerOption, NhAssistantAgentRunApiService, AgentObjectAgents, AgentObjectAgent, AgentRunResult, AgentBoard, AgentBoardAgent } from '@newheap/platform-ai-chat';
3
+ import { AgentProposal, AgentInboxGroup, AgentThreadLookup, AgentProposalDecisionRight, AgentTriggerReceipt, NhAssistantError, AgentProposalFeedback, AgentProposalOrigin, AgentProposalDecision, AgentExecutionResolution, AgentSubjectRole, AgentRun, ɵnhAssistantCodeKeys as _nhAssistantCodeKeys, AgentRunRetryMode, AgentThreadMemory, AgentArtifact, AgentConsultation, NhAssistantConsultationRoute, AgentSubjectWork, AgentSubjectWorkAgent, AgentSubjectType, ɵNhAssistantPickerOption as _NhAssistantPickerOption, NhAssistantAgentRunApiService, AgentObjectAgents, AgentObjectAgent, AgentRunResult, AgentBoard, AgentBoardAgent } from '@newheap/platform-ai-chat';
4
4
  import { Observable } from 'rxjs';
5
5
 
6
6
  /**
@@ -14,15 +14,49 @@ import { Observable } from 'rxjs';
14
14
  * longer fits, for example because someone did the work by hand, stays as a closed card with the
15
15
  * reason until it is dismissed. A proposal a run placed at its object from another subject, such as a
16
16
  * run for the whole application, names that run; `openConversation` emits its conversation.
17
+ *
18
+ * `agentId`, `subjectType`, `divisionId` and `runId` filter the inbox; changing a filter, or `grouped`,
19
+ * reloads it from the first page. With `grouped` the inbox shows the proposals per parent, such as a
20
+ * project with its own proposals and those of its tasks, and per subject, optionally per run
21
+ * (`groupByRun`); a group that goes on on another page says so, and "Select group" selects only its
22
+ * proposals shown here. With `markNew` (on by default) it marks the proposals made since the person's
23
+ * last visit of the inbox in its scope, the whole application or the division of `divisionId`, and
24
+ * those that arrive while it is shown; with `recordVisit` (on by default) showing it records the
25
+ * visit. Turn `recordVisit` off for an inbox that shows only part of the scope, such as one agent's
26
+ * proposals, so the person's next visit of the whole inbox still marks what they have not seen.
17
27
  */
18
28
  declare class NhAssistantAgentInboxComponent {
19
29
  private readonly api;
20
30
  private readonly proposalList;
21
31
  private subscription?;
32
+ private visitSubscription?;
33
+ /** The scope whose visit this view recorded; the visit is recorded once per scope shown. */
34
+ private visited;
35
+ /**
36
+ * What the first read of the shown scope found: the visit before this one and the proposals that
37
+ * were new since. Later reads, after live updates, paging or a decision, compare with both, so what
38
+ * was new when the inbox was opened stays new while it is shown.
39
+ */
40
+ private opened;
22
41
  /** Limits the inbox to one agent. */
23
42
  readonly agentId: _angular_core.InputSignal<string | undefined>;
24
43
  /** Limits the inbox to one kind of subject, for example `project`. */
25
44
  readonly subjectType: _angular_core.InputSignal<string | undefined>;
45
+ /**
46
+ * Limits the inbox to the subjects of one division, for example the active division; its visits are
47
+ * then those of that division.
48
+ */
49
+ readonly divisionId: _angular_core.InputSignal<string | null | undefined>;
50
+ /** Limits the inbox to the proposals of one run. */
51
+ readonly runId: _angular_core.InputSignal<string | null | undefined>;
52
+ /** Groups the proposals per parent and subject instead of listing them by expiry alone. */
53
+ readonly grouped: _angular_core.InputSignal<boolean>;
54
+ /** In a grouped inbox, also shows a header per run within a subject. */
55
+ readonly groupByRun: _angular_core.InputSignal<boolean>;
56
+ /** Marks the proposals made since the person's last visit of the inbox, and those that arrive while it is shown. */
57
+ readonly markNew: _angular_core.InputSignal<boolean>;
58
+ /** Records the person's visit of the inbox in its scope when it is shown. */
59
+ readonly recordVisit: _angular_core.InputSignal<boolean>;
26
60
  readonly itemsPerPage: _angular_core.InputSignal<number>;
27
61
  /**
28
62
  * Emits the conversation of the run that placed a proposal at its object from another subject, so
@@ -36,6 +70,15 @@ declare class NhAssistantAgentInboxComponent {
36
70
  readonly loadFailed: _angular_core.WritableSignal<boolean>;
37
71
  readonly items: _angular_core.WritableSignal<AgentProposal[]>;
38
72
  readonly total: _angular_core.WritableSignal<number>;
73
+ /** The groups of the page in a grouped inbox; `null` for the flat inbox. */
74
+ readonly groups: _angular_core.WritableSignal<AgentInboxGroup[] | null>;
75
+ /** The proposals of the page marked as new. */
76
+ readonly newIds: _angular_core.WritableSignal<ReadonlySet<string>>;
77
+ /**
78
+ * The person's visit of the shown scope before the inbox was opened: `null` before their first
79
+ * visit, `undefined` while unknown or when new proposals are not marked.
80
+ */
81
+ readonly previousVisit: _angular_core.WritableSignal<string | null | undefined>;
39
82
  readonly pages: _angular_core.Signal<number>;
40
83
  constructor();
41
84
  load(): void;
@@ -47,8 +90,19 @@ declare class NhAssistantAgentInboxComponent {
47
90
  */
48
91
  private refresh;
49
92
  private fetch;
93
+ /**
94
+ * Marks what is new: what the server marks since the visit this view recorded, and what was made
95
+ * after the person's visit before the inbox was opened, on any page. Before the first visit
96
+ * everything is new. A server without visits marks nothing.
97
+ */
98
+ private markNewOf;
99
+ /**
100
+ * Records the visit of the shown scope after its first read, so that read still marks what arrived
101
+ * since the visit before.
102
+ */
103
+ private recordVisitOf;
50
104
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<NhAssistantAgentInboxComponent, never>;
51
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<NhAssistantAgentInboxComponent, "nh-assistant-agent-inbox", never, { "agentId": { "alias": "agentId"; "required": false; "isSignal": true; }; "subjectType": { "alias": "subjectType"; "required": false; "isSignal": true; }; "itemsPerPage": { "alias": "itemsPerPage"; "required": false; "isSignal": true; }; }, { "openConversation": "openConversation"; }, never, never, true, never>;
105
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<NhAssistantAgentInboxComponent, "nh-assistant-agent-inbox", never, { "agentId": { "alias": "agentId"; "required": false; "isSignal": true; }; "subjectType": { "alias": "subjectType"; "required": false; "isSignal": true; }; "divisionId": { "alias": "divisionId"; "required": false; "isSignal": true; }; "runId": { "alias": "runId"; "required": false; "isSignal": true; }; "grouped": { "alias": "grouped"; "required": false; "isSignal": true; }; "groupByRun": { "alias": "groupByRun"; "required": false; "isSignal": true; }; "markNew": { "alias": "markNew"; "required": false; "isSignal": true; }; "recordVisit": { "alias": "recordVisit"; "required": false; "isSignal": true; }; "itemsPerPage": { "alias": "itemsPerPage"; "required": false; "isSignal": true; }; }, { "openConversation": "openConversation"; }, never, never, true, never>;
52
106
  }
53
107
 
54
108
  type NhAssistantAgentThreadTab = 'proposals' | 'runs' | 'consultations' | 'memory' | 'artifacts';
@@ -64,6 +118,7 @@ declare class NhAssistantAgentThreadViewComponent {
64
118
  private readonly proposalList;
65
119
  private subscription?;
66
120
  private proposalSubscription?;
121
+ private rightsSubscription?;
67
122
  private startSubscription?;
68
123
  readonly agentId: _angular_core.InputSignal<string>;
69
124
  readonly subjectType: _angular_core.InputSignal<string>;
@@ -78,6 +133,13 @@ declare class NhAssistantAgentThreadViewComponent {
78
133
  readonly loadFailed: _angular_core.WritableSignal<boolean>;
79
134
  readonly lookup: _angular_core.WritableSignal<AgentThreadLookup | null>;
80
135
  readonly proposals: _angular_core.WritableSignal<AgentProposal[]>;
136
+ /**
137
+ * The caller's live right to decide each pending proposal, as the server checks it for the decision:
138
+ * four-eyes keeps the person who asked for a consultation's proposal out, also as an approver, and
139
+ * nobody decides here what the asker decides in their own chat. Without an answer the caller's role
140
+ * decides what is offered; the server checks every decision again.
141
+ */
142
+ readonly rights: _angular_core.WritableSignal<ReadonlyMap<string, AgentProposalDecisionRight> | null>;
81
143
  readonly message: _angular_core.WritableSignal<string>;
82
144
  readonly starting: _angular_core.WritableSignal<boolean>;
83
145
  readonly receipt: _angular_core.WritableSignal<AgentTriggerReceipt | null>;
@@ -105,10 +167,54 @@ declare class NhAssistantAgentThreadViewComponent {
105
167
  private refresh;
106
168
  private fetch;
107
169
  private fetchProposals;
170
+ /**
171
+ * Reads the caller's live right to decide each pending proposal, in batches of
172
+ * `NH_ASSISTANT_MAX_PROPOSAL_LOOKUP`, as the run result and the subject's work do.
173
+ */
174
+ private readRights;
108
175
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<NhAssistantAgentThreadViewComponent, never>;
109
176
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<NhAssistantAgentThreadViewComponent, "nh-assistant-agent-thread-view", never, { "agentId": { "alias": "agentId"; "required": true; "isSignal": true; }; "subjectType": { "alias": "subjectType"; "required": true; "isSignal": true; }; "subjectId": { "alias": "subjectId"; "required": true; "isSignal": true; }; }, { "openConversation": "openConversation"; }, never, never, true, never>;
110
177
  }
111
178
 
179
+ /** The proposals of one run within a subject of a grouped list, in the order the list gave them. */
180
+ interface NhAssistantRunSection {
181
+ key: string;
182
+ runId: string | null;
183
+ agentId: string;
184
+ /** When the run's first proposal on the page was made. */
185
+ proposedAt: string;
186
+ items: AgentProposal[];
187
+ }
188
+ /** One subject within a group of a grouped list. */
189
+ interface NhAssistantSubjectSection {
190
+ key: string;
191
+ subjectType: string;
192
+ subjectId: string;
193
+ label: string;
194
+ typeName: string | null;
195
+ link: string | null;
196
+ /** The group's own subject, whose proposals stand directly under the group's header. */
197
+ own: boolean;
198
+ count: number;
199
+ total: number;
200
+ runs: NhAssistantRunSection[];
201
+ }
202
+ /** One group of a grouped list, such as a parent subject of the grouped inbox. */
203
+ interface NhAssistantGroupSection {
204
+ key: string;
205
+ subjectType: string;
206
+ subjectId: string;
207
+ label: string;
208
+ typeName: string | null;
209
+ link: string | null;
210
+ count: number;
211
+ total: number;
212
+ continuesFromPreviousPage: boolean;
213
+ continuesOnNextPage: boolean;
214
+ subjects: NhAssistantSubjectSection[];
215
+ /** The group's pending proposals on this page that the caller may decide: what "Select group" selects. */
216
+ selectableIds: string[];
217
+ }
112
218
  /** A feedback question: after a rejection above the list, or from a card's own action. */
113
219
  interface NhAssistantFeedbackRequest {
114
220
  approvalIds: string[];
@@ -132,7 +238,13 @@ interface NhAssistantFeedbackRequest {
132
238
  * replaced, as a closed card when it closes while shown, or when an approval is refused because of
133
239
  * it, until the person dismisses it. It reads those proposals by id with one lookup, never through
134
240
  * their threads. A proposal that a run placed here from another subject, such as a run for the whole
135
- * application, says so and offers that run's conversation through `openConversation`.
241
+ * application, says so and offers that run's conversation through `openConversation`. With `groups`
242
+ * from the grouped inbox the list shows a header per group and per subject, optionally per run
243
+ * (`groupByRun`), and "Select group" selects only the group's pending proposals in this list that
244
+ * the caller may decide, never those on another page. `newIds` marks proposals as new. A proposal of
245
+ * a consultation names who asked and its route: one the person who asked decides in their own chat
246
+ * (`asker-decides`) waits for them without actions here; one that runs with the agent's own rights
247
+ * (`subject-agent-rights`) says so, and the person who asked reads why another approver decides.
136
248
  */
137
249
  declare class NhAssistantAgentProposalsComponent {
138
250
  private readonly api;
@@ -154,6 +266,16 @@ declare class NhAssistantAgentProposalsComponent {
154
266
  * it closes.
155
267
  */
156
268
  readonly holdClosedCards: _angular_core.InputSignal<boolean>;
269
+ /**
270
+ * The groups of the grouped inbox (`AgentInbox.groups`) for `proposals` in the order the inbox gave
271
+ * them: the first `count` proposals belong to the first group, and so on. Without groups, or when
272
+ * they do not describe `proposals`, the list is flat.
273
+ */
274
+ readonly groups: _angular_core.InputSignal<readonly AgentInboxGroup[] | null>;
275
+ /** Shows a header per run within a subject of a grouped list. */
276
+ readonly groupByRun: _angular_core.InputSignal<boolean>;
277
+ /** Proposals to mark as new, by approval id, for example those made since the last visit of the inbox. */
278
+ readonly newIds: _angular_core.InputSignal<ReadonlySet<string> | null>;
157
279
  /** Emits after a proposal or its feedback changed, so the host reloads its list. */
158
280
  readonly changed: _angular_core.OutputEmitterRef<void>;
159
281
  /**
@@ -175,6 +297,11 @@ declare class NhAssistantAgentProposalsComponent {
175
297
  /** The held closed cards first, then the proposals the host gave. */
176
298
  readonly shown: _angular_core.Signal<AgentProposal[]>;
177
299
  private readonly lookups;
300
+ /**
301
+ * The grouped list: the held closed cards stay above it; `null` for a flat list, or when the groups
302
+ * do not describe the proposals.
303
+ */
304
+ readonly sections: _angular_core.Signal<NhAssistantGroupSection[] | null>;
178
305
  constructor();
179
306
  /**
180
307
  * The translation key of a proposal's status: the kind of a stale proposal, "replaced" for a
@@ -189,6 +316,16 @@ declare class NhAssistantAgentProposalsComponent {
189
316
  key: string;
190
317
  params: Record<string, string>;
191
318
  };
319
+ /** Whether the proposal is marked as new. */
320
+ isNew(proposal: AgentProposal): boolean;
321
+ /** Whether every proposal "Select group" would select in the group is selected. */
322
+ groupSelected(group: NhAssistantGroupSection): boolean;
323
+ /**
324
+ * Selects the group's pending proposals in this list that the caller may decide, or deselects them
325
+ * when all are selected. Proposals of the group on another page are never selected: an approver
326
+ * decides only what they see.
327
+ */
328
+ toggleGroup(group: NhAssistantGroupSection): void;
192
329
  /** True when the newer proposal that replaced this one is in the list. */
193
330
  hasSuccessor(proposal: AgentProposal): boolean;
194
331
  /** Moves focus to the newer proposal that replaced this one. */
@@ -202,13 +339,28 @@ declare class NhAssistantAgentProposalsComponent {
202
339
  * the shown pending proposals that left the list because they closed as stale or were replaced.
203
340
  */
204
341
  holdClosed(previous: readonly AgentProposal[], next: readonly AgentProposal[]): void;
205
- /** Whether the caller may decide this proposal: its own right when one was given, otherwise `canDecide`. */
342
+ /**
343
+ * Whether the caller may decide this proposal: its own right when one was given, otherwise
344
+ * `canDecide`. Nobody decides a proposal here that the person who asked decides in their own chat.
345
+ */
206
346
  mayDecide(proposal: AgentProposal): boolean;
347
+ /**
348
+ * Whether a pending proposal of a consultation waits for the person who asked, who decides it in
349
+ * their own chat: its route says so, or the server's reason for the caller's right.
350
+ */
351
+ waitsForAsker(proposal: AgentProposal): boolean;
207
352
  /**
208
353
  * Who decides a pending proposal that has a right the caller lacks: another approver when
209
- * four-eyes keeps out the person who started the work, otherwise an approver.
354
+ * four-eyes keeps out the person who started the work, which for a consultation's proposal that
355
+ * runs with the agent's own rights is the person who asked, otherwise an approver. A proposal that
356
+ * waits for the person who asked says so on its own (`waitsForAsker`).
210
357
  */
211
358
  waitingForKey(proposal: AgentProposal): string | null;
359
+ /**
360
+ * The badge of a consultation's proposal that runs with the agent's own rights: those of a technical
361
+ * account when the agent answers to one, otherwise the agent's own; `null` for other proposals.
362
+ */
363
+ agentRightsKey(proposal: AgentProposal): string | null;
212
364
  toggle(proposal: AgentProposal): void;
213
365
  toggleAll(): void;
214
366
  decide(proposal: AgentProposal, decision: AgentProposalDecision): void;
@@ -224,6 +376,7 @@ declare class NhAssistantAgentProposalsComponent {
224
376
  onFeedbackSaved(): void;
225
377
  /** Closes the question; from a card, focus returns to the card's feedback action. */
226
378
  onFeedbackDismissed(): void;
379
+ private groupSection;
227
380
  private ask;
228
381
  /**
229
382
  * Reads `proposals` again by id and keeps those that closed as stale or were replaced as closed
@@ -232,7 +385,7 @@ declare class NhAssistantAgentProposalsComponent {
232
385
  private holdStale;
233
386
  private run;
234
387
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<NhAssistantAgentProposalsComponent, never>;
235
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<NhAssistantAgentProposalsComponent, "nh-assistant-agent-proposals", never, { "proposals": { "alias": "proposals"; "required": true; "isSignal": true; }; "canDecide": { "alias": "canDecide"; "required": false; "isSignal": true; }; "decisionRights": { "alias": "decisionRights"; "required": false; "isSignal": true; }; "selectable": { "alias": "selectable"; "required": false; "isSignal": true; }; "holdClosedCards": { "alias": "holdClosedCards"; "required": false; "isSignal": true; }; }, { "changed": "changed"; "openConversation": "openConversation"; }, never, never, true, never>;
388
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<NhAssistantAgentProposalsComponent, "nh-assistant-agent-proposals", never, { "proposals": { "alias": "proposals"; "required": true; "isSignal": true; }; "canDecide": { "alias": "canDecide"; "required": false; "isSignal": true; }; "decisionRights": { "alias": "decisionRights"; "required": false; "isSignal": true; }; "selectable": { "alias": "selectable"; "required": false; "isSignal": true; }; "holdClosedCards": { "alias": "holdClosedCards"; "required": false; "isSignal": true; }; "groups": { "alias": "groups"; "required": false; "isSignal": true; }; "groupByRun": { "alias": "groupByRun"; "required": false; "isSignal": true; }; "newIds": { "alias": "newIds"; "required": false; "isSignal": true; }; }, { "changed": "changed"; "openConversation": "openConversation"; }, never, never, true, never>;
236
389
  }
237
390
 
238
391
  /**
@@ -333,9 +486,9 @@ declare class NhAssistantAgentArtifactsComponent {
333
486
 
334
487
  /**
335
488
  * Who consulted the thread's agent through another assistant, newest first: the person whose rights
336
- * were used, the asking assistant, the outcome, the usage and the proposals left for approvers. The
337
- * question and the answer stay in the asking conversation and are never shown here. With live
338
- * updates the list reloads by itself when a run or proposal of the thread changes.
489
+ * were used, the asking assistant, the outcome, the usage and the proposals it left, with their
490
+ * number per route. The question and the answer stay in the asking conversation and are never shown
491
+ * here. With live updates the list reloads by itself when a run or proposal of the thread changes.
339
492
  */
340
493
  declare class NhAssistantAgentConsultationsComponent {
341
494
  private readonly api;
@@ -348,6 +501,11 @@ declare class NhAssistantAgentConsultationsComponent {
348
501
  readonly codeKeys: typeof _nhAssistantCodeKeys;
349
502
  constructor();
350
503
  load(): void;
504
+ /** The proposals the consultation left per route, in a fixed order; routes without proposals are left out. */
505
+ routeCounts(consultation: AgentConsultation): {
506
+ route: NhAssistantConsultationRoute;
507
+ count: number;
508
+ }[];
351
509
  /** A quiet load, after a live update, shows no loading state and keeps the list when it fails. */
352
510
  private fetch;
353
511
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<NhAssistantAgentConsultationsComponent, never>;
@@ -690,11 +848,18 @@ interface RunDuration {
690
848
  * its object, for the whole application the agent's view policy, administrators every run. The
691
849
  * thread view's run timeline and the administration's runs view open it; an application may show
692
850
  * it anywhere with a run id. With live updates it reloads by itself while the run works.
851
+ *
852
+ * The run's pending proposals that the reader may decide, by the same live check as the inbox and the
853
+ * subject's work (`POST approvals/lookup`), can be decided in place, one by one or selected together
854
+ * with "Select all"; a pending proposal the reader may not decide says who does, and a reader who may
855
+ * decide none sees no selection. After a rejection the list asks, optionally, what was wrong, and a
856
+ * proposal refused because it no longer fits stays as a closed card with the reason until dismissed.
693
857
  */
694
858
  declare class NhAssistantRunResultComponent {
695
859
  private readonly api;
696
860
  private readonly document;
697
861
  private subscription?;
862
+ private rightsSubscription?;
698
863
  /** The run to show. */
699
864
  readonly runId: _angular_core.InputSignal<string>;
700
865
  /**
@@ -718,11 +883,25 @@ declare class NhAssistantRunResultComponent {
718
883
  /** The text of the download's failure, then the text that a file could not be downloaded. */
719
884
  readonly downloadErrorKeys: _angular_core.Signal<string[]>;
720
885
  readonly codeKeys: typeof _nhAssistantCodeKeys;
886
+ /**
887
+ * The reader's live right to decide each pending proposal of the run, by approval id; `null` until
888
+ * it is known, when nobody may decide.
889
+ */
890
+ readonly rights: _angular_core.WritableSignal<ReadonlyMap<string, AgentProposalDecisionRight> | null>;
891
+ /** Whether the reader may decide at least one of the run's proposals: only then can they select. */
892
+ readonly decidable: _angular_core.Signal<boolean>;
721
893
  readonly duration: _angular_core.Signal<RunDuration | null>;
722
894
  readonly tokens: _angular_core.Signal<number>;
723
895
  constructor();
724
896
  load(): void;
897
+ /** A proposal was decided or its feedback given: the run's proposals and the rights are read again. */
898
+ onProposalsChanged(): void;
725
899
  download(artifact: AgentArtifact): Promise<void>;
900
+ /**
901
+ * Reads the reader's live right to decide each pending proposal of the run, as the server checks it
902
+ * for every decision. Without an answer nobody may decide here; the server checks again anyway.
903
+ */
904
+ private readRights;
726
905
  /**
727
906
  * Reads the run. A quiet reload, after a live update, keeps what is shown when it fails and shows
728
907
  * no loading state.