@newheap/platform-ai-chat 0.16.0 → 0.17.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 +13 -0
- package/agent-runs/index.d.ts +147 -4
- package/fesm2022/newheap-platform-ai-chat-admin.mjs +52 -6
- package/fesm2022/newheap-platform-ai-chat-admin.mjs.map +1 -1
- package/fesm2022/newheap-platform-ai-chat-agent-runs.mjs +297 -30
- package/fesm2022/newheap-platform-ai-chat-agent-runs.mjs.map +1 -1
- package/fesm2022/newheap-platform-ai-chat-testing.mjs +174 -13
- package/fesm2022/newheap-platform-ai-chat-testing.mjs.map +1 -1
- package/fesm2022/newheap-platform-ai-chat.mjs +56 -3
- package/fesm2022/newheap-platform-ai-chat.mjs.map +1 -1
- package/i18n/en.json +21 -1
- package/i18n/nl.json +21 -1
- package/index.d.ts +112 -2
- package/package.json +1 -1
- package/testing/index.d.ts +12 -1
|
@@ -25,6 +25,7 @@ const statusTable = {
|
|
|
25
25
|
'assistant-run-filter-invalid',
|
|
26
26
|
'assistant-board-scope-invalid',
|
|
27
27
|
'assistant-feedback-invalid',
|
|
28
|
+
'assistant-trigger-filter-not-found',
|
|
28
29
|
'assistant-replay-not-shadow',
|
|
29
30
|
'assistant-evaluation-not-variant',
|
|
30
31
|
'assistant-instructions-too-long',
|
|
@@ -2222,6 +2223,9 @@ const maxDescription$1 = 300;
|
|
|
2222
2223
|
const maxInstructions = 20_000;
|
|
2223
2224
|
const maxMessage$1 = 2_000;
|
|
2224
2225
|
const maxReason$1 = 500;
|
|
2226
|
+
/** A data trigger applies at most this many filters of its event, each named in lowercase dash-case. */
|
|
2227
|
+
const maxTriggerFilters = 10;
|
|
2228
|
+
const filterName = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
2225
2229
|
/** The platform's default file limits (`NhAssistantLimits`). */
|
|
2226
2230
|
const defaultFileLimits = {
|
|
2227
2231
|
maxFileBytes: 20 * 1024 * 1024,
|
|
@@ -2249,7 +2253,8 @@ class NhAssistantMockRunConfiguration {
|
|
|
2249
2253
|
this.triggers = new Map();
|
|
2250
2254
|
const approvalPolicies = scenario.runCatalog?.approvalPolicies ?? scenario.policies ?? [];
|
|
2251
2255
|
this.catalog = {
|
|
2252
|
-
|
|
2256
|
+
// A trigger event lists its named filters, none unless the scenario's application registers some.
|
|
2257
|
+
triggerEvents: (scenario.runCatalog?.triggerEvents ?? []).map(event => ({ ...event, filters: event.filters ?? [] })),
|
|
2253
2258
|
subjectSets: scenario.runCatalog?.subjectSets ?? [],
|
|
2254
2259
|
ruleHandlers: scenario.runCatalog?.ruleHandlers ?? [],
|
|
2255
2260
|
approvalPolicies,
|
|
@@ -2375,8 +2380,13 @@ class NhAssistantMockRunConfiguration {
|
|
|
2375
2380
|
*/
|
|
2376
2381
|
triggerProblem(agent, trigger) {
|
|
2377
2382
|
if (trigger.source === 'event') {
|
|
2378
|
-
const
|
|
2379
|
-
|
|
2383
|
+
const event = this.catalog.triggerEvents.find(item => item.name === trigger.event);
|
|
2384
|
+
if (event?.subjectType && !mockWorksOnCovers(agent, event.subjectType)) {
|
|
2385
|
+
return 'not-worked-on';
|
|
2386
|
+
}
|
|
2387
|
+
// A filter the event no longer offers keeps the trigger from firing.
|
|
2388
|
+
const offered = (event?.filters ?? []).map(filter => filter.name);
|
|
2389
|
+
return (trigger.filters ?? []).some(name => !offered.includes(name)) ? 'unknown-filter' : null;
|
|
2380
2390
|
}
|
|
2381
2391
|
return trigger.subjectSet === null && !mockWorksOnCovers(agent, mockSystemSubjectType) ? 'not-worked-on' : null;
|
|
2382
2392
|
}
|
|
@@ -2706,9 +2716,20 @@ class NhAssistantMockRunConfiguration {
|
|
|
2706
2716
|
if (skill !== null && !this.skillIds(agent).includes(skill)) {
|
|
2707
2717
|
errors['skill'] = ['not-found'];
|
|
2708
2718
|
}
|
|
2719
|
+
// The filters in the order chosen, each once; only an event trigger takes them.
|
|
2720
|
+
const filters = [...new Set((request.filters ?? []).map(name => (typeof name === 'string' ? name.trim() : '')))];
|
|
2721
|
+
if (filters.length > maxTriggerFilters || filters.some(name => name.length > 64 || !filterName.test(name)) || (schedule && filters.length > 0)) {
|
|
2722
|
+
errors['filters'] = ['invalid'];
|
|
2723
|
+
}
|
|
2709
2724
|
if (Object.keys(errors).length > 0) {
|
|
2710
2725
|
return mockFailure('assistant-validation', errors);
|
|
2711
2726
|
}
|
|
2727
|
+
if (request.source === 'event') {
|
|
2728
|
+
const offered = (this.catalog.triggerEvents.find(item => item.name === text(request.event))?.filters ?? []).map(filter => filter.name);
|
|
2729
|
+
if (filters.some(name => !offered.includes(name))) {
|
|
2730
|
+
return mockFailure('assistant-trigger-filter-not-found', { filters: ['not-found'] });
|
|
2731
|
+
}
|
|
2732
|
+
}
|
|
2712
2733
|
if ((request.expectedVersion ?? null) !== (existing?.version ?? null)) {
|
|
2713
2734
|
return mockFailure('assistant-version-conflict');
|
|
2714
2735
|
}
|
|
@@ -2729,7 +2750,8 @@ class NhAssistantMockRunConfiguration {
|
|
|
2729
2750
|
changedBy: 'current-user',
|
|
2730
2751
|
reason: text(request.reason),
|
|
2731
2752
|
inEffect: true,
|
|
2732
|
-
problem: null
|
|
2753
|
+
problem: null,
|
|
2754
|
+
filters: schedule ? [] : filters
|
|
2733
2755
|
};
|
|
2734
2756
|
this.triggers.set(triggerId, Object.assign(saved, { [ownerKey]: agent.id }));
|
|
2735
2757
|
return { status: 200, body: withoutOwner(saved) };
|
|
@@ -3653,7 +3675,7 @@ class NhAssistantMockAgentRuns {
|
|
|
3653
3675
|
result: this.answerOf(found.run.id, language),
|
|
3654
3676
|
resultTruncated: this.truncated.has(found.run.id),
|
|
3655
3677
|
summary: found.run.summary,
|
|
3656
|
-
proposals: [],
|
|
3678
|
+
proposals: this.context.runProposals?.(found.run.id) ?? [],
|
|
3657
3679
|
hiddenProposals: 0,
|
|
3658
3680
|
artifacts: [],
|
|
3659
3681
|
canOpenConversation: this.mayView(found.thread, language)
|
|
@@ -4388,7 +4410,7 @@ const maxGroupId = 64;
|
|
|
4388
4410
|
const maxGroups = 100;
|
|
4389
4411
|
const maxName = 100;
|
|
4390
4412
|
const maxDescription = 300;
|
|
4391
|
-
const guid = /^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/i;
|
|
4413
|
+
const guid$1 = /^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/i;
|
|
4392
4414
|
/**
|
|
4393
4415
|
* Groups and boards of the mock API (K15, K16), as the server serves them: the scenario's
|
|
4394
4416
|
* `agentGroups` are the groups in code with their names per language, checked as the server checks
|
|
@@ -4515,7 +4537,7 @@ class NhAssistantMockBoards {
|
|
|
4515
4537
|
}
|
|
4516
4538
|
const groupId = segments[1];
|
|
4517
4539
|
const divisionId = query.get('divisionId');
|
|
4518
|
-
if (divisionId !== null && divisionId !== '' && !guid.test(divisionId)) {
|
|
4540
|
+
if (divisionId !== null && divisionId !== '' && !guid$1.test(divisionId)) {
|
|
4519
4541
|
return mockFailure('assistant-board-scope-invalid');
|
|
4520
4542
|
}
|
|
4521
4543
|
const division = divisionId ? this.division(divisionId, requested) : null;
|
|
@@ -4656,6 +4678,7 @@ const dashCase = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
|
|
|
4656
4678
|
const maxReason = 500;
|
|
4657
4679
|
const maxItemsPerPage = 100;
|
|
4658
4680
|
const maxBulkDecisions = 50;
|
|
4681
|
+
const guid = /^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/i;
|
|
4659
4682
|
const lifetimeMs = 3 * 24 * 60 * 60 * 1000;
|
|
4660
4683
|
/** The platform's subject type of the whole application. */
|
|
4661
4684
|
const systemType = 'nh-system';
|
|
@@ -4671,12 +4694,15 @@ const systemType = 'nh-system';
|
|
|
4671
4694
|
* answers `404` and deciding it `404 assistant-approval-not-found`.
|
|
4672
4695
|
*/
|
|
4673
4696
|
class NhAssistantMockProposals {
|
|
4674
|
-
constructor(scenario = [], actorId, now, mayDecideApplication = () => true, decided = () => undefined) {
|
|
4697
|
+
constructor(scenario = [], actorId, now, mayDecideApplication = () => true, decided = () => undefined, mayWorkIn = () => true) {
|
|
4675
4698
|
this.actorId = actorId;
|
|
4676
4699
|
this.now = now;
|
|
4677
4700
|
this.mayDecideApplication = mayDecideApplication;
|
|
4678
4701
|
this.decided = decided;
|
|
4702
|
+
this.mayWorkIn = mayWorkIn;
|
|
4679
4703
|
this.proposals = new Map();
|
|
4704
|
+
/** When the caller last looked at the inbox, by scope key. */
|
|
4705
|
+
this.visits = new Map();
|
|
4680
4706
|
const created = new Date(now()).getTime();
|
|
4681
4707
|
for (const item of scenario) {
|
|
4682
4708
|
if (this.proposals.has(item.approvalId)) {
|
|
@@ -4707,8 +4733,8 @@ class NhAssistantMockProposals {
|
|
|
4707
4733
|
mode: 'deferred',
|
|
4708
4734
|
policyId: null,
|
|
4709
4735
|
grantSource: 'agent',
|
|
4710
|
-
createdAt: new Date(created).toISOString(),
|
|
4711
|
-
expiresAt: new Date(created + lifetimeMs).toISOString(),
|
|
4736
|
+
createdAt: item.createdAt ?? new Date(created).toISOString(),
|
|
4737
|
+
expiresAt: item.expiresAt ?? new Date(Date.parse(item.createdAt ?? new Date(created).toISOString()) + lifetimeMs).toISOString(),
|
|
4712
4738
|
initiatorActorId: null,
|
|
4713
4739
|
decidedByActorId: null,
|
|
4714
4740
|
decidedAt: null,
|
|
@@ -4716,8 +4742,10 @@ class NhAssistantMockProposals {
|
|
|
4716
4742
|
executedAt: null,
|
|
4717
4743
|
rationale: item.rationale ?? null,
|
|
4718
4744
|
placedBy: item.placedBy ?? null,
|
|
4745
|
+
parent: item.parent ?? null,
|
|
4719
4746
|
canGiveFeedback: false
|
|
4720
4747
|
},
|
|
4748
|
+
divisionId: item.divisionId ?? null,
|
|
4721
4749
|
canDecide: item.canDecide ?? true,
|
|
4722
4750
|
reasonCode: item.canDecide === false ? item.reasonCode ?? 'assistant-approval-policy-denied' : null
|
|
4723
4751
|
});
|
|
@@ -4728,6 +4756,9 @@ class NhAssistantMockProposals {
|
|
|
4728
4756
|
if (segments.length === 2 && segments[1] === 'inbox') {
|
|
4729
4757
|
return method === 'GET' ? this.inbox(query) : { status: 405 };
|
|
4730
4758
|
}
|
|
4759
|
+
if (segments.length === 3 && segments[1] === 'inbox' && segments[2] === 'visit') {
|
|
4760
|
+
return method === 'POST' ? this.visit(query) : { status: 405 };
|
|
4761
|
+
}
|
|
4731
4762
|
if (segments.length === 2 && segments[1] === 'lookup') {
|
|
4732
4763
|
return method === 'POST' ? this.lookup(body) : { status: 405 };
|
|
4733
4764
|
}
|
|
@@ -4750,6 +4781,12 @@ class NhAssistantMockProposals {
|
|
|
4750
4781
|
.reverse();
|
|
4751
4782
|
return items.length === 0 ? null : items;
|
|
4752
4783
|
}
|
|
4784
|
+
/** The proposals of a run the caller may see, in the order the scenario lists them. */
|
|
4785
|
+
ofRun(runId) {
|
|
4786
|
+
return this.visible()
|
|
4787
|
+
.filter(item => item.proposal.runId === runId)
|
|
4788
|
+
.map(item => item.proposal);
|
|
4789
|
+
}
|
|
4753
4790
|
/** The pending proposals on a subject with the caller's right to decide each, earliest expiry first. */
|
|
4754
4791
|
openOfSubject(subjectType, subjectId) {
|
|
4755
4792
|
return this.visible()
|
|
@@ -4779,19 +4816,49 @@ class NhAssistantMockProposals {
|
|
|
4779
4816
|
}
|
|
4780
4817
|
const agentId = query.get('agentId');
|
|
4781
4818
|
const runId = query.get('runId');
|
|
4819
|
+
const divisionId = query.get('divisionId');
|
|
4820
|
+
if (divisionId !== null && !guid.test(divisionId)) {
|
|
4821
|
+
return { status: 400 };
|
|
4822
|
+
}
|
|
4823
|
+
const grouped = query.get('grouped') === 'true';
|
|
4782
4824
|
const items = this.visible()
|
|
4783
4825
|
.filter(item => item.proposal.status === 'pending' && item.canDecide)
|
|
4826
|
+
.filter(item => divisionId === null || sameGuid(item.divisionId, divisionId))
|
|
4784
4827
|
.map(item => item.proposal)
|
|
4785
4828
|
.filter(proposal => (subjectType === null || proposal.subjectType === subjectType)
|
|
4786
4829
|
&& (agentId === null || proposal.agentId === agentId)
|
|
4787
4830
|
&& (runId === null || proposal.runId === runId))
|
|
4788
4831
|
.sort((left, right) => left.expiresAt.localeCompare(right.expiresAt) || left.approvalId.localeCompare(right.approvalId));
|
|
4832
|
+
const ordered = grouped ? groupedOrder(items) : items;
|
|
4833
|
+
const offset = (page - 1) * itemsPerPage;
|
|
4834
|
+
const pageItems = ordered.slice(offset, offset + itemsPerPage);
|
|
4835
|
+
const scopeKey = scopeKeyOf(divisionId);
|
|
4836
|
+
const lastVisitedAt = this.visits.get(scopeKey) ?? null;
|
|
4789
4837
|
const body = {
|
|
4790
|
-
items:
|
|
4791
|
-
total: items.length
|
|
4838
|
+
items: pageItems,
|
|
4839
|
+
total: items.length,
|
|
4840
|
+
scopeKey,
|
|
4841
|
+
lastVisitedAt,
|
|
4842
|
+
newApprovalIds: pageItems
|
|
4843
|
+
.filter(proposal => lastVisitedAt === null || Date.parse(proposal.createdAt) > Date.parse(lastVisitedAt))
|
|
4844
|
+
.map(proposal => proposal.approvalId),
|
|
4845
|
+
groups: grouped ? groupsOf(ordered, offset, pageItems.length) : null
|
|
4792
4846
|
};
|
|
4793
4847
|
return { status: 200, body };
|
|
4794
4848
|
}
|
|
4849
|
+
/** `POST approvals/inbox/visit`: the whole inbox, or that of a division the caller works in. */
|
|
4850
|
+
visit(query) {
|
|
4851
|
+
const divisionId = query.get('divisionId');
|
|
4852
|
+
if (divisionId !== null && !guid.test(divisionId)) {
|
|
4853
|
+
return { status: 400 };
|
|
4854
|
+
}
|
|
4855
|
+
if (divisionId !== null && !this.mayWorkIn(divisionId)) {
|
|
4856
|
+
return mockFailure('assistant-subject-not-found');
|
|
4857
|
+
}
|
|
4858
|
+
const body = { scopeKey: scopeKeyOf(divisionId), visitedAt: this.now() };
|
|
4859
|
+
this.visits.set(body.scopeKey, body.visitedAt);
|
|
4860
|
+
return { status: 200, body };
|
|
4861
|
+
}
|
|
4795
4862
|
read(approvalId) {
|
|
4796
4863
|
const stored = this.find(approvalId);
|
|
4797
4864
|
return stored ? { status: 200, body: this.withRight(stored) } : mockFailure('assistant-approval-not-found');
|
|
@@ -4879,6 +4946,99 @@ class NhAssistantMockProposals {
|
|
|
4879
4946
|
};
|
|
4880
4947
|
}
|
|
4881
4948
|
}
|
|
4949
|
+
/** The scope of the inbox's visits: `global`, or the scope key of a division. */
|
|
4950
|
+
function scopeKeyOf(divisionId) {
|
|
4951
|
+
return divisionId === null ? 'global' : `division:${divisionId.replaceAll('-', '').toLowerCase()}`;
|
|
4952
|
+
}
|
|
4953
|
+
function sameGuid(left, right) {
|
|
4954
|
+
return left !== null && left.replaceAll('-', '').toLowerCase() === right.replaceAll('-', '').toLowerCase();
|
|
4955
|
+
}
|
|
4956
|
+
/** The group a proposal belongs to: its parent, or its own subject without one. */
|
|
4957
|
+
function groupKeyOf(proposal) {
|
|
4958
|
+
return proposal.parent
|
|
4959
|
+
? `${proposal.parent.subjectType}|${proposal.parent.subjectId}`
|
|
4960
|
+
: `${proposal.subjectType}|${proposal.subjectId}`;
|
|
4961
|
+
}
|
|
4962
|
+
function subjectKeyOf(proposal) {
|
|
4963
|
+
return `${groupKeyOf(proposal)}|${proposal.subjectType}|${proposal.subjectId}`;
|
|
4964
|
+
}
|
|
4965
|
+
function firstExpiries(items, key) {
|
|
4966
|
+
const first = new Map();
|
|
4967
|
+
for (const proposal of items) {
|
|
4968
|
+
const current = first.get(key(proposal));
|
|
4969
|
+
if (current === undefined || proposal.expiresAt < current) {
|
|
4970
|
+
first.set(key(proposal), proposal.expiresAt);
|
|
4971
|
+
}
|
|
4972
|
+
}
|
|
4973
|
+
return first;
|
|
4974
|
+
}
|
|
4975
|
+
/**
|
|
4976
|
+
* The order of the grouped inbox, as the server sorts: groups by their first expiry, a group's own
|
|
4977
|
+
* subject first, then its other subjects by their first expiry, one run's proposals together, then by
|
|
4978
|
+
* expiry.
|
|
4979
|
+
*/
|
|
4980
|
+
function groupedOrder(items) {
|
|
4981
|
+
const groups = firstExpiries(items, groupKeyOf);
|
|
4982
|
+
const subjects = firstExpiries(items, subjectKeyOf);
|
|
4983
|
+
const compare = (left, right) => (left < right ? -1 : left > right ? 1 : 0);
|
|
4984
|
+
return [...items].sort((left, right) => compare(groups.get(groupKeyOf(left)), groups.get(groupKeyOf(right)))
|
|
4985
|
+
|| compare(groupKeyOf(left), groupKeyOf(right))
|
|
4986
|
+
|| (left.parent ? 1 : 0) - (right.parent ? 1 : 0)
|
|
4987
|
+
|| compare(subjects.get(subjectKeyOf(left)), subjects.get(subjectKeyOf(right)))
|
|
4988
|
+
|| compare(subjectKeyOf(left), subjectKeyOf(right))
|
|
4989
|
+
|| (left.runId === null ? 1 : 0) - (right.runId === null ? 1 : 0)
|
|
4990
|
+
|| compare(left.runId ?? '', right.runId ?? '')
|
|
4991
|
+
|| compare(left.expiresAt, right.expiresAt)
|
|
4992
|
+
|| compare(left.approvalId, right.approvalId));
|
|
4993
|
+
}
|
|
4994
|
+
/** The groups of the page `ordered[offset, offset + count)`, with their totals and continuation. */
|
|
4995
|
+
function groupsOf(ordered, offset, count) {
|
|
4996
|
+
const page = ordered.slice(offset, offset + count);
|
|
4997
|
+
const previous = offset > 0 ? ordered[offset - 1] : undefined;
|
|
4998
|
+
const next = ordered[offset + count];
|
|
4999
|
+
const groups = [];
|
|
5000
|
+
for (let index = 0; index < page.length;) {
|
|
5001
|
+
const key = groupKeyOf(page[index]);
|
|
5002
|
+
let end = index;
|
|
5003
|
+
while (end < page.length && groupKeyOf(page[end]) === key) {
|
|
5004
|
+
end++;
|
|
5005
|
+
}
|
|
5006
|
+
const members = page.slice(index, end);
|
|
5007
|
+
const own = members.find(proposal => !proposal.parent);
|
|
5008
|
+
const parent = members.find(proposal => proposal.parent)?.parent ?? null;
|
|
5009
|
+
const subjects = [];
|
|
5010
|
+
for (let at = 0; at < members.length;) {
|
|
5011
|
+
const subjectKey = subjectKeyOf(members[at]);
|
|
5012
|
+
let stop = at;
|
|
5013
|
+
while (stop < members.length && subjectKeyOf(members[stop]) === subjectKey) {
|
|
5014
|
+
stop++;
|
|
5015
|
+
}
|
|
5016
|
+
subjects.push({
|
|
5017
|
+
subjectType: members[at].subjectType,
|
|
5018
|
+
subjectId: members[at].subjectId,
|
|
5019
|
+
count: stop - at,
|
|
5020
|
+
total: ordered.filter(proposal => subjectKeyOf(proposal) === subjectKey).length,
|
|
5021
|
+
continuesFromPreviousPage: index === 0 && at === 0 && previous !== undefined && subjectKeyOf(previous) === subjectKey,
|
|
5022
|
+
continuesOnNextPage: end === page.length && stop === members.length && next !== undefined && subjectKeyOf(next) === subjectKey
|
|
5023
|
+
});
|
|
5024
|
+
at = stop;
|
|
5025
|
+
}
|
|
5026
|
+
groups.push({
|
|
5027
|
+
subjectType: own?.subjectType ?? parent.subjectType,
|
|
5028
|
+
subjectId: own?.subjectId ?? parent.subjectId,
|
|
5029
|
+
displayName: own ? own.subjectDisplayName : parent.displayName,
|
|
5030
|
+
subjectTypeName: own ? own.subjectTypeName ?? null : parent.subjectTypeName ?? null,
|
|
5031
|
+
subjectLink: own ? own.subjectLink ?? null : parent.subjectLink ?? null,
|
|
5032
|
+
count: members.length,
|
|
5033
|
+
total: ordered.filter(proposal => groupKeyOf(proposal) === key).length,
|
|
5034
|
+
continuesFromPreviousPage: index === 0 && previous !== undefined && groupKeyOf(previous) === key,
|
|
5035
|
+
continuesOnNextPage: end === page.length && next !== undefined && groupKeyOf(next) === key,
|
|
5036
|
+
subjects
|
|
5037
|
+
});
|
|
5038
|
+
index = end;
|
|
5039
|
+
}
|
|
5040
|
+
return groups;
|
|
5041
|
+
}
|
|
4882
5042
|
function validDecision(request) {
|
|
4883
5043
|
return !!request
|
|
4884
5044
|
&& (request.decision === 'approve' || request.decision === 'reject')
|
|
@@ -4946,12 +5106,13 @@ class NhAssistantMockBackend {
|
|
|
4946
5106
|
runId: proposal.runId,
|
|
4947
5107
|
subjectType: proposal.subjectType,
|
|
4948
5108
|
subjectId: proposal.subjectId
|
|
4949
|
-
}, proposal.agentId));
|
|
5109
|
+
}, proposal.agentId), (divisionId) => this.subjects.describe(mockSystemSubjectType, divisionSubjectId({ id: divisionId, name: '' }), null, this.admin.administers) != null);
|
|
4950
5110
|
this.subjects = new NhAssistantMockSubjects(this.scenario.subjectTypes, this.scenario.divisions, (type, id) => this.proposals.openOfSubject(type, id));
|
|
4951
5111
|
this.agentRuns = new NhAssistantMockAgentRuns(this.scenario, this.subjects, {
|
|
4952
5112
|
agents: () => this.admin.allAgents(),
|
|
4953
5113
|
administers: () => this.admin.administers,
|
|
4954
5114
|
threadProposals: conversationId => this.proposals.ofThread(conversationId),
|
|
5115
|
+
runProposals: runId => this.proposals.ofRun(runId),
|
|
4955
5116
|
workChanged: (change, agentId) => this.publishAgentWork(change, agentId)
|
|
4956
5117
|
}, () => new Date().toISOString());
|
|
4957
5118
|
this.boards = new NhAssistantMockBoards(this.scenario, this.subjects, this.agentRuns, {
|