@genesislcap/ai-assistant 15.24.2 → 15.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai-assistant.api.json +1065 -33
- package/dist/ai-assistant.d.ts +288 -102
- package/dist/chat-driver.cjs +630 -378
- package/dist/chat-driver.cjs.map +4 -4
- package/dist/chat-driver.mjs +630 -378
- package/dist/chat-driver.mjs.map +4 -4
- package/dist/custom-elements.json +1198 -388
- package/dist/dts/components/agent-session/agent-session.d.ts +134 -0
- package/dist/dts/components/agent-session/agent-session.d.ts.map +1 -0
- package/dist/dts/components/agent-session/index.d.ts +2 -0
- package/dist/dts/components/agent-session/index.d.ts.map +1 -0
- package/dist/dts/components/ai-driver/ai-driver.d.ts +31 -4
- package/dist/dts/components/ai-driver/ai-driver.d.ts.map +1 -1
- package/dist/dts/components/chat-driver/chat-driver.constants.d.ts +52 -0
- package/dist/dts/components/chat-driver/chat-driver.constants.d.ts.map +1 -0
- package/dist/dts/components/chat-driver/chat-driver.d.ts +100 -82
- package/dist/dts/components/chat-driver/chat-driver.d.ts.map +1 -1
- package/dist/dts/components/chat-driver/fold-controller.d.ts +82 -0
- package/dist/dts/components/chat-driver/fold-controller.d.ts.map +1 -0
- package/dist/dts/components/chat-driver/turn-failures.d.ts +20 -1
- package/dist/dts/components/chat-driver/turn-failures.d.ts.map +1 -1
- package/dist/dts/components/orchestrating-driver/orchestrating-driver.d.ts +14 -24
- package/dist/dts/components/orchestrating-driver/orchestrating-driver.d.ts.map +1 -1
- package/dist/dts/index.d.ts +1 -0
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/dts/main/main.d.ts +6 -16
- package/dist/dts/main/main.d.ts.map +1 -1
- package/dist/dts/suggestions/generate-suggestions.d.ts +35 -0
- package/dist/dts/suggestions/generate-suggestions.d.ts.map +1 -0
- package/dist/dts/utils/agents-key.d.ts +10 -0
- package/dist/dts/utils/agents-key.d.ts.map +1 -0
- package/dist/dts/utils/resolve-turn-input.d.ts +9 -0
- package/dist/dts/utils/resolve-turn-input.d.ts.map +1 -0
- package/dist/esm/components/agent-session/agent-session.js +208 -0
- package/dist/esm/components/agent-session/index.js +1 -0
- package/dist/esm/components/chat-driver/chat-driver.constants.js +72 -0
- package/dist/esm/components/chat-driver/chat-driver.js +190 -395
- package/dist/esm/components/chat-driver/fold-controller.js +184 -0
- package/dist/esm/components/chat-driver/turn-failures.js +14 -0
- package/dist/esm/components/orchestrating-driver/orchestrating-driver.js +48 -131
- package/dist/esm/index.js +1 -0
- package/dist/esm/main/main.js +11 -38
- package/dist/esm/suggestions/generate-suggestions.js +123 -0
- package/dist/esm/utils/agents-key.js +24 -0
- package/dist/esm/utils/resolve-turn-input.js +16 -0
- package/docs/migration-GENC-1580.md +44 -36
- package/package.json +16 -16
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { __awaiter } from "tslib";
|
|
2
|
+
import { logger } from '../utils/logger';
|
|
3
|
+
/** Turns of transcript given to the model when suggesting follow-ups. */
|
|
4
|
+
const HISTORY_WINDOW = 8;
|
|
5
|
+
/**
|
|
6
|
+
* The capabilities block: what the assistant can do, so suggestions cannot promise more.
|
|
7
|
+
*
|
|
8
|
+
* Prefers the host's full agent list; falls back to the active agent's own tools when the caller
|
|
9
|
+
* has no cross-agent view.
|
|
10
|
+
*/
|
|
11
|
+
function capabilities(ctx, allAgentInfo) {
|
|
12
|
+
let agentContext = '';
|
|
13
|
+
let toolContext = '';
|
|
14
|
+
if (allAgentInfo === null || allAgentInfo === void 0 ? void 0 : allAgentInfo.length) {
|
|
15
|
+
const agentDescriptions = allAgentInfo
|
|
16
|
+
.map((agent) => {
|
|
17
|
+
const tools = agent.tools.map((t) => t.name).join(', ');
|
|
18
|
+
return `- ${agent.name} (${agent.description}): ${tools ? `(Tools: ${tools})` : 'No tools'}`;
|
|
19
|
+
})
|
|
20
|
+
.join('\n');
|
|
21
|
+
agentContext = `The assistant has the following capabilities:\n${agentDescriptions}`;
|
|
22
|
+
const allToolNames = [
|
|
23
|
+
...new Set(allAgentInfo.flatMap((agent) => agent.tools.map((t) => t.name))),
|
|
24
|
+
].join(', ');
|
|
25
|
+
toolContext = allToolNames
|
|
26
|
+
? `You have access to the following tools across all agents: ${allToolNames}.`
|
|
27
|
+
: '';
|
|
28
|
+
}
|
|
29
|
+
else if (ctx.activeAgentName) {
|
|
30
|
+
const toolNames = ctx.toolDefinitions.map((tool) => tool.name).join(', ');
|
|
31
|
+
agentContext = `You are currently acting as the "${ctx.activeAgentName}" agent.`;
|
|
32
|
+
toolContext = toolNames ? `You have access to the following tools: ${toolNames}.` : '';
|
|
33
|
+
}
|
|
34
|
+
return agentContext || toolContext
|
|
35
|
+
? `\n\n<capabilities>\n${[agentContext, toolContext]
|
|
36
|
+
.filter(Boolean)
|
|
37
|
+
.join('\n')}\n</capabilities>\nSuggestions must only cover what the agent is capable of. Do not suggest anything outside these capabilities.`
|
|
38
|
+
: '';
|
|
39
|
+
}
|
|
40
|
+
const OUTPUT_FORMAT = (count) => `\n\nOutput format (strict):\n` +
|
|
41
|
+
`- Exactly ${count} lines.\n` +
|
|
42
|
+
`- One suggestion per line.\n` +
|
|
43
|
+
`- No numbering, bullets, markdown, emojis, code blocks, or quotes around the suggestion.\n` +
|
|
44
|
+
`- No preamble, headings, summary, or commentary before or after the list.`;
|
|
45
|
+
/**
|
|
46
|
+
* The system prompt sets the role only.
|
|
47
|
+
*
|
|
48
|
+
* Concrete instructions live in the user message *after* the transcript, so the context
|
|
49
|
+
* immediately preceding the model is "here is data, now do X" rather than "here is a dialogue,
|
|
50
|
+
* continue it". This matters for Anthropic — without it, Claude reads the transcript as an
|
|
51
|
+
* in-progress conversation and produces a normal assistant turn instead of a list.
|
|
52
|
+
*/
|
|
53
|
+
export const SUGGESTIONS_SYSTEM_PROMPT = 'You generate suggested prompts that a user could send to an AI assistant. ' +
|
|
54
|
+
'You never continue the conversation or roleplay as the assistant.';
|
|
55
|
+
/** Build the user message: starter prompts for an empty transcript, follow-ups otherwise. */
|
|
56
|
+
export function buildSuggestionsPrompt(ctx, history, prompt, count, allAgentInfo) {
|
|
57
|
+
const capabilitiesBlock = capabilities(ctx, allAgentInfo);
|
|
58
|
+
const guidanceBlock = prompt ? `\n\nAdditional guidance: "${prompt}"` : '';
|
|
59
|
+
if (history.length === 0) {
|
|
60
|
+
return (`Generate exactly ${count} brief starter prompts to show a user what an AI assistant can do. ` +
|
|
61
|
+
`Phrase each one as the user would write it. Keep them short and generic — do not invent specific names, IDs, or data (e.g. prefer "Search for a trade" over "Find all trades with Client A").` +
|
|
62
|
+
capabilitiesBlock +
|
|
63
|
+
guidanceBlock +
|
|
64
|
+
OUTPUT_FORMAT(count));
|
|
65
|
+
}
|
|
66
|
+
const conversationContext = history
|
|
67
|
+
.filter((m) => {
|
|
68
|
+
var _a, _b;
|
|
69
|
+
return (m.role === 'user' || m.role === 'assistant') &&
|
|
70
|
+
!((_a = m.toolCalls) === null || _a === void 0 ? void 0 : _a.length) &&
|
|
71
|
+
!m.thinking &&
|
|
72
|
+
!!((_b = m.content) === null || _b === void 0 ? void 0 : _b.trim());
|
|
73
|
+
})
|
|
74
|
+
.slice(-HISTORY_WINDOW)
|
|
75
|
+
.map((m) => `${m.role === 'user' ? 'User' : 'Assistant'}: ${m.content}`)
|
|
76
|
+
.join('\n');
|
|
77
|
+
return (`<conversation_history>\n${conversationContext}\n</conversation_history>\n\n` +
|
|
78
|
+
`The conversation above has ended. Do not continue it or respond as the assistant. ` +
|
|
79
|
+
`Generate exactly ${count} follow-up prompts the *user* might send next, phrased in first person as the user would write them. ` +
|
|
80
|
+
`The first ${Math.max(0, count - 1)} should be natural follow-ups to the last turn. ` +
|
|
81
|
+
`Do not invent specific names, IDs, or data values that do not appear in <conversation_history>.` +
|
|
82
|
+
capabilitiesBlock +
|
|
83
|
+
guidanceBlock +
|
|
84
|
+
OUTPUT_FORMAT(count));
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Lenient parsing, as a backstop: even with the strict format above, models slip in numbering,
|
|
88
|
+
* bullets or surrounding markdown.
|
|
89
|
+
*/
|
|
90
|
+
export function parseSuggestions(text, count) {
|
|
91
|
+
return (text
|
|
92
|
+
.split('\n')
|
|
93
|
+
.map((s) => s.trim())
|
|
94
|
+
// leading bullets/numbers ("- ", "* ", "• ", "1. ", "1) ")
|
|
95
|
+
.map((s) => s.replace(/^([-*•]|\d+[.)])\s+/, ''))
|
|
96
|
+
// surrounding bold/italic markers
|
|
97
|
+
.map((s) => s.replace(/^[*_]{1,3}|[*_]{1,3}$/g, '').trim())
|
|
98
|
+
.filter((s) => s.length > 0)
|
|
99
|
+
.filter((s) => !/^[-=]{2,}$/.test(s))
|
|
100
|
+
.filter((s) => !/^here (are|is) /i.test(s))
|
|
101
|
+
.filter((s) => !s.endsWith(':'))
|
|
102
|
+
.slice(0, count));
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Suggested prompts for the composer.
|
|
106
|
+
*
|
|
107
|
+
* Best-effort throughout: a default provider with no `prompt()` means no suggestions, not an
|
|
108
|
+
* error, because this is an out-of-turn UI helper.
|
|
109
|
+
*/
|
|
110
|
+
export function generateSuggestions(ctx, history, prompt, count, allAgentInfo) {
|
|
111
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
112
|
+
const defaultProvider = ctx.registry.default();
|
|
113
|
+
if (!defaultProvider.prompt) {
|
|
114
|
+
logger.warn('ChatDriver: default AI provider does not implement prompt()');
|
|
115
|
+
return [];
|
|
116
|
+
}
|
|
117
|
+
const userMessage = buildSuggestionsPrompt(ctx, history, prompt, count, allAgentInfo);
|
|
118
|
+
const text = yield defaultProvider.prompt(userMessage, {
|
|
119
|
+
systemPrompt: SUGGESTIONS_SYSTEM_PROMPT,
|
|
120
|
+
});
|
|
121
|
+
return parseSuggestions(text, count);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A stable fingerprint for an agents array, compared against the installed driver's to decide
|
|
3
|
+
* whether an `agents` change needs the driver rebuilt.
|
|
4
|
+
*
|
|
5
|
+
* So it must change when the driver's tool surface would, and not otherwise: handler key order is
|
|
6
|
+
* sorted out, agent order is significant.
|
|
7
|
+
*/
|
|
8
|
+
export function agentsKey(agents) {
|
|
9
|
+
if (!(agents === null || agents === void 0 ? void 0 : agents.length))
|
|
10
|
+
return '';
|
|
11
|
+
return agents
|
|
12
|
+
.map((a) => {
|
|
13
|
+
var _a;
|
|
14
|
+
// Function-form handlers resolve per turn, so their key set is unknowable here. The marker
|
|
15
|
+
// still separates static from dynamic; two different resolvers are indistinguishable.
|
|
16
|
+
const toolNames = typeof a.toolHandlers === 'function'
|
|
17
|
+
? '<fn>'
|
|
18
|
+
: Object.keys((_a = a.toolHandlers) !== null && _a !== void 0 ? _a : {})
|
|
19
|
+
.sort()
|
|
20
|
+
.join('+');
|
|
21
|
+
return `${a.name}[${toolNames}]`;
|
|
22
|
+
})
|
|
23
|
+
.join(',');
|
|
24
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { __awaiter } from "tslib";
|
|
2
|
+
/**
|
|
3
|
+
* Resolve a config input that may be a static value or a per-turn resolver.
|
|
4
|
+
*
|
|
5
|
+
* `undefined` in, `undefined` out — an unset input stays unset rather than resolving to a default
|
|
6
|
+
* the caller never asked for.
|
|
7
|
+
*/
|
|
8
|
+
export function resolveTurnInput(input, ctx) {
|
|
9
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
10
|
+
if (input === undefined)
|
|
11
|
+
return undefined;
|
|
12
|
+
return typeof input === 'function'
|
|
13
|
+
? input(ctx)
|
|
14
|
+
: input;
|
|
15
|
+
});
|
|
16
|
+
}
|
|
@@ -1,22 +1,29 @@
|
|
|
1
1
|
# Migration Guide — GENC-1580 (agent lifecycle leaves the orchestrator)
|
|
2
2
|
|
|
3
|
-
> ## ⚠️
|
|
3
|
+
> ## ⚠️ Partly shipped — the rename has not landed, so do not action the rename
|
|
4
4
|
>
|
|
5
|
-
>
|
|
6
|
-
>
|
|
7
|
-
>
|
|
5
|
+
> The structural half of this change is in. What is **not** in is the one part that would break
|
|
6
|
+
> you: `ChatDriver.applyAgent` has not been renamed. It was held back deliberately, to land alone
|
|
7
|
+
> as the last PR of GENC-1580 — the rename cannot be caught by a compiler in a JavaScript caller,
|
|
8
|
+
> so it is worth scheduling rather than absorbing alongside a refactor.
|
|
8
9
|
>
|
|
9
|
-
> **
|
|
10
|
+
> **What the package you are reading this in actually has:**
|
|
10
11
|
>
|
|
11
12
|
> | This guide says | Actually available today |
|
|
12
13
|
> | --- | --- |
|
|
13
|
-
> | `ChatDriver.
|
|
14
|
-
> | `ChatDriver.
|
|
15
|
-
> | `
|
|
16
|
-
> | `
|
|
14
|
+
> | `ChatDriver.activateAgent` | ✓ — available, fires the lifecycle hooks |
|
|
15
|
+
> | `ChatDriver.agentSession` | ✓ — available (`@internal`) |
|
|
16
|
+
> | `getActiveAgent` / `primeRestoredAgentState` implemented by both drivers | ✓ — and `setPinnedAgent` / `setFlowOwner` are on the interface now, all four **optional** |
|
|
17
|
+
> | `ChatDriver.installAgent` | ✗ — **still `ChatDriver.applyAgent`, unchanged** |
|
|
18
|
+
> | `pinned-changed` is dispatched | ✗ — still dead wiring (§7.2 of `code-health.md`) |
|
|
17
19
|
>
|
|
18
20
|
> **Self-check, whatever version you are on:** if `installAgent` is not present on `ChatDriver`,
|
|
19
|
-
>
|
|
21
|
+
> the rename has not landed and you should not touch your `applyAgent` calls. §4 is also **not**
|
|
22
|
+
> shipped — it carries its own notice. Everything else here is current.
|
|
23
|
+
>
|
|
24
|
+
> **Nothing you have today breaks on this release.** `applyAgent` keeps working, and every
|
|
25
|
+
> `AiDriver` member this ticket touched is declared optional, so an implementor of that interface
|
|
26
|
+
> is unaffected too.
|
|
20
27
|
>
|
|
21
28
|
> GENC-1580 ships in more than one PR. The first delivered an internal decomposition of `main.ts`
|
|
22
29
|
> only — five feature controllers, no public API change of any kind. **The agent-lifecycle work
|
|
@@ -110,45 +117,46 @@ session per conversation, and the inner driver outlives any routing decision mad
|
|
|
110
117
|
also puts `getAgentReleaseRequested()` and the session that responds to it in the same object,
|
|
111
118
|
which is the coupling that used to span two classes.
|
|
112
119
|
|
|
113
|
-
### 3. Four `AiDriver` members are
|
|
120
|
+
### 3. Four `AiDriver` members are implemented by both drivers
|
|
114
121
|
|
|
115
|
-
|
|
122
|
+
`ChatDriver` now implements all four, so they are no longer orchestrator-only:
|
|
116
123
|
|
|
117
124
|
| Member | Was | Now |
|
|
118
125
|
| --- | --- | --- |
|
|
119
|
-
| `getActiveAgent()` | `OrchestratingDriver` only | both |
|
|
120
|
-
| `setPinnedAgent(name)` |
|
|
121
|
-
| `setFlowOwner(name)` |
|
|
122
|
-
| `primeRestoredAgentState(snapshots)` | `OrchestratingDriver` only | both |
|
|
126
|
+
| `getActiveAgent?()` | `OrchestratingDriver` only | both |
|
|
127
|
+
| `setPinnedAgent?(name)` | not on the interface | both |
|
|
128
|
+
| `setFlowOwner?(name)` | not on the interface | both |
|
|
129
|
+
| `primeRestoredAgentState?(snapshots)` | `OrchestratingDriver` only | both |
|
|
123
130
|
|
|
124
|
-
**
|
|
125
|
-
|
|
126
|
-
your
|
|
131
|
+
**Nothing to do, and nothing breaks.** All four are declared **optional**, so a third party
|
|
132
|
+
implementing `AiDriver` is unaffected: two were already optional and two are new additions. Keep
|
|
133
|
+
your `?.()` guards — they still type-check, and the interface makes no promise a caller can lean
|
|
134
|
+
on yet.
|
|
127
135
|
|
|
128
|
-
|
|
136
|
+
The `?` comes off in the same release as the `installAgent` rename, which is the only breaking
|
|
137
|
+
change in this ticket. That is when the guards can go:
|
|
129
138
|
|
|
130
139
|
```ts
|
|
131
|
-
// before
|
|
132
|
-
const reserve = driver.getActiveAgent
|
|
133
|
-
|
|
134
|
-
// after
|
|
135
|
-
const reserve = driver.getActiveAgent()?.contextReserve;
|
|
140
|
+
// after the breaking release, not before
|
|
141
|
+
const reserve = driver.getActiveAgent().contextReserve;
|
|
136
142
|
```
|
|
137
143
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
144
|
+
Fourteen members on `AiDriver` remain optional. They are a separate problem, and `ai-driver.ts`
|
|
145
|
+
still carries a doc comment claiming the element depends only on this interface, which is not yet
|
|
146
|
+
true.
|
|
147
|
+
|
|
148
|
+
### 4. `pinned-changed` — still not dispatched, still nothing to do
|
|
141
149
|
|
|
142
|
-
|
|
150
|
+
> **Not in this release.** Described here because it is part of the intended contract; the code is
|
|
151
|
+
> not written. Do not act on this section.
|
|
143
152
|
|
|
144
|
-
`setPinnedAgent
|
|
145
|
-
|
|
146
|
-
|
|
153
|
+
`setPinnedAgent` is a bare write that emits nothing, while the element registers a listener for
|
|
154
|
+
`pinned-changed` and a comment asserting the driver does emit it. Neither half is right, and
|
|
155
|
+
GENC-1580 did not change it: `AgentSession.setPinned` is still a plain assignment, and nothing in
|
|
156
|
+
the package calls `dispatchEvent` with `pinned-changed`.
|
|
147
157
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
If you were not, nothing changes — the element's own pin path writes through its
|
|
151
|
-
`pinnedAgentName` setter and guards against the redundant round-trip.
|
|
158
|
+
The intended fix is for the pin write to report a transition the owning driver dispatches, the way
|
|
159
|
+
`flow-owner-changed` already works. Until then, a listener receives nothing — as before.
|
|
152
160
|
|
|
153
161
|
### 5. Stateful agents no longer depend on the orchestrator
|
|
154
162
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@genesislcap/ai-assistant",
|
|
3
3
|
"description": "Genesis AI Assistant micro-frontend",
|
|
4
|
-
"version": "15.
|
|
4
|
+
"version": "15.26.0",
|
|
5
5
|
"license": "SEE LICENSE IN license.txt",
|
|
6
6
|
"main": "dist/esm/index.js",
|
|
7
7
|
"types": "dist/ai-assistant.d.ts",
|
|
@@ -74,26 +74,26 @@
|
|
|
74
74
|
}
|
|
75
75
|
},
|
|
76
76
|
"devDependencies": {
|
|
77
|
-
"@genesislcap/foundation-testing": "15.
|
|
78
|
-
"@genesislcap/genx": "15.
|
|
79
|
-
"@genesislcap/rollup-builder": "15.
|
|
80
|
-
"@genesislcap/ts-builder": "15.
|
|
81
|
-
"@genesislcap/uvu-playwright-builder": "15.
|
|
82
|
-
"@genesislcap/vite-builder": "15.
|
|
83
|
-
"@genesislcap/webpack-builder": "15.
|
|
77
|
+
"@genesislcap/foundation-testing": "15.26.0",
|
|
78
|
+
"@genesislcap/genx": "15.26.0",
|
|
79
|
+
"@genesislcap/rollup-builder": "15.26.0",
|
|
80
|
+
"@genesislcap/ts-builder": "15.26.0",
|
|
81
|
+
"@genesislcap/uvu-playwright-builder": "15.26.0",
|
|
82
|
+
"@genesislcap/vite-builder": "15.26.0",
|
|
83
|
+
"@genesislcap/webpack-builder": "15.26.0",
|
|
84
84
|
"@types/dompurify": "^3.0.5",
|
|
85
85
|
"@types/marked": "^5.0.2",
|
|
86
86
|
"esbuild": "0.25.12"
|
|
87
87
|
},
|
|
88
88
|
"dependencies": {
|
|
89
|
-
"@genesislcap/foundation-ai": "15.
|
|
90
|
-
"@genesislcap/foundation-logger": "15.
|
|
91
|
-
"@genesislcap/foundation-notifications": "15.
|
|
92
|
-
"@genesislcap/foundation-redux": "15.
|
|
93
|
-
"@genesislcap/foundation-ui": "15.
|
|
94
|
-
"@genesislcap/foundation-utils": "15.
|
|
95
|
-
"@genesislcap/rapid-design-system": "15.
|
|
96
|
-
"@genesislcap/web-core": "15.
|
|
89
|
+
"@genesislcap/foundation-ai": "15.26.0",
|
|
90
|
+
"@genesislcap/foundation-logger": "15.26.0",
|
|
91
|
+
"@genesislcap/foundation-notifications": "15.26.0",
|
|
92
|
+
"@genesislcap/foundation-redux": "15.26.0",
|
|
93
|
+
"@genesislcap/foundation-ui": "15.26.0",
|
|
94
|
+
"@genesislcap/foundation-utils": "15.26.0",
|
|
95
|
+
"@genesislcap/rapid-design-system": "15.26.0",
|
|
96
|
+
"@genesislcap/web-core": "15.26.0",
|
|
97
97
|
"dompurify": "^3.3.1",
|
|
98
98
|
"marked": "^17.0.3"
|
|
99
99
|
},
|