@arcgis/portal-components 5.2.0-next.53 → 5.2.0-next.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cdn/{BZRUGC5P.js → 2WEWH5G3.js} +1 -1
- package/dist/cdn/{POIXW2OA.js → 5DE3XVTY.js} +1 -1
- package/dist/cdn/{75N65DHR.js → C2DREZD4.js} +1 -1
- package/dist/cdn/{F3G5N2UU.js → C4UBEDKI.js} +1 -1
- package/dist/cdn/DHD74RG3.js +619 -0
- package/dist/cdn/{DZJMNZY6.js → IZOGASBD.js} +1 -1
- package/dist/cdn/{XVFCF4AX.js → NADYAODN.js} +34 -34
- package/dist/cdn/index.js +1 -1
- package/dist/chunks/utils.js +13 -9
- package/dist/components/arcgis-portal-ai-assistant/customElement.js +562 -554
- package/dist/docs/api.json +1 -1
- package/dist/docs/docs.json +1 -1
- package/dist/docs/web-types.json +1 -1
- package/package.json +5 -6
- package/dist/cdn/AGVSKS3A.js +0 -645
|
@@ -1,151 +1,175 @@
|
|
|
1
1
|
/* COPYRIGHT Esri - https://js.arcgis.com/5.2/LICENSE.txt */
|
|
2
|
-
import { c as
|
|
3
|
-
import { LitElement as
|
|
4
|
-
import { css as
|
|
5
|
-
import { createRef as
|
|
6
|
-
import { u as
|
|
7
|
-
import { a as
|
|
8
|
-
import { NodeInterrupt as
|
|
9
|
-
import { sendTraceMessage as g, invokeStructuredPrompt as
|
|
10
|
-
import
|
|
11
|
-
import { a as
|
|
12
|
-
import
|
|
13
|
-
import
|
|
14
|
-
import { ChatPromptTemplate as
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const { portal: t, user: e } = s ?? {};
|
|
22
|
-
return !!s && !!t && !!e;
|
|
2
|
+
import { c as pt } from "../../chunks/runtime.js";
|
|
3
|
+
import { LitElement as dt, createEvent as mt } from "@arcgis/lumina";
|
|
4
|
+
import { css as gt, render as ht, html as M } from "lit";
|
|
5
|
+
import { createRef as T, ref as A } from "lit/directives/ref.js";
|
|
6
|
+
import { u as ft } from "../../chunks/useT9n.js";
|
|
7
|
+
import { a as C, t as yt, b as wt } from "../../chunks/functionalities.js";
|
|
8
|
+
import { NodeInterrupt as Y, Annotation as y, StateGraph as N, START as P, END as w } from "@langchain/langgraph/web";
|
|
9
|
+
import { sendTraceMessage as g, invokeStructuredPrompt as v, sendUXSuggestion as E, createAgentRuntimeStateWithSharedState as k, createChatModel as D } from "@arcgis/ai-components/utils/index.js";
|
|
10
|
+
import n from "zod";
|
|
11
|
+
import { a as bt, c as vt, q as It } from "../../chunks/groups2.js";
|
|
12
|
+
import xt from "@arcgis/core/identity/IdentityManager.js";
|
|
13
|
+
import F from "@arcgis/core/request.js";
|
|
14
|
+
import { ChatPromptTemplate as U } from "@langchain/core/prompts";
|
|
15
|
+
import { tool as _ } from "@langchain/core/tools";
|
|
16
|
+
import { s as St, a as Mt } from "../../chunks/item.js";
|
|
17
|
+
import { c as Gt, d as Tt, i as At, b as Ct, g as Nt } from "../../chunks/groups.js";
|
|
18
|
+
const H = (a) => {
|
|
19
|
+
const { portal: t, user: e } = a ?? {};
|
|
20
|
+
return !!a && !!t && !!e;
|
|
23
21
|
};
|
|
24
|
-
function
|
|
25
|
-
if (!
|
|
22
|
+
function I(a) {
|
|
23
|
+
if (!H(a))
|
|
26
24
|
throw new Error("Invalid context: PortalAssistantContext with portal and user is required.");
|
|
27
25
|
}
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
const Pt = `
|
|
27
|
+
Write a concise, friendly success message for adding members to a group.
|
|
28
|
+
|
|
29
|
+
Rules:
|
|
30
|
+
- Keep it to 1-2 short sentences.
|
|
31
|
+
- Use plain text only.
|
|
32
|
+
- If there is no notAddedMembers, confirm that all requested members were added successfully.
|
|
33
|
+
- If there are notAddedMembers, acknowledge that some members could not be added and list the added and not added members separately then mention why based on the context
|
|
34
|
+
- Make sure to bold the usernames
|
|
35
|
+
|
|
36
|
+
Added members:
|
|
37
|
+
{addedMembers}
|
|
38
|
+
|
|
39
|
+
Not added members:
|
|
40
|
+
{notAddedMembers}
|
|
41
|
+
`, kt = (a) => a.map((t) => `"${t}"`).join(", "), zt = n.object({
|
|
42
|
+
successMessage: n.string().default("")
|
|
43
|
+
}), V = "portal-group-creation", j = "approveAddMembers", qt = async (a, t) => {
|
|
44
|
+
if (a.intentParams.intent !== "addMembers")
|
|
32
45
|
return {
|
|
33
46
|
status: "success",
|
|
34
47
|
outputMessage: "Use @mention usernames for the members you want to add."
|
|
35
48
|
};
|
|
36
|
-
const e =
|
|
49
|
+
const e = a.agentExecutionContext.sharedState.createdGroupId?.value;
|
|
37
50
|
if (!e)
|
|
38
51
|
return {
|
|
39
52
|
status: "success",
|
|
40
53
|
outputMessage: "Create a group first, then add members using @mention usernames."
|
|
41
54
|
};
|
|
42
|
-
const
|
|
43
|
-
if (!
|
|
55
|
+
const s = a.intentParams.memberInfo.memberIdentifiers.map((d) => d.trim()).filter(Boolean);
|
|
56
|
+
if (!s.length)
|
|
44
57
|
return {
|
|
45
58
|
status: "success",
|
|
46
59
|
outputMessage: "Use @mention usernames for the members you want to add."
|
|
47
60
|
};
|
|
48
|
-
const
|
|
61
|
+
const l = `The following member(s) will be added to the newly created group:
|
|
49
62
|
|
|
50
|
-
${
|
|
63
|
+
${s.map((d) => `- **@${d}**`).join(`
|
|
51
64
|
`)}
|
|
52
65
|
|
|
53
|
-
Do you want to continue?`, { hitlResponse:
|
|
54
|
-
if (
|
|
66
|
+
Do you want to continue?`, { hitlResponse: c } = t?.configurable ?? {};
|
|
67
|
+
if (c?.agentId !== V || c.id !== j) {
|
|
55
68
|
const d = {
|
|
56
69
|
agentId: V,
|
|
57
70
|
id: j,
|
|
58
71
|
kind: "booleanChoice",
|
|
59
|
-
message:
|
|
72
|
+
message: l,
|
|
60
73
|
metadata: {
|
|
61
74
|
action: "addMembers",
|
|
62
75
|
groupId: e,
|
|
63
|
-
members: [...
|
|
76
|
+
members: [...s]
|
|
64
77
|
}
|
|
65
78
|
};
|
|
66
|
-
throw new
|
|
79
|
+
throw new Y(d);
|
|
67
80
|
}
|
|
68
|
-
if (
|
|
81
|
+
if (c.payload !== !0)
|
|
69
82
|
return {
|
|
70
83
|
status: "success",
|
|
71
84
|
outputMessage: "Okay, I cancelled adding members to the group."
|
|
72
85
|
};
|
|
73
86
|
await g(
|
|
74
|
-
{ text: `Adding members ${
|
|
87
|
+
{ text: `Adding members ${kt(s)}...`, agentName: "group-creation" },
|
|
75
88
|
t
|
|
76
89
|
);
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
const { result:
|
|
80
|
-
if (
|
|
90
|
+
const i = t?.configurable?.context;
|
|
91
|
+
I(i);
|
|
92
|
+
const { result: u, error: r } = await bt(i.portal, e, s);
|
|
93
|
+
if (r || !u)
|
|
81
94
|
return {
|
|
82
95
|
status: "success",
|
|
83
96
|
outputMessage: "I could not add members to that group. Please confirm group access and user accounts, then try again."
|
|
84
97
|
};
|
|
85
|
-
const { addedUsernames: p, notAddedUsers: m } =
|
|
98
|
+
const { addedUsernames: p, notAddedUsers: m } = u;
|
|
86
99
|
try {
|
|
87
|
-
const
|
|
88
|
-
promptText:
|
|
89
|
-
schema:
|
|
100
|
+
const h = (await v({
|
|
101
|
+
promptText: Pt,
|
|
102
|
+
schema: zt,
|
|
90
103
|
modelTier: "fast",
|
|
91
104
|
inputVariables: {
|
|
92
105
|
addedMembers: p.join(", "),
|
|
93
106
|
notAddedMembers: JSON.stringify(
|
|
94
|
-
m.map((
|
|
107
|
+
m.map((f) => ({ username: f.username, reason: f.error.message }))
|
|
95
108
|
)
|
|
96
109
|
}
|
|
97
110
|
})).successMessage;
|
|
98
|
-
if (
|
|
99
|
-
return { status: "success", outputMessage:
|
|
111
|
+
if (h)
|
|
112
|
+
return { status: "success", outputMessage: h };
|
|
100
113
|
} catch (d) {
|
|
101
114
|
console.error("Error generating add-members success message:", d);
|
|
102
115
|
}
|
|
103
116
|
return {};
|
|
104
|
-
},
|
|
105
|
-
Write a concise, friendly success message
|
|
117
|
+
}, $t = `
|
|
118
|
+
Write a concise, friendly success message after creating a portal group.
|
|
119
|
+
|
|
120
|
+
Rules:
|
|
121
|
+
- Mention that the group was created successfully.
|
|
122
|
+
- Mention that the user can add members by using @mention usernames.
|
|
123
|
+
- Keep it to 1-2 short sentences.
|
|
124
|
+
- Make sure to bold the group title in the message.
|
|
125
|
+
|
|
126
|
+
Group title:
|
|
127
|
+
{groupTitle}
|
|
128
|
+
`, Et = `
|
|
129
|
+
Write a concise, friendly failure message after an attempt to create a portal group.
|
|
106
130
|
|
|
107
131
|
Rules:
|
|
108
132
|
- Keep it to 1-2 short sentences.
|
|
109
133
|
- Use plain text only.
|
|
110
|
-
-
|
|
111
|
-
-
|
|
112
|
-
-
|
|
134
|
+
- Mention that group creation failed.
|
|
135
|
+
- Include the failure reason in user-friendly language.
|
|
136
|
+
- End with a clear next step the user can try.
|
|
113
137
|
|
|
114
|
-
|
|
115
|
-
{
|
|
138
|
+
Group title:
|
|
139
|
+
{groupTitle}
|
|
116
140
|
|
|
117
|
-
|
|
118
|
-
{
|
|
119
|
-
`, L = "portal-group-creation", B = "approveCreateGroup",
|
|
120
|
-
successMessage:
|
|
121
|
-
}),
|
|
122
|
-
failureMessage:
|
|
123
|
-
}),
|
|
124
|
-
if (
|
|
141
|
+
Failure reason:
|
|
142
|
+
{failureReason}
|
|
143
|
+
`, L = "portal-group-creation", B = "approveCreateGroup", Dt = n.object({
|
|
144
|
+
successMessage: n.string().default("")
|
|
145
|
+
}), Ut = n.object({
|
|
146
|
+
failureMessage: n.string().default("")
|
|
147
|
+
}), Rt = async (a, t) => {
|
|
148
|
+
if (a.intentParams.intent !== "create")
|
|
125
149
|
return {
|
|
126
150
|
status: "success",
|
|
127
151
|
outputMessage: "Tell me the group title you want to use."
|
|
128
152
|
};
|
|
129
|
-
const e =
|
|
153
|
+
const e = a.intentParams.title.trim();
|
|
130
154
|
if (!e)
|
|
131
155
|
return {
|
|
132
156
|
status: "success",
|
|
133
157
|
outputMessage: "What title would you like for the new group?"
|
|
134
158
|
};
|
|
135
|
-
const
|
|
159
|
+
const s = `A group with the title **${e}** will be created. Do you want to continue?`, { hitlResponse: o } = t?.configurable;
|
|
136
160
|
if (o?.agentId !== L || o.id !== B) {
|
|
137
|
-
const
|
|
161
|
+
const r = {
|
|
138
162
|
agentId: L,
|
|
139
163
|
id: B,
|
|
140
164
|
kind: "booleanChoice",
|
|
141
|
-
message:
|
|
165
|
+
message: s,
|
|
142
166
|
metadata: {
|
|
143
167
|
action: "createGroup",
|
|
144
168
|
title: e,
|
|
145
169
|
access: "private"
|
|
146
170
|
}
|
|
147
171
|
};
|
|
148
|
-
throw new
|
|
172
|
+
throw new Y(r);
|
|
149
173
|
}
|
|
150
174
|
if (o.payload !== !0)
|
|
151
175
|
return {
|
|
@@ -153,22 +177,22 @@ Not added members:
|
|
|
153
177
|
outputMessage: `Okay, I cancelled creating **${e}**.`
|
|
154
178
|
};
|
|
155
179
|
await g({ text: `Creating group "${e}"...`, agentName: "group-creation" }, t);
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
const { result:
|
|
180
|
+
const l = t?.configurable?.context;
|
|
181
|
+
I(l);
|
|
182
|
+
const { result: c, error: i } = await vt(l.portal, {
|
|
159
183
|
title: e,
|
|
160
184
|
access: "private"
|
|
161
185
|
});
|
|
162
|
-
if (
|
|
163
|
-
const
|
|
186
|
+
if (i || !c) {
|
|
187
|
+
const r = i?.message?.trim() || "No additional details were provided.";
|
|
164
188
|
try {
|
|
165
|
-
const m = (await
|
|
166
|
-
promptText:
|
|
167
|
-
schema:
|
|
189
|
+
const m = (await v({
|
|
190
|
+
promptText: Et,
|
|
191
|
+
schema: Ut,
|
|
168
192
|
modelTier: "fast",
|
|
169
193
|
inputVariables: {
|
|
170
194
|
groupTitle: e,
|
|
171
|
-
failureReason:
|
|
195
|
+
failureReason: r
|
|
172
196
|
}
|
|
173
197
|
})).failureMessage.trim();
|
|
174
198
|
if (m)
|
|
@@ -184,11 +208,11 @@ Not added members:
|
|
|
184
208
|
outputMessage: "I could not create that group. Please confirm your permissions and try again with the group title."
|
|
185
209
|
};
|
|
186
210
|
}
|
|
187
|
-
const
|
|
211
|
+
const u = c.id;
|
|
188
212
|
try {
|
|
189
|
-
const p = (await
|
|
190
|
-
promptText:
|
|
191
|
-
schema:
|
|
213
|
+
const p = (await v({
|
|
214
|
+
promptText: $t,
|
|
215
|
+
schema: Dt,
|
|
192
216
|
modelTier: "fast",
|
|
193
217
|
inputVariables: {
|
|
194
218
|
groupTitle: e
|
|
@@ -198,71 +222,27 @@ Not added members:
|
|
|
198
222
|
return {
|
|
199
223
|
status: "success",
|
|
200
224
|
outputMessage: p,
|
|
201
|
-
sharedStatePatch: { createdGroupId: { value:
|
|
202
|
-
createdGroupId:
|
|
225
|
+
sharedStatePatch: { createdGroupId: { value: u } },
|
|
226
|
+
createdGroupId: u
|
|
203
227
|
};
|
|
204
|
-
} catch (
|
|
205
|
-
console.error("Error generating create-group success message:",
|
|
228
|
+
} catch (r) {
|
|
229
|
+
console.error("Error generating create-group success message:", r);
|
|
206
230
|
}
|
|
207
231
|
return {};
|
|
208
|
-
},
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
Rules:
|
|
212
|
-
- Mention that the group was created successfully.
|
|
213
|
-
- Mention that the user can add members by using @mention usernames.
|
|
214
|
-
- Keep it to 1-2 short sentences.
|
|
215
|
-
- Make sure to bold the group title in the message.
|
|
216
|
-
|
|
217
|
-
Group title:
|
|
218
|
-
{groupTitle}
|
|
219
|
-
`, Ut = `
|
|
220
|
-
Write a concise, friendly failure message after an attempt to create a portal group.
|
|
221
|
-
|
|
222
|
-
Rules:
|
|
223
|
-
- Keep it to 1-2 short sentences.
|
|
224
|
-
- Use plain text only.
|
|
225
|
-
- Mention that group creation failed.
|
|
226
|
-
- Include the failure reason in user-friendly language.
|
|
227
|
-
- End with a clear next step the user can try.
|
|
228
|
-
|
|
229
|
-
Group title:
|
|
230
|
-
{groupTitle}
|
|
231
|
-
|
|
232
|
-
Failure reason:
|
|
233
|
-
{failureReason}
|
|
234
|
-
`, I = (s) => {
|
|
235
|
-
for (let t = s.length - 1; t >= 0; t -= 1) {
|
|
236
|
-
const e = s[t];
|
|
232
|
+
}, x = (a) => {
|
|
233
|
+
for (let t = a.length - 1; t >= 0; t -= 1) {
|
|
234
|
+
const e = a[t];
|
|
237
235
|
if (e.type !== "human")
|
|
238
236
|
continue;
|
|
239
|
-
const
|
|
240
|
-
if (typeof
|
|
241
|
-
return
|
|
242
|
-
if (Array.isArray(
|
|
243
|
-
return
|
|
237
|
+
const s = e.content;
|
|
238
|
+
if (typeof s == "string")
|
|
239
|
+
return s;
|
|
240
|
+
if (Array.isArray(s))
|
|
241
|
+
return s.map(
|
|
244
242
|
(o) => typeof o == "string" ? o : "text" in o && typeof o.text == "string" ? o.text : ""
|
|
245
243
|
).join(" ").trim();
|
|
246
244
|
}
|
|
247
245
|
return "";
|
|
248
|
-
}, Rt = r.object({
|
|
249
|
-
intent: r.enum(["clarify", "create", "addMembers"]).default("clarify"),
|
|
250
|
-
title: r.string().default(""),
|
|
251
|
-
memberIdentifiers: r.array(r.string()).default([]),
|
|
252
|
-
clarifyMessage: r.string().default("")
|
|
253
|
-
}), Ft = async (s, t) => {
|
|
254
|
-
await g({ text: "Thinking about groups...", agentName: "group-creation" }, t);
|
|
255
|
-
const e = I(s.agentExecutionContext.messages).trim(), a = await b({
|
|
256
|
-
promptText: Ot,
|
|
257
|
-
schema: Rt,
|
|
258
|
-
modelTier: "default",
|
|
259
|
-
inputVariables: { userMessage: e }
|
|
260
|
-
}), o = a.title.trim(), i = a.memberIdentifiers.filter(Boolean), u = a.clarifyMessage.trim(), l = a.intent === "create" && !!o, c = a.intent === "addMembers" && i.length > 0;
|
|
261
|
-
return {
|
|
262
|
-
intentParams: l ? { intent: "create", title: o } : c ? { intent: "addMembers", memberInfo: { memberIdentifiers: i } } : { intent: "clarify" },
|
|
263
|
-
status: "success",
|
|
264
|
-
outputMessage: !l && !c ? u : ""
|
|
265
|
-
};
|
|
266
246
|
}, Ot = `
|
|
267
247
|
You classify whether a user is asking to create a new ArcGIS Portal group or add members to an existing group.
|
|
268
248
|
|
|
@@ -289,7 +269,25 @@ Examples:
|
|
|
289
269
|
|
|
290
270
|
User message:
|
|
291
271
|
{userMessage}
|
|
292
|
-
`,
|
|
272
|
+
`, Ft = n.object({
|
|
273
|
+
intent: n.enum(["clarify", "create", "addMembers"]).default("clarify"),
|
|
274
|
+
title: n.string().default(""),
|
|
275
|
+
memberIdentifiers: n.array(n.string()).default([]),
|
|
276
|
+
clarifyMessage: n.string().default("")
|
|
277
|
+
}), Vt = async (a, t) => {
|
|
278
|
+
await g({ text: "Thinking about groups...", agentName: "group-creation" }, t);
|
|
279
|
+
const e = x(a.agentExecutionContext.messages).trim(), s = await v({
|
|
280
|
+
promptText: Ot,
|
|
281
|
+
schema: Ft,
|
|
282
|
+
modelTier: "default",
|
|
283
|
+
inputVariables: { userMessage: e }
|
|
284
|
+
}), o = s.title.trim(), l = s.memberIdentifiers.filter(Boolean), c = s.clarifyMessage.trim(), i = s.intent === "create" && !!o, u = s.intent === "addMembers" && l.length > 0;
|
|
285
|
+
return {
|
|
286
|
+
intentParams: i ? { intent: "create", title: o } : u ? { intent: "addMembers", memberInfo: { memberIdentifiers: l } } : { intent: "clarify" },
|
|
287
|
+
status: "success",
|
|
288
|
+
outputMessage: !i && !u ? c : ""
|
|
289
|
+
};
|
|
290
|
+
}, jt = n.enum([
|
|
293
291
|
"portal-content",
|
|
294
292
|
"portal-content-favorites",
|
|
295
293
|
"portal-content-group",
|
|
@@ -304,158 +302,158 @@ User message:
|
|
|
304
302
|
"portal-notebooks",
|
|
305
303
|
"portal-scene-viewer",
|
|
306
304
|
"portal-settings-security"
|
|
307
|
-
]),
|
|
308
|
-
destinationType:
|
|
309
|
-
}),
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
destinationType:
|
|
313
|
-
itemId:
|
|
305
|
+
]), Lt = n.object({
|
|
306
|
+
destinationType: jt
|
|
307
|
+
}), Bt = n.union([
|
|
308
|
+
Lt,
|
|
309
|
+
n.object({
|
|
310
|
+
destinationType: n.literal("portal-item"),
|
|
311
|
+
itemId: n.string().trim().min(1)
|
|
314
312
|
}),
|
|
315
|
-
|
|
316
|
-
destinationType:
|
|
317
|
-
groupId:
|
|
313
|
+
n.object({
|
|
314
|
+
destinationType: n.literal("portal-group"),
|
|
315
|
+
groupId: n.string().trim().min(1)
|
|
318
316
|
})
|
|
319
|
-
]),
|
|
317
|
+
]), X = "portal-navigation", R = async (a, t) => {
|
|
320
318
|
const e = t?.configurable?.context;
|
|
321
|
-
!
|
|
322
|
-
},
|
|
323
|
-
const e =
|
|
319
|
+
!H(e) || !e.navigationTargetMap?.[a.destinationType] || await E({ type: X, data: { ...a } }, t);
|
|
320
|
+
}, Qt = async (a, t) => {
|
|
321
|
+
const e = a.createdGroupId ?? a.agentExecutionContext.sharedState.createdGroupId?.value;
|
|
324
322
|
return e ? (await g({ text: "Preparing navigation...", agentName: "group-creation" }, t), await R({ destinationType: "portal-group", groupId: e }, t), {}) : {};
|
|
325
|
-
}, Q = (
|
|
326
|
-
...
|
|
323
|
+
}, Q = (a, t) => t ?? a, Z = y.Root({
|
|
324
|
+
...k(),
|
|
327
325
|
// * Shared state between nodes (but not persisted to the agent execution context)
|
|
328
326
|
/** Parameters related to the user's intent for group creation actions */
|
|
329
|
-
intentParams:
|
|
327
|
+
intentParams: y({ reducer: Q, default: () => ({ intent: "clarify" }) }),
|
|
330
328
|
/** The ID of the group that was created
|
|
331
329
|
* even though we already have this in the shared state
|
|
332
330
|
* we still need it here to also share between nodes
|
|
333
331
|
*/
|
|
334
|
-
createdGroupId:
|
|
335
|
-
}),
|
|
332
|
+
createdGroupId: y({ reducer: Q, default: () => "" })
|
|
333
|
+
}), Kt = () => new N(Z).addNode("detectGroupCreationIntent", Vt).addNode("createPortalGroup", Rt).addNode("addMembersToPortalGroup", qt).addNode("suggestCreatedGroupNavigation", Qt).addEdge(P, "detectGroupCreationIntent").addConditionalEdges("detectGroupCreationIntent", (t) => {
|
|
336
334
|
switch (t.intentParams.intent) {
|
|
337
335
|
case "create":
|
|
338
336
|
return "createPortalGroup";
|
|
339
337
|
case "addMembers":
|
|
340
338
|
return "addMembersToPortalGroup";
|
|
341
339
|
default:
|
|
342
|
-
return
|
|
340
|
+
return w;
|
|
343
341
|
}
|
|
344
|
-
}).addEdge("createPortalGroup", "suggestCreatedGroupNavigation").addEdge("addMembersToPortalGroup", "suggestCreatedGroupNavigation").addEdge("suggestCreatedGroupNavigation",
|
|
342
|
+
}).addEdge("createPortalGroup", "suggestCreatedGroupNavigation").addEdge("addMembersToPortalGroup", "suggestCreatedGroupNavigation").addEdge("suggestCreatedGroupNavigation", w), Jt = String.raw`- **portal-group-creation** - Portal group creation assistant:
|
|
345
343
|
- creates a new ArcGIS Portal group for the signed-in user
|
|
346
344
|
- adds users to the newly created group using @mention usernames
|
|
347
|
-
`,
|
|
345
|
+
`, Wt = {
|
|
348
346
|
id: "portal-group-creation",
|
|
349
347
|
name: "Portal Group Creation",
|
|
350
|
-
description:
|
|
351
|
-
createGraph:
|
|
352
|
-
workspace:
|
|
353
|
-
},
|
|
354
|
-
const t =
|
|
348
|
+
description: Jt,
|
|
349
|
+
createGraph: Kt,
|
|
350
|
+
workspace: Z
|
|
351
|
+
}, tt = "portalDocAssistantMemory", Yt = () => ({ conversationId: "" }), _t = (a) => {
|
|
352
|
+
const t = a?.[tt]?.value;
|
|
355
353
|
if (!t || typeof t != "object")
|
|
356
|
-
return
|
|
354
|
+
return Yt();
|
|
357
355
|
const e = t;
|
|
358
356
|
return {
|
|
359
357
|
conversationId: typeof e.conversationId == "string" ? e.conversationId : ""
|
|
360
358
|
};
|
|
361
|
-
},
|
|
362
|
-
[
|
|
359
|
+
}, Ht = (a) => ({
|
|
360
|
+
[tt]: { value: a }
|
|
363
361
|
});
|
|
364
|
-
async function
|
|
365
|
-
portal:
|
|
362
|
+
async function Xt({
|
|
363
|
+
portal: a,
|
|
366
364
|
question: t,
|
|
367
365
|
persona: e,
|
|
368
|
-
previousConversationId:
|
|
366
|
+
previousConversationId: s,
|
|
369
367
|
signal: o,
|
|
370
|
-
skillId:
|
|
368
|
+
skillId: l
|
|
371
369
|
}) {
|
|
372
|
-
|
|
373
|
-
const
|
|
374
|
-
portal:
|
|
375
|
-
skillId:
|
|
370
|
+
l ??= "doc_ai_assistant";
|
|
371
|
+
const i = await Zt({
|
|
372
|
+
portal: a,
|
|
373
|
+
skillId: l,
|
|
376
374
|
message: t,
|
|
377
375
|
options: { context: {
|
|
378
376
|
kind: "DocAIAssistantRequest",
|
|
379
377
|
filters: { persona: { persona: e } }
|
|
380
|
-
}, previousConversationId:
|
|
378
|
+
}, previousConversationId: s, signal: o }
|
|
381
379
|
});
|
|
382
380
|
return {
|
|
383
|
-
reply:
|
|
384
|
-
conversationId:
|
|
381
|
+
reply: te(i, l),
|
|
382
|
+
conversationId: i[0]?.conversationId ?? ""
|
|
385
383
|
};
|
|
386
384
|
}
|
|
387
|
-
async function
|
|
388
|
-
portal:
|
|
385
|
+
async function Zt({
|
|
386
|
+
portal: a,
|
|
389
387
|
skillId: t,
|
|
390
388
|
message: e,
|
|
391
|
-
options:
|
|
389
|
+
options: s
|
|
392
390
|
}) {
|
|
393
|
-
const
|
|
391
|
+
const l = `${a.helperServices.aiAssistantServices.url}/skills/${t}/chat`, c = {
|
|
394
392
|
"Content-Type": "application/json",
|
|
395
|
-
token:
|
|
396
|
-
},
|
|
393
|
+
token: xt.findCredential(a.url)?.token ?? ""
|
|
394
|
+
}, i = await F(l, {
|
|
397
395
|
method: "post",
|
|
398
396
|
body: JSON.stringify({
|
|
399
397
|
message: e,
|
|
400
|
-
context:
|
|
401
|
-
conversationId:
|
|
398
|
+
context: s.context,
|
|
399
|
+
conversationId: s.previousConversationId
|
|
402
400
|
}),
|
|
403
|
-
headers:
|
|
404
|
-
signal:
|
|
401
|
+
headers: c,
|
|
402
|
+
signal: s.signal
|
|
405
403
|
});
|
|
406
|
-
if (
|
|
407
|
-
throw new Error(`Doc assistant chat failed (${
|
|
408
|
-
cause:
|
|
404
|
+
if (i.httpStatus !== 200)
|
|
405
|
+
throw new Error(`Doc assistant chat failed (${i.httpStatus})`, {
|
|
406
|
+
cause: i.data
|
|
409
407
|
});
|
|
410
|
-
const
|
|
411
|
-
if (!
|
|
408
|
+
const u = i.data, r = [u], { conversationId: p, inquiryId: m } = u, d = async (h, f) => {
|
|
409
|
+
if (!f)
|
|
412
410
|
return;
|
|
413
|
-
await
|
|
414
|
-
const
|
|
411
|
+
await yt(1e3);
|
|
412
|
+
const b = await F(l, {
|
|
415
413
|
method: "post",
|
|
416
|
-
body: JSON.stringify({ conversationId: p, inquiryId: m, ackSequenceNumber:
|
|
417
|
-
headers:
|
|
418
|
-
signal:
|
|
414
|
+
body: JSON.stringify({ conversationId: p, inquiryId: m, ackSequenceNumber: h }),
|
|
415
|
+
headers: c,
|
|
416
|
+
signal: s.signal
|
|
419
417
|
});
|
|
420
|
-
if (
|
|
421
|
-
throw new Error(`Doc assistant poll failed (${
|
|
422
|
-
cause:
|
|
418
|
+
if (b.httpStatus !== 200)
|
|
419
|
+
throw new Error(`Doc assistant poll failed (${b.httpStatus})`, {
|
|
420
|
+
cause: b.data
|
|
423
421
|
});
|
|
424
|
-
const S =
|
|
425
|
-
|
|
422
|
+
const S = b.data;
|
|
423
|
+
r.push(S), await d(S.sequenceNumber, S.hasMore);
|
|
426
424
|
};
|
|
427
|
-
return
|
|
425
|
+
return u.hasMore && await d(u.sequenceNumber, u.hasMore), r;
|
|
428
426
|
}
|
|
429
|
-
function
|
|
427
|
+
function te(a, t) {
|
|
430
428
|
switch (t) {
|
|
431
429
|
case "doc_chat":
|
|
432
|
-
return
|
|
430
|
+
return a.find((e) => e.message != null)?.message ?? "";
|
|
433
431
|
case "doc_ai_assistant":
|
|
434
|
-
for (let e =
|
|
435
|
-
const
|
|
436
|
-
if (
|
|
437
|
-
const o =
|
|
432
|
+
for (let e = a.length - 1; e >= 0; e -= 1) {
|
|
433
|
+
const s = a[e];
|
|
434
|
+
if (s.context?.kind === "DocAIAssistantContext") {
|
|
435
|
+
const o = s.context.results?.[0]?.reply;
|
|
438
436
|
if (o)
|
|
439
437
|
return o;
|
|
440
438
|
}
|
|
441
439
|
}
|
|
442
440
|
return "";
|
|
443
441
|
default:
|
|
444
|
-
return
|
|
442
|
+
return C(t);
|
|
445
443
|
}
|
|
446
444
|
}
|
|
447
|
-
const
|
|
445
|
+
const ee = async (a, t) => {
|
|
448
446
|
await g({ text: "Asking documentation assistant...", agentName: "doc-assistant" }, t);
|
|
449
|
-
const e =
|
|
447
|
+
const e = x(a.agentExecutionContext.messages).trim();
|
|
450
448
|
if (!e)
|
|
451
449
|
return {
|
|
452
450
|
status: "success",
|
|
453
451
|
outputMessage: "Please share your question and I can help with ArcGIS and Portal documentation."
|
|
454
452
|
};
|
|
455
|
-
const
|
|
456
|
-
|
|
457
|
-
const o =
|
|
458
|
-
portal:
|
|
453
|
+
const s = t?.configurable?.context;
|
|
454
|
+
I(s);
|
|
455
|
+
const o = _t(a.agentExecutionContext.sharedState), { reply: l, conversationId: c } = await Xt({
|
|
456
|
+
portal: s.portal,
|
|
459
457
|
question: e,
|
|
460
458
|
previousConversationId: o.conversationId || void 0,
|
|
461
459
|
skillId: "doc_ai_assistant",
|
|
@@ -463,20 +461,20 @@ const te = async (s, t) => {
|
|
|
463
461
|
});
|
|
464
462
|
return {
|
|
465
463
|
status: "success",
|
|
466
|
-
outputMessage:
|
|
467
|
-
sharedStatePatch:
|
|
468
|
-
conversationId:
|
|
464
|
+
outputMessage: l.trim() || "I could not retrieve a response from the documentation assistant.",
|
|
465
|
+
sharedStatePatch: Ht({
|
|
466
|
+
conversationId: c || o.conversationId
|
|
469
467
|
})
|
|
470
468
|
};
|
|
471
|
-
},
|
|
472
|
-
async ({ groupTitle:
|
|
473
|
-
const e =
|
|
469
|
+
}, et = _(
|
|
470
|
+
async ({ groupTitle: a }, t) => {
|
|
471
|
+
const e = a.trim();
|
|
474
472
|
if (!e)
|
|
475
473
|
return null;
|
|
476
|
-
const
|
|
477
|
-
|
|
474
|
+
const s = t?.configurable?.context;
|
|
475
|
+
I(s);
|
|
478
476
|
try {
|
|
479
|
-
return (await
|
|
477
|
+
return (await It(s.portal, { query: `title:${e}`, num: 1 }))?.results[0]?.id || null;
|
|
480
478
|
} catch (o) {
|
|
481
479
|
return console.error("Error searching for portal group by title:", o), null;
|
|
482
480
|
}
|
|
@@ -484,28 +482,36 @@ const te = async (s, t) => {
|
|
|
484
482
|
{
|
|
485
483
|
name: "resolvePortalGroupIdByTitle",
|
|
486
484
|
description: "Resolves an ArcGIS Portal group title to the best-match group id. Use this when a user references a group by title instead of an explicit group id.",
|
|
487
|
-
schema:
|
|
488
|
-
groupTitle:
|
|
485
|
+
schema: n.object({
|
|
486
|
+
groupTitle: n.string().describe("The portal group title to resolve to a group id.")
|
|
489
487
|
})
|
|
490
488
|
}
|
|
491
|
-
),
|
|
492
|
-
async ({ itemTitle:
|
|
493
|
-
const e =
|
|
489
|
+
), at = _(
|
|
490
|
+
async ({ itemTitle: a }, t) => {
|
|
491
|
+
const e = a.trim();
|
|
494
492
|
if (!e)
|
|
495
493
|
return null;
|
|
496
|
-
const
|
|
497
|
-
|
|
498
|
-
const { result: o, error:
|
|
499
|
-
return
|
|
494
|
+
const s = t?.configurable?.context;
|
|
495
|
+
I(s);
|
|
496
|
+
const { result: o, error: l } = await St(s.portal, e, { num: 1 });
|
|
497
|
+
return l && console.error("Error searching for portal item by title:", l), o?.results[0]?.id || null;
|
|
500
498
|
},
|
|
501
499
|
{
|
|
502
500
|
name: "resolvePortalItemIdByTitle",
|
|
503
501
|
description: 'Resolves an ArcGIS Portal item title to the best-match item id. Use this when a user references an item by title (including hash mentions like #title or #"title with spaces") instead of an explicit item id.',
|
|
504
|
-
schema:
|
|
505
|
-
itemTitle:
|
|
502
|
+
schema: n.object({
|
|
503
|
+
itemTitle: n.string().describe("The portal item title to resolve to an item id.")
|
|
506
504
|
})
|
|
507
505
|
}
|
|
508
|
-
)
|
|
506
|
+
);
|
|
507
|
+
function G(a, t = "#") {
|
|
508
|
+
const e = a.match(new RegExp(`\\${t}"([^"]+)"`, "u"));
|
|
509
|
+
if (e?.[1])
|
|
510
|
+
return e[1].trim();
|
|
511
|
+
const s = a.match(new RegExp(`\\${t}([^\\s"']+)`, "u"));
|
|
512
|
+
return s?.[1] ? s[1].trim() : null;
|
|
513
|
+
}
|
|
514
|
+
const st = {
|
|
509
515
|
"portal-content": {
|
|
510
516
|
description: "The main content page of the portal.",
|
|
511
517
|
hints: ["My content", "Content"],
|
|
@@ -586,10 +592,10 @@ const te = async (s, t) => {
|
|
|
586
592
|
hints: ["Organization settings", "Security", "Organization > Settings > Security"],
|
|
587
593
|
scope: "entity"
|
|
588
594
|
}
|
|
589
|
-
},
|
|
590
|
-
([
|
|
595
|
+
}, ae = wt(st), se = Object.entries(st).map(
|
|
596
|
+
([a, { description: t, hints: e, scope: s }]) => ` - ${a}: ${t} (scope: ${s}; hints: ${e.join(", ")})`
|
|
591
597
|
).join(`
|
|
592
|
-
`),
|
|
598
|
+
`), oe = `
|
|
593
599
|
You decide whether the assistant response should include a navigation action to ArcGIS Portal.
|
|
594
600
|
|
|
595
601
|
Given the user question and assistant response:
|
|
@@ -618,38 +624,40 @@ User question:
|
|
|
618
624
|
|
|
619
625
|
Assistant response:
|
|
620
626
|
{response}
|
|
621
|
-
`, K =
|
|
622
|
-
shouldSuggestNavigation:
|
|
623
|
-
destinationType:
|
|
624
|
-
itemId:
|
|
625
|
-
groupId:
|
|
626
|
-
confidence:
|
|
627
|
-
}),
|
|
627
|
+
`, K = n.object({
|
|
628
|
+
shouldSuggestNavigation: n.boolean().default(!1),
|
|
629
|
+
destinationType: n.enum(["none", ...ae]).default("none"),
|
|
630
|
+
itemId: n.string().default(""),
|
|
631
|
+
groupId: n.string().default(""),
|
|
632
|
+
confidence: n.number().min(0).max(1).default(0)
|
|
633
|
+
}), re = async (a, t) => {
|
|
628
634
|
await g({ text: "Extracting navigation intent...", agentName: "doc-assistant" }, t);
|
|
629
|
-
const e =
|
|
635
|
+
const e = a.outputMessage.trim();
|
|
630
636
|
if (!e)
|
|
631
637
|
return {};
|
|
632
|
-
const
|
|
633
|
-
question:
|
|
638
|
+
const s = x(a.agentExecutionContext.messages).trim(), o = await U.fromTemplate(oe).format({
|
|
639
|
+
question: s,
|
|
634
640
|
response: e
|
|
635
|
-
}),
|
|
636
|
-
|
|
637
|
-
tools: [tt, Z],
|
|
638
|
-
systemPrompt: o,
|
|
639
|
-
responseFormat: K,
|
|
640
|
-
checkpointer: !0
|
|
641
|
-
}).invoke({ messages: s.agentExecutionContext.messages }, t), l = K.parse(u.structuredResponse ?? {});
|
|
642
|
-
if (!l.shouldSuggestNavigation || l.destinationType === "none")
|
|
641
|
+
}), c = (await D({ modelTier: "fast" })).withStructuredOutput(K), i = K.parse(await c.invoke(o));
|
|
642
|
+
if (!i.shouldSuggestNavigation || i.destinationType === "none")
|
|
643
643
|
return {};
|
|
644
|
-
|
|
645
|
-
|
|
644
|
+
if (i.destinationType === "portal-item" && !i.itemId) {
|
|
645
|
+
const r = G(s, "#");
|
|
646
|
+
r && (i.itemId = await at.invoke({ itemTitle: r }, t) ?? "");
|
|
647
|
+
}
|
|
648
|
+
if (i.destinationType === "portal-group" && !i.groupId) {
|
|
649
|
+
const r = G(s, "$") ?? G(s, "#");
|
|
650
|
+
r && (i.groupId = await et.invoke({ groupTitle: r }, t) ?? "");
|
|
651
|
+
}
|
|
652
|
+
const u = ne(i);
|
|
653
|
+
return u ? (await R(u, t), {}) : {};
|
|
646
654
|
};
|
|
647
|
-
function
|
|
648
|
-
destinationType:
|
|
655
|
+
function ne({
|
|
656
|
+
destinationType: a,
|
|
649
657
|
itemId: t,
|
|
650
658
|
groupId: e
|
|
651
659
|
}) {
|
|
652
|
-
switch (
|
|
660
|
+
switch (a) {
|
|
653
661
|
case "portal-content":
|
|
654
662
|
case "portal-content-favorites":
|
|
655
663
|
case "portal-content-group":
|
|
@@ -664,7 +672,7 @@ function re({
|
|
|
664
672
|
case "portal-notebooks":
|
|
665
673
|
case "portal-scene-viewer":
|
|
666
674
|
case "portal-settings-security":
|
|
667
|
-
return { destinationType:
|
|
675
|
+
return { destinationType: a };
|
|
668
676
|
case "portal-item":
|
|
669
677
|
return t ? { destinationType: "portal-item", itemId: t } : null;
|
|
670
678
|
case "portal-group":
|
|
@@ -672,56 +680,34 @@ function re({
|
|
|
672
680
|
case "none":
|
|
673
681
|
return null;
|
|
674
682
|
default:
|
|
675
|
-
return
|
|
683
|
+
return C(a);
|
|
676
684
|
}
|
|
677
685
|
}
|
|
678
|
-
const
|
|
679
|
-
...
|
|
680
|
-
}),
|
|
686
|
+
const ot = y.Root({
|
|
687
|
+
...k()
|
|
688
|
+
}), ie = () => new N(ot).addNode("answerDocQuestion", ee).addNode("extractNavigationIntent", re).addEdge(P, "answerDocQuestion").addEdge("answerDocQuestion", "extractNavigationIntent").addEdge("extractNavigationIntent", w), le = String.raw`- **portal-doc-assistant** - General ArcGIS documentation and Portal help assistant:
|
|
681
689
|
- answers general ArcGIS, Portal, Enterprise, and JavaScript SDK questions
|
|
682
690
|
- acts as a fallback when specialized agents are not applicable
|
|
683
|
-
`,
|
|
691
|
+
`, ue = {
|
|
684
692
|
id: "portal-doc-assistant",
|
|
685
693
|
name: "Portal Doc Assistant",
|
|
686
|
-
description:
|
|
687
|
-
createGraph:
|
|
688
|
-
workspace:
|
|
689
|
-
},
|
|
694
|
+
description: le,
|
|
695
|
+
createGraph: ie,
|
|
696
|
+
workspace: ot
|
|
697
|
+
}, ce = () => ({ latestGroupId: null, memory: {} }), z = (a) => {
|
|
698
|
+
const t = a?.agentExecutionContext.sharedState.portalGroupSummaryMemory?.value;
|
|
699
|
+
return t ? { latestGroupId: t.latestGroupId, memory: t.memory } : ce();
|
|
700
|
+
}, rt = `
|
|
690
701
|
Shared markdown formatting rules:
|
|
691
702
|
- Use clear markdown headings (##) to separate sections.
|
|
692
703
|
- Use concise bullet points for lists of facts, counts, or signals.
|
|
693
704
|
- Emphasize key metrics with bold labels (for example: **Recent items:** 4).
|
|
694
705
|
- Keep wording direct and analytical; avoid filler language but make sure the language is friendly.
|
|
695
706
|
- Do not include raw internal IDs unless explicitly requested.
|
|
696
|
-
`,
|
|
697
|
-
const t = s?.agentExecutionContext.sharedState.portalGroupSummaryMemory?.value;
|
|
698
|
-
return t ? { latestGroupId: t.latestGroupId, memory: t.memory } : ue();
|
|
699
|
-
}, ce = async (s, t) => {
|
|
700
|
-
await g({ text: "Answering group follow-up...", agentName: "group-analytics" }, t);
|
|
701
|
-
const e = k(s), a = s.groupSummaryGroupId ?? e.latestGroupId, o = a ? e.memory[a] : void 0, i = s.groupSummaryQuestion || I(s.agentExecutionContext.messages);
|
|
702
|
-
return o ? {
|
|
703
|
-
status: "success",
|
|
704
|
-
outputMessage: (await b({
|
|
705
|
-
promptText: de,
|
|
706
|
-
schema: pe,
|
|
707
|
-
modelTier: "default",
|
|
708
|
-
inputVariables: {
|
|
709
|
-
summary: o.summary,
|
|
710
|
-
question: i,
|
|
711
|
-
fullContext: JSON.stringify(o.fullContext)
|
|
712
|
-
}
|
|
713
|
-
})).answer
|
|
714
|
-
} : {
|
|
715
|
-
status: "success",
|
|
716
|
-
outputMessage: "I do not have group analytics context yet. Ask me to analyze a group first with analyze group <group id>."
|
|
717
|
-
};
|
|
718
|
-
}, pe = r.object({
|
|
719
|
-
answer: r.string(),
|
|
720
|
-
isRelevant: r.boolean()
|
|
721
|
-
}), de = `
|
|
707
|
+
`, pe = `
|
|
722
708
|
You answer follow-up questions about ArcGIS group analytics.
|
|
723
709
|
|
|
724
|
-
${
|
|
710
|
+
${rt}
|
|
725
711
|
|
|
726
712
|
Ground your answer in the provided group analytics summary and context.
|
|
727
713
|
If the answer is not available from the provided context, state that clearly and suggest what to check next.
|
|
@@ -743,30 +729,29 @@ Group full context:
|
|
|
743
729
|
|
|
744
730
|
Question:
|
|
745
731
|
{question}
|
|
746
|
-
`,
|
|
747
|
-
await g({ text: "
|
|
748
|
-
const e =
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
732
|
+
`, de = async (a, t) => {
|
|
733
|
+
await g({ text: "Answering group follow-up...", agentName: "group-analytics" }, t);
|
|
734
|
+
const e = z(a), s = a.groupSummaryGroupId ?? e.latestGroupId, o = s ? e.memory[s] : void 0, l = a.groupSummaryQuestion || x(a.agentExecutionContext.messages);
|
|
735
|
+
return o ? {
|
|
736
|
+
status: "success",
|
|
737
|
+
outputMessage: (await v({
|
|
738
|
+
promptText: pe,
|
|
739
|
+
schema: me,
|
|
740
|
+
modelTier: "default",
|
|
741
|
+
inputVariables: {
|
|
742
|
+
summary: o.summary,
|
|
743
|
+
question: l,
|
|
744
|
+
fullContext: JSON.stringify(o.fullContext)
|
|
745
|
+
}
|
|
746
|
+
})).answer
|
|
747
|
+
} : {
|
|
762
748
|
status: "success",
|
|
763
|
-
outputMessage:
|
|
749
|
+
outputMessage: "I do not have group analytics context yet. Ask me to analyze a group first with analyze group <group id>."
|
|
764
750
|
};
|
|
765
|
-
},
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
}), he = `
|
|
751
|
+
}, me = n.object({
|
|
752
|
+
answer: n.string(),
|
|
753
|
+
isRelevant: n.boolean()
|
|
754
|
+
}), ge = `
|
|
770
755
|
Classify the user's request for ArcGIS Portal group analytics.
|
|
771
756
|
|
|
772
757
|
Rules:
|
|
@@ -795,35 +780,58 @@ hasAnalyticsContext:
|
|
|
795
780
|
|
|
796
781
|
User message:
|
|
797
782
|
{userMessage}
|
|
798
|
-
`,
|
|
799
|
-
|
|
783
|
+
`, he = async (a, t) => {
|
|
784
|
+
await g({ text: "Analyzing group-analytics intent...", agentName: "group-analytics" }, t);
|
|
785
|
+
const e = x(a.agentExecutionContext.messages), s = !!z(a).latestGroupId, o = await U.fromTemplate(ge).format({
|
|
786
|
+
userMessage: e,
|
|
787
|
+
hasAnalyticsContext: String(s)
|
|
788
|
+
}), c = (await D({ modelTier: "fast" })).withStructuredOutput(J), i = J.parse(await c.invoke(o));
|
|
789
|
+
let u = i.groupId;
|
|
790
|
+
if ((i.intent === "summarize" || i.intent === "navigation") && !u) {
|
|
791
|
+
const f = G(e, "$");
|
|
792
|
+
f && (u = await et.invoke({ groupTitle: f }, t) ?? "");
|
|
793
|
+
}
|
|
794
|
+
const { intent: r, question: p } = i, m = r === "summarize" && !u, d = r === "followUp" && !(p ?? "").trim(), h = r === "clarify" || m || d;
|
|
795
|
+
return {
|
|
796
|
+
groupSummaryIntent: h ? "clarify" : r,
|
|
797
|
+
groupSummaryGroupId: u || null,
|
|
798
|
+
groupSummaryQuestion: p || "",
|
|
799
|
+
status: "success",
|
|
800
|
+
outputMessage: h ? "Please clarify with a group id or title" : ""
|
|
801
|
+
};
|
|
802
|
+
}, J = n.object({
|
|
803
|
+
intent: n.enum(["summarize", "followUp", "navigation", "clarify"]),
|
|
804
|
+
groupId: n.string().default(""),
|
|
805
|
+
question: n.string().default("")
|
|
806
|
+
}), fe = async (a, t) => {
|
|
807
|
+
const e = z(a), s = a.groupSummaryGroupId ?? e.latestGroupId;
|
|
800
808
|
return await g({ text: "Preparing navigation...", agentName: "group-analytics" }, t), await R(
|
|
801
|
-
|
|
809
|
+
s ? { destinationType: "portal-group", groupId: s } : { destinationType: "portal-groups" },
|
|
802
810
|
t
|
|
803
811
|
), { status: "success" };
|
|
804
812
|
};
|
|
805
|
-
function
|
|
806
|
-
return
|
|
813
|
+
function nt({ timestamp: a, now: t, windowMs: e }) {
|
|
814
|
+
return a ? t - a <= e : !1;
|
|
807
815
|
}
|
|
808
816
|
const ye = 720 * 60 * 60 * 1e3;
|
|
809
|
-
function we(
|
|
810
|
-
const t =
|
|
817
|
+
function we(a) {
|
|
818
|
+
const t = Gt(a);
|
|
811
819
|
return {
|
|
812
|
-
id:
|
|
813
|
-
title:
|
|
814
|
-
description:
|
|
815
|
-
snippet:
|
|
816
|
-
access:
|
|
817
|
-
owner:
|
|
818
|
-
tags:
|
|
819
|
-
created:
|
|
820
|
-
modified:
|
|
821
|
-
isInvitationOnly:
|
|
820
|
+
id: a.id ?? "",
|
|
821
|
+
title: a.title ?? "",
|
|
822
|
+
description: a.description ?? "",
|
|
823
|
+
snippet: a.snippet ?? "",
|
|
824
|
+
access: a.access ?? null,
|
|
825
|
+
owner: a.owner ?? "",
|
|
826
|
+
tags: a.tags ?? [],
|
|
827
|
+
created: a.created?.getTime(),
|
|
828
|
+
modified: a.modified?.getTime(),
|
|
829
|
+
isInvitationOnly: a.isInvitationOnly,
|
|
822
830
|
sourceSignals: {
|
|
823
|
-
capabilities:
|
|
824
|
-
membershipAccess:
|
|
825
|
-
isOpenData: At(
|
|
826
|
-
isDistributedCollaborationGroup:
|
|
831
|
+
capabilities: Nt(a),
|
|
832
|
+
membershipAccess: Ct(a),
|
|
833
|
+
isOpenData: At(a),
|
|
834
|
+
isDistributedCollaborationGroup: Tt(a),
|
|
827
835
|
orgId: t.orgId,
|
|
828
836
|
hiddenMembers: t.hiddenMembers,
|
|
829
837
|
isViewOnly: t.isViewOnly,
|
|
@@ -832,16 +840,16 @@ function we(s) {
|
|
|
832
840
|
}
|
|
833
841
|
};
|
|
834
842
|
}
|
|
835
|
-
async function be(
|
|
836
|
-
const t = { owner:
|
|
843
|
+
async function be(a) {
|
|
844
|
+
const t = { owner: a.owner ?? "", admins: [], users: [] };
|
|
837
845
|
try {
|
|
838
|
-
return await
|
|
846
|
+
return await a.fetchMembers();
|
|
839
847
|
} catch (e) {
|
|
840
848
|
return console.warn("Unable to fetch group members for analytics context", e), t;
|
|
841
849
|
}
|
|
842
850
|
}
|
|
843
|
-
function ve(
|
|
844
|
-
return
|
|
851
|
+
function ve(a) {
|
|
852
|
+
return a.map((t) => ({
|
|
845
853
|
id: t.id ?? "",
|
|
846
854
|
title: t.title ?? "Untitled",
|
|
847
855
|
type: t.type ?? "Unknown",
|
|
@@ -850,87 +858,43 @@ function ve(s) {
|
|
|
850
858
|
modified: t.modified?.getTime()
|
|
851
859
|
}));
|
|
852
860
|
}
|
|
853
|
-
function Ie(
|
|
854
|
-
return
|
|
855
|
-
(e) => e.modified ?
|
|
861
|
+
function Ie(a, t) {
|
|
862
|
+
return a.filter(
|
|
863
|
+
(e) => e.modified ? nt({ timestamp: e.modified, now: t, windowMs: ye }) : !1
|
|
856
864
|
);
|
|
857
865
|
}
|
|
858
|
-
function xe(
|
|
866
|
+
function xe(a) {
|
|
859
867
|
const t = /* @__PURE__ */ new Map();
|
|
860
|
-
for (const e of
|
|
868
|
+
for (const e of a)
|
|
861
869
|
t.set(e.type, (t.get(e.type) ?? 0) + 1);
|
|
862
|
-
return [...t.entries()].sort((e,
|
|
870
|
+
return [...t.entries()].sort((e, s) => s[1] - e[1] || e[0].localeCompare(s[0])).slice(0, 6).map(([e, s]) => ({ type: e, count: s }));
|
|
863
871
|
}
|
|
864
|
-
async function Se(
|
|
865
|
-
const t = await
|
|
872
|
+
async function Se(a) {
|
|
873
|
+
const t = await a.queryItems({ num: 20, sortField: "modified", sortOrder: "desc" }), e = ve(t.results), s = Date.now();
|
|
866
874
|
return {
|
|
867
875
|
total: t.total,
|
|
868
876
|
topItems: e,
|
|
869
|
-
recentlyModifiedItems: Ie(e,
|
|
877
|
+
recentlyModifiedItems: Ie(e, s),
|
|
870
878
|
topItemTypes: xe(e)
|
|
871
879
|
};
|
|
872
880
|
}
|
|
873
|
-
async function Me(
|
|
881
|
+
async function Me(a, t) {
|
|
874
882
|
if (!t)
|
|
875
883
|
return { error: { code: "missingGroupId", message: "Group id is required." } };
|
|
876
884
|
try {
|
|
877
|
-
const
|
|
878
|
-
if (!
|
|
885
|
+
const s = (await a.queryGroups({ query: `id:${t}`, num: 1 })).results[0];
|
|
886
|
+
if (!s)
|
|
879
887
|
return { error: { code: "groupNotFound", message: `No group found for id: ${t}` } };
|
|
880
|
-
const o = we(
|
|
881
|
-
return { result: { group: o, members:
|
|
888
|
+
const o = we(s), l = await be(s), c = await Se(s);
|
|
889
|
+
return { result: { group: o, members: l, items: c } };
|
|
882
890
|
} catch (e) {
|
|
883
891
|
return console.error("Error fetching portal group analytics context:", e), { error: { code: "unhandledError" } };
|
|
884
892
|
}
|
|
885
893
|
}
|
|
886
|
-
const Ge =
|
|
887
|
-
const e = s.groupSummaryGroupId;
|
|
888
|
-
if (!e)
|
|
889
|
-
return {
|
|
890
|
-
status: "success",
|
|
891
|
-
outputMessage: 'Please clarify with analyze group <group id>, analyze group $<title>, or analyze group $"<title with spaces>".'
|
|
892
|
-
};
|
|
893
|
-
await g({ text: `Analyzing group ${e}...`, agentName: "group-analytics" }, t);
|
|
894
|
-
const a = t?.configurable?.context;
|
|
895
|
-
v(a);
|
|
896
|
-
const { result: o, error: i } = await Me(a.portal, e);
|
|
897
|
-
if (i || !o)
|
|
898
|
-
return await g({ text: "Failed to fetch group context", agentName: "group-analytics" }, t), {
|
|
899
|
-
status: "success",
|
|
900
|
-
outputMessage: "Unable to retrieve group context for analytics."
|
|
901
|
-
};
|
|
902
|
-
const { group: u, items: l } = o, c = Date.now(), n = u.modified, p = n ? ot({ timestamp: n, now: c, windowMs: Ge }) : !1, m = l.recentlyModifiedItems.length, d = m > 0, y = p || d, x = await b({
|
|
903
|
-
promptText: Ce,
|
|
904
|
-
schema: Te,
|
|
905
|
-
modelTier: "default",
|
|
906
|
-
inputVariables: {
|
|
907
|
-
context: JSON.stringify(o),
|
|
908
|
-
deterministicSignals: JSON.stringify({
|
|
909
|
-
isGroupActive: y,
|
|
910
|
-
isGroupRecentlyModified: p,
|
|
911
|
-
hasRecentlyAddedOrUpdatedContent: d,
|
|
912
|
-
recentItemCount: m
|
|
913
|
-
})
|
|
914
|
-
}
|
|
915
|
-
}), { followUpQuestions: w, summary: S } = x, it = k(s), lt = {
|
|
916
|
-
latestGroupId: e,
|
|
917
|
-
memory: {
|
|
918
|
-
...it.memory,
|
|
919
|
-
[e]: { summary: S, followUpQuestions: w, fullContext: o }
|
|
920
|
-
}
|
|
921
|
-
};
|
|
922
|
-
return w.length && await $({ type: "suggested-prompts", data: { prompts: w } }, t), {
|
|
923
|
-
status: "success",
|
|
924
|
-
outputMessage: S,
|
|
925
|
-
sharedStatePatch: { portalGroupSummaryMemory: { value: lt } }
|
|
926
|
-
};
|
|
927
|
-
}, Te = r.object({
|
|
928
|
-
summary: r.string(),
|
|
929
|
-
followUpQuestions: r.array(r.string()).default([])
|
|
930
|
-
}), Ce = `
|
|
894
|
+
const Ge = `
|
|
931
895
|
You summarize ArcGIS Portal groups based on structured context and deterministic activity signals.
|
|
932
896
|
|
|
933
|
-
${
|
|
897
|
+
${rt}
|
|
934
898
|
|
|
935
899
|
Output format requirements:
|
|
936
900
|
- Return concise markdown with clear sections in this order:
|
|
@@ -966,21 +930,65 @@ Group context:
|
|
|
966
930
|
|
|
967
931
|
Deterministic signals:
|
|
968
932
|
{deterministicSignals}
|
|
969
|
-
`,
|
|
970
|
-
|
|
971
|
-
|
|
933
|
+
`, Te = 2160 * 60 * 60 * 1e3, Ae = async (a, t) => {
|
|
934
|
+
const e = a.groupSummaryGroupId;
|
|
935
|
+
if (!e)
|
|
936
|
+
return {
|
|
937
|
+
status: "success",
|
|
938
|
+
outputMessage: 'Please clarify with analyze group <group id>, analyze group $<title>, or analyze group $"<title with spaces>".'
|
|
939
|
+
};
|
|
940
|
+
await g({ text: `Analyzing group ${e}...`, agentName: "group-analytics" }, t);
|
|
941
|
+
const s = t?.configurable?.context;
|
|
942
|
+
I(s);
|
|
943
|
+
const { result: o, error: l } = await Me(s.portal, e);
|
|
944
|
+
if (l || !o)
|
|
945
|
+
return await g({ text: "Failed to fetch group context", agentName: "group-analytics" }, t), {
|
|
946
|
+
status: "success",
|
|
947
|
+
outputMessage: "Unable to retrieve group context for analytics."
|
|
948
|
+
};
|
|
949
|
+
const { group: c, items: i } = o, u = Date.now(), r = c.modified, p = r ? nt({ timestamp: r, now: u, windowMs: Te }) : !1, m = i.recentlyModifiedItems.length, d = m > 0, h = p || d, f = await v({
|
|
950
|
+
promptText: Ge,
|
|
951
|
+
schema: Ce,
|
|
952
|
+
modelTier: "default",
|
|
953
|
+
inputVariables: {
|
|
954
|
+
context: JSON.stringify(o),
|
|
955
|
+
deterministicSignals: JSON.stringify({
|
|
956
|
+
isGroupActive: h,
|
|
957
|
+
isGroupRecentlyModified: p,
|
|
958
|
+
hasRecentlyAddedOrUpdatedContent: d,
|
|
959
|
+
recentItemCount: m
|
|
960
|
+
})
|
|
961
|
+
}
|
|
962
|
+
}), { followUpQuestions: b, summary: S } = f, ut = z(a), ct = {
|
|
963
|
+
latestGroupId: e,
|
|
964
|
+
memory: {
|
|
965
|
+
...ut.memory,
|
|
966
|
+
[e]: { summary: S, followUpQuestions: b, fullContext: o }
|
|
967
|
+
}
|
|
968
|
+
};
|
|
969
|
+
return b.length && await E({ type: "suggested-prompts", data: { prompts: b } }, t), {
|
|
970
|
+
status: "success",
|
|
971
|
+
outputMessage: S,
|
|
972
|
+
sharedStatePatch: { portalGroupSummaryMemory: { value: ct } }
|
|
973
|
+
};
|
|
974
|
+
}, Ce = n.object({
|
|
975
|
+
summary: n.string(),
|
|
976
|
+
followUpQuestions: n.array(n.string()).default([])
|
|
977
|
+
}), q = (a, t) => t ?? a, it = y.Root({
|
|
978
|
+
...k(),
|
|
979
|
+
groupSummaryIntent: y({
|
|
972
980
|
reducer: q,
|
|
973
981
|
default: () => "clarify"
|
|
974
982
|
}),
|
|
975
|
-
groupSummaryGroupId:
|
|
983
|
+
groupSummaryGroupId: y({
|
|
976
984
|
reducer: q,
|
|
977
985
|
default: () => null
|
|
978
986
|
}),
|
|
979
|
-
groupSummaryQuestion:
|
|
987
|
+
groupSummaryQuestion: y({
|
|
980
988
|
reducer: q,
|
|
981
989
|
default: () => ""
|
|
982
990
|
})
|
|
983
|
-
}), Ne = () => new
|
|
991
|
+
}), Ne = () => new N(it).addNode("detectGroupSummaryIntent", he).addNode("summarizePortalGroup", Ae).addNode("answerGroupSummaryFollowUp", de).addNode("suggestGroupSummaryNavigation", fe).addEdge(P, "detectGroupSummaryIntent").addConditionalEdges("detectGroupSummaryIntent", (t) => t.groupSummaryIntent === "summarize" ? "summarizePortalGroup" : t.groupSummaryIntent === "followUp" ? "answerGroupSummaryFollowUp" : t.groupSummaryIntent === "navigation" ? "suggestGroupSummaryNavigation" : w).addEdge("summarizePortalGroup", w).addEdge("answerGroupSummaryFollowUp", w).addEdge("suggestGroupSummaryNavigation", w), Pe = String.raw`- **portal-group-analytics** - Portal group analytics assistant:
|
|
984
992
|
- summarizes ArcGIS portal groups from group context and sourceJSON details
|
|
985
993
|
- answers follow-up questions grounded in the summarized group
|
|
986
994
|
- suggests navigation to groups when relevant
|
|
@@ -989,34 +997,15 @@ Deterministic signals:
|
|
|
989
997
|
name: "Portal Group Analytics",
|
|
990
998
|
description: Pe,
|
|
991
999
|
createGraph: Ne,
|
|
992
|
-
workspace:
|
|
993
|
-
},
|
|
994
|
-
const t =
|
|
995
|
-
return t ? { latestItemId: t.latestItemId, memory: t.memory } :
|
|
996
|
-
},
|
|
997
|
-
intent:
|
|
998
|
-
itemId:
|
|
999
|
-
question:
|
|
1000
|
-
}),
|
|
1001
|
-
await g({ text: "Answering follow-up...", agentName: "analytics" }, t);
|
|
1002
|
-
const e = F(s), a = s.analyticsItemId ?? e.latestItemId, o = a ? e.memory[a] : void 0, i = s.analyticsQuestion || I(s.agentExecutionContext.messages);
|
|
1003
|
-
return o ? {
|
|
1004
|
-
status: "success",
|
|
1005
|
-
outputMessage: (await b({
|
|
1006
|
-
promptText: Ue,
|
|
1007
|
-
schema: Ee,
|
|
1008
|
-
modelTier: "default",
|
|
1009
|
-
inputVariables: {
|
|
1010
|
-
summary: o.summary,
|
|
1011
|
-
question: i,
|
|
1012
|
-
fullContext: JSON.stringify(o.fullContext)
|
|
1013
|
-
}
|
|
1014
|
-
})).answer
|
|
1015
|
-
} : {
|
|
1016
|
-
status: "success",
|
|
1017
|
-
outputMessage: "I don't have enough information yet. Please ask me to summarize the item first using summarize item <item id>."
|
|
1018
|
-
};
|
|
1019
|
-
}, Ue = `
|
|
1000
|
+
workspace: it
|
|
1001
|
+
}, ze = () => ({ latestItemId: null, memory: {} }), O = (a) => {
|
|
1002
|
+
const t = a?.agentExecutionContext.sharedState.portalItemAnalyticsSummaryMemory?.value;
|
|
1003
|
+
return t ? { latestItemId: t.latestItemId, memory: t.memory } : ze();
|
|
1004
|
+
}, W = n.object({
|
|
1005
|
+
intent: n.enum(["summarize", "followUp", "clarify"]),
|
|
1006
|
+
itemId: n.string().default(""),
|
|
1007
|
+
question: n.string().default("")
|
|
1008
|
+
}), qe = n.object({ summary: n.string(), followUpQuestions: n.array(n.string()).default([]) }), $e = n.object({ answer: n.string(), isRelevant: n.boolean() }), Ee = `
|
|
1020
1009
|
You answer follow-up questions about an ArcGIS item.
|
|
1021
1010
|
|
|
1022
1011
|
Ground your answer in the provided item context.
|
|
@@ -1036,27 +1025,26 @@ Item full context
|
|
|
1036
1025
|
|
|
1037
1026
|
Question:
|
|
1038
1027
|
{question}
|
|
1039
|
-
`,
|
|
1040
|
-
await g({ text: "
|
|
1041
|
-
const e =
|
|
1042
|
-
|
|
1043
|
-
hasSummaryContext: String(a)
|
|
1044
|
-
}), u = await U({
|
|
1045
|
-
model: await E({ modelTier: "fast" }),
|
|
1046
|
-
tools: [tt],
|
|
1047
|
-
systemPrompt: o,
|
|
1048
|
-
responseFormat: ze,
|
|
1049
|
-
checkpointer: !0
|
|
1050
|
-
}).invoke({ messages: s.agentExecutionContext.messages }, t), { intent: l, itemId: c, question: n } = u.structuredResponse, d = l === "clarify" || l === "summarize" && !c || l === "followUp" && !n;
|
|
1051
|
-
return {
|
|
1052
|
-
agentExecutionContext: { ...s.agentExecutionContext },
|
|
1053
|
-
analyticsIntent: d ? "clarify" : l,
|
|
1054
|
-
analyticsItemId: c || null,
|
|
1055
|
-
analyticsQuestion: n || "",
|
|
1028
|
+
`, De = async (a, t) => {
|
|
1029
|
+
await g({ text: "Answering follow-up...", agentName: "analytics" }, t);
|
|
1030
|
+
const e = O(a), s = a.analyticsItemId ?? e.latestItemId, o = s ? e.memory[s] : void 0, l = a.analyticsQuestion || x(a.agentExecutionContext.messages);
|
|
1031
|
+
return o ? {
|
|
1056
1032
|
status: "success",
|
|
1057
|
-
outputMessage:
|
|
1033
|
+
outputMessage: (await v({
|
|
1034
|
+
promptText: Ee,
|
|
1035
|
+
schema: $e,
|
|
1036
|
+
modelTier: "default",
|
|
1037
|
+
inputVariables: {
|
|
1038
|
+
summary: o.summary,
|
|
1039
|
+
question: l,
|
|
1040
|
+
fullContext: JSON.stringify(o.fullContext)
|
|
1041
|
+
}
|
|
1042
|
+
})).answer
|
|
1043
|
+
} : {
|
|
1044
|
+
status: "success",
|
|
1045
|
+
outputMessage: "I don't have enough information yet. Please ask me to summarize the item first using summarize item <item id>."
|
|
1058
1046
|
};
|
|
1059
|
-
},
|
|
1047
|
+
}, Ue = `
|
|
1060
1048
|
Classify the user analytics request.
|
|
1061
1049
|
|
|
1062
1050
|
Rules:
|
|
@@ -1086,85 +1074,105 @@ hasSummaryContext:
|
|
|
1086
1074
|
|
|
1087
1075
|
User message:
|
|
1088
1076
|
{userMessage}
|
|
1089
|
-
`,
|
|
1090
|
-
|
|
1077
|
+
`, Re = async (a, t) => {
|
|
1078
|
+
await g({ text: "Analyzing intent...", agentName: "analytics" }, t);
|
|
1079
|
+
const e = x(a.agentExecutionContext.messages), s = !!O(a).latestItemId, o = await U.fromTemplate(Ue).format({
|
|
1080
|
+
userMessage: e,
|
|
1081
|
+
hasSummaryContext: String(s)
|
|
1082
|
+
}), c = (await D({ modelTier: "fast" })).withStructuredOutput(W), i = W.parse(await c.invoke(o));
|
|
1083
|
+
let u = i.itemId;
|
|
1084
|
+
if (i.intent === "summarize" && !u) {
|
|
1085
|
+
const f = G(e, "#");
|
|
1086
|
+
f && (u = await at.invoke({ itemTitle: f }, t) ?? "");
|
|
1087
|
+
}
|
|
1088
|
+
const { intent: r, question: p } = i, h = r === "clarify" || r === "summarize" && !u || r === "followUp" && !p;
|
|
1089
|
+
return {
|
|
1090
|
+
agentExecutionContext: { ...a.agentExecutionContext },
|
|
1091
|
+
analyticsIntent: h ? "clarify" : r,
|
|
1092
|
+
analyticsItemId: u || null,
|
|
1093
|
+
analyticsQuestion: p || "",
|
|
1094
|
+
status: "success",
|
|
1095
|
+
outputMessage: h ? 'Please clarify with summarize item <item id>, summarize item #<title>, or summarize item #"<title with spaces>".' : ""
|
|
1096
|
+
};
|
|
1097
|
+
}, Oe = `
|
|
1098
|
+
You are a item summary tool for ArcGIS. Your job is to summarize an item's info based on the provided context.
|
|
1099
|
+
Summary rules:
|
|
1100
|
+
- The summary should be concise markdown, make sure to format the output nicely so it's easy to read.
|
|
1101
|
+
- Target length: 80-150 words.
|
|
1102
|
+
- Provide one short descriptive paragraph.
|
|
1103
|
+
- Also propose 3 concise follow-up questions grounded in the item summary.
|
|
1104
|
+
- Keep follow-up questions specific and actionable.
|
|
1105
|
+
Follow-up questions rules:
|
|
1106
|
+
- These questions should be in the format of a prompt that the user can click on.
|
|
1107
|
+
- Make sure the questions are relevant to the item summary and that you can answer based solely on the provided context.
|
|
1108
|
+
Do not include internal identifiers.
|
|
1109
|
+
If the user asks for a detailed summary, you may expand the response up to 300 words.
|
|
1110
|
+
Item context:
|
|
1111
|
+
{context}
|
|
1112
|
+
`, Fe = async (a, t) => {
|
|
1113
|
+
const e = a.analyticsItemId;
|
|
1091
1114
|
if (!e)
|
|
1092
1115
|
return {
|
|
1093
1116
|
status: "success",
|
|
1094
1117
|
outputMessage: 'Please clarify with summarize item <item id>, summarize item #<title>, or summarize item #"<title with spaces>".'
|
|
1095
1118
|
};
|
|
1096
1119
|
await g({ text: `Summarizing item ${e}...`, agentName: "analytics" }, t);
|
|
1097
|
-
const
|
|
1098
|
-
|
|
1099
|
-
const { portal: o, user:
|
|
1100
|
-
if (
|
|
1120
|
+
const s = t?.configurable?.context;
|
|
1121
|
+
I(s);
|
|
1122
|
+
const { portal: o, user: l } = s, { result: c, error: i } = await Mt(l, o, e);
|
|
1123
|
+
if (i || !c)
|
|
1101
1124
|
return await g({ text: "Failed to get item context for summarization", agentName: "analytics" }, t), {
|
|
1102
1125
|
status: "success",
|
|
1103
1126
|
outputMessage: "Unable to retrieve item context for summarization."
|
|
1104
1127
|
};
|
|
1105
|
-
const { context:
|
|
1106
|
-
promptText:
|
|
1107
|
-
schema:
|
|
1128
|
+
const { context: u } = c, r = await v({
|
|
1129
|
+
promptText: Oe,
|
|
1130
|
+
schema: qe,
|
|
1108
1131
|
modelTier: "default",
|
|
1109
|
-
inputVariables: { context: JSON.stringify(
|
|
1110
|
-
}), { followUpQuestions: p, summary: m } =
|
|
1132
|
+
inputVariables: { context: JSON.stringify(u) }
|
|
1133
|
+
}), { followUpQuestions: p, summary: m } = r, d = O(a), h = {
|
|
1111
1134
|
latestItemId: e,
|
|
1112
1135
|
memory: {
|
|
1113
1136
|
...d.memory,
|
|
1114
|
-
[e]: { summary: m, followUpQuestions: p, fullContext:
|
|
1137
|
+
[e]: { summary: m, followUpQuestions: p, fullContext: u }
|
|
1115
1138
|
}
|
|
1116
1139
|
};
|
|
1117
|
-
return p.length && await
|
|
1140
|
+
return p.length && await E({ type: "suggested-prompts", data: { prompts: p } }, t), {
|
|
1118
1141
|
status: "success",
|
|
1119
1142
|
outputMessage: m,
|
|
1120
|
-
sharedStatePatch: { portalItemAnalyticsSummaryMemory: { value:
|
|
1143
|
+
sharedStatePatch: { portalItemAnalyticsSummaryMemory: { value: h } }
|
|
1121
1144
|
};
|
|
1122
|
-
},
|
|
1123
|
-
|
|
1124
|
-
Summary rules:
|
|
1125
|
-
- The summary should be concise markdown, make sure to format the output nicely so it's easy to read.
|
|
1126
|
-
- Target length: 80-150 words.
|
|
1127
|
-
- Provide one short descriptive paragraph.
|
|
1128
|
-
- Also propose 3 concise follow-up questions grounded in the item summary.
|
|
1129
|
-
- Keep follow-up questions specific and actionable.
|
|
1130
|
-
Follow-up questions rules:
|
|
1131
|
-
- These questions should be in the format of a prompt that the user can click on.
|
|
1132
|
-
- Make sure the questions are relevant to the item summary and that you can answer based solely on the provided context.
|
|
1133
|
-
Do not include internal identifiers.
|
|
1134
|
-
If the user asks for a detailed summary, you may expand the response up to 300 words.
|
|
1135
|
-
Item context:
|
|
1136
|
-
{context}
|
|
1137
|
-
`, z = (s, t) => t ?? s, nt = h.Root({
|
|
1138
|
-
...P(),
|
|
1145
|
+
}, $ = (a, t) => t ?? a, lt = y.Root({
|
|
1146
|
+
...k(),
|
|
1139
1147
|
// States shared only across nodes in the graph, not between invocations
|
|
1140
|
-
analyticsIntent:
|
|
1141
|
-
reducer:
|
|
1148
|
+
analyticsIntent: y({
|
|
1149
|
+
reducer: $,
|
|
1142
1150
|
default: () => "clarify"
|
|
1143
1151
|
}),
|
|
1144
|
-
analyticsItemId:
|
|
1145
|
-
reducer:
|
|
1152
|
+
analyticsItemId: y({
|
|
1153
|
+
reducer: $,
|
|
1146
1154
|
default: () => null
|
|
1147
1155
|
}),
|
|
1148
|
-
analyticsQuestion:
|
|
1149
|
-
reducer:
|
|
1156
|
+
analyticsQuestion: y({
|
|
1157
|
+
reducer: $,
|
|
1150
1158
|
default: () => ""
|
|
1151
1159
|
})
|
|
1152
|
-
}),
|
|
1160
|
+
}), Ve = () => new N(lt).addNode("detectAnalyticsIntent", Re).addNode("summarizePortalItem", Fe).addNode("answerAnalyticsFollowUp", De).addEdge(P, "detectAnalyticsIntent").addConditionalEdges("detectAnalyticsIntent", (t) => t.analyticsIntent === "summarize" ? "summarizePortalItem" : t.analyticsIntent === "followUp" ? "answerAnalyticsFollowUp" : w).addEdge("summarizePortalItem", w).addEdge("answerAnalyticsFollowUp", w), je = String.raw`- **portal-item-analytics** - Portal item analytics assistant:
|
|
1153
1161
|
- answers questions about one specific ArcGIS portal item when item context is present
|
|
1154
1162
|
- summarizes item details, metadata, and context grounded in that item
|
|
1155
1163
|
- suggests follow-up prompts grounded in the same item
|
|
1156
1164
|
- use for item-specific requests, not for gallery browsing, featured content, or opening Map Viewer
|
|
1157
|
-
`,
|
|
1165
|
+
`, Le = {
|
|
1158
1166
|
id: "portal-item-analytics",
|
|
1159
1167
|
name: "Portal Item Analytics",
|
|
1160
|
-
description:
|
|
1161
|
-
createGraph:
|
|
1162
|
-
workspace:
|
|
1163
|
-
},
|
|
1164
|
-
function
|
|
1168
|
+
description: je,
|
|
1169
|
+
createGraph: Ve,
|
|
1170
|
+
workspace: lt
|
|
1171
|
+
}, Be = gt`:host{height:100%;border-width:1px;border-style:solid;border-color:var(--calcite-color-border-3);display:block;width:100%;--tw-shadow: 0 1px 6px -1px rgba(0, 0, 0, .16), 0 1px 2px -1px rgba(0, 0, 0, .08);--tw-shadow-colored: 0 1px 6px -1px var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.chat-entry{display:flex;flex-direction:column;gap:.75rem;width:100%}.chat-actions{display:flex;justify-content:flex-end;gap:.5rem}.header-actions{display:flex;gap:.5rem;padding-inline-start:.75rem}.navigation-block{display:flex;flex-direction:column;align-items:stretch;gap:.35rem;margin-top:.5rem}.navigation-button{width:100%;margin-block:.25rem}.navigation-block-description{font-size:.75rem;color:var(--calcite-color-text-3)}`;
|
|
1172
|
+
function Qe(a, t) {
|
|
1165
1173
|
if (!t)
|
|
1166
1174
|
return;
|
|
1167
|
-
const { destinationType: e } =
|
|
1175
|
+
const { destinationType: e } = a;
|
|
1168
1176
|
switch (e) {
|
|
1169
1177
|
case "portal-content":
|
|
1170
1178
|
case "portal-content-favorites":
|
|
@@ -1182,50 +1190,50 @@ function Ke(s, t) {
|
|
|
1182
1190
|
case "portal-settings-security":
|
|
1183
1191
|
return t[e];
|
|
1184
1192
|
case "portal-item":
|
|
1185
|
-
return t[e]?.(
|
|
1193
|
+
return t[e]?.(a.itemId);
|
|
1186
1194
|
case "portal-group":
|
|
1187
|
-
return t[e]?.(
|
|
1195
|
+
return t[e]?.(a.groupId);
|
|
1188
1196
|
default:
|
|
1189
|
-
return
|
|
1197
|
+
return C(e);
|
|
1190
1198
|
}
|
|
1191
1199
|
}
|
|
1192
|
-
function
|
|
1193
|
-
const t =
|
|
1200
|
+
function Ke(a) {
|
|
1201
|
+
const t = Bt.safeParse(a);
|
|
1194
1202
|
return t.success ? t.data : void 0;
|
|
1195
1203
|
}
|
|
1196
|
-
class
|
|
1204
|
+
class Je extends dt {
|
|
1197
1205
|
constructor() {
|
|
1198
|
-
super(...arguments), this.t9n =
|
|
1199
|
-
const e = t.detail,
|
|
1200
|
-
if (!
|
|
1206
|
+
super(...arguments), this.t9n = ft({ blocking: !0 }), this.assistantEl = T(), this.formEl = T(), this.voiceInputEl = T(), this.inputEl = T(), this.navigationSlotElements = /* @__PURE__ */ new Map(), this.handleSlottableRequest = (t) => {
|
|
1207
|
+
const e = t.detail, s = e.data?.block;
|
|
1208
|
+
if (!s)
|
|
1201
1209
|
return;
|
|
1202
|
-
const o = this.getNavigationAction(
|
|
1210
|
+
const o = this.getNavigationAction(s);
|
|
1203
1211
|
o && this.upsertNavigationSlotElement(e.slotName, o);
|
|
1204
|
-
}, this.inputText = "", this.showVoiceInput = !0, this.isListening = !1, this.isVoiceInputDisabled = !1, this.interrupt = null, this.autoDestroyDisabled = !1, this.defaultClosed = !1, this.arcgisPortalNavigationRequest =
|
|
1212
|
+
}, this.inputText = "", this.showVoiceInput = !0, this.isListening = !1, this.isVoiceInputDisabled = !1, this.interrupt = null, this.autoDestroyDisabled = !1, this.defaultClosed = !1, this.arcgisPortalNavigationRequest = mt();
|
|
1205
1213
|
}
|
|
1206
1214
|
static {
|
|
1207
1215
|
this.properties = { inputText: 16, showVoiceInput: 16, isListening: 16, isVoiceInputDisabled: 16, interrupt: 16, autoDestroyDisabled: 5, portal: 0, user: 0, config: 0, navigationTargetMap: 0, defaultClosed: 5 };
|
|
1208
1216
|
}
|
|
1209
1217
|
static {
|
|
1210
|
-
this.styles =
|
|
1218
|
+
this.styles = Be;
|
|
1211
1219
|
}
|
|
1212
1220
|
getNavigationAction(t) {
|
|
1213
|
-
if (t?.type !==
|
|
1221
|
+
if (t?.type !== X)
|
|
1214
1222
|
return;
|
|
1215
|
-
const e =
|
|
1223
|
+
const e = Ke(t.data);
|
|
1216
1224
|
if (!e)
|
|
1217
1225
|
return;
|
|
1218
|
-
const
|
|
1219
|
-
if (
|
|
1220
|
-
return { href:
|
|
1226
|
+
const s = Qe(e, this.navigationTargetMap);
|
|
1227
|
+
if (s)
|
|
1228
|
+
return { href: s, targetDetail: e, label: this.getNavigationText(e.destinationType) };
|
|
1221
1229
|
}
|
|
1222
1230
|
upsertNavigationSlotElement(t, e) {
|
|
1223
|
-
const
|
|
1224
|
-
if (!
|
|
1231
|
+
const s = this.assistantEl.value;
|
|
1232
|
+
if (!s)
|
|
1225
1233
|
return;
|
|
1226
1234
|
let o = this.navigationSlotElements.get(t);
|
|
1227
|
-
o || (o = document.createElement("div"), o.slot = t, this.navigationSlotElements.set(t, o),
|
|
1228
|
-
|
|
1235
|
+
o || (o = document.createElement("div"), o.slot = t, this.navigationSlotElements.set(t, o), s.append(o)), ht(M`<div><calcite-button class="navigation-button" appearance=outline width=full .href=${e.href} icon-end=launch @click=${(l) => {
|
|
1236
|
+
l.preventDefault(), this.arcgisPortalNavigationRequest.emit({
|
|
1229
1237
|
href: e.href,
|
|
1230
1238
|
targetDetail: e.targetDetail
|
|
1231
1239
|
});
|
|
@@ -1267,49 +1275,49 @@ class We extends ct {
|
|
|
1267
1275
|
case "portal-group":
|
|
1268
1276
|
return e.openGroup;
|
|
1269
1277
|
default:
|
|
1270
|
-
return
|
|
1278
|
+
return C(t);
|
|
1271
1279
|
}
|
|
1272
1280
|
}
|
|
1273
1281
|
render() {
|
|
1274
|
-
const { t9n: t, inputText: e, portal:
|
|
1275
|
-
return M`<arcgis-assistant log-enabled keep-suggested-prompts .heading=${t.heading} .entryMessage=${t.entryMessage} @arcgisSlottableRequest=${this.handleSlottableRequest} @arcgisInterrupt=${({ detail:
|
|
1276
|
-
this.interrupt =
|
|
1282
|
+
const { t9n: t, inputText: e, portal: s, user: o, navigationTargetMap: l, showVoiceInput: c, isListening: i, isVoiceInputDisabled: u } = this;
|
|
1283
|
+
return M`<arcgis-assistant log-enabled keep-suggested-prompts .heading=${t.heading} .entryMessage=${t.entryMessage} @arcgisSlottableRequest=${this.handleSlottableRequest} @arcgisInterrupt=${({ detail: r }) => {
|
|
1284
|
+
this.interrupt = r;
|
|
1277
1285
|
}} @arcgisInterruptCancel=${() => {
|
|
1278
1286
|
this.interrupt = null;
|
|
1279
1287
|
}} @arcgisInterruptSubmit=${() => {
|
|
1280
1288
|
this.interrupt = null;
|
|
1281
|
-
}} @arcgisPromptSelect=${({ detail:
|
|
1282
|
-
this.inputText =
|
|
1289
|
+
}} @arcgisPromptSelect=${({ detail: r }) => {
|
|
1290
|
+
this.inputText = r.prompt, requestAnimationFrame(() => {
|
|
1283
1291
|
this.inputEl.value?.focusTextArea();
|
|
1284
1292
|
});
|
|
1285
|
-
}} ${A(this.assistantEl)}><div slot=header-actions-start class="header-actions"><calcite-icon icon=effects></calcite-icon></div><form slot=chat-entry class="chat-entry" @submit=${(
|
|
1286
|
-
|
|
1293
|
+
}} ${A(this.assistantEl)}><div slot=header-actions-start class="header-actions"><calcite-icon icon=effects></calcite-icon></div><form slot=chat-entry class="chat-entry" @submit=${(r) => {
|
|
1294
|
+
r.preventDefault();
|
|
1287
1295
|
const p = e.trim();
|
|
1288
1296
|
p && (this.assistantEl.value?.submitMessage(p), this.inputText = "");
|
|
1289
|
-
}} ${A(this.formEl)}><arcgis-portal-mentionable-text-area .portal=${
|
|
1290
|
-
|
|
1291
|
-
}} @arcgisUserMentionableTextAreaChange=${({ detail:
|
|
1292
|
-
this.inputText =
|
|
1297
|
+
}} ${A(this.formEl)}><arcgis-portal-mentionable-text-area .portal=${s} .user=${o} rows=3 .popoverListLabel=${t.mentionEntities} .placeholder=${t.placeholder} .value=${e} @arcgisUserMentionableTextAreaKeyDown=${({ detail: r }) => {
|
|
1298
|
+
r.key === "Enter" && !r.shiftKey && (r.preventDefault(), this.formEl.value?.requestSubmit());
|
|
1299
|
+
}} @arcgisUserMentionableTextAreaChange=${({ detail: r }) => {
|
|
1300
|
+
this.inputText = r ?? "";
|
|
1293
1301
|
}} ${A(this.inputEl)}></arcgis-portal-mentionable-text-area><div class="chat-actions"><arcgis-portal-voice-input @arcgisVoiceInputStart=${() => {
|
|
1294
1302
|
this.isListening = !0, this.isVoiceInputDisabled = !1;
|
|
1295
1303
|
}} @arcgisVoiceInputStop=${() => {
|
|
1296
1304
|
this.isListening = !1, this.isVoiceInputDisabled = !1;
|
|
1297
|
-
}} @arcgisVoiceInputError=${(
|
|
1298
|
-
|
|
1299
|
-
}} @arcgisVoiceInputInterimTranscription=${(
|
|
1300
|
-
this.inputText =
|
|
1301
|
-
}} ${A(this.voiceInputEl)}></arcgis-portal-voice-input>${
|
|
1305
|
+
}} @arcgisVoiceInputError=${(r) => {
|
|
1306
|
+
r.detail.errorCode === "not-supported" && (this.showVoiceInput = !1);
|
|
1307
|
+
}} @arcgisVoiceInputInterimTranscription=${(r) => {
|
|
1308
|
+
this.inputText = r.detail.text;
|
|
1309
|
+
}} ${A(this.voiceInputEl)}></arcgis-portal-voice-input>${c && M`<calcite-button icon-start=microphone .label=${t.voiceInput} round .disabled=${u} .appearance=${i ? "solid" : "outline-fill"} @click=${async () => {
|
|
1302
1310
|
this.isVoiceInputDisabled = !0;
|
|
1303
|
-
const
|
|
1304
|
-
|
|
1305
|
-
}}></calcite-button>` || ""}<calcite-button type=submit icon-start=send round .disabled=${!e.trim()} .label=${t.send}>${t.send}</calcite-button></div></form><arcgis-assistant-agent .agent=${
|
|
1306
|
-
this.assistantEl.value?.submitInterrupt(
|
|
1311
|
+
const r = this.voiceInputEl.value;
|
|
1312
|
+
i ? await r?.stopListening() : await r?.startListening();
|
|
1313
|
+
}}></calcite-button>` || ""}<calcite-button type=submit icon-start=send round .disabled=${!e.trim()} .label=${t.send}>${t.send}</calcite-button></div></form><arcgis-assistant-agent .agent=${Le} .context=${{ portal: s, user: o, navigationTargetMap: l }}></arcgis-assistant-agent><arcgis-assistant-agent .agent=${Wt} .context=${{ portal: s, user: o, navigationTargetMap: l }}></arcgis-assistant-agent><arcgis-assistant-agent .agent=${ue} .context=${{ portal: s, user: o, navigationTargetMap: l }}></arcgis-assistant-agent><arcgis-assistant-agent .agent=${ke} .context=${{ portal: s, user: o, navigationTargetMap: l }}></arcgis-assistant-agent>${this.interrupt && M`<arcgis-portal-ai-assistant-interrupt slot=interrupt .type=${this.interrupt.type} .message=${this.interrupt.message} .options=${this.interrupt.options} @arcgisSubmit=${({ detail: r }) => {
|
|
1314
|
+
this.assistantEl.value?.submitInterrupt(r);
|
|
1307
1315
|
}} @arcgisCancel=${() => {
|
|
1308
1316
|
this.assistantEl.value?.cancelInterrupt();
|
|
1309
1317
|
}}></arcgis-portal-ai-assistant-interrupt>` || ""}</arcgis-assistant>`;
|
|
1310
1318
|
}
|
|
1311
1319
|
}
|
|
1312
|
-
|
|
1320
|
+
pt("arcgis-portal-ai-assistant", Je);
|
|
1313
1321
|
export {
|
|
1314
|
-
|
|
1322
|
+
Je as ArcgisPortalAiAssistant
|
|
1315
1323
|
};
|