@arcgis/portal-components 5.2.0-next.2 → 5.2.0-next.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/dist/cdn/25UUUQAQ.js +71 -0
  2. package/dist/cdn/{OQDPULPD.js → 2RGMWFHB.js} +1 -1
  3. package/dist/cdn/3KS5IDT2.js +2 -0
  4. package/dist/cdn/{AQWTJKUH.js → 3MQIRMUM.js} +9 -7
  5. package/dist/cdn/{JNRN6DTV.js → 47NPIL2S.js} +1 -1
  6. package/dist/cdn/{LQ3DMZ3K.js → 5VHBNEN3.js} +1 -1
  7. package/dist/cdn/6AGZRMJC.js +2 -0
  8. package/dist/cdn/6W2IHKCA.js +2 -0
  9. package/dist/cdn/{WOZDQW3S.js → DBKSQGEI.js} +1 -1
  10. package/dist/cdn/DFTUMKSN.js +3 -0
  11. package/dist/cdn/{YMPTDKT6.js → EETBNQU2.js} +1 -1
  12. package/dist/cdn/EHRAFAEA.js +65 -0
  13. package/dist/cdn/EKO6SVAF.js +2 -0
  14. package/dist/cdn/{GHQ3ZW4U.js → FI45QCN2.js} +1 -1
  15. package/dist/cdn/GEIZTD7F.js +2 -0
  16. package/dist/cdn/{ZTHTFEYA.js → HGSK6OFA.js} +1 -1
  17. package/dist/cdn/{LAFNDBTQ.js → HIRM34QB.js} +1 -1
  18. package/dist/cdn/HMBSJR37.js +2 -0
  19. package/dist/cdn/KT7PE6UE.js +2 -0
  20. package/dist/cdn/{BEHLBKKM.js → KY7Q7DH3.js} +1 -1
  21. package/dist/cdn/{5DPWJ7DI.js → KZWW4BWJ.js} +1 -1
  22. package/dist/cdn/{N6G6Z7BF.js → MH7KZ5G3.js} +256 -154
  23. package/dist/cdn/MLTQECPL.js +2 -0
  24. package/dist/cdn/{G47ZZQYL.js → OKRYML2G.js} +1 -1
  25. package/dist/cdn/PDL3DPMG.js +2 -0
  26. package/dist/cdn/{QNUYUNEY.js → QJ2UHWPU.js} +1 -1
  27. package/dist/cdn/{GT26WGJS.js → SXZRHHXC.js} +1 -1
  28. package/dist/cdn/TSLW4FSA.js +2 -0
  29. package/dist/cdn/{72N3KAXN.js → TW4LFQA5.js} +1 -1
  30. package/dist/cdn/{7WZHZP6U.js → UR7W4CEV.js} +8 -2
  31. package/dist/cdn/{W6PSG4GX.js → VRXKORTR.js} +9 -4
  32. package/dist/cdn/VXCB2YBR.js +3 -0
  33. package/dist/cdn/{DHHSKOUY.js → WJ2NMHDE.js} +1 -1
  34. package/dist/cdn/{2UUZHENH.js → WSNLUGEP.js} +1 -1
  35. package/dist/cdn/{53MSUMA3.js → XCZSPNKS.js} +16 -0
  36. package/dist/cdn/{K3HS2LQ7.js → YECI7XG3.js} +1 -1
  37. package/dist/cdn/ZDLFZJBT.js +2 -0
  38. package/dist/cdn/assets/portal-group-badges/t9n/messages.en.json +1 -0
  39. package/dist/cdn/assets/portal-group-card/t9n/messages.en.json +1 -0
  40. package/dist/cdn/assets/portal-item-type/icons/parquetfeaturelayer16.svg +1 -0
  41. package/dist/cdn/assets/portal-item-type/icons/parquetfeaturelayer32.svg +1 -0
  42. package/dist/cdn/assets/portal-item-type/icons/storymapframe16.svg +1 -0
  43. package/dist/cdn/assets/portal-item-type/icons/storymapframe32.svg +1 -0
  44. package/dist/cdn/assets/portal-item-type/t9n/messages.en.json +1 -1
  45. package/dist/cdn/assets/portal-user-popup/t9n/messages.en.json +1 -0
  46. package/dist/cdn/index.js +1 -1
  47. package/dist/cdn/main.css +1 -1
  48. package/dist/chunks/groups.js +7 -83
  49. package/dist/chunks/item2.js +86 -0
  50. package/dist/chunks/portal.js +48 -8
  51. package/dist/chunks/user2.js +26 -25
  52. package/dist/components/arcgis-portal-ai-assistant/agents/types.d.ts +11 -2
  53. package/dist/components/arcgis-portal-ai-assistant/customElement.d.ts +4 -2
  54. package/dist/components/arcgis-portal-ai-assistant/customElement.js +797 -488
  55. package/dist/components/arcgis-portal-ai-assistant-interrupt/customElement.js +10 -10
  56. package/dist/components/arcgis-portal-group-badges/customElement.d.ts +102 -0
  57. package/dist/components/arcgis-portal-group-badges/customElement.js +50 -0
  58. package/dist/components/arcgis-portal-group-badges/index.d.ts +1 -0
  59. package/dist/components/arcgis-portal-group-badges/index.js +3 -0
  60. package/dist/components/arcgis-portal-group-badges/types.d.ts +3 -0
  61. package/dist/components/arcgis-portal-group-card/customElement.d.ts +167 -0
  62. package/dist/components/arcgis-portal-group-card/customElement.js +187 -0
  63. package/dist/components/arcgis-portal-group-card/index.d.ts +1 -0
  64. package/dist/components/arcgis-portal-group-card/index.js +8 -0
  65. package/dist/components/arcgis-portal-group-thumbnail/customElement.d.ts +32 -0
  66. package/dist/components/arcgis-portal-group-thumbnail/customElement.js +153 -0
  67. package/dist/components/arcgis-portal-group-thumbnail/index.d.ts +1 -0
  68. package/dist/components/arcgis-portal-group-thumbnail/index.js +3 -0
  69. package/dist/components/arcgis-portal-item-type/customElement.d.ts +2 -0
  70. package/dist/components/arcgis-portal-item-type/customElement.js +45 -37
  71. package/dist/components/arcgis-portal-mentionable-text-area/customElement.js +1 -1
  72. package/dist/components/arcgis-portal-replacement-item-redirect/customElement.js +53 -42
  73. package/dist/components/arcgis-portal-user-popup/customElement.d.ts +111 -0
  74. package/dist/components/arcgis-portal-user-popup/customElement.js +231 -0
  75. package/dist/components/arcgis-portal-user-popup/index.d.ts +1 -0
  76. package/dist/components/arcgis-portal-user-popup/index.js +5 -0
  77. package/dist/components/arcgis-portal-voice-input/customElement.d.ts +1 -1
  78. package/dist/docs/api.json +1 -1
  79. package/dist/docs/docs.json +1 -1
  80. package/dist/docs/vscode.html-custom-data.json +1 -1
  81. package/dist/docs/web-types.json +1 -1
  82. package/dist/index.d.ts +30 -2
  83. package/dist/loader.js +8 -4
  84. package/dist/types/lumina.d.ts +26 -1
  85. package/dist/types/preact.d.ts +30 -1
  86. package/dist/types/react.d.ts +34 -1
  87. package/dist/types/stencil.d.ts +26 -1
  88. package/dist/types/tracking.d.ts +10 -0
  89. package/dist/types/user.d.ts +2 -2
  90. package/package.json +7 -7
  91. package/dist/cdn/5VSDGPHH.js +0 -2
  92. package/dist/cdn/CI5ENGVT.js +0 -2
  93. package/dist/cdn/EVDOPN3G.js +0 -54
  94. package/dist/cdn/GNOZCQ34.js +0 -2
  95. package/dist/cdn/KEKBRUUC.js +0 -2
  96. package/dist/cdn/RNLVNDGG.js +0 -2
  97. package/dist/cdn/SM4GWLRA.js +0 -66
  98. package/dist/cdn/TMYTUOSS.js +0 -2
  99. package/dist/cdn/YG5YYL6X.js +0 -2
  100. /package/dist/cdn/{B7633S2A.js → 5NIJVBS7.js} +0 -0
@@ -1,302 +1,106 @@
1
1
  /* COPYRIGHT Esri - https://js.arcgis.com/5.2/LICENSE.txt */
2
- import { c as Z } from "../../chunks/runtime.js";
3
- import { LitElement as tt, createEvent as et } from "@arcgis/lumina";
4
- import { css as st, render as at, html as w } from "lit";
5
- import { createRef as M, ref as T } from "lit/directives/ref.js";
6
- import { u as rt } from "../../chunks/useT9n.js";
7
- import { a as P, t as ot } from "../../chunks/functionalities.js";
8
- import { Annotation as h, StateGraph as $, START as G, END as y, NodeInterrupt as V } from "@langchain/langgraph/web";
9
- import { sendTraceMessage as g, invokeStructuredPrompt as b, createChatModel as F, sendUXSuggestion as B, createAgentRuntimeStateWithSharedState as E } from "@arcgis/ai-components/utils/index.js";
10
- import n from "zod";
11
- import { ChatPromptTemplate as L } from "@langchain/core/prompts";
12
- import { createAgent as Q } from "langchain";
13
- import { tool as K } from "@langchain/core/tools";
14
- import { s as nt, g as it, a as lt, c as ct, q as ut } from "../../chunks/groups.js";
15
- import mt from "@arcgis/core/identity/IdentityManager.js";
16
- import k from "@arcgis/core/request.js";
17
- import { Annotation as dt } from "@langchain/langgraph";
18
- const x = (s) => {
19
- for (let t = s.length - 1; t >= 0; t -= 1) {
20
- const e = s[t];
21
- if (e.type !== "human")
22
- continue;
23
- const a = e.content;
24
- if (typeof a == "string")
25
- return a;
26
- if (Array.isArray(a))
27
- return a.map(
28
- (r) => typeof r == "string" ? r : "text" in r && typeof r.text == "string" ? r.text : ""
29
- ).join(" ").trim();
30
- }
31
- return "";
32
- }, pt = () => ({ latestItemId: null, memory: {} }), N = (s) => {
33
- const t = s?.agentExecutionContext.sharedState.portalItemAnalyticsSummaryMemory?.value;
34
- return t ? { latestItemId: t.latestItemId, memory: t.memory } : pt();
35
- }, gt = n.object({
36
- intent: n.enum(["summarize", "followUp", "clarify"]),
37
- itemId: n.string().default(""),
38
- question: n.string().default("")
39
- }), ht = n.object({ summary: n.string(), followUpQuestions: n.array(n.string()).default([]) }), ft = n.object({ answer: n.string(), isRelevant: n.boolean() }), yt = async (s, t) => {
40
- await g({ text: "Answering follow-up...", agentName: "analytics" }, t);
41
- const e = N(s), a = s.analyticsItemId ?? e.latestItemId, r = a ? e.memory[a] : void 0, l = s.analyticsQuestion || x(s.agentExecutionContext.messages);
42
- return r ? {
43
- status: "success",
44
- outputMessage: (await b({
45
- promptText: bt,
46
- schema: ft,
47
- modelTier: "default",
48
- inputVariables: {
49
- summary: r.summary,
50
- question: l,
51
- fullContext: JSON.stringify(r.fullContext)
52
- }
53
- })).answer
54
- } : {
55
- status: "success",
56
- outputMessage: "I don't have enough information yet. Please ask me to summarize the item first using summarize item <item id>."
57
- };
58
- }, bt = `
59
- You answer follow-up questions about an ArcGIS item.
60
-
61
- Ground your answer in the provided item context.
62
- If the answer is not available from the provided context, state that clearly and suggest what to check next.
63
-
64
- Response rules:
65
- - Reply in concise markdown.
66
- - Keep the answer focused on the follow-up question.
67
- - Do not include internal identifiers.
68
- - Mark isRelevant=false when the question is not about this item or cannot be grounded in this item context.
69
-
70
- Item summary:
71
- {summary}
72
-
73
- Item full context
74
- {fullContext}
75
-
76
- Question:
77
- {question}
78
- `;
79
- function I(s) {
80
- const { portal: t, user: e } = s ?? {};
81
- if (!s || !t || !e)
2
+ import { c as ut } from "../../chunks/runtime.js";
3
+ import { LitElement as lt, createEvent as ct } from "@arcgis/lumina";
4
+ import { css as mt, render as dt, html as G } from "lit";
5
+ import { createRef as M, ref as A } from "lit/directives/ref.js";
6
+ import { u as pt } from "../../chunks/useT9n.js";
7
+ import { a as T, t as gt } from "../../chunks/functionalities.js";
8
+ import { NodeInterrupt as K, Annotation as f, StateGraph as C, START as P, END as h } from "@langchain/langgraph/web";
9
+ import { sendTraceMessage as g, invokeStructuredPrompt as b, sendUXSuggestion as E, createAgentRuntimeStateWithSharedState as N, createChatModel as D } from "@arcgis/ai-components/utils/index.js";
10
+ import o from "zod";
11
+ import { a as ft, c as ht, q as yt, s as wt, g as bt } from "../../chunks/item2.js";
12
+ import It from "@arcgis/core/identity/IdentityManager.js";
13
+ import j from "@arcgis/core/request.js";
14
+ import { ChatPromptTemplate as z } from "@langchain/core/prompts";
15
+ import { createAgent as U } from "langchain";
16
+ import { tool as W } from "@langchain/core/tools";
17
+ import { Annotation as xt } from "@langchain/langgraph";
18
+ import { c as vt, d as St, i as Gt, b as Mt, g as At } from "../../chunks/groups.js";
19
+ const Y = (e) => {
20
+ const { portal: t, user: s } = e ?? {};
21
+ return !!e && !!t && !!s;
22
+ };
23
+ function I(e) {
24
+ if (!Y(e))
82
25
  throw new Error("Invalid context: PortalAssistantContext with portal and user is required.");
83
26
  }
84
- const W = K(
85
- async ({ itemTitle: s }, t) => {
86
- const e = s.trim();
87
- if (!e)
88
- return null;
89
- const a = t?.configurable?.context;
90
- I(a);
91
- const { result: r, error: l } = await nt(a.portal, e, { num: 1 });
92
- return l && console.error("Error searching for portal item by title:", l), r?.results[0]?.id || null;
93
- },
94
- {
95
- name: "resolvePortalItemIdByTitle",
96
- 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.',
97
- schema: n.object({
98
- itemTitle: n.string().describe("The portal item title to resolve to an item id.")
99
- })
100
- }
101
- ), It = async (s, t) => {
102
- await g({ text: "Analyzing intent...", agentName: "analytics" }, t);
103
- const e = x(s.agentExecutionContext.messages), a = !!N(s).latestItemId, r = await L.fromTemplate(wt).format({
104
- userMessage: e,
105
- hasSummaryContext: String(a)
106
- }), c = await Q({
107
- model: await F("fast"),
108
- tools: [W],
109
- systemPrompt: r,
110
- responseFormat: gt,
111
- checkpointer: !0
112
- }).invoke({ messages: s.agentExecutionContext.messages }, t), { intent: i, itemId: o, question: u } = c.structuredResponse, m = i === "clarify" || i === "summarize" && !o || i === "followUp" && !u;
113
- return {
114
- agentExecutionContext: { ...s.agentExecutionContext },
115
- analyticsIntent: m ? "clarify" : i,
116
- analyticsItemId: o || null,
117
- analyticsQuestion: u || "",
118
- status: "success",
119
- outputMessage: m ? 'Please clarify with summarize item <item id>, summarize item #<title>, or summarize item #"<title with spaces>".' : ""
120
- };
121
- }, wt = `
122
- Classify the user analytics request.
123
-
124
- Rules:
125
- - intent="summarize" only when the user explicitly asks to summarize/overview/recap an item.
126
- - intent="followUp" for analytical questions about item details, including schema/fields/attributes/layers.
127
- - intent="clarify" when neither summarize nor follow-up intent is clear.
128
- - itemId must be the final resolved item id.
129
- - If request has explicit item id, set itemId directly.
130
- - If request references item title (for example #title, #"title with spaces", or plain quoted title), call resolvePortalItemIdByTitle and set itemId to the returned value.
131
- - Never return item titles in output fields.
132
- - If intent is "followUp", set question to the user's full question/request text.
133
- - If intent is "summarize", set question="".
134
- - When user asks to show/list/explain fields, schema, attributes, columns, or layer details, classify as "followUp" unless they explicitly request a summary.
135
- - If hasSummaryContext is true, prefer "followUp" for detail-oriented requests that do not explicitly ask to summarize.
136
-
137
- Examples:
138
- - "Summarize item 0123456789abcdef0123456789abcdef" => summarize, itemId="0123456789abcdef0123456789abcdef"
139
- - "Summarize item #california" => summarize, call resolvePortalItemIdByTitle("california") and set itemId to tool result
140
- - "Summarize item #"california farmland"" => summarize, call resolvePortalItemIdByTitle("california farmland") and set itemId to tool result
141
- - "Show the layer's available fields" => followUp
142
- - "List attributes and explain what status means" => followUp
143
- - "What fields are available?" with hasSummaryContext=true => followUp
144
- - "Give me an overview of item 0123456789abcdef0123456789abcdef" => summarize
145
-
146
- hasSummaryContext:
147
- {hasSummaryContext}
148
-
149
- User message:
150
- {userMessage}
151
- `, xt = async (s, t) => {
152
- const e = s.analyticsItemId;
153
- if (!e)
154
- return {
155
- status: "success",
156
- outputMessage: 'Please clarify with summarize item <item id>, summarize item #<title>, or summarize item #"<title with spaces>".'
157
- };
158
- await g({ text: `Summarizing item ${e}...`, agentName: "analytics" }, t);
159
- const a = t?.configurable?.context;
160
- I(a);
161
- const { portal: r, user: l } = a, { result: c, error: i } = await it(l, r, e);
162
- if (i || !c)
163
- return await g({ text: "Failed to get item context for summarization", agentName: "analytics" }, t), {
164
- status: "success",
165
- outputMessage: "Unable to retrieve item context for summarization."
166
- };
167
- const { context: o } = c, u = await b({
168
- promptText: vt,
169
- schema: ht,
170
- modelTier: "default",
171
- inputVariables: { context: JSON.stringify(o) }
172
- }), { followUpQuestions: d, summary: p } = u, m = N(s), f = {
173
- latestItemId: e,
174
- memory: {
175
- ...m.memory,
176
- [e]: { summary: p, followUpQuestions: d, fullContext: o }
177
- }
178
- };
179
- return d.length && await B({ type: "suggested-prompts", data: { prompts: d } }, t), {
180
- status: "success",
181
- outputMessage: p,
182
- sharedStatePatch: { portalItemAnalyticsSummaryMemory: { value: f } }
183
- };
184
- }, vt = `
185
- You are a item summary tool for ArcGIS. Your job is to summarize an item's info based on the provided context.
186
- Summary rules:
187
- - The summary should be concise markdown, make sure to format the output nicely so it's easy to read.
188
- - Target length: 80-150 words.
189
- - Provide one short descriptive paragraph.
190
- - Also propose 3 concise follow-up questions grounded in the item summary.
191
- - Keep follow-up questions specific and actionable.
192
- Follow-up questions rules:
193
- - These questions should be in the format of a prompt that the user can click on.
194
- - Make sure the questions are relevant to the item summary and that you can answer based solely on the provided context.
195
- Do not include internal identifiers.
196
- If the user asks for a detailed summary, you may expand the response up to 300 words.
197
- Item context:
198
- {context}
199
- `, C = (s, t) => t ?? s, O = h.Root({
200
- ...E(),
201
- // States shared only across nodes in the graph, not between invocations
202
- analyticsIntent: h({
203
- reducer: C,
204
- default: () => "clarify"
205
- }),
206
- analyticsItemId: h({
207
- reducer: C,
208
- default: () => null
209
- }),
210
- analyticsQuestion: h({
211
- reducer: C,
212
- default: () => ""
213
- })
214
- }), St = () => new $(O).addNode("detectAnalyticsIntent", It).addNode("summarizePortalItem", xt).addNode("answerAnalyticsFollowUp", yt).addEdge(G, "detectAnalyticsIntent").addConditionalEdges("detectAnalyticsIntent", (t) => t.analyticsIntent === "summarize" ? "summarizePortalItem" : t.analyticsIntent === "followUp" ? "answerAnalyticsFollowUp" : y).addEdge("summarizePortalItem", y).addEdge("answerAnalyticsFollowUp", y), Mt = String.raw`- **portal-item-analytics** - Portal item analytics assistant:
215
- - summarizes ArcGIS portal items from item context
216
- - suggests follow-up prompts grounded in the item
217
- `, Tt = {
218
- id: "portal-item-analytics",
219
- name: "Portal Item Analytics",
220
- description: Mt,
221
- createGraph: St,
222
- workspace: O
223
- }, Pt = (s) => s.map((t) => `"${t}"`).join(", "), At = n.object({
224
- successMessage: n.string().default("")
225
- }), q = "portal-group-creation", D = "approveAddMembers", Ct = async (s, t) => {
226
- if (s.intentParams.intent !== "addMembers")
27
+ const Tt = (e) => e.map((t) => `"${t}"`).join(", "), Ct = o.object({
28
+ successMessage: o.string().default("")
29
+ }), O = "portal-group-creation", V = "approveAddMembers", Pt = async (e, t) => {
30
+ if (e.intentParams.intent !== "addMembers")
227
31
  return {
228
32
  status: "success",
229
33
  outputMessage: "Use @mention usernames for the members you want to add."
230
34
  };
231
- const e = s.agentExecutionContext.sharedState.createdGroupId?.value;
232
- if (!e)
35
+ const s = e.agentExecutionContext.sharedState.createdGroupId?.value;
36
+ if (!s)
233
37
  return {
234
38
  status: "success",
235
39
  outputMessage: "Create a group first, then add members using @mention usernames."
236
40
  };
237
- const a = s.intentParams.memberInfo.memberIdentifiers.map((m) => m.trim()).filter(Boolean);
41
+ const a = e.intentParams.memberInfo.memberIdentifiers.map((d) => d.trim()).filter(Boolean);
238
42
  if (!a.length)
239
43
  return {
240
44
  status: "success",
241
45
  outputMessage: "Use @mention usernames for the members you want to add."
242
46
  };
243
- const l = `The following member(s) will be added to the newly created group:
47
+ const i = `The following member(s) will be added to the newly created group:
244
48
 
245
- ${a.map((m) => `- **@${m}**`).join(`
49
+ ${a.map((d) => `- **@${d}**`).join(`
246
50
  `)}
247
51
 
248
- Do you want to continue?`, { hitlResponse: c } = t?.configurable ?? {};
249
- if (c?.agentId !== q || c.id !== D) {
250
- const m = {
251
- agentId: q,
252
- id: D,
52
+ Do you want to continue?`, { hitlResponse: l } = t?.configurable ?? {};
53
+ if (l?.agentId !== O || l.id !== V) {
54
+ const d = {
55
+ agentId: O,
56
+ id: V,
253
57
  kind: "booleanChoice",
254
- message: l,
58
+ message: i,
255
59
  metadata: {
256
60
  action: "addMembers",
257
- groupId: e,
61
+ groupId: s,
258
62
  members: [...a]
259
63
  }
260
64
  };
261
- throw new V(m);
65
+ throw new K(d);
262
66
  }
263
- if (c.payload !== !0)
67
+ if (l.payload !== !0)
264
68
  return {
265
69
  status: "success",
266
70
  outputMessage: "Okay, I cancelled adding members to the group."
267
71
  };
268
72
  await g(
269
- { text: `Adding members ${Pt(a)}...`, agentName: "group-creation" },
73
+ { text: `Adding members ${Tt(a)}...`, agentName: "group-creation" },
270
74
  t
271
75
  );
272
- const i = t?.configurable?.context;
273
- I(i);
274
- const { result: o, error: u } = await lt(i.portal, e, a);
275
- if (u || !o)
76
+ const u = t?.configurable?.context;
77
+ I(u);
78
+ const { result: c, error: n } = await ft(u.portal, s, a);
79
+ if (n || !c)
276
80
  return {
277
81
  status: "success",
278
82
  outputMessage: "I could not add members to that group. Please confirm group access and user accounts, then try again."
279
83
  };
280
- const { addedUsernames: d, notAddedUsers: p } = o;
84
+ const { addedUsernames: m, notAddedUsers: p } = c;
281
85
  try {
282
- const f = (await b({
283
- promptText: $t,
284
- schema: At,
86
+ const y = (await b({
87
+ promptText: Nt,
88
+ schema: Ct,
285
89
  modelTier: "fast",
286
90
  inputVariables: {
287
- addedMembers: d.join(", "),
91
+ addedMembers: m.join(", "),
288
92
  notAddedMembers: JSON.stringify(
289
93
  p.map((v) => ({ username: v.username, reason: v.error.message }))
290
94
  )
291
95
  }
292
96
  })).successMessage;
293
- if (f)
294
- return { status: "success", outputMessage: f };
295
- } catch (m) {
296
- console.error("Error generating add-members success message:", m);
97
+ if (y)
98
+ return { status: "success", outputMessage: y };
99
+ } catch (d) {
100
+ console.error("Error generating add-members success message:", d);
297
101
  }
298
102
  return {};
299
- }, $t = `
103
+ }, Nt = `
300
104
  Write a concise, friendly success message for adding members to a group.
301
105
 
302
106
  Rules:
@@ -311,59 +115,59 @@ Added members:
311
115
 
312
116
  Not added members:
313
117
  {notAddedMembers}
314
- `, R = "portal-group-creation", U = "approveCreateGroup", Gt = n.object({
315
- successMessage: n.string().default("")
316
- }), Et = n.object({
317
- failureMessage: n.string().default("")
318
- }), Nt = async (s, t) => {
319
- if (s.intentParams.intent !== "create")
118
+ `, B = "portal-group-creation", Q = "approveCreateGroup", qt = o.object({
119
+ successMessage: o.string().default("")
120
+ }), $t = o.object({
121
+ failureMessage: o.string().default("")
122
+ }), kt = async (e, t) => {
123
+ if (e.intentParams.intent !== "create")
320
124
  return {
321
125
  status: "success",
322
126
  outputMessage: "Tell me the group title you want to use."
323
127
  };
324
- const e = s.intentParams.title.trim();
325
- if (!e)
128
+ const s = e.intentParams.title.trim();
129
+ if (!s)
326
130
  return {
327
131
  status: "success",
328
132
  outputMessage: "What title would you like for the new group?"
329
133
  };
330
- const a = `A group with the title **${e}** will be created. Do you want to continue?`, { hitlResponse: r } = t?.configurable;
331
- if (r?.agentId !== R || r.id !== U) {
332
- const u = {
333
- agentId: R,
334
- id: U,
134
+ const a = `A group with the title **${s}** will be created. Do you want to continue?`, { hitlResponse: r } = t?.configurable;
135
+ if (r?.agentId !== B || r.id !== Q) {
136
+ const n = {
137
+ agentId: B,
138
+ id: Q,
335
139
  kind: "booleanChoice",
336
140
  message: a,
337
141
  metadata: {
338
142
  action: "createGroup",
339
- title: e,
143
+ title: s,
340
144
  access: "private"
341
145
  }
342
146
  };
343
- throw new V(u);
147
+ throw new K(n);
344
148
  }
345
149
  if (r.payload !== !0)
346
150
  return {
347
151
  status: "success",
348
- outputMessage: `Okay, I cancelled creating **${e}**.`
152
+ outputMessage: `Okay, I cancelled creating **${s}**.`
349
153
  };
350
- await g({ text: `Creating group "${e}"...`, agentName: "group-creation" }, t);
351
- const l = t?.configurable?.context;
352
- I(l);
353
- const { result: c, error: i } = await ct(l.portal, {
354
- title: e,
154
+ await g({ text: `Creating group "${s}"...`, agentName: "group-creation" }, t);
155
+ const i = t?.configurable?.context;
156
+ I(i);
157
+ const { result: l, error: u } = await ht(i.portal, {
158
+ title: s,
355
159
  access: "private"
356
160
  });
357
- if (i || !c) {
358
- const u = i?.message?.trim() || "No additional details were provided.";
161
+ if (u || !l) {
162
+ const n = u?.message?.trim() || "No additional details were provided.";
359
163
  try {
360
164
  const p = (await b({
361
- promptText: qt,
362
- schema: Et,
165
+ promptText: Dt,
166
+ schema: $t,
363
167
  modelTier: "fast",
364
168
  inputVariables: {
365
- groupTitle: e,
366
- failureReason: u
169
+ groupTitle: s,
170
+ failureReason: n
367
171
  }
368
172
  })).failureMessage.trim();
369
173
  if (p)
@@ -371,36 +175,36 @@ Not added members:
371
175
  status: "success",
372
176
  outputMessage: p
373
177
  };
374
- } catch (d) {
375
- console.error("Error generating create-group failure message:", d);
178
+ } catch (m) {
179
+ console.error("Error generating create-group failure message:", m);
376
180
  }
377
181
  return {
378
182
  status: "success",
379
183
  outputMessage: "I could not create that group. Please confirm your permissions and try again with the group title."
380
184
  };
381
185
  }
382
- const o = c.id;
186
+ const c = l.id;
383
187
  try {
384
- const d = (await b({
385
- promptText: kt,
386
- schema: Gt,
188
+ const m = (await b({
189
+ promptText: Et,
190
+ schema: qt,
387
191
  modelTier: "fast",
388
192
  inputVariables: {
389
- groupTitle: e
193
+ groupTitle: s
390
194
  }
391
195
  })).successMessage.trim();
392
- if (d)
196
+ if (m)
393
197
  return {
394
198
  status: "success",
395
- outputMessage: d,
396
- sharedStatePatch: { createdGroupId: { value: o } },
397
- createdGroupId: o
199
+ outputMessage: m,
200
+ sharedStatePatch: { createdGroupId: { value: c } },
201
+ createdGroupId: c
398
202
  };
399
- } catch (u) {
400
- console.error("Error generating create-group success message:", u);
203
+ } catch (n) {
204
+ console.error("Error generating create-group success message:", n);
401
205
  }
402
206
  return {};
403
- }, kt = `
207
+ }, Et = `
404
208
  Write a concise, friendly success message after creating a portal group.
405
209
 
406
210
  Rules:
@@ -411,7 +215,7 @@ Rules:
411
215
 
412
216
  Group title:
413
217
  {groupTitle}
414
- `, qt = `
218
+ `, Dt = `
415
219
  Write a concise, friendly failure message after an attempt to create a portal group.
416
220
 
417
221
  Rules:
@@ -426,25 +230,39 @@ Group title:
426
230
 
427
231
  Failure reason:
428
232
  {failureReason}
429
- `, Dt = n.object({
430
- intent: n.enum(["clarify", "create", "addMembers"]).default("clarify"),
431
- title: n.string().default(""),
432
- memberIdentifiers: n.array(n.string()).default([]),
433
- clarifyMessage: n.string().default("")
434
- }), Rt = async (s, t) => {
233
+ `, x = (e) => {
234
+ for (let t = e.length - 1; t >= 0; t -= 1) {
235
+ const s = e[t];
236
+ if (s.type !== "human")
237
+ continue;
238
+ const a = s.content;
239
+ if (typeof a == "string")
240
+ return a;
241
+ if (Array.isArray(a))
242
+ return a.map(
243
+ (r) => typeof r == "string" ? r : "text" in r && typeof r.text == "string" ? r.text : ""
244
+ ).join(" ").trim();
245
+ }
246
+ return "";
247
+ }, zt = o.object({
248
+ intent: o.enum(["clarify", "create", "addMembers"]).default("clarify"),
249
+ title: o.string().default(""),
250
+ memberIdentifiers: o.array(o.string()).default([]),
251
+ clarifyMessage: o.string().default("")
252
+ }), Ut = async (e, t) => {
435
253
  await g({ text: "Thinking about groups...", agentName: "group-creation" }, t);
436
- const e = x(s.agentExecutionContext.messages).trim(), a = await b({
437
- promptText: Ut,
438
- schema: Dt,
254
+ const s = x(e.agentExecutionContext.messages).trim(), a = await b({
255
+ promptText: Rt,
256
+ schema: zt,
439
257
  modelTier: "default",
440
- inputVariables: { userMessage: e }
441
- }), r = a.title.trim(), l = a.memberIdentifiers.filter(Boolean), c = a.clarifyMessage.trim(), i = a.intent === "create" && !!r, o = a.intent === "addMembers" && l.length > 0;
258
+ inputVariables: { userMessage: s }
259
+ }), r = a.title.trim(), i = a.memberIdentifiers.filter(Boolean), l = a.clarifyMessage.trim(), u = a.intent === "create" && !!r, c = a.intent === "addMembers" && i.length > 0;
442
260
  return {
443
- intentParams: i ? { intent: "create", title: r } : o ? { intent: "addMembers", memberInfo: { memberIdentifiers: l } } : { intent: "clarify" },
261
+ intentParams: u ? { intent: "create", title: r } : c ? { intent: "addMembers", memberInfo: { memberIdentifiers: i } } : { intent: "clarify" },
444
262
  status: "success",
445
- outputMessage: !i && !o ? c : ""
263
+ outputMessage: !u && !c ? l : ""
446
264
  };
447
- }, Ut = `
265
+ }, Rt = `
448
266
  You classify whether a user is asking to create a new ArcGIS Portal group or add members to an existing group.
449
267
 
450
268
  Rules:
@@ -470,142 +288,138 @@ Examples:
470
288
 
471
289
  User message:
472
290
  {userMessage}
473
- `, zt = n.discriminatedUnion("destinationType", [
474
- n.object({
475
- destinationType: n.literal("portal-content")
291
+ `, Ft = o.discriminatedUnion("destinationType", [
292
+ o.object({
293
+ destinationType: o.literal("portal-content")
476
294
  }),
477
- n.object({
478
- destinationType: n.literal("portal-groups")
295
+ o.object({
296
+ destinationType: o.literal("portal-groups")
479
297
  }),
480
- n.object({
481
- destinationType: n.literal("portal-item"),
482
- itemId: n.string().trim().min(1)
298
+ o.object({
299
+ destinationType: o.literal("portal-item"),
300
+ itemId: o.string().trim().min(1)
483
301
  }),
484
- n.object({
485
- destinationType: n.literal("portal-group"),
486
- groupId: n.string().trim().min(1)
302
+ o.object({
303
+ destinationType: o.literal("portal-group"),
304
+ groupId: o.string().trim().min(1)
487
305
  })
488
- ]);
489
- function jt(s) {
490
- const t = zt.safeParse(s);
491
- return t.success ? t.data : void 0;
492
- }
493
- const _ = "portal-navigation", J = async (s, t) => {
494
- await B({ type: _, data: { ...s } }, t);
495
- }, Vt = async (s, t) => {
496
- const e = s.createdGroupId ?? s.agentExecutionContext.sharedState.createdGroupId?.value;
497
- return e ? (await g({ text: "Preparing navigation...", agentName: "group-creation" }, t), await J({ destinationType: "portal-group", groupId: e }, t), {}) : {};
498
- }, z = (s, t) => t ?? s, Y = h.Root({
499
- ...E(),
306
+ ]), _ = "portal-navigation", R = async (e, t) => {
307
+ const s = t?.configurable?.context;
308
+ !Y(s) || !s.navigationTargetMap?.[e.destinationType] || await E({ type: _, data: { ...e } }, t);
309
+ }, jt = async (e, t) => {
310
+ const s = e.createdGroupId ?? e.agentExecutionContext.sharedState.createdGroupId?.value;
311
+ return s ? (await g({ text: "Preparing navigation...", agentName: "group-creation" }, t), await R({ destinationType: "portal-group", groupId: s }, t), {}) : {};
312
+ }, L = (e, t) => t ?? e, H = f.Root({
313
+ ...N(),
500
314
  // * Shared state between nodes (but not persisted to the agent execution context)
501
315
  /** Parameters related to the user's intent for group creation actions */
502
- intentParams: h({ reducer: z, default: () => ({ intent: "clarify" }) }),
316
+ intentParams: f({ reducer: L, default: () => ({ intent: "clarify" }) }),
503
317
  /** The ID of the group that was created
504
318
  * even though we already have this in the shared state
505
319
  * we still need it here to also share between nodes
506
320
  */
507
- createdGroupId: h({ reducer: z, default: () => "" })
508
- }), Ft = () => new $(Y).addNode("detectGroupCreationIntent", Rt).addNode("createPortalGroup", Nt).addNode("addMembersToPortalGroup", Ct).addNode("suggestCreatedGroupNavigation", Vt).addEdge(G, "detectGroupCreationIntent").addConditionalEdges("detectGroupCreationIntent", (t) => {
321
+ createdGroupId: f({ reducer: L, default: () => "" })
322
+ }), Ot = () => new C(H).addNode("detectGroupCreationIntent", Ut).addNode("createPortalGroup", kt).addNode("addMembersToPortalGroup", Pt).addNode("suggestCreatedGroupNavigation", jt).addEdge(P, "detectGroupCreationIntent").addConditionalEdges("detectGroupCreationIntent", (t) => {
509
323
  switch (t.intentParams.intent) {
510
324
  case "create":
511
325
  return "createPortalGroup";
512
326
  case "addMembers":
513
327
  return "addMembersToPortalGroup";
514
328
  default:
515
- return y;
329
+ return h;
516
330
  }
517
- }).addEdge("createPortalGroup", "suggestCreatedGroupNavigation").addEdge("addMembersToPortalGroup", "suggestCreatedGroupNavigation").addEdge("suggestCreatedGroupNavigation", y), Bt = String.raw`- **portal-group-creation** - Portal group creation assistant:
331
+ }).addEdge("createPortalGroup", "suggestCreatedGroupNavigation").addEdge("addMembersToPortalGroup", "suggestCreatedGroupNavigation").addEdge("suggestCreatedGroupNavigation", h), Vt = String.raw`- **portal-group-creation** - Portal group creation assistant:
518
332
  - creates a new ArcGIS Portal group for the signed-in user
519
333
  - adds users to the newly created group using @mention usernames
520
- `, Lt = {
334
+ `, Bt = {
521
335
  id: "portal-group-creation",
522
336
  name: "Portal Group Creation",
523
- description: Bt,
524
- createGraph: Ft,
525
- workspace: Y
526
- }, H = "portalDocAssistantMemory", Qt = () => ({ conversationId: "" }), Kt = (s) => {
527
- const t = s?.[H]?.value;
337
+ description: Vt,
338
+ createGraph: Ot,
339
+ workspace: H
340
+ }, X = "portalDocAssistantMemory", Qt = () => ({ conversationId: "" }), Lt = (e) => {
341
+ const t = e?.[X]?.value;
528
342
  if (!t || typeof t != "object")
529
343
  return Qt();
530
- const e = t;
344
+ const s = t;
531
345
  return {
532
- conversationId: typeof e.conversationId == "string" ? e.conversationId : ""
346
+ conversationId: typeof s.conversationId == "string" ? s.conversationId : ""
533
347
  };
534
- }, Wt = (s) => ({
535
- [H]: { value: s }
348
+ }, Jt = (e) => ({
349
+ [X]: { value: e }
536
350
  });
537
- async function Ot({
538
- portal: s,
351
+ async function Kt({
352
+ portal: e,
539
353
  question: t,
540
- persona: e,
354
+ persona: s,
541
355
  previousConversationId: a,
542
356
  signal: r,
543
- skillId: l
357
+ skillId: i
544
358
  }) {
545
- l ??= "doc_ai_assistant";
546
- const i = await _t({
547
- portal: s,
548
- skillId: l,
359
+ i ??= "doc_ai_assistant";
360
+ const u = await Wt({
361
+ portal: e,
362
+ skillId: i,
549
363
  message: t,
550
364
  options: { context: {
551
365
  kind: "DocAIAssistantRequest",
552
- filters: { persona: { persona: e } }
366
+ filters: { persona: { persona: s } }
553
367
  }, previousConversationId: a, signal: r }
554
368
  });
555
369
  return {
556
- reply: Jt(i, l),
557
- conversationId: i[0]?.conversationId ?? ""
370
+ reply: Yt(u, i),
371
+ conversationId: u[0]?.conversationId ?? ""
558
372
  };
559
373
  }
560
- async function _t({
561
- portal: s,
374
+ async function Wt({
375
+ portal: e,
562
376
  skillId: t,
563
- message: e,
377
+ message: s,
564
378
  options: a
565
379
  }) {
566
- const l = `${s.helperServices.aiAssistantServices.url}/skills/${t}/chat`, c = {
380
+ const i = `${e.helperServices.aiAssistantServices.url}/skills/${t}/chat`, l = {
567
381
  "Content-Type": "application/json",
568
- token: mt.findCredential(s.url)?.token ?? ""
569
- }, i = await k(l, {
382
+ token: It.findCredential(e.url)?.token ?? ""
383
+ }, u = await j(i, {
570
384
  method: "post",
571
385
  body: JSON.stringify({
572
- message: e,
386
+ message: s,
573
387
  context: a.context,
574
388
  conversationId: a.previousConversationId
575
389
  }),
576
- headers: c,
390
+ headers: l,
577
391
  signal: a.signal
578
392
  });
579
- if (i.httpStatus !== 200)
580
- throw new Error(`Doc assistant chat failed (${i.httpStatus})`, {
581
- cause: i.data
393
+ if (u.httpStatus !== 200)
394
+ throw new Error(`Doc assistant chat failed (${u.httpStatus})`, {
395
+ cause: u.data
582
396
  });
583
- const o = i.data, u = [o], { conversationId: d, inquiryId: p } = o, m = async (f, v) => {
397
+ const c = u.data, n = [c], { conversationId: m, inquiryId: p } = c, d = async (y, v) => {
584
398
  if (!v)
585
399
  return;
586
- await ot(1e3);
587
- const S = await k(l, {
400
+ await gt(1e3);
401
+ const w = await j(i, {
588
402
  method: "post",
589
- body: JSON.stringify({ conversationId: d, inquiryId: p, ackSequenceNumber: f }),
590
- headers: c,
403
+ body: JSON.stringify({ conversationId: m, inquiryId: p, ackSequenceNumber: y }),
404
+ headers: l,
591
405
  signal: a.signal
592
406
  });
593
- if (S.httpStatus !== 200)
594
- throw new Error(`Doc assistant poll failed (${S.httpStatus})`, {
595
- cause: S.data
407
+ if (w.httpStatus !== 200)
408
+ throw new Error(`Doc assistant poll failed (${w.httpStatus})`, {
409
+ cause: w.data
596
410
  });
597
- const A = S.data;
598
- u.push(A), await m(A.sequenceNumber, A.hasMore);
411
+ const S = w.data;
412
+ n.push(S), await d(S.sequenceNumber, S.hasMore);
599
413
  };
600
- return o.hasMore && await m(o.sequenceNumber, o.hasMore), u;
414
+ return c.hasMore && await d(c.sequenceNumber, c.hasMore), n;
601
415
  }
602
- function Jt(s, t) {
416
+ function Yt(e, t) {
603
417
  switch (t) {
604
418
  case "doc_chat":
605
- return s.find((e) => e.message != null)?.message ?? "";
419
+ return e.find((s) => s.message != null)?.message ?? "";
606
420
  case "doc_ai_assistant":
607
- for (let e = s.length - 1; e >= 0; e -= 1) {
608
- const a = s[e];
421
+ for (let s = e.length - 1; s >= 0; s -= 1) {
422
+ const a = e[s];
609
423
  if (a.context?.kind === "DocAIAssistantContext") {
610
424
  const r = a.context.results?.[0]?.reply;
611
425
  if (r)
@@ -614,42 +428,42 @@ function Jt(s, t) {
614
428
  }
615
429
  return "";
616
430
  default:
617
- return P(t);
431
+ return T(t);
618
432
  }
619
433
  }
620
- const Yt = async (s, t) => {
434
+ const _t = async (e, t) => {
621
435
  await g({ text: "Asking documentation assistant...", agentName: "doc-assistant" }, t);
622
- const e = x(s.agentExecutionContext.messages).trim();
623
- if (!e)
436
+ const s = x(e.agentExecutionContext.messages).trim();
437
+ if (!s)
624
438
  return {
625
439
  status: "success",
626
440
  outputMessage: "Please share your question and I can help with ArcGIS and Portal documentation."
627
441
  };
628
442
  const a = t?.configurable?.context;
629
443
  I(a);
630
- const r = Kt(s.agentExecutionContext.sharedState), { reply: l, conversationId: c } = await Ot({
444
+ const r = Lt(e.agentExecutionContext.sharedState), { reply: i, conversationId: l } = await Kt({
631
445
  portal: a.portal,
632
- question: e,
446
+ question: s,
633
447
  previousConversationId: r.conversationId || void 0,
634
448
  skillId: "doc_ai_assistant",
635
449
  persona: "developers"
636
450
  });
637
451
  return {
638
452
  status: "success",
639
- outputMessage: l.trim() || "I could not retrieve a response from the documentation assistant.",
640
- sharedStatePatch: Wt({
641
- conversationId: c || r.conversationId
453
+ outputMessage: i.trim() || "I could not retrieve a response from the documentation assistant.",
454
+ sharedStatePatch: Jt({
455
+ conversationId: l || r.conversationId
642
456
  })
643
457
  };
644
- }, Ht = K(
645
- async ({ groupTitle: s }, t) => {
646
- const e = s.trim();
647
- if (!e)
458
+ }, Z = W(
459
+ async ({ groupTitle: e }, t) => {
460
+ const s = e.trim();
461
+ if (!s)
648
462
  return null;
649
463
  const a = t?.configurable?.context;
650
464
  I(a);
651
465
  try {
652
- return (await ut(a.portal, { query: `title:${e}`, num: 1 }))?.results[0]?.id || null;
466
+ return (await yt(a.portal, { query: `title:${s}`, num: 1 }))?.results[0]?.id || null;
653
467
  } catch (r) {
654
468
  return console.error("Error searching for portal group by title:", r), null;
655
469
  }
@@ -657,41 +471,58 @@ const Yt = async (s, t) => {
657
471
  {
658
472
  name: "resolvePortalGroupIdByTitle",
659
473
  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.",
660
- schema: n.object({
661
- groupTitle: n.string().describe("The portal group title to resolve to a group id.")
474
+ schema: o.object({
475
+ groupTitle: o.string().describe("The portal group title to resolve to a group id.")
662
476
  })
663
477
  }
664
- ), j = n.object({
665
- shouldSuggestNavigation: n.boolean().default(!1),
666
- destinationType: n.enum(["none", "portal-content", "portal-item", "portal-groups", "portal-group"]).default("none"),
667
- itemId: n.string().default(""),
668
- groupId: n.string().default("")
669
- }), Xt = async (s, t) => {
478
+ ), tt = W(
479
+ async ({ itemTitle: e }, t) => {
480
+ const s = e.trim();
481
+ if (!s)
482
+ return null;
483
+ const a = t?.configurable?.context;
484
+ I(a);
485
+ const { result: r, error: i } = await wt(a.portal, s, { num: 1 });
486
+ return i && console.error("Error searching for portal item by title:", i), r?.results[0]?.id || null;
487
+ },
488
+ {
489
+ name: "resolvePortalItemIdByTitle",
490
+ 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.',
491
+ schema: o.object({
492
+ itemTitle: o.string().describe("The portal item title to resolve to an item id.")
493
+ })
494
+ }
495
+ ), J = o.object({
496
+ shouldSuggestNavigation: o.boolean().default(!1),
497
+ destinationType: o.enum(["none", "portal-content", "portal-item", "portal-groups", "portal-group"]).default("none"),
498
+ itemId: o.string().default(""),
499
+ groupId: o.string().default("")
500
+ }), Ht = async (e, t) => {
670
501
  await g({ text: "Extracting navigation intent...", agentName: "doc-assistant" }, t);
671
- const e = s.outputMessage.trim();
672
- if (!e)
502
+ const s = e.outputMessage.trim();
503
+ if (!s)
673
504
  return {};
674
- const a = x(s.agentExecutionContext.messages).trim(), r = await L.fromTemplate(te).format({
505
+ const a = x(e.agentExecutionContext.messages).trim(), r = await z.fromTemplate(Zt).format({
675
506
  question: a,
676
- response: e
677
- }), c = await Q({
678
- model: await F("default"),
679
- tools: [W, Ht],
507
+ response: s
508
+ }), l = await U({
509
+ model: await D({ modelTier: "default" }),
510
+ tools: [tt, Z],
680
511
  systemPrompt: r,
681
- responseFormat: j,
512
+ responseFormat: J,
682
513
  checkpointer: !0
683
- }).invoke({ messages: s.agentExecutionContext.messages }, t), i = j.parse(c.structuredResponse ?? {});
684
- if (!i.shouldSuggestNavigation || i.destinationType === "none")
514
+ }).invoke({ messages: e.agentExecutionContext.messages }, t), u = J.parse(l.structuredResponse ?? {});
515
+ if (!u.shouldSuggestNavigation || u.destinationType === "none")
685
516
  return {};
686
- const o = Zt(i);
687
- return o ? (await J(o, t), {}) : {};
517
+ const c = Xt(u);
518
+ return c ? (await R(c, t), {}) : {};
688
519
  };
689
- function Zt({
690
- destinationType: s,
520
+ function Xt({
521
+ destinationType: e,
691
522
  itemId: t,
692
- groupId: e
523
+ groupId: s
693
524
  }) {
694
- switch (s) {
525
+ switch (e) {
695
526
  case "portal-content":
696
527
  return { destinationType: "portal-content" };
697
528
  case "portal-groups":
@@ -699,14 +530,14 @@ function Zt({
699
530
  case "portal-item":
700
531
  return t ? { destinationType: "portal-item", itemId: t } : null;
701
532
  case "portal-group":
702
- return e ? { destinationType: "portal-group", groupId: e } : null;
533
+ return s ? { destinationType: "portal-group", groupId: s } : null;
703
534
  case "none":
704
535
  return null;
705
536
  default:
706
- return P(s);
537
+ return T(e);
707
538
  }
708
539
  }
709
- const te = `
540
+ const Zt = `
710
541
  You decide whether the assistant response should include a navigation action to ArcGIS Portal.
711
542
 
712
543
  Given the user question and assistant response:
@@ -730,125 +561,603 @@ User question:
730
561
 
731
562
  Assistant response:
732
563
  {response}
733
- `, X = dt.Root({
734
- ...E()
735
- }), ee = () => new $(X).addNode("answerDocQuestion", Yt).addNode("extractNavigationIntent", Xt).addEdge(G, "answerDocQuestion").addEdge("answerDocQuestion", "extractNavigationIntent").addEdge("extractNavigationIntent", y), se = String.raw`- **portal-doc-assistant** - General ArcGIS documentation and Portal help assistant:
564
+ `, et = xt.Root({
565
+ ...N()
566
+ }), te = () => new C(et).addNode("answerDocQuestion", _t).addNode("extractNavigationIntent", Ht).addEdge(P, "answerDocQuestion").addEdge("answerDocQuestion", "extractNavigationIntent").addEdge("extractNavigationIntent", h), ee = String.raw`- **portal-doc-assistant** - General ArcGIS documentation and Portal help assistant:
736
567
  - answers general ArcGIS, Portal, Enterprise, and JavaScript SDK questions
737
568
  - acts as a fallback when specialized agents are not applicable
738
- `, ae = {
569
+ `, se = {
739
570
  id: "portal-doc-assistant",
740
571
  name: "Portal Doc Assistant",
741
- description: se,
742
- createGraph: ee,
743
- workspace: X
744
- }, re = st`: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)}`, oe = (s, t) => {
745
- const { destinationType: e } = s, a = `${t.url}/home`;
746
- switch (e) {
572
+ description: ee,
573
+ createGraph: te,
574
+ workspace: et
575
+ }, st = `
576
+ Shared markdown formatting rules:
577
+ - Use clear markdown headings (##) to separate sections.
578
+ - Use concise bullet points for lists of facts, counts, or signals.
579
+ - Emphasize key metrics with bold labels (for example: **Recent items:** 4).
580
+ - Keep wording direct and analytical; avoid filler language but make sure the language is friendly.
581
+ - Do not include raw internal IDs unless explicitly requested.
582
+ `, ae = () => ({ latestGroupId: null, memory: {} }), q = (e) => {
583
+ const t = e?.agentExecutionContext.sharedState.portalGroupSummaryMemory?.value;
584
+ return t ? { latestGroupId: t.latestGroupId, memory: t.memory } : ae();
585
+ }, re = async (e, t) => {
586
+ await g({ text: "Answering group follow-up...", agentName: "group-analytics" }, t);
587
+ const s = q(e), a = e.groupSummaryGroupId ?? s.latestGroupId, r = a ? s.memory[a] : void 0, i = e.groupSummaryQuestion || x(e.agentExecutionContext.messages);
588
+ return r ? {
589
+ status: "success",
590
+ outputMessage: (await b({
591
+ promptText: ne,
592
+ schema: oe,
593
+ modelTier: "default",
594
+ inputVariables: {
595
+ summary: r.summary,
596
+ question: i,
597
+ fullContext: JSON.stringify(r.fullContext)
598
+ }
599
+ })).answer
600
+ } : {
601
+ status: "success",
602
+ outputMessage: "I do not have group analytics context yet. Ask me to analyze a group first with analyze group <group id>."
603
+ };
604
+ }, oe = o.object({
605
+ answer: o.string(),
606
+ isRelevant: o.boolean()
607
+ }), ne = `
608
+ You answer follow-up questions about ArcGIS group analytics.
609
+
610
+ ${st}
611
+
612
+ Ground your answer in the provided group analytics summary and context.
613
+ If the answer is not available from the provided context, state that clearly and suggest what to check next.
614
+
615
+ Response rules:
616
+ - Reply in concise markdown with this section structure:
617
+ 1) ## Answer
618
+ 2) ## Evidence
619
+ 3) ## Gaps (only when data is missing)
620
+ - Keep the answer focused on the follow-up question.
621
+ - Do not include internal identifiers.
622
+ - Mark isRelevant=false when the question is not about this group or cannot be grounded in this group context.
623
+
624
+ Group analytics summary:
625
+ {summary}
626
+
627
+ Group full context:
628
+ {fullContext}
629
+
630
+ Question:
631
+ {question}
632
+ `, ie = async (e, t) => {
633
+ await g({ text: "Analyzing group-analytics intent...", agentName: "group-analytics" }, t);
634
+ const s = x(e.agentExecutionContext.messages), a = !!q(e).latestGroupId, r = await z.fromTemplate(le).format({
635
+ userMessage: s,
636
+ hasAnalyticsContext: String(a)
637
+ }), l = await U({
638
+ model: await D({ modelTier: "fast" }),
639
+ tools: [Z],
640
+ systemPrompt: r,
641
+ responseFormat: ue,
642
+ checkpointer: !0
643
+ }).invoke({ messages: e.agentExecutionContext.messages }, t), { intent: u, groupId: c, question: n } = l.structuredResponse, m = u === "summarize" && !c, p = u === "followUp" && !(n ?? "").trim(), d = u === "clarify" || m || p;
644
+ return {
645
+ groupSummaryIntent: d ? "clarify" : u,
646
+ groupSummaryGroupId: c || null,
647
+ groupSummaryQuestion: n || "",
648
+ status: "success",
649
+ outputMessage: d ? "Please clarify with a group id or title" : ""
650
+ };
651
+ }, ue = o.object({
652
+ intent: o.enum(["summarize", "followUp", "navigation", "clarify"]),
653
+ groupId: o.string().default(""),
654
+ question: o.string().default("")
655
+ }), le = `
656
+ Classify the user's request for ArcGIS Portal group analytics.
657
+
658
+ Rules:
659
+ - intent="summarize" only when the user explicitly asks to summarize, analyze, overview, or recap a group.
660
+ - intent="followUp" for follow-up questions about a previously analyzed group.
661
+ - intent="navigation" when the user asks to open, go to, navigate to, or view the group page.
662
+ - intent="clarify" when intent or required group target is missing.
663
+ - groupId must be the final resolved group id.
664
+ - If request has explicit group id, set groupId directly.
665
+ - If request references group title (for example $title, $"title with spaces", or plain quoted group title), call resolvePortalGroupIdByTitle and set groupId to the tool result.
666
+ - Never return group titles in output fields.
667
+ - If intent is "followUp", set question to the user's full question/request text.
668
+ - If intent is "navigation", set question="".
669
+ - If intent is "summarize", set question="".
670
+ - If intent is "navigation" and no group is specified, leave groupId empty so the system can navigate to the groups listing page.
671
+ - If hasAnalyticsContext is true and the user asks about the same group context without an explicit summarize/analyze command, prefer "followUp".
672
+
673
+ Examples:
674
+ - "Analyze group 0123456789abcdef0123456789abcdef" => summarize, groupId="0123456789abcdef0123456789abcdef"
675
+ - "Analyze group $living atlas" => summarize, call resolvePortalGroupIdByTitle("living atlas") and set groupId to tool result
676
+ - "Analyze group $"living atlas basemaps"" => summarize, call resolvePortalGroupIdByTitle("living atlas basemaps") and set groupId to tool result
677
+ - "Is this group active?" with hasAnalyticsContext=true => followUp
678
+
679
+ hasAnalyticsContext:
680
+ {hasAnalyticsContext}
681
+
682
+ User message:
683
+ {userMessage}
684
+ `, ce = async (e, t) => {
685
+ const s = q(e), a = e.groupSummaryGroupId ?? s.latestGroupId;
686
+ return await g({ text: "Preparing navigation...", agentName: "group-analytics" }, t), await R(
687
+ a ? { destinationType: "portal-group", groupId: a } : { destinationType: "portal-groups" },
688
+ t
689
+ ), { status: "success" };
690
+ };
691
+ function at({ timestamp: e, now: t, windowMs: s }) {
692
+ return e ? t - e <= s : !1;
693
+ }
694
+ const me = 720 * 60 * 60 * 1e3;
695
+ function de(e) {
696
+ const t = vt(e);
697
+ return {
698
+ id: e.id ?? "",
699
+ title: e.title ?? "",
700
+ description: e.description ?? "",
701
+ snippet: e.snippet ?? "",
702
+ access: e.access ?? null,
703
+ owner: e.owner ?? "",
704
+ tags: e.tags ?? [],
705
+ created: e.created?.getTime(),
706
+ modified: e.modified?.getTime(),
707
+ isInvitationOnly: e.isInvitationOnly,
708
+ sourceSignals: {
709
+ capabilities: At(e),
710
+ membershipAccess: Mt(e),
711
+ isOpenData: Gt(e),
712
+ isDistributedCollaborationGroup: St(e),
713
+ orgId: t.orgId,
714
+ hiddenMembers: t.hiddenMembers,
715
+ isViewOnly: t.isViewOnly,
716
+ isReadOnly: t.isReadOnly,
717
+ leavingDisallowed: t.leavingDisallowed
718
+ }
719
+ };
720
+ }
721
+ async function pe(e) {
722
+ const t = { owner: e.owner ?? "", admins: [], users: [] };
723
+ try {
724
+ return await e.fetchMembers();
725
+ } catch (s) {
726
+ return console.warn("Unable to fetch group members for analytics context", s), t;
727
+ }
728
+ }
729
+ function ge(e) {
730
+ return e.map((t) => ({
731
+ id: t.id ?? "",
732
+ title: t.title ?? "Untitled",
733
+ type: t.type ?? "Unknown",
734
+ owner: t.owner ?? "",
735
+ created: t.created?.getTime(),
736
+ modified: t.modified?.getTime()
737
+ }));
738
+ }
739
+ function fe(e, t) {
740
+ return e.filter(
741
+ (s) => s.modified ? at({ timestamp: s.modified, now: t, windowMs: me }) : !1
742
+ );
743
+ }
744
+ function he(e) {
745
+ const t = /* @__PURE__ */ new Map();
746
+ for (const s of e)
747
+ t.set(s.type, (t.get(s.type) ?? 0) + 1);
748
+ return [...t.entries()].sort((s, a) => a[1] - s[1] || s[0].localeCompare(a[0])).slice(0, 6).map(([s, a]) => ({ type: s, count: a }));
749
+ }
750
+ async function ye(e) {
751
+ const t = await e.queryItems({ num: 20, sortField: "modified", sortOrder: "desc" }), s = ge(t.results), a = Date.now();
752
+ return {
753
+ total: t.total,
754
+ topItems: s,
755
+ recentlyModifiedItems: fe(s, a),
756
+ topItemTypes: he(s)
757
+ };
758
+ }
759
+ async function we(e, t) {
760
+ if (!t)
761
+ return { error: { code: "missingGroupId", message: "Group id is required." } };
762
+ try {
763
+ const a = (await e.queryGroups({ query: `id:${t}`, num: 1 })).results[0];
764
+ if (!a)
765
+ return { error: { code: "groupNotFound", message: `No group found for id: ${t}` } };
766
+ const r = de(a), i = await pe(a), l = await ye(a);
767
+ return { result: { group: r, members: i, items: l } };
768
+ } catch (s) {
769
+ return console.error("Error fetching portal group analytics context:", s), { error: { code: "unhandledError" } };
770
+ }
771
+ }
772
+ const be = 2160 * 60 * 60 * 1e3, Ie = async (e, t) => {
773
+ const s = e.groupSummaryGroupId;
774
+ if (!s)
775
+ return {
776
+ status: "success",
777
+ outputMessage: 'Please clarify with analyze group <group id>, analyze group $<title>, or analyze group $"<title with spaces>".'
778
+ };
779
+ await g({ text: `Analyzing group ${s}...`, agentName: "group-analytics" }, t);
780
+ const a = t?.configurable?.context;
781
+ I(a);
782
+ const { result: r, error: i } = await we(a.portal, s);
783
+ if (i || !r)
784
+ return await g({ text: "Failed to fetch group context", agentName: "group-analytics" }, t), {
785
+ status: "success",
786
+ outputMessage: "Unable to retrieve group context for analytics."
787
+ };
788
+ const { group: l, items: u } = r, c = Date.now(), n = l.modified, m = n ? at({ timestamp: n, now: c, windowMs: be }) : !1, p = u.recentlyModifiedItems.length, d = p > 0, y = m || d, v = await b({
789
+ promptText: ve,
790
+ schema: xe,
791
+ modelTier: "default",
792
+ inputVariables: {
793
+ context: JSON.stringify(r),
794
+ deterministicSignals: JSON.stringify({
795
+ isGroupActive: y,
796
+ isGroupRecentlyModified: m,
797
+ hasRecentlyAddedOrUpdatedContent: d,
798
+ recentItemCount: p
799
+ })
800
+ }
801
+ }), { followUpQuestions: w, summary: S } = v, nt = q(e), it = {
802
+ latestGroupId: s,
803
+ memory: {
804
+ ...nt.memory,
805
+ [s]: { summary: S, followUpQuestions: w, fullContext: r }
806
+ }
807
+ };
808
+ return w.length && await E({ type: "suggested-prompts", data: { prompts: w } }, t), {
809
+ status: "success",
810
+ outputMessage: S,
811
+ sharedStatePatch: { portalGroupSummaryMemory: { value: it } }
812
+ };
813
+ }, xe = o.object({
814
+ summary: o.string(),
815
+ followUpQuestions: o.array(o.string()).default([])
816
+ }), ve = `
817
+ You summarize ArcGIS Portal groups based on structured context and deterministic activity signals.
818
+
819
+ ${st}
820
+
821
+ Output format requirements:
822
+ - Return concise markdown with clear sections in this order:
823
+ 1) Overview
824
+ 2) Activity
825
+ 3) Members
826
+ 4) Content Theme
827
+ 5) Contribution Model
828
+ 6) Unknowns / Data Gaps
829
+ - Keep total response about 180-280 words unless the user asked for extra detail.
830
+ - Avoid internal-only implementation details and do not expose raw IDs unless user explicitly asks.
831
+
832
+ Reasoning rules:
833
+ - Use deterministicSignals as the source of truth for active/recent status.
834
+ - If group description/snippet are empty, infer purpose from tags, item title patterns, and item type distribution.
835
+ - For members, report owner/admin/user counts when available; if unavailable due to permission scope, explicitly say so.
836
+ - For contribution model, use membershipAccess, capabilities, and sourceJSON flags to characterize collaboration vs distribution behavior.
837
+ - Be explicit when signals are heuristic or unavailable.
838
+
839
+ Follow-up prompt rules:
840
+ - Generate exactly 3 follow-up prompts.
841
+ - Write them as direct first-person user chat prompts that can be clicked and sent as-is.
842
+ - Do not write meta-questions such as "Would you like..." or "Do you want me to...".
843
+ - Keep each prompt short, specific, and actionable.
844
+ - Every prompt must be answerable using only the provided group context and deterministic signals.
845
+ - Do not require external data, navigation, or additional fetches.
846
+ - Tailor each prompt to this specific group's available signals (content mix, activity, members, and contribution model).
847
+ - Avoid repeating phrasing from prior prompts or using generic template wording.
848
+ - If a signal is unavailable (for example members), do not ask follow-ups that depend on that missing signal.
849
+
850
+ Group context:
851
+ {context}
852
+
853
+ Deterministic signals:
854
+ {deterministicSignals}
855
+ `, $ = (e, t) => t ?? e, rt = f.Root({
856
+ ...N(),
857
+ groupSummaryIntent: f({
858
+ reducer: $,
859
+ default: () => "clarify"
860
+ }),
861
+ groupSummaryGroupId: f({
862
+ reducer: $,
863
+ default: () => null
864
+ }),
865
+ groupSummaryQuestion: f({
866
+ reducer: $,
867
+ default: () => ""
868
+ })
869
+ }), Se = () => new C(rt).addNode("detectGroupSummaryIntent", ie).addNode("summarizePortalGroup", Ie).addNode("answerGroupSummaryFollowUp", re).addNode("suggestGroupSummaryNavigation", ce).addEdge(P, "detectGroupSummaryIntent").addConditionalEdges("detectGroupSummaryIntent", (t) => t.groupSummaryIntent === "summarize" ? "summarizePortalGroup" : t.groupSummaryIntent === "followUp" ? "answerGroupSummaryFollowUp" : t.groupSummaryIntent === "navigation" ? "suggestGroupSummaryNavigation" : h).addEdge("summarizePortalGroup", h).addEdge("answerGroupSummaryFollowUp", h).addEdge("suggestGroupSummaryNavigation", h), Ge = String.raw`- **portal-group-analytics** - Portal group analytics assistant:
870
+ - summarizes ArcGIS portal groups from group context and sourceJSON details
871
+ - answers follow-up questions grounded in the summarized group
872
+ - suggests navigation to groups when relevant
873
+ `, Me = {
874
+ id: "portal-group-analytics",
875
+ name: "Portal Group Analytics",
876
+ description: Ge,
877
+ createGraph: Se,
878
+ workspace: rt
879
+ }, Ae = () => ({ latestItemId: null, memory: {} }), F = (e) => {
880
+ const t = e?.agentExecutionContext.sharedState.portalItemAnalyticsSummaryMemory?.value;
881
+ return t ? { latestItemId: t.latestItemId, memory: t.memory } : Ae();
882
+ }, Te = o.object({
883
+ intent: o.enum(["summarize", "followUp", "clarify"]),
884
+ itemId: o.string().default(""),
885
+ question: o.string().default("")
886
+ }), Ce = o.object({ summary: o.string(), followUpQuestions: o.array(o.string()).default([]) }), Pe = o.object({ answer: o.string(), isRelevant: o.boolean() }), Ne = async (e, t) => {
887
+ await g({ text: "Answering follow-up...", agentName: "analytics" }, t);
888
+ const s = F(e), a = e.analyticsItemId ?? s.latestItemId, r = a ? s.memory[a] : void 0, i = e.analyticsQuestion || x(e.agentExecutionContext.messages);
889
+ return r ? {
890
+ status: "success",
891
+ outputMessage: (await b({
892
+ promptText: qe,
893
+ schema: Pe,
894
+ modelTier: "default",
895
+ inputVariables: {
896
+ summary: r.summary,
897
+ question: i,
898
+ fullContext: JSON.stringify(r.fullContext)
899
+ }
900
+ })).answer
901
+ } : {
902
+ status: "success",
903
+ outputMessage: "I don't have enough information yet. Please ask me to summarize the item first using summarize item <item id>."
904
+ };
905
+ }, qe = `
906
+ You answer follow-up questions about an ArcGIS item.
907
+
908
+ Ground your answer in the provided item context.
909
+ If the answer is not available from the provided context, state that clearly and suggest what to check next.
910
+
911
+ Response rules:
912
+ - Reply in concise markdown.
913
+ - Keep the answer focused on the follow-up question.
914
+ - Do not include internal identifiers.
915
+ - Mark isRelevant=false when the question is not about this item or cannot be grounded in this item context.
916
+
917
+ Item summary:
918
+ {summary}
919
+
920
+ Item full context
921
+ {fullContext}
922
+
923
+ Question:
924
+ {question}
925
+ `, $e = async (e, t) => {
926
+ await g({ text: "Analyzing intent...", agentName: "analytics" }, t);
927
+ const s = x(e.agentExecutionContext.messages), a = !!F(e).latestItemId, r = await z.fromTemplate(ke).format({
928
+ userMessage: s,
929
+ hasSummaryContext: String(a)
930
+ }), l = await U({
931
+ model: await D({ modelTier: "fast" }),
932
+ tools: [tt],
933
+ systemPrompt: r,
934
+ responseFormat: Te,
935
+ checkpointer: !0
936
+ }).invoke({ messages: e.agentExecutionContext.messages }, t), { intent: u, itemId: c, question: n } = l.structuredResponse, d = u === "clarify" || u === "summarize" && !c || u === "followUp" && !n;
937
+ return {
938
+ agentExecutionContext: { ...e.agentExecutionContext },
939
+ analyticsIntent: d ? "clarify" : u,
940
+ analyticsItemId: c || null,
941
+ analyticsQuestion: n || "",
942
+ status: "success",
943
+ outputMessage: d ? 'Please clarify with summarize item <item id>, summarize item #<title>, or summarize item #"<title with spaces>".' : ""
944
+ };
945
+ }, ke = `
946
+ Classify the user analytics request.
947
+
948
+ Rules:
949
+ - intent="summarize" only when the user explicitly asks to summarize/overview/recap an item.
950
+ - intent="followUp" for analytical questions about item details, including schema/fields/attributes/layers.
951
+ - intent="clarify" when neither summarize nor follow-up intent is clear.
952
+ - itemId must be the final resolved item id.
953
+ - If request has explicit item id, set itemId directly.
954
+ - If request references item title (for example #title, #"title with spaces", or plain quoted title), call resolvePortalItemIdByTitle and set itemId to the returned value.
955
+ - Never return item titles in output fields.
956
+ - If intent is "followUp", set question to the user's full question/request text.
957
+ - If intent is "summarize", set question="".
958
+ - When user asks to show/list/explain fields, schema, attributes, columns, or layer details, classify as "followUp" unless they explicitly request a summary.
959
+ - If hasSummaryContext is true, prefer "followUp" for detail-oriented requests that do not explicitly ask to summarize.
960
+
961
+ Examples:
962
+ - "Summarize item 0123456789abcdef0123456789abcdef" => summarize, itemId="0123456789abcdef0123456789abcdef"
963
+ - "Summarize item #california" => summarize, call resolvePortalItemIdByTitle("california") and set itemId to tool result
964
+ - "Summarize item #"california farmland"" => summarize, call resolvePortalItemIdByTitle("california farmland") and set itemId to tool result
965
+ - "Show the layer's available fields" => followUp
966
+ - "List attributes and explain what status means" => followUp
967
+ - "What fields are available?" with hasSummaryContext=true => followUp
968
+ - "Give me an overview of item 0123456789abcdef0123456789abcdef" => summarize
969
+
970
+ hasSummaryContext:
971
+ {hasSummaryContext}
972
+
973
+ User message:
974
+ {userMessage}
975
+ `, Ee = async (e, t) => {
976
+ const s = e.analyticsItemId;
977
+ if (!s)
978
+ return {
979
+ status: "success",
980
+ outputMessage: 'Please clarify with summarize item <item id>, summarize item #<title>, or summarize item #"<title with spaces>".'
981
+ };
982
+ await g({ text: `Summarizing item ${s}...`, agentName: "analytics" }, t);
983
+ const a = t?.configurable?.context;
984
+ I(a);
985
+ const { portal: r, user: i } = a, { result: l, error: u } = await bt(i, r, s);
986
+ if (u || !l)
987
+ return await g({ text: "Failed to get item context for summarization", agentName: "analytics" }, t), {
988
+ status: "success",
989
+ outputMessage: "Unable to retrieve item context for summarization."
990
+ };
991
+ const { context: c } = l, n = await b({
992
+ promptText: De,
993
+ schema: Ce,
994
+ modelTier: "default",
995
+ inputVariables: { context: JSON.stringify(c) }
996
+ }), { followUpQuestions: m, summary: p } = n, d = F(e), y = {
997
+ latestItemId: s,
998
+ memory: {
999
+ ...d.memory,
1000
+ [s]: { summary: p, followUpQuestions: m, fullContext: c }
1001
+ }
1002
+ };
1003
+ return m.length && await E({ type: "suggested-prompts", data: { prompts: m } }, t), {
1004
+ status: "success",
1005
+ outputMessage: p,
1006
+ sharedStatePatch: { portalItemAnalyticsSummaryMemory: { value: y } }
1007
+ };
1008
+ }, De = `
1009
+ You are a item summary tool for ArcGIS. Your job is to summarize an item's info based on the provided context.
1010
+ Summary rules:
1011
+ - The summary should be concise markdown, make sure to format the output nicely so it's easy to read.
1012
+ - Target length: 80-150 words.
1013
+ - Provide one short descriptive paragraph.
1014
+ - Also propose 3 concise follow-up questions grounded in the item summary.
1015
+ - Keep follow-up questions specific and actionable.
1016
+ Follow-up questions rules:
1017
+ - These questions should be in the format of a prompt that the user can click on.
1018
+ - Make sure the questions are relevant to the item summary and that you can answer based solely on the provided context.
1019
+ Do not include internal identifiers.
1020
+ If the user asks for a detailed summary, you may expand the response up to 300 words.
1021
+ Item context:
1022
+ {context}
1023
+ `, k = (e, t) => t ?? e, ot = f.Root({
1024
+ ...N(),
1025
+ // States shared only across nodes in the graph, not between invocations
1026
+ analyticsIntent: f({
1027
+ reducer: k,
1028
+ default: () => "clarify"
1029
+ }),
1030
+ analyticsItemId: f({
1031
+ reducer: k,
1032
+ default: () => null
1033
+ }),
1034
+ analyticsQuestion: f({
1035
+ reducer: k,
1036
+ default: () => ""
1037
+ })
1038
+ }), ze = () => new C(ot).addNode("detectAnalyticsIntent", $e).addNode("summarizePortalItem", Ee).addNode("answerAnalyticsFollowUp", Ne).addEdge(P, "detectAnalyticsIntent").addConditionalEdges("detectAnalyticsIntent", (t) => t.analyticsIntent === "summarize" ? "summarizePortalItem" : t.analyticsIntent === "followUp" ? "answerAnalyticsFollowUp" : h).addEdge("summarizePortalItem", h).addEdge("answerAnalyticsFollowUp", h), Ue = String.raw`- **portal-item-analytics** - Portal item analytics assistant:
1039
+ - summarizes ArcGIS portal items from item context
1040
+ - suggests follow-up prompts grounded in the item
1041
+ `, Re = {
1042
+ id: "portal-item-analytics",
1043
+ name: "Portal Item Analytics",
1044
+ description: Ue,
1045
+ createGraph: ze,
1046
+ workspace: ot
1047
+ }, Fe = mt`: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)}`;
1048
+ function je(e, t) {
1049
+ if (!t)
1050
+ return;
1051
+ const { destinationType: s } = e;
1052
+ switch (s) {
747
1053
  case "portal-content":
748
- return `${a}/content.html`;
749
1054
  case "portal-groups":
750
- return `${a}/groups.html`;
1055
+ return t[s];
751
1056
  case "portal-item":
752
- return `${a}/item.html?id=${s.itemId}`;
1057
+ return t[s]?.(e.itemId);
753
1058
  case "portal-group":
754
- return `${a}/group.html?id=${s.groupId}`;
1059
+ return t[s]?.(e.groupId);
755
1060
  default:
756
- return P(e);
1061
+ return T(s);
757
1062
  }
758
- };
759
- class ne extends tt {
1063
+ }
1064
+ function Oe(e) {
1065
+ const t = Ft.safeParse(e);
1066
+ return t.success ? t.data : void 0;
1067
+ }
1068
+ class Ve extends lt {
760
1069
  constructor() {
761
- super(...arguments), this.t9n = rt({ blocking: !0 }), this.assistantEl = M(), this.formEl = M(), this.voiceInputEl = M(), this.inputEl = M(), this.navigationSlotElements = /* @__PURE__ */ new Map(), this.handleSlottableRequest = (t) => {
762
- const e = t.detail, a = e.data?.block;
1070
+ super(...arguments), this.t9n = pt({ blocking: !0 }), this.assistantEl = M(), this.formEl = M(), this.voiceInputEl = M(), this.inputEl = M(), this.navigationSlotElements = /* @__PURE__ */ new Map(), this.handleSlottableRequest = (t) => {
1071
+ const s = t.detail, a = s.data?.block;
763
1072
  if (!a)
764
1073
  return;
765
1074
  const r = this.getNavigationAction(a);
766
- r && this.upsertNavigationSlotElement(e.slotName, r);
767
- }, this.inputText = "", this.showVoiceInput = !0, this.isListening = !1, this.isVoiceInputDisabled = !1, this.interrupt = null, this.autoDestroyDisabled = !1, this.defaultClosed = !1, this.arcgisPortalNavigationRequest = et();
1075
+ r && this.upsertNavigationSlotElement(s.slotName, r);
1076
+ }, this.inputText = "", this.showVoiceInput = !0, this.isListening = !1, this.isVoiceInputDisabled = !1, this.interrupt = null, this.autoDestroyDisabled = !1, this.defaultClosed = !1, this.arcgisPortalNavigationRequest = ct();
768
1077
  }
769
1078
  static {
770
- this.properties = { inputText: 16, showVoiceInput: 16, isListening: 16, isVoiceInputDisabled: 16, interrupt: 16, autoDestroyDisabled: 5, portal: 0, user: 0, config: 0, defaultClosed: 5 };
1079
+ this.properties = { inputText: 16, showVoiceInput: 16, isListening: 16, isVoiceInputDisabled: 16, interrupt: 16, autoDestroyDisabled: 5, portal: 0, user: 0, config: 0, navigationTargetMap: 0, defaultClosed: 5 };
771
1080
  }
772
1081
  static {
773
- this.styles = re;
1082
+ this.styles = Fe;
774
1083
  }
775
1084
  getNavigationAction(t) {
776
1085
  if (t?.type !== _)
777
1086
  return;
778
- const e = jt(t.data);
779
- if (!e)
1087
+ const s = Oe(t.data);
1088
+ if (!s)
780
1089
  return;
781
- const a = oe(e, this.portal);
1090
+ const a = je(s, this.navigationTargetMap);
782
1091
  if (a)
783
- return { href: a, targetDetail: e, label: this.getNavigationText(e.destinationType) };
1092
+ return { href: a, targetDetail: s, label: this.getNavigationText(s.destinationType) };
784
1093
  }
785
- upsertNavigationSlotElement(t, e) {
1094
+ upsertNavigationSlotElement(t, s) {
786
1095
  const a = this.assistantEl.value;
787
1096
  if (!a)
788
1097
  return;
789
1098
  let r = this.navigationSlotElements.get(t);
790
- r || (r = document.createElement("div"), r.slot = t, this.navigationSlotElements.set(t, r), a.append(r)), at(w`<div><calcite-button class="navigation-button" appearance=outline width=full .href=${e.href} icon-end=launch @click=${(l) => {
791
- l.preventDefault(), this.arcgisPortalNavigationRequest.emit({
792
- href: e.href,
793
- targetDetail: e.targetDetail
1099
+ r || (r = document.createElement("div"), r.slot = t, this.navigationSlotElements.set(t, r), a.append(r)), dt(G`<div><calcite-button class="navigation-button" appearance=outline width=full .href=${s.href} icon-end=launch @click=${(i) => {
1100
+ i.preventDefault(), this.arcgisPortalNavigationRequest.emit({
1101
+ href: s.href,
1102
+ targetDetail: s.targetDetail
794
1103
  });
795
- }}>${e.label}</calcite-button>${e.description ? w`<div class="navigation-block-description">${e.description}</div>` : null}</div>`, r);
1104
+ }}>${s.label}</calcite-button>${s.description ? G`<div class="navigation-block-description">${s.description}</div>` : null}</div>`, r);
796
1105
  }
797
1106
  getNavigationText(t) {
798
- const e = this.t9n.navigation;
1107
+ const s = this.t9n.navigation;
799
1108
  switch (t) {
800
1109
  case "portal-content":
801
- return e.openContent;
1110
+ return s.openContent;
802
1111
  case "portal-groups":
803
- return e.openGroups;
1112
+ return s.openGroups;
804
1113
  case "portal-item":
805
- return e.openItem;
1114
+ return s.openItem;
806
1115
  case "portal-group":
807
- return e.openGroup;
1116
+ return s.openGroup;
808
1117
  default:
809
- return P(t);
1118
+ return T(t);
810
1119
  }
811
1120
  }
812
1121
  render() {
813
- const { t9n: t, inputText: e, portal: a, user: r, showVoiceInput: l, isListening: c, isVoiceInputDisabled: i } = this;
814
- return w`<arcgis-assistant log-enabled keep-suggested-prompts .heading=${t.heading} .entryMessage=${t.entryMessage} @arcgisSlottableRequest=${this.handleSlottableRequest} @arcgisInterrupt=${({ detail: o }) => {
815
- this.interrupt = o;
1122
+ const { t9n: t, inputText: s, portal: a, user: r, navigationTargetMap: i, showVoiceInput: l, isListening: u, isVoiceInputDisabled: c } = this;
1123
+ return G`<arcgis-assistant log-enabled keep-suggested-prompts .heading=${t.heading} .entryMessage=${t.entryMessage} @arcgisSlottableRequest=${this.handleSlottableRequest} @arcgisInterrupt=${({ detail: n }) => {
1124
+ this.interrupt = n;
816
1125
  }} @arcgisInterruptCancel=${() => {
817
1126
  this.interrupt = null;
818
1127
  }} @arcgisInterruptSubmit=${() => {
819
1128
  this.interrupt = null;
820
- }} @arcgisPromptSelect=${({ detail: o }) => {
821
- this.inputText = o.prompt, requestAnimationFrame(() => {
1129
+ }} @arcgisPromptSelect=${({ detail: n }) => {
1130
+ this.inputText = n.prompt, requestAnimationFrame(() => {
822
1131
  this.inputEl.value?.focusTextArea();
823
1132
  });
824
- }} ${T(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=${(o) => {
825
- o.preventDefault();
826
- const u = e.trim();
827
- u && (this.assistantEl.value?.submitMessage(u), this.inputText = "");
828
- }} ${T(this.formEl)}><arcgis-portal-mentionable-text-area .portal=${a} .user=${r} rows=3 .popoverListLabel=${t.mentionEntities} .placeholder=${t.placeholder} .value=${e} @arcgisUserMentionableTextAreaKeyDown=${({ detail: o }) => {
829
- o.key === "Enter" && !o.shiftKey && (o.preventDefault(), this.formEl.value?.requestSubmit());
830
- }} @arcgisUserMentionableTextAreaChange=${({ detail: o }) => {
831
- this.inputText = o ?? "";
832
- }} ${T(this.inputEl)}></arcgis-portal-mentionable-text-area><div class="chat-actions"><arcgis-portal-voice-input @arcgisVoiceInputStart=${() => {
1133
+ }} ${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=${(n) => {
1134
+ n.preventDefault();
1135
+ const m = s.trim();
1136
+ m && (this.assistantEl.value?.submitMessage(m), this.inputText = "");
1137
+ }} ${A(this.formEl)}><arcgis-portal-mentionable-text-area .portal=${a} .user=${r} rows=3 .popoverListLabel=${t.mentionEntities} .placeholder=${t.placeholder} .value=${s} @arcgisUserMentionableTextAreaKeyDown=${({ detail: n }) => {
1138
+ n.key === "Enter" && !n.shiftKey && (n.preventDefault(), this.formEl.value?.requestSubmit());
1139
+ }} @arcgisUserMentionableTextAreaChange=${({ detail: n }) => {
1140
+ this.inputText = n ?? "";
1141
+ }} ${A(this.inputEl)}></arcgis-portal-mentionable-text-area><div class="chat-actions"><arcgis-portal-voice-input @arcgisVoiceInputStart=${() => {
833
1142
  this.isListening = !0, this.isVoiceInputDisabled = !1;
834
1143
  }} @arcgisVoiceInputStop=${() => {
835
1144
  this.isListening = !1, this.isVoiceInputDisabled = !1;
836
- }} @arcgisVoiceInputError=${(o) => {
837
- o.detail.errorCode === "not-supported" && (this.showVoiceInput = !1);
838
- }} @arcgisVoiceInputInterimTranscription=${(o) => {
839
- this.inputText = o.detail.text;
840
- }} ${T(this.voiceInputEl)}></arcgis-portal-voice-input>${l && w`<calcite-button icon-start=microphone .label=${t.voiceInput} round .disabled=${i} .appearance=${c ? "solid" : "outline-fill"} @click=${async () => {
1145
+ }} @arcgisVoiceInputError=${(n) => {
1146
+ n.detail.errorCode === "not-supported" && (this.showVoiceInput = !1);
1147
+ }} @arcgisVoiceInputInterimTranscription=${(n) => {
1148
+ this.inputText = n.detail.text;
1149
+ }} ${A(this.voiceInputEl)}></arcgis-portal-voice-input>${l && G`<calcite-button icon-start=microphone .label=${t.voiceInput} round .disabled=${c} .appearance=${u ? "solid" : "outline-fill"} @click=${async () => {
841
1150
  this.isVoiceInputDisabled = !0;
842
- const o = this.voiceInputEl.value;
843
- c ? await o?.stopListening() : await o?.startListening();
844
- }}></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=${Tt} .context=${{ portal: a, user: r }}></arcgis-assistant-agent><arcgis-assistant-agent .agent=${Lt} .context=${{ portal: a, user: r }}></arcgis-assistant-agent><arcgis-assistant-agent .agent=${ae} .context=${{ portal: a, user: r }}></arcgis-assistant-agent>${this.interrupt && w`<arcgis-portal-ai-assistant-interrupt slot=interrupt .type=${this.interrupt.type} .message=${this.interrupt.message} .options=${this.interrupt.options} @arcgisSubmit=${({ detail: o }) => {
845
- this.assistantEl.value?.submitInterrupt(o);
1151
+ const n = this.voiceInputEl.value;
1152
+ u ? await n?.stopListening() : await n?.startListening();
1153
+ }}></calcite-button>` || ""}<calcite-button type=submit icon-start=send round .disabled=${!s.trim()} .label=${t.send}>${t.send}</calcite-button></div></form><arcgis-assistant-agent .agent=${Re} .context=${{ portal: a, user: r, navigationTargetMap: i }}></arcgis-assistant-agent><arcgis-assistant-agent .agent=${Bt} .context=${{ portal: a, user: r, navigationTargetMap: i }}></arcgis-assistant-agent><arcgis-assistant-agent .agent=${se} .context=${{ portal: a, user: r, navigationTargetMap: i }}></arcgis-assistant-agent><arcgis-assistant-agent .agent=${Me} .context=${{ portal: a, user: r, navigationTargetMap: i }}></arcgis-assistant-agent>${this.interrupt && G`<arcgis-portal-ai-assistant-interrupt slot=interrupt .type=${this.interrupt.type} .message=${this.interrupt.message} .options=${this.interrupt.options} @arcgisSubmit=${({ detail: n }) => {
1154
+ this.assistantEl.value?.submitInterrupt(n);
846
1155
  }} @arcgisCancel=${() => {
847
1156
  this.assistantEl.value?.cancelInterrupt();
848
1157
  }}></arcgis-portal-ai-assistant-interrupt>` || ""}</arcgis-assistant>`;
849
1158
  }
850
1159
  }
851
- Z("arcgis-portal-ai-assistant", ne);
1160
+ ut("arcgis-portal-ai-assistant", Ve);
852
1161
  export {
853
- ne as ArcgisPortalAiAssistant
1162
+ Ve as ArcgisPortalAiAssistant
854
1163
  };