@chengxianglibra/dsh-data-analysis 0.1.2 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +135 -0
- package/README.md +105 -98
- package/cordis.patch.yml +1 -1
- package/lib/bin/environment.js +8 -6
- package/lib/client/credentials/changes.js +74 -0
- package/lib/client/credentials/create-datasource.js +126 -22
- package/lib/client/credentials/credential-draft.js +42 -0
- package/lib/client/credentials/defaults.js +11 -0
- package/lib/client/credentials/descriptions.js +46 -0
- package/lib/client/credentials/install.js +209 -81
- package/lib/client/credentials/model.js +323 -51
- package/lib/client/credentials/report-publishing.js +96 -0
- package/lib/client/credentials/styles.js +13 -9
- package/lib/client/i18n/context.js +22 -0
- package/lib/client/i18n/copy.js +60 -0
- package/lib/client/i18n/credentials.js +475 -0
- package/lib/client/i18n/host.js +28 -0
- package/lib/client/i18n/navigation.js +41 -0
- package/lib/client/i18n/presentation.js +577 -0
- package/lib/client/i18n/python.js +36 -0
- package/lib/client/i18n/semantic.js +441 -0
- package/lib/client/i18n/settings.js +30 -0
- package/lib/client/input-context.js +21 -0
- package/lib/client/python-tool/card.js +35 -0
- package/lib/client/python-tool/execution-error.js +35 -0
- package/lib/client/python-tool/install.js +9 -0
- package/lib/client/python-tool/model.js +101 -0
- package/lib/client/right-tabs/install.js +535 -0
- package/lib/client/right-tabs/live-delivery.js +58 -0
- package/lib/client/right-tabs/navigation.js +47 -0
- package/lib/client/right-tabs/page.js +178 -0
- package/lib/client/right-tabs/styles.js +11 -0
- package/lib/client/rpc.js +5 -0
- package/lib/client/semantic-reference.js +10 -0
- package/lib/client/settings/card.js +90 -0
- package/lib/client/settings/install.js +10 -0
- package/lib/client/workspace-header-action.js +14 -1
- package/lib/client/workspace-shortcuts.js +26 -0
- package/lib/client.js +388 -242
- package/lib/compatibility.js +1 -1
- package/lib/datasource/authoring.js +43 -4
- package/lib/datasource/bridge-programs.js +23 -20
- package/lib/datasource/bridge.js +46 -3
- package/lib/datasource/changes-contract.js +41 -0
- package/lib/datasource/changes.js +49 -0
- package/lib/datasource/configure.js +39 -0
- package/lib/datasource/defaults.js +25 -0
- package/lib/datasource/index.js +2 -1
- package/lib/datasource/python-options.js +15 -0
- package/lib/datasource/python.js +119 -25
- package/lib/datasource/rpc.js +75 -13
- package/lib/datasource/service.js +286 -11
- package/lib/datasource/test.js +3 -2
- package/lib/disclosure/activation.js +19 -7
- package/lib/disclosure/execution-guidance.js +49 -0
- package/lib/disclosure/help.js +4 -1
- package/lib/environment/runtime.js +35 -34
- package/lib/environment/workspace.js +18 -1
- package/lib/lifecycle.js +33 -0
- package/lib/plugin-agents.js +154 -0
- package/lib/plugin.js +98 -172
- package/lib/presentation/asset.js +34 -0
- package/lib/presentation/assets/portable.js +14 -14
- package/lib/presentation/assets/static.js +344 -73
- package/lib/presentation/build/index.js +3 -2
- package/lib/presentation/commit.js +19 -12
- package/lib/presentation/contracts/asset-path.js +9 -0
- package/lib/presentation/contracts/catalog.js +62 -0
- package/lib/presentation/contracts/charts.js +0 -23
- package/lib/presentation/contracts/index.js +17 -5
- package/lib/presentation/contracts/types.js +1 -1
- package/lib/presentation/delivery.js +45 -30
- package/lib/presentation/export-html.js +214 -0
- package/lib/presentation/files.js +4 -5
- package/lib/presentation/projection/index.js +2 -1
- package/lib/presentation/projection/program.js +2 -9
- package/lib/presentation/projection/sql-code.js +13 -13
- package/lib/presentation/reports.js +114 -17
- package/lib/presentation/rpc.js +96 -58
- package/lib/presentation/tool.js +6 -10
- package/lib/report-publishing/adapters.js +111 -0
- package/lib/report-publishing/config.js +69 -0
- package/lib/report-publishing/service.js +180 -0
- package/lib/rpc.js +49 -0
- package/lib/semantic-browser/contracts.js +17 -0
- package/lib/semantic-browser/program.js +10 -0
- package/lib/semantic-browser/service.js +40 -6
- package/lib/semantic-reference/bridge.js +10 -1
- package/lib/semantic-reference/contracts.js +20 -6
- package/lib/semantic-reference/environment.js +56 -0
- package/lib/semantic-reference/labels.js +16 -0
- package/lib/semantic-reference/rpc.js +39 -18
- package/lib/semantic-reference/search.js +5 -4
- package/lib/semantic-reference/usage.js +12 -3
- package/lib/settings.js +21 -0
- package/lib/tool-lifecycle.js +22 -0
- package/lib/types/client/credentials/changes.d.ts +9 -0
- package/lib/types/client/credentials/create-datasource.d.ts +3 -1
- package/lib/types/client/credentials/credential-draft.d.ts +14 -0
- package/lib/types/client/credentials/defaults.d.ts +2 -0
- package/lib/types/client/credentials/descriptions.d.ts +1 -0
- package/lib/types/client/credentials/install.d.ts +19 -1
- package/lib/types/client/credentials/model.d.ts +31 -11
- package/lib/types/client/credentials/report-publishing.d.ts +5 -0
- package/lib/types/client/credentials/styles.d.ts +1 -1
- package/lib/types/client/i18n/context.d.ts +17 -0
- package/lib/types/client/i18n/copy.d.ts +821 -0
- package/lib/types/client/i18n/credentials.d.ts +475 -0
- package/lib/types/client/i18n/host.d.ts +17 -0
- package/lib/types/client/i18n/navigation.d.ts +41 -0
- package/lib/types/client/i18n/presentation.d.ts +577 -0
- package/lib/types/client/i18n/python.d.ts +19 -0
- package/lib/types/client/i18n/semantic.d.ts +441 -0
- package/lib/types/client/i18n/settings.d.ts +16 -0
- package/lib/types/client/input-context.d.ts +19 -0
- package/lib/types/client/presentation/ask-dsh.d.ts +4 -8
- package/lib/types/client/presentation/catalog-model.d.ts +24 -0
- package/lib/types/client/presentation/catalog.d.ts +20 -0
- package/lib/types/client/presentation/chart-tooltip.d.ts +2 -2
- package/lib/types/client/presentation/context-reference.d.ts +12 -0
- package/lib/types/client/presentation/copy-context.d.ts +2 -2
- package/lib/types/client/presentation/delivery-model.d.ts +27 -6
- package/lib/types/client/presentation/delivery.d.ts +8 -7
- package/lib/types/client/presentation/download.d.ts +2 -0
- package/lib/types/client/presentation/export-menu.d.ts +26 -0
- package/lib/types/client/presentation/export-view.d.ts +63 -0
- package/lib/types/client/presentation/host-entry.d.ts +8 -2
- package/lib/types/client/presentation/icons.d.ts +1 -1
- package/lib/types/client/presentation/model.d.ts +14 -15
- package/lib/types/client/presentation/reader.d.ts +15 -2
- package/lib/types/client/presentation/reference-source.d.ts +9 -0
- package/lib/types/client/presentation/source-code-model.d.ts +2 -1
- package/lib/types/client/presentation/source-code.d.ts +0 -5
- package/lib/types/client/presentation/source-dialog.d.ts +1 -2
- package/lib/types/client/presentation/sources.d.ts +5 -5
- package/lib/types/client/presentation/styles.d.ts +1 -1
- package/lib/types/client/presentation/table.d.ts +5 -1
- package/lib/types/client/python-tool/card.d.ts +2 -0
- package/lib/types/client/python-tool/execution-error.d.ts +3 -0
- package/lib/types/client/python-tool/install.d.ts +2 -0
- package/lib/types/client/python-tool/model.d.ts +20 -0
- package/lib/types/client/right-tabs/install.d.ts +18 -0
- package/lib/types/client/right-tabs/live-delivery.d.ts +8 -0
- package/lib/types/client/right-tabs/navigation.d.ts +17 -0
- package/lib/types/client/right-tabs/page.d.ts +36 -0
- package/lib/types/client/right-tabs/styles.d.ts +2 -0
- package/lib/types/client/rpc.d.ts +3 -0
- package/lib/types/client/semantic-reference.d.ts +4 -0
- package/lib/types/client/settings/card.d.ts +9 -0
- package/lib/types/client/settings/install.d.ts +2 -0
- package/lib/types/client/workspace-header-action.d.ts +1 -1
- package/lib/types/client/workspace-shortcuts.d.ts +15 -0
- package/lib/types/client.d.ts +5 -2
- package/lib/types/compatibility.d.ts +1 -1
- package/lib/types/datasource/authoring.d.ts +10 -0
- package/lib/types/datasource/bridge.d.ts +23 -2
- package/lib/types/datasource/changes-contract.d.ts +18 -0
- package/lib/types/datasource/changes.d.ts +15 -0
- package/lib/types/datasource/configure.d.ts +7 -0
- package/lib/types/datasource/defaults.d.ts +7 -0
- package/lib/types/datasource/index.d.ts +6 -1
- package/lib/types/datasource/python-options.d.ts +8 -0
- package/lib/types/datasource/python.d.ts +17 -2
- package/lib/types/datasource/rpc.d.ts +2 -1
- package/lib/types/datasource/service.d.ts +48 -5
- package/lib/types/datasource/test.d.ts +1 -1
- package/lib/types/disclosure/activation.d.ts +2 -1
- package/lib/types/disclosure/execution-guidance.d.ts +6 -0
- package/lib/types/disclosure/help.d.ts +1 -1
- package/lib/types/environment/types.d.ts +2 -1
- package/lib/types/environment/workspace.d.ts +1 -0
- package/lib/types/lifecycle.d.ts +8 -0
- package/lib/types/plugin-agents.d.ts +29 -0
- package/lib/types/plugin.d.ts +12 -28
- package/lib/types/presentation/asset.d.ts +6 -0
- package/lib/types/presentation/build/index.d.ts +7 -2
- package/lib/types/presentation/commit.d.ts +1 -1
- package/lib/types/presentation/contracts/asset-path.d.ts +2 -0
- package/lib/types/presentation/contracts/catalog.d.ts +27 -0
- package/lib/types/presentation/contracts/charts.d.ts +0 -2
- package/lib/types/presentation/contracts/types.d.ts +7 -4
- package/lib/types/presentation/delivery.d.ts +1 -1
- package/lib/types/presentation/export-html.d.ts +13 -0
- package/lib/types/presentation/reports.d.ts +6 -1
- package/lib/types/presentation/rpc.d.ts +3 -2
- package/lib/types/presentation/tool.d.ts +2 -2
- package/lib/types/report-publishing/adapters.d.ts +6 -0
- package/lib/types/report-publishing/config.d.ts +22 -0
- package/lib/types/report-publishing/service.d.ts +68 -0
- package/lib/types/rpc.d.ts +3 -0
- package/lib/types/semantic-browser/contracts.d.ts +7 -0
- package/lib/types/semantic-browser/service.d.ts +7 -1
- package/lib/types/semantic-reference/bridge.d.ts +1 -0
- package/lib/types/semantic-reference/contracts.d.ts +5 -2
- package/lib/types/semantic-reference/environment.d.ts +22 -0
- package/lib/types/semantic-reference/labels.d.ts +16 -0
- package/lib/types/semantic-reference/rpc.d.ts +1 -1
- package/lib/types/semantic-reference/search.d.ts +1 -1
- package/lib/types/settings.d.ts +14 -0
- package/lib/types/tool-lifecycle.d.ts +4 -0
- package/lib/types/workspace-identity.d.ts +6 -0
- package/lib/workspace-identity.js +9 -0
- package/package.json +93 -61
- package/python/presentation-kit/dist/dsh_data_analysis_presentation_kit-1.1.0-py3-none-any.whl +0 -0
- package/skills/dsh-data-analysis-files/SKILL.md +44 -0
- package/skills/dsh-data-analysis-files/references/delivery.md +15 -0
- package/skills/dsh-data-analysis-files/references/examples.md +93 -0
- package/skills/dsh-data-analysis-presentation/SKILL.md +15 -15
- package/skills/dsh-data-analysis-presentation/references/examples/artifact.draft.json +13 -4
- package/skills/dsh-data-analysis-presentation/references/examples/charts.draft.json +3 -2
- package/skills/dsh-data-analysis-presentation/references/examples/comparison.draft.json +3 -2
- package/skills/dsh-data-analysis-presentation/references/examples/computed-sources.draft.json +12 -5
- package/skills/dsh-data-analysis-presentation/references/examples/computed.draft.json +3 -2
- package/skills/dsh-data-analysis-presentation/references/examples/interaction.draft.json +3 -2
- package/skills/dsh-data-analysis-presentation/references/examples/source-only.draft.json +12 -4
- package/skills/dsh-data-analysis-presentation/references/examples.md +3 -1
- package/skills/dsh-data-analysis-presentation/references/export-html.md +7 -0
- package/skills/dsh-data-analysis-presentation/references/interaction.md +1 -1
- package/skills/dsh-data-analysis-presentation/references/narrative.md +1 -1
- package/skills/dsh-data-analysis-presentation/references/publishing.md +3 -0
- package/skills/dsh-data-analysis-presentation/references/schema.md +29 -2
- package/lib/types/client/presentation/install.d.ts +0 -15
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createUserMessage } from '@deepseek-ai/dsh-llm';
|
|
2
2
|
import { scopeParentOf } from '@deepseek-ai/dsh-scope';
|
|
3
|
+
import { finishCleanup, PendingTasks } from "../lifecycle.js";
|
|
3
4
|
import { MARIVO_HELP_TOOL_NAME, readMarivoHelpTargets, registerMarivoHelpTool, renderMarivoHelpValue, resolveMarivoHelpBridge, } from "./help.js";
|
|
4
5
|
const SKILL_TOOL_NAME = 'skill';
|
|
5
6
|
export const MARIVO_ROOT_HELP_TARGETS = Object.freeze({
|
|
@@ -119,6 +120,8 @@ export class MarivoDisclosureController {
|
|
|
119
120
|
#visibleHelp = new Map();
|
|
120
121
|
#lifecycleAbort = new AbortController();
|
|
121
122
|
#disposers = [];
|
|
123
|
+
#tasks = new PendingTasks();
|
|
124
|
+
#closing;
|
|
122
125
|
#disposed = false;
|
|
123
126
|
#telemetry = { activations: [], rootHelp: [], failures: [] };
|
|
124
127
|
constructor(agent, bridgeSource, options = {}) {
|
|
@@ -181,7 +184,10 @@ export class MarivoDisclosureController {
|
|
|
181
184
|
return 'already-visible';
|
|
182
185
|
return visible === undefined ? 'delivered' : 'replacement';
|
|
183
186
|
}
|
|
184
|
-
|
|
187
|
+
prepareStep(messages, signal) {
|
|
188
|
+
return this.#tasks.track(this.#prepareStep(messages, signal));
|
|
189
|
+
}
|
|
190
|
+
async #prepareStep(messages, signal) {
|
|
185
191
|
if (this.#disposed)
|
|
186
192
|
throw this.#lifecycleAbort.signal.reason;
|
|
187
193
|
this.#observeExplicitInvocations(messages);
|
|
@@ -273,13 +279,16 @@ export class MarivoDisclosureController {
|
|
|
273
279
|
return;
|
|
274
280
|
this.#disposed = true;
|
|
275
281
|
this.#lifecycleAbort.abort(new Error('Marivo disclosure controller disposed'));
|
|
276
|
-
|
|
277
|
-
disposer();
|
|
282
|
+
this.#closing = finishCleanup([...this.#disposers.reverse(), () => this.#tasks.drain()]);
|
|
278
283
|
this.#disposers = [];
|
|
279
284
|
this.#activeSkills.clear();
|
|
280
285
|
this.#pendingSkills.clear();
|
|
281
286
|
this.#visibleHelp.clear();
|
|
282
287
|
}
|
|
288
|
+
close() {
|
|
289
|
+
this.dispose();
|
|
290
|
+
return this.#closing;
|
|
291
|
+
}
|
|
283
292
|
#inheritedSkillToolVisible() {
|
|
284
293
|
const inheritedSkillTool = this.agent.ctx.tools.get(SKILL_TOOL_NAME, scopeParentOf(this.agent));
|
|
285
294
|
return (inheritedSkillTool !== undefined &&
|
|
@@ -294,7 +303,7 @@ export class MarivoDisclosureController {
|
|
|
294
303
|
}
|
|
295
304
|
}
|
|
296
305
|
#restoreActiveSkills() {
|
|
297
|
-
for (const event of this.agent.session.
|
|
306
|
+
for (const event of this.agent.session.snapshotEvents()) {
|
|
298
307
|
if (event.type !== 'user/message')
|
|
299
308
|
continue;
|
|
300
309
|
const disclosure = rootHelpSource(event.data.source);
|
|
@@ -309,7 +318,7 @@ export class MarivoDisclosureController {
|
|
|
309
318
|
#refreshVisibleHelp(messages) {
|
|
310
319
|
this.#visibleHelp.clear();
|
|
311
320
|
const visible = new Set(this.agent.session.surface.nodes);
|
|
312
|
-
for (const event of this.agent.session.
|
|
321
|
+
for (const event of this.agent.session.snapshotEvents()) {
|
|
313
322
|
if (!visible.has(event.seq))
|
|
314
323
|
continue;
|
|
315
324
|
if (event.type === 'user/message') {
|
|
@@ -340,7 +349,9 @@ export class MarivoDisclosureController {
|
|
|
340
349
|
}
|
|
341
350
|
}
|
|
342
351
|
#hasHistoricalDisclosure(skill) {
|
|
343
|
-
return this.agent.session
|
|
352
|
+
return this.agent.session
|
|
353
|
+
.snapshotEvents()
|
|
354
|
+
.some((event) => event.type === 'user/message' && rootHelpSource(event.data.source)?.skill === skill);
|
|
344
355
|
}
|
|
345
356
|
}
|
|
346
357
|
/** Install skill-triggered Marivo live-help disclosure for one Agent scope. */
|
|
@@ -356,9 +367,10 @@ export function installMarivoDisclosure(_ctx, agent, bridgeSource, options = {})
|
|
|
356
367
|
if (decision.kind === 'reject')
|
|
357
368
|
return decision;
|
|
358
369
|
const injections = await controller.prepareStep(decision.messages, signal);
|
|
370
|
+
signal.throwIfAborted();
|
|
359
371
|
return injections.length === 0
|
|
360
372
|
? decision
|
|
361
|
-
: {
|
|
373
|
+
: { ...decision, messages: [...decision.messages, ...injections] };
|
|
362
374
|
}, true));
|
|
363
375
|
return controller;
|
|
364
376
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { createUserMessage } from '@deepseek-ai/dsh-llm';
|
|
2
|
+
export const MARIVO_DATASOURCE_CREDENTIAL_PROMPT = [
|
|
3
|
+
'These are Host execution and credential rules; Marivo API and semantic contracts come from the bound Runtime Skill and live Help.',
|
|
4
|
+
'DSH Credentials owns Marivo datasource secrets. Never request values in chat, read credential files or ~/.marivo/secrets.toml, or write secrets to scripts, arguments, environment variables, reports or logs.',
|
|
5
|
+
'Use marivo_datasource_configure for missing datasource setup or connection configuration repair; the user owns configuration in the Web form. Use marivo_datasource_test for connection checks under its tool contract. Configured credentials alone do not prove connection or read access.',
|
|
6
|
+
'Execute analysis, metadata inspection and semantic data reads through marivo_python in the bound Runtime and Workspace. Declare all exact Marivo datasource names this execution may access, including datasources without passwords; use datasources: [] for local pandas or native DuckDB without Marivo datasource access.',
|
|
7
|
+
'Each marivo_python call is a separate process. Create/resume Marivo Sessions inside the call, close them in finally, and retain the persisted Session identity when continuing the same analysis. Closing process resources does not delete durable Artifacts. Do not replace the credential resolver, read SecretValue contents, or bypass Host scope with environment/cache configuration.',
|
|
8
|
+
'Preserve real failures. After uncertain execution, inspect existing effects before retrying; never automatically replay a script with possible side effects.',
|
|
9
|
+
].join('\n');
|
|
10
|
+
export const MARIVO_ANALYSIS_CLOSEOUT_PROMPT = [
|
|
11
|
+
'Analysis semantics and execution contracts come from the activated Runtime Skill and current Help.',
|
|
12
|
+
'Before completing any analysis, including a text-only answer, check each user question and each requested comparison scope against its evidence. Keep incomplete branches explicit; preserve comparison sides, direction and denominator. Match conclusion strength to evidence, and reflect limitations in the claims themselves.',
|
|
13
|
+
].join(' ');
|
|
14
|
+
/** Bridge rules activated after system prompt assembly, without changing their wording. */
|
|
15
|
+
function executionGuidanceSupplement(before, after) {
|
|
16
|
+
const rules = [];
|
|
17
|
+
if (before.length === 0 && after.length > 0)
|
|
18
|
+
rules.push(MARIVO_DATASOURCE_CREDENTIAL_PROMPT);
|
|
19
|
+
if (!before.includes('marivo-analysis') && after.includes('marivo-analysis'))
|
|
20
|
+
rules.push(MARIVO_ANALYSIS_CLOSEOUT_PROMPT);
|
|
21
|
+
if (rules.length === 0)
|
|
22
|
+
return [];
|
|
23
|
+
return [
|
|
24
|
+
createUserMessage({
|
|
25
|
+
content: [
|
|
26
|
+
{
|
|
27
|
+
type: 'text',
|
|
28
|
+
text: ['<marivo_execution_guidance>', ...rules, '</marivo_execution_guidance>'].join('\n\n'),
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
source: { kind: 'plugin', plugin: 'dsh-data-analysis' },
|
|
32
|
+
}),
|
|
33
|
+
];
|
|
34
|
+
}
|
|
35
|
+
/** Full-plugin seam: requires its execution tools, credentials service and system sections. */
|
|
36
|
+
export function installMarivoExecutionGuidance(agent, controller) {
|
|
37
|
+
return agent.ctx.on('agent/pre-step', async ({ signal }, next) => {
|
|
38
|
+
// Prepend after Help installation to wrap its successful disclosure decision.
|
|
39
|
+
const previouslyActive = controller.activeSkills;
|
|
40
|
+
const decision = await next();
|
|
41
|
+
if (decision.kind === 'reject')
|
|
42
|
+
return decision;
|
|
43
|
+
signal.throwIfAborted();
|
|
44
|
+
const guidance = executionGuidanceSupplement(previouslyActive, controller.activeSkills);
|
|
45
|
+
return guidance.length === 0
|
|
46
|
+
? decision
|
|
47
|
+
: { ...decision, messages: [...decision.messages, ...guidance] };
|
|
48
|
+
}, true);
|
|
49
|
+
}
|
package/lib/disclosure/help.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
import { defineTool } from '@deepseek-ai/dsh-tools';
|
|
3
|
+
import { registerMarivoTool } from "../tool-lifecycle.js";
|
|
3
4
|
import { MarivoHelpError, resolveMarivoHelpBridge, } from "./bridge.js";
|
|
4
5
|
export { MarivoHelpError, resolveMarivoHelpBridge } from "./bridge.js";
|
|
5
6
|
export const MARIVO_HELP_TOOL_NAME = 'marivo_help';
|
|
@@ -203,12 +204,14 @@ export function createMarivoHelpTool(bridgeSource, limitOverrides = {}, resolveD
|
|
|
203
204
|
},
|
|
204
205
|
timeoutMs: limits.toolTimeoutMs,
|
|
205
206
|
async execute(args, exec) {
|
|
207
|
+
exec.signal.throwIfAborted();
|
|
206
208
|
const bridge = await resolveMarivoHelpBridge(bridgeSource);
|
|
207
209
|
const internal = await readMarivoHelpTargets(bridge, args.targets, {
|
|
208
210
|
limits,
|
|
209
211
|
signal: exec.signal,
|
|
210
212
|
resolveDelivery,
|
|
211
213
|
});
|
|
214
|
+
exec.signal.throwIfAborted();
|
|
212
215
|
const value = {
|
|
213
216
|
environment: { version: internal.environment.version },
|
|
214
217
|
targets: internal.targets,
|
|
@@ -223,5 +226,5 @@ export function createMarivoHelpTool(bridgeSource, limitOverrides = {}, resolveD
|
|
|
223
226
|
}
|
|
224
227
|
/** Register the focused Help Tool; skill-triggered root disclosure is composed separately. */
|
|
225
228
|
export function registerMarivoHelpTool(ctx, bridgeSource, limits = {}, resolveDelivery) {
|
|
226
|
-
return ctx
|
|
229
|
+
return registerMarivoTool(ctx, createMarivoHelpTool(bridgeSource, limits, resolveDelivery));
|
|
227
230
|
}
|
|
@@ -25,6 +25,7 @@ import os
|
|
|
25
25
|
import sys
|
|
26
26
|
from importlib.metadata import distribution
|
|
27
27
|
import marivo
|
|
28
|
+
import ibis.backends.duckdb
|
|
28
29
|
from marivo.semantic.definition import SemanticDefinition
|
|
29
30
|
import pandas
|
|
30
31
|
import dsh_data_analysis_presentation
|
|
@@ -166,7 +167,7 @@ async function probeRuntime(runtimeRoot, executable, environment, timeoutMs, pre
|
|
|
166
167
|
});
|
|
167
168
|
const repair = administrator ? administratorRepair(canonical, presentationKitWheel) : undefined;
|
|
168
169
|
if (administrator && result.exitCode !== 0) {
|
|
169
|
-
throw new MarivoEnvironmentError('shared-runtime-package-unavailable', `Administrator Python must provide Marivo ${PINNED_MARIVO_VERSION}, pandas ${PRESENTATION_KIT_PANDAS_RANGE}, and ${PRESENTATION_KIT_DISTRIBUTION} ${PRESENTATION_KIT_VERSION}. ${repair.message}`, {
|
|
170
|
+
throw new MarivoEnvironmentError('shared-runtime-package-unavailable', `Administrator Python must provide Marivo ${PINNED_MARIVO_VERSION} with the duckdb extra, pandas ${PRESENTATION_KIT_PANDAS_RANGE}, and ${PRESENTATION_KIT_DISTRIBUTION} ${PRESENTATION_KIT_VERSION}. ${repair.message}`, {
|
|
170
171
|
pythonExecutable: canonical,
|
|
171
172
|
marivoVersion: PINNED_MARIVO_VERSION,
|
|
172
173
|
pandasRange: PRESENTATION_KIT_PANDAS_RANGE,
|
|
@@ -462,50 +463,48 @@ async function backupInvalidRuntime(runtimeRoot) {
|
|
|
462
463
|
}
|
|
463
464
|
await rename(runtimeRoot, `${runtimeRoot}.invalid-${Date.now()}-${randomUUID()}`);
|
|
464
465
|
}
|
|
465
|
-
async function installManagedRuntime(runtimeRoot,
|
|
466
|
+
async function installManagedRuntime(runtimeRoot, bootstrapPythonExecutable, presentationKitWheel, environment, timeoutMs) {
|
|
466
467
|
const policy = new FixedSubprocessPolicy(runtimeRoot, environment);
|
|
467
468
|
const limits = { timeoutMs, stdoutMaxBytes: 1_048_576, stderrMaxBytes: 1_048_576 };
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
}
|
|
482
|
-
const canonicalManagedPython = await assertExecutable(managedPython);
|
|
483
|
-
const version = parseJsonObject('validate managed Python', await policy.run({
|
|
484
|
-
executable: canonicalManagedPython,
|
|
485
|
-
args: ['-c', PYTHON_VERSION_SCRIPT],
|
|
486
|
-
limits,
|
|
487
|
-
}));
|
|
469
|
+
let version;
|
|
470
|
+
try {
|
|
471
|
+
version = parseJsonObject('validate local Python', await policy.run({
|
|
472
|
+
executable: bootstrapPythonExecutable,
|
|
473
|
+
args: ['-c', PYTHON_VERSION_SCRIPT],
|
|
474
|
+
limits,
|
|
475
|
+
}));
|
|
476
|
+
}
|
|
477
|
+
catch (error) {
|
|
478
|
+
if (!(error instanceof MarivoEnvironmentError))
|
|
479
|
+
throw error;
|
|
480
|
+
throw new MarivoEnvironmentError('shared-runtime-install-failed', 'Could not validate local Python. Install Python 3.10+ with venv/ensurepip, or set bootstrapPythonExecutable to its absolute path.', { pythonExecutable: bootstrapPythonExecutable, causeCode: error.code });
|
|
481
|
+
}
|
|
488
482
|
if (!Array.isArray(version.version) ||
|
|
489
483
|
typeof version.version[0] !== 'number' ||
|
|
490
484
|
typeof version.version[1] !== 'number' ||
|
|
491
485
|
version.version[0] < 3 ||
|
|
492
486
|
(version.version[0] === 3 && version.version[1] < 10)) {
|
|
493
|
-
throw new MarivoEnvironmentError('shared-runtime-install-failed',
|
|
487
|
+
throw new MarivoEnvironmentError('shared-runtime-install-failed', `Local Python does not satisfy Marivo >=${SHARED_PYTHON_SPEC}; detected ${Array.isArray(version.version) ? version.version.join('.') : 'unknown'}`, { version: version.version, pythonExecutable: bootstrapPythonExecutable });
|
|
488
|
+
}
|
|
489
|
+
if (typeof version.python_executable !== 'string' ||
|
|
490
|
+
!path.isAbsolute(version.python_executable)) {
|
|
491
|
+
throw new MarivoEnvironmentError('shared-runtime-install-failed', 'Local Python returned a non-absolute interpreter path');
|
|
494
492
|
}
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
493
|
+
const canonicalPython = await assertExecutable(version.python_executable);
|
|
494
|
+
requireSuccess('create shared virtual environment (requires Python venv/ensurepip; install python3-venv on Debian/Ubuntu)', await policy.run({
|
|
495
|
+
executable: canonicalPython,
|
|
496
|
+
args: ['-m', 'venv', path.join(runtimeRoot, '.venv')],
|
|
498
497
|
limits,
|
|
499
498
|
}));
|
|
500
499
|
const executable = venvPython(runtimeRoot);
|
|
501
500
|
requireSuccess(`install Marivo ${PINNED_MARIVO_VERSION}`, await policy.run({
|
|
502
|
-
executable
|
|
503
|
-
args: ['
|
|
501
|
+
executable,
|
|
502
|
+
args: ['-m', 'pip', 'install', '--upgrade', SHARED_MARIVO_PACKAGE_SPEC],
|
|
504
503
|
limits,
|
|
505
504
|
}));
|
|
506
505
|
requireSuccess(`install presentation kit ${PRESENTATION_KIT_VERSION}`, await policy.run({
|
|
507
|
-
executable
|
|
508
|
-
args: ['
|
|
506
|
+
executable,
|
|
507
|
+
args: ['-m', 'pip', 'install', '--no-deps', presentationKitWheel],
|
|
509
508
|
limits,
|
|
510
509
|
}));
|
|
511
510
|
return probeRuntime(runtimeRoot, executable, environment, timeoutMs, presentationKitWheel, false, PINNED_MARIVO_VERSION);
|
|
@@ -518,9 +517,11 @@ export async function ensureSharedMarivoRuntime(config = {}, options = {}) {
|
|
|
518
517
|
const configuredPython = config.pythonExecutable === undefined
|
|
519
518
|
? undefined
|
|
520
519
|
: normalizeAbsolute('pythonExecutable', config.pythonExecutable);
|
|
521
|
-
const
|
|
522
|
-
? '
|
|
523
|
-
|
|
520
|
+
const bootstrapPythonExecutable = config.bootstrapPythonExecutable === undefined
|
|
521
|
+
? process.platform === 'win32'
|
|
522
|
+
? 'python'
|
|
523
|
+
: 'python3'
|
|
524
|
+
: normalizeAbsolute('bootstrapPythonExecutable', config.bootstrapPythonExecutable);
|
|
524
525
|
const timeoutMs = positiveTimeout(config.installTimeoutMs);
|
|
525
526
|
const presentationKitWheel = path.normalize(path.resolve(options.presentationKitWheelPath ?? bundledPresentationKitWheel()));
|
|
526
527
|
const existing = await validatedExisting(runtimeRoot, configuredPython, options.environment, timeoutMs, presentationKitWheel);
|
|
@@ -538,7 +539,7 @@ export async function ensureSharedMarivoRuntime(config = {}, options = {}) {
|
|
|
538
539
|
await backupInvalidRuntime(runtimeRoot);
|
|
539
540
|
await mkdir(runtimeRoot, { recursive: true });
|
|
540
541
|
const probe = configuredPython === undefined
|
|
541
|
-
? await installManagedRuntime(runtimeRoot,
|
|
542
|
+
? await installManagedRuntime(runtimeRoot, bootstrapPythonExecutable, presentationKitWheel, options.environment, timeoutMs)
|
|
542
543
|
: await probeRuntime(runtimeRoot, configuredPython, options.environment, timeoutMs, presentationKitWheel, true, PINNED_MARIVO_VERSION);
|
|
543
544
|
const skillsRoot = await syncSkills(runtimeRoot, probe.package_path);
|
|
544
545
|
const record = {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { realpath, stat } from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
+
import { finishCleanup, PendingTasks } from "../lifecycle.js";
|
|
3
4
|
import { bindMarivoEnvironment } from "./binding.js";
|
|
4
5
|
import { MarivoEnvironmentError } from "./errors.js";
|
|
5
6
|
async function assertDirectory(target, label) {
|
|
@@ -26,13 +27,23 @@ async function canonicalWorkspaceRoot(projectRoot) {
|
|
|
26
27
|
}
|
|
27
28
|
/** Cache one zero-init Workspace binding while retaining project-specific doctor state. */
|
|
28
29
|
export class MarivoWorkspaceEnvironmentManager {
|
|
30
|
+
#tasks = new PendingTasks();
|
|
31
|
+
#disposed = false;
|
|
32
|
+
#closing;
|
|
29
33
|
runtime;
|
|
30
34
|
#bindings = new Map();
|
|
31
35
|
constructor(runtime) {
|
|
32
36
|
this.runtime = runtime;
|
|
33
37
|
}
|
|
34
|
-
|
|
38
|
+
resolve(projectRoot) {
|
|
39
|
+
return this.#tasks.track(this.#resolve(projectRoot));
|
|
40
|
+
}
|
|
41
|
+
async #resolve(projectRoot) {
|
|
42
|
+
if (this.#disposed)
|
|
43
|
+
throw new Error('Marivo Workspace manager disposed');
|
|
35
44
|
const canonicalRoot = await canonicalWorkspaceRoot(projectRoot);
|
|
45
|
+
if (this.#disposed)
|
|
46
|
+
throw new Error('Marivo Workspace manager disposed');
|
|
36
47
|
let binding = this.#bindings.get(canonicalRoot);
|
|
37
48
|
if (binding === undefined) {
|
|
38
49
|
binding = bindMarivoEnvironment({
|
|
@@ -48,7 +59,13 @@ export class MarivoWorkspaceEnvironmentManager {
|
|
|
48
59
|
}
|
|
49
60
|
return binding;
|
|
50
61
|
}
|
|
62
|
+
close() {
|
|
63
|
+
this.dispose();
|
|
64
|
+
this.#closing ??= finishCleanup([() => this.#tasks.drain()]);
|
|
65
|
+
return this.#closing;
|
|
66
|
+
}
|
|
51
67
|
dispose() {
|
|
68
|
+
this.#disposed = true;
|
|
52
69
|
this.#bindings.clear();
|
|
53
70
|
}
|
|
54
71
|
}
|
package/lib/lifecycle.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** Tracks owned work, including work whose caller stopped waiting after cancellation. */
|
|
2
|
+
export class PendingTasks {
|
|
3
|
+
#tasks = new Set();
|
|
4
|
+
track(task) {
|
|
5
|
+
const settled = task.then(() => { }, () => { });
|
|
6
|
+
this.#tasks.add(settled);
|
|
7
|
+
void settled.then(() => this.#tasks.delete(settled));
|
|
8
|
+
return task;
|
|
9
|
+
}
|
|
10
|
+
async drain() {
|
|
11
|
+
while (this.#tasks.size)
|
|
12
|
+
await Promise.all([...this.#tasks]);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/** Start every stop synchronously, then await every cleanup even if another one fails. */
|
|
16
|
+
export function finishCleanup(actions) {
|
|
17
|
+
const pending = actions.map((action) => {
|
|
18
|
+
try {
|
|
19
|
+
return Promise.resolve(action());
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
return Promise.reject(error);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
const completion = Promise.allSettled(pending).then((results) => {
|
|
26
|
+
const failures = results.flatMap((result) => result.status === 'rejected' ? [result.reason] : []);
|
|
27
|
+
if (failures.length)
|
|
28
|
+
throw new AggregateError(failures, 'Marivo cleanup failed');
|
|
29
|
+
});
|
|
30
|
+
// Legacy synchronous callers may ignore completion; awaiting it still reports failures.
|
|
31
|
+
void completion.catch(() => { });
|
|
32
|
+
return completion;
|
|
33
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { createMarivoBridgeSet } from "./bridges.js";
|
|
2
|
+
import { registerMarivoDatasourceConfigureTool } from "./datasource/configure.js";
|
|
3
|
+
import { registerMarivoPythonTool } from "./datasource/python.js";
|
|
4
|
+
import { resolvePythonOptions } from "./datasource/python-options.js";
|
|
5
|
+
import { MarivoCredentialService } from "./datasource/service.js";
|
|
6
|
+
import { registerMarivoDatasourceTestTool } from "./datasource/test.js";
|
|
7
|
+
import { installMarivoExecutionGuidance, MARIVO_ANALYSIS_CLOSEOUT_PROMPT, MARIVO_DATASOURCE_CREDENTIAL_PROMPT, } from "./disclosure/execution-guidance.js";
|
|
8
|
+
import { installMarivoDisclosure, } from "./disclosure/index.js";
|
|
9
|
+
import { MarivoEnvironment, resolveMarivoEnvironmentSource, } from "./environment/index.js";
|
|
10
|
+
import { finishCleanup, PendingTasks } from "./lifecycle.js";
|
|
11
|
+
import { registerMarivoExportHtmlTool } from "./presentation/export-html.js";
|
|
12
|
+
import { installMarivoPresentationCodeDelivery, registerMarivoPresentTool, } from "./presentation/index.js";
|
|
13
|
+
import { registerReportPublishTool } from "./report-publishing/adapters.js";
|
|
14
|
+
import { resolvePresentationWorkspace } from "./workspace-identity.js";
|
|
15
|
+
const PRESENTATION_PROMPT = 'Match delivery to the user request. Ordinary answers and simple comparison tables can stay in chat. For analysis of attachments or Workspace data files, including short chat comparisons, first load dsh-data-analysis-files; requested CSV, JSON or PNG files use native present. For interactive charts or tables, saved reports, dashboards, report updates or visual source panels, load dsh-data-analysis-presentation and use marivo_present; that Skill also covers report export and publication when requested. Existing results can be presented directly. Use the Runtime skills and live Help for Marivo analysis or semantic authoring; local pandas or native DuckDB file analysis needs no Marivo semantic setup. When analysis reveals a reusable business definition or semantic gap, follow the relevant Skill to assess reuse or handoff to marivo-semantic, limited to what the current task needs or the user has authorized; stop when that scope is answered or its blockers are explicit.';
|
|
16
|
+
/**
|
|
17
|
+
* Install one already-bound environment into every live or subsequently published Agent scope.
|
|
18
|
+
* Installation is transactional for existing Agents and is disposed with the Cordis plugin.
|
|
19
|
+
*/
|
|
20
|
+
export function createMarivoAgentInstallation(ctx, environmentOrResolver, options = {}) {
|
|
21
|
+
const pythonOptions = resolvePythonOptions(options);
|
|
22
|
+
const installed = new Map();
|
|
23
|
+
const credentials = options.credentials ?? ctx.credentials;
|
|
24
|
+
if (credentials === undefined) {
|
|
25
|
+
throw new Error('dsh-data-analysis requires the DSH credentials service');
|
|
26
|
+
}
|
|
27
|
+
const credentialService = options.credentialService ??
|
|
28
|
+
new MarivoCredentialService(credentials, options.credentialInteraction);
|
|
29
|
+
const ownsCredentials = options.credentialService === undefined;
|
|
30
|
+
const retiring = new PendingTasks();
|
|
31
|
+
const failures = [];
|
|
32
|
+
const stops = [];
|
|
33
|
+
let active = true;
|
|
34
|
+
let closing;
|
|
35
|
+
const retire = (controller) => {
|
|
36
|
+
retiring.track(controller.close().catch((error) => {
|
|
37
|
+
failures.push(error);
|
|
38
|
+
}));
|
|
39
|
+
};
|
|
40
|
+
const close = () => {
|
|
41
|
+
if (closing)
|
|
42
|
+
return closing;
|
|
43
|
+
active = false;
|
|
44
|
+
closing = finishCleanup([
|
|
45
|
+
...stops.reverse(),
|
|
46
|
+
...[...installed.values()].map((controller) => () => retire(controller)),
|
|
47
|
+
...(ownsCredentials ? [() => credentialService.close()] : []),
|
|
48
|
+
async () => {
|
|
49
|
+
await retiring.drain();
|
|
50
|
+
if (failures.length)
|
|
51
|
+
throw new AggregateError(failures, 'Marivo Agent cleanup failed');
|
|
52
|
+
},
|
|
53
|
+
]);
|
|
54
|
+
installed.clear();
|
|
55
|
+
return closing;
|
|
56
|
+
};
|
|
57
|
+
const bridgeSets = new WeakMap();
|
|
58
|
+
const install = (agent) => {
|
|
59
|
+
if (!active || installed.has(agent))
|
|
60
|
+
return;
|
|
61
|
+
const source = environmentOrResolver instanceof MarivoEnvironment
|
|
62
|
+
? environmentOrResolver
|
|
63
|
+
: () => Promise.resolve(environmentOrResolver(agent));
|
|
64
|
+
const resolveBridgeSet = async () => {
|
|
65
|
+
const environment = await resolveMarivoEnvironmentSource(source);
|
|
66
|
+
let bridges = bridgeSets.get(environment);
|
|
67
|
+
if (bridges === undefined) {
|
|
68
|
+
bridges = createMarivoBridgeSet(environment);
|
|
69
|
+
bridgeSets.set(environment, bridges);
|
|
70
|
+
}
|
|
71
|
+
return bridges;
|
|
72
|
+
};
|
|
73
|
+
const helpSource = options.helpBridgeSource ?? (async () => (await resolveBridgeSet()).help);
|
|
74
|
+
const datasourceSource = async () => (await resolveBridgeSet()).datasource;
|
|
75
|
+
const presentationSource = async () => {
|
|
76
|
+
const workspace = resolvePresentationWorkspace(ctx, String(agent.session.id));
|
|
77
|
+
const projection = (await resolveBridgeSet()).presentation;
|
|
78
|
+
const current = resolvePresentationWorkspace(ctx, String(agent.session.id));
|
|
79
|
+
if (workspace.id !== current.id ||
|
|
80
|
+
workspace.path !== current.path ||
|
|
81
|
+
projection.binding.projectRoot !== current.path)
|
|
82
|
+
throw new Error('Presentation Workspace changed or does not match the bound Runtime');
|
|
83
|
+
return { workspaceId: current.id, projection };
|
|
84
|
+
};
|
|
85
|
+
const controller = installMarivoDisclosure(ctx, agent, helpSource, options);
|
|
86
|
+
try {
|
|
87
|
+
controller.addDisposer(installMarivoExecutionGuidance(agent, controller));
|
|
88
|
+
controller.addDisposer(registerMarivoDatasourceTestTool(agent.ctx, datasourceSource, credentialService));
|
|
89
|
+
controller.addDisposer(registerMarivoDatasourceConfigureTool(agent.ctx, datasourceSource, credentialService));
|
|
90
|
+
controller.addDisposer(registerMarivoPythonTool(agent.ctx, datasourceSource, credentialService, options.pythonOptionsSource ?? pythonOptions));
|
|
91
|
+
controller.addDisposer(() => credentialService.disposeAgent(agent));
|
|
92
|
+
controller.addDisposer(registerMarivoPresentTool(agent.ctx, presentationSource, agent.session));
|
|
93
|
+
controller.addDisposer(registerMarivoExportHtmlTool(agent.ctx, () => resolvePresentationWorkspace(ctx, String(agent.session.id)), agent.session));
|
|
94
|
+
if (options.reportPublishing)
|
|
95
|
+
controller.addDisposer(registerReportPublishTool(agent.ctx, options.reportPublishing, agent.session.id));
|
|
96
|
+
controller.addDisposer(installMarivoPresentationCodeDelivery(agent.ctx));
|
|
97
|
+
controller.addDisposer(agent.ctx.systemPrompt.section({
|
|
98
|
+
name: 'marivo:presentation',
|
|
99
|
+
order: 180,
|
|
100
|
+
text: PRESENTATION_PROMPT,
|
|
101
|
+
}));
|
|
102
|
+
controller.addDisposer(agent.ctx.systemPrompt.section({
|
|
103
|
+
name: 'marivo:datasource-credentials',
|
|
104
|
+
order: 170,
|
|
105
|
+
text: () => controller.activeSkills.some((skill) => ['marivo-analysis', 'marivo-semantic'].includes(skill))
|
|
106
|
+
? MARIVO_DATASOURCE_CREDENTIAL_PROMPT
|
|
107
|
+
: '',
|
|
108
|
+
}));
|
|
109
|
+
controller.addDisposer(agent.ctx.systemPrompt.section({
|
|
110
|
+
name: 'marivo:analysis-closeout',
|
|
111
|
+
order: 175,
|
|
112
|
+
text: () => controller.activeSkills.includes('marivo-analysis')
|
|
113
|
+
? MARIVO_ANALYSIS_CLOSEOUT_PROMPT
|
|
114
|
+
: '',
|
|
115
|
+
}));
|
|
116
|
+
installed.set(agent, controller);
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
retire(controller);
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
return {
|
|
124
|
+
install() {
|
|
125
|
+
if (!active)
|
|
126
|
+
throw new Error('Marivo Agent installation disposed');
|
|
127
|
+
try {
|
|
128
|
+
stops.push(ctx.on('credentials/reference-updated', (ref) => credentialService.invalidateStorageRef(ref)));
|
|
129
|
+
for (const agent of ctx.agents.list())
|
|
130
|
+
install(agent);
|
|
131
|
+
stops.push(ctx.on('agent/created', ({ agent }) => {
|
|
132
|
+
install(agent);
|
|
133
|
+
}));
|
|
134
|
+
stops.push(ctx.on('agent/disposed', ({ agent }) => {
|
|
135
|
+
const controller = installed.get(agent);
|
|
136
|
+
if (controller)
|
|
137
|
+
retire(controller);
|
|
138
|
+
installed.delete(agent);
|
|
139
|
+
}));
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
void close();
|
|
143
|
+
throw error;
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
close,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
/** Stops synchronously; the returned Promise also waits for all owned work. */
|
|
150
|
+
export function installMarivoPlugin(...args) {
|
|
151
|
+
const installation = createMarivoAgentInstallation(...args);
|
|
152
|
+
installation.install();
|
|
153
|
+
return installation.close;
|
|
154
|
+
}
|