@inflexa-ai/harness 0.19.2 → 0.21.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/agents/conversation-agent.d.ts +26 -14
- package/dist/agents/conversation-agent.js +12 -23
- package/dist/agents/report-session-agent.d.ts +31 -5
- package/dist/agents/report-session-agent.js +31 -6
- package/dist/app/chat-turn.js +3 -1
- package/dist/app/message-assembly.d.ts +15 -1
- package/dist/app/message-assembly.js +22 -8
- package/dist/app/report-session-runtime.d.ts +21 -4
- package/dist/app/report-session-runtime.js +53 -6
- package/dist/app/spawn-report-session.d.ts +174 -17
- package/dist/app/spawn-report-session.js +233 -21
- package/dist/contracts/chat-events.d.ts +7 -2
- package/dist/contracts/message.d.ts +10 -0
- package/dist/contracts/report-blocks.d.ts +743 -19
- package/dist/contracts/report-blocks.js +186 -11
- package/dist/contracts/report-reference.d.ts +88 -0
- package/dist/contracts/report-reference.js +48 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +20 -0
- package/dist/lib/chrome.d.ts +26 -6
- package/dist/lib/chrome.js +99 -32
- package/dist/lib/eyes.d.ts +57 -0
- package/dist/lib/eyes.js +45 -0
- package/dist/lib/page-capture.d.ts +14 -0
- package/dist/lib/page-capture.js +56 -2
- package/dist/literature/sources/pubmed.js +2 -1
- package/dist/loop/run-agent.js +58 -23
- package/dist/loop/tool-detail.d.ts +19 -2
- package/dist/loop/tool-detail.js +35 -2
- package/dist/memory/content-to-cortex.d.ts +3 -2
- package/dist/memory/content-to-cortex.js +21 -12
- package/dist/memory/conversation-display-replay.js +14 -7
- package/dist/memory/thread-history.d.ts +60 -3
- package/dist/memory/thread-history.js +55 -16
- package/dist/memory/thread-store.d.ts +11 -1
- package/dist/memory/thread-store.js +12 -2
- package/dist/prompts/conversation.d.ts +1 -1
- package/dist/prompts/conversation.js +23 -6
- package/dist/prompts/report-session.d.ts +1 -1
- package/dist/prompts/report-session.js +183 -9
- package/dist/report-model/authoring-grammar.d.ts +463 -0
- package/dist/report-model/authoring-grammar.js +77 -0
- package/dist/report-model/block-walk.d.ts +57 -14
- package/dist/report-model/block-walk.js +116 -11
- package/dist/report-model/draft-finish.d.ts +22 -4
- package/dist/report-model/draft-finish.js +39 -7
- package/dist/report-model/draft-operations.d.ts +3 -0
- package/dist/report-model/draft-operations.js +19 -5
- package/dist/report-model/draft-read.d.ts +8 -5
- package/dist/report-model/draft-read.js +21 -5
- package/dist/report-model/fixture-resolver.js +15 -4
- package/dist/report-model/pin-snapshot.d.ts +24 -6
- package/dist/report-model/pin-snapshot.js +204 -6
- package/dist/report-model/production-resolver.js +15 -4
- package/dist/report-model/reference-resolver.d.ts +50 -1
- package/dist/report-model/reference-resolver.js +94 -1
- package/dist/report-model/reference-stamp.d.ts +45 -0
- package/dist/report-model/reference-stamp.js +173 -0
- package/dist/report-model/structural-validation.d.ts +4 -1
- package/dist/report-model/structural-validation.js +48 -3
- package/dist/report-model/validate.d.ts +1 -1
- package/dist/report-model/validate.js +1 -1
- package/dist/report-render/asset-lookup.d.ts +19 -0
- package/dist/report-render/asset-lookup.js +37 -0
- package/dist/report-render/assets.d.ts +45 -1
- package/dist/report-render/assets.js +65 -6
- package/dist/report-render/chart-presets.d.ts +102 -0
- package/dist/report-render/chart-presets.js +205 -0
- package/dist/report-render/chart.d.ts +112 -10
- package/dist/report-render/chart.js +1164 -41
- package/dist/report-render/design.d.ts +99 -0
- package/dist/report-render/design.js +289 -107
- package/dist/report-render/number-format.d.ts +117 -0
- package/dist/report-render/number-format.js +479 -0
- package/dist/report-render/page.d.ts +121 -5
- package/dist/report-render/page.js +689 -7
- package/dist/report-render/references.d.ts +70 -16
- package/dist/report-render/references.js +54 -22
- package/dist/report-render/render.d.ts +23 -5
- package/dist/report-render/render.js +81 -22
- package/dist/report-render/table-data.d.ts +92 -0
- package/dist/report-render/table-data.js +129 -0
- package/dist/report-render/types.d.ts +15 -0
- package/dist/report-render/value-bridge.js +6 -2
- package/dist/report-render/views/chart-view.d.ts +12 -5
- package/dist/report-render/views/chart-view.js +14 -8
- package/dist/report-render/views/page-view.d.ts +36 -15
- package/dist/report-render/views/page-view.js +45 -23
- package/dist/report-render/views/prose.d.ts +12 -2
- package/dist/report-render/views/prose.js +29 -7
- package/dist/report-render/views/references-view.d.ts +22 -8
- package/dist/report-render/views/references-view.js +101 -13
- package/dist/report-render/views/values.d.ts +128 -13
- package/dist/report-render/views/values.js +199 -18
- package/dist/runtime/assemble.d.ts +39 -5
- package/dist/runtime/assemble.js +47 -6
- package/dist/sandbox/client.d.ts +10 -1
- package/dist/sandbox/create-sandbox.d.ts +9 -4
- package/dist/sandbox/create-sandbox.js +22 -16
- package/dist/sandbox/docker-client.js +10 -7
- package/dist/sandbox/k8s-client.js +11 -18
- package/dist/sandbox/mount-plan.d.ts +45 -7
- package/dist/sandbox/mount-plan.js +43 -5
- package/dist/sandbox/types.d.ts +10 -6
- package/dist/state/init.js +38 -9
- package/dist/state/report-session-state.d.ts +42 -1
- package/dist/state/report-session-state.js +70 -2
- package/dist/state/report-versions.d.ts +22 -17
- package/dist/state/report-versions.js +48 -35
- package/dist/state/snapshot-parse.js +16 -1
- package/dist/tasks/data-profile.d.ts +7 -4
- package/dist/tasks/data-profile.js +9 -9
- package/dist/tools/define-tool.d.ts +32 -0
- package/dist/tools/define-tool.js +4 -0
- package/dist/tools/detail-resolver.d.ts +7 -2
- package/dist/tools/detail-resolver.js +7 -2
- package/dist/tools/iterate-report.d.ts +1 -1
- package/dist/tools/report/preview-snapshot.js +1 -0
- package/dist/tools/report-authoring/authoring-tools.d.ts +15 -6
- package/dist/tools/report-authoring/authoring-tools.js +99 -18
- package/dist/tools/report-session/derive-table.d.ts +162 -0
- package/dist/tools/report-session/derive-table.js +459 -0
- package/dist/tools/report-session/examine-page.d.ts +48 -18
- package/dist/tools/report-session/examine-page.js +204 -24
- package/dist/tools/report-session/index.d.ts +2 -0
- package/dist/tools/report-session/index.js +2 -0
- package/dist/tools/report-session/list-artifacts.d.ts +97 -0
- package/dist/tools/report-session/list-artifacts.js +197 -0
- package/dist/tools/report-session/preview-report.d.ts +6 -0
- package/dist/tools/report-session/preview-report.js +180 -28
- package/dist/tools/report-session/record-version.d.ts +22 -10
- package/dist/tools/report-session/record-version.js +99 -14
- package/dist/tools/start-report-session.d.ts +115 -0
- package/dist/tools/start-report-session.js +179 -0
- package/dist/workflows/sandbox-step.d.ts +7 -4
- package/dist/workflows/sandbox-step.js +10 -12
- package/dist/workspace/paths.d.ts +50 -0
- package/dist/workspace/paths.js +63 -0
- package/package.json +2 -1
|
@@ -14,21 +14,18 @@
|
|
|
14
14
|
* `execute_analysis` is wired here — it launches the DBOS `executeAnalysis` parent
|
|
15
15
|
* workflow under `workflowId = runId` (the bare run UUID) through the
|
|
16
16
|
* `RunLauncher` seam and returns the runId (results are pull-only via
|
|
17
|
-
* `inspectRun` on a later turn).
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* and drives in-process Nunjucks rendering via the `report-builder` agent, no
|
|
21
|
-
* sandbox). The 4 custom tools the builder itself drives (`build_report`, its
|
|
22
|
-
* own terminal `submit_report`, `preview_snapshot`, `mint_preview_url`) are
|
|
23
|
-
* constructed inside the runner so they share closure-captured outcome state +
|
|
24
|
-
* preview-dir paths.
|
|
17
|
+
* `inspectRun` on a later turn). `start_report_session` is the one report path.
|
|
18
|
+
* It starts a report thread as a child of the conversation, and the Report
|
|
19
|
+
* Builder composes the report in that thread.
|
|
25
20
|
* The workspace read surface (`read_file`, `grep`, `workspace_search`) is
|
|
26
21
|
* wired here over the `WorkspaceFilesystem` seam.
|
|
27
22
|
*/
|
|
28
23
|
import type { Pool } from "pg";
|
|
29
24
|
import type { ExecuteAnalysisInput, ExecuteAnalysisResult } from "../workflows/execute-analysis.js";
|
|
25
|
+
import type { EnsureSessionStateResult } from "../app/report-session-runtime.js";
|
|
30
26
|
import type { ResourcePolicy } from "../config/resource-limits.js";
|
|
31
27
|
import type { ChromeConfig } from "../lib/chrome.js";
|
|
28
|
+
import type { AcquireEyes } from "../lib/eyes.js";
|
|
32
29
|
import type { AgentDefinition } from "../loop/types.js";
|
|
33
30
|
import type { ChatProvider, EmbeddingProvider } from "../providers/types.js";
|
|
34
31
|
import type { Tool } from "../tools/define-tool.js";
|
|
@@ -38,7 +35,7 @@ import { type BioToolKeys } from "../tools/bio/keys.js";
|
|
|
38
35
|
import type { EnvironmentStorePaths } from "../config/environment-stores.js";
|
|
39
36
|
import type { RunAuthorizer } from "../execution/run-authorizer.js";
|
|
40
37
|
import type { RunLauncher } from "../execution/run-launcher.js";
|
|
41
|
-
import {
|
|
38
|
+
import type { SubmitReportDeps } from "../tools/iterate-report.js";
|
|
42
39
|
import type { Logger } from "../lib/logger.js";
|
|
43
40
|
import type { UsageRecorder } from "../billing/usage-recorder.js";
|
|
44
41
|
import type { CitationResolver } from "../citations/types.js";
|
|
@@ -80,6 +77,13 @@ export interface ConversationAgentDeps extends EnvironmentStorePaths {
|
|
|
80
77
|
* launches it through the `RunLauncher` seam to start the run.
|
|
81
78
|
*/
|
|
82
79
|
readonly executeAnalysisWorkflow: (input: ExecuteAnalysisInput) => Promise<ExecuteAnalysisResult>;
|
|
80
|
+
/**
|
|
81
|
+
* The anchor operation of the report session runtime — produced by
|
|
82
|
+
* `createReportSessionRuntime` and wired by `assembleCoreRuntime`. The spawn
|
|
83
|
+
* of `start_report_session` runs it after the seed of the child lands, thus
|
|
84
|
+
* the transcript anchor and the data snapshot pin at one moment.
|
|
85
|
+
*/
|
|
86
|
+
readonly anchorReportSession: (threadId: string) => Promise<EnsureSessionStateResult>;
|
|
83
87
|
/** Workspace-root resolution seam (see workspace/paths.ts). */
|
|
84
88
|
readonly resolveWorkspaceRoot: ResolveWorkspaceRoot;
|
|
85
89
|
/**
|
|
@@ -95,19 +99,27 @@ export interface ConversationAgentDeps extends EnvironmentStorePaths {
|
|
|
95
99
|
*/
|
|
96
100
|
readonly runLauncher: RunLauncher;
|
|
97
101
|
/**
|
|
98
|
-
* Preview-publishing seam factory
|
|
99
|
-
*
|
|
100
|
-
*
|
|
102
|
+
* Preview-publishing seam factory. No tool of the roster reads it. The field
|
|
103
|
+
* stays, because a change to the deps breaks an embedder at its composition
|
|
104
|
+
* root.
|
|
101
105
|
*/
|
|
102
106
|
readonly createPreviewPublisher: SubmitReportDeps["createPreviewPublisher"];
|
|
103
107
|
/** API keys for the external bio/chem data sources. */
|
|
104
108
|
readonly bioKeys: BioToolKeys;
|
|
105
|
-
/** Root templates dir
|
|
109
|
+
/** Root templates dir. No tool of the roster reads it. */
|
|
106
110
|
readonly templatesDir: string;
|
|
107
|
-
/** Skills root
|
|
111
|
+
/** Skills root. No tool of the roster reads it. */
|
|
108
112
|
readonly skillsDir: string;
|
|
109
113
|
/** Headless-Chrome config for report snapshot/preview rendering. */
|
|
110
114
|
readonly chrome: ChromeConfig;
|
|
115
|
+
/**
|
|
116
|
+
* The eyes of a report session — where a browser comes from for one look at
|
|
117
|
+
* the rendered page. `start_report_session` hands it to its spawn, thus a
|
|
118
|
+
* composition that binds the seam and names no browser still starts a
|
|
119
|
+
* session. The assembly resolves the eyes one time, and the agent that looks
|
|
120
|
+
* at a page reads that same answer.
|
|
121
|
+
*/
|
|
122
|
+
readonly eyes?: AcquireEyes;
|
|
111
123
|
/**
|
|
112
124
|
* Host resource policy — per-step ceilings + machine budget. `generate_plan`
|
|
113
125
|
* states the ceilings to the planner and validates against them;
|
|
@@ -14,14 +14,9 @@
|
|
|
14
14
|
* `execute_analysis` is wired here — it launches the DBOS `executeAnalysis` parent
|
|
15
15
|
* workflow under `workflowId = runId` (the bare run UUID) through the
|
|
16
16
|
* `RunLauncher` seam and returns the runId (results are pull-only via
|
|
17
|
-
* `inspectRun` on a later turn).
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* and drives in-process Nunjucks rendering via the `report-builder` agent, no
|
|
21
|
-
* sandbox). The 4 custom tools the builder itself drives (`build_report`, its
|
|
22
|
-
* own terminal `submit_report`, `preview_snapshot`, `mint_preview_url`) are
|
|
23
|
-
* constructed inside the runner so they share closure-captured outcome state +
|
|
24
|
-
* preview-dir paths.
|
|
17
|
+
* `inspectRun` on a later turn). `start_report_session` is the one report path.
|
|
18
|
+
* It starts a report thread as a child of the conversation, and the Report
|
|
19
|
+
* Builder composes the report in that thread.
|
|
25
20
|
* The workspace read surface (`read_file`, `grep`, `workspace_search`) is
|
|
26
21
|
* wired here over the `WorkspaceFilesystem` seam.
|
|
27
22
|
*/
|
|
@@ -39,7 +34,7 @@ import { createUpdateWorkingMemoryTool } from "../tools/memory/index.js";
|
|
|
39
34
|
import { createListAvailablePackagesTool } from "../tools/sandbox/list-available-packages.js";
|
|
40
35
|
import { createListAvailableRefsTool } from "../tools/sandbox/list-available-refs.js";
|
|
41
36
|
import { createExecuteAnalysisTool } from "../tools/execute-analysis.js";
|
|
42
|
-
import {
|
|
37
|
+
import { createStartReportSessionTool } from "../tools/start-report-session.js";
|
|
43
38
|
import { createResolveCitationTool } from "../tools/research/resolve-citation.js";
|
|
44
39
|
/** Canonical agent id — the single source of truth. */
|
|
45
40
|
export const CONVERSATION_AGENT_ID = "conversation-agent";
|
|
@@ -47,7 +42,7 @@ export const CONVERSATION_AGENT_ID = "conversation-agent";
|
|
|
47
42
|
const CONVERSATION_MAX_ITERATIONS = 50;
|
|
48
43
|
/** Build the conversation `AgentDefinition` with every tool fully dep-bound. */
|
|
49
44
|
export function createConversationAgent(deps) {
|
|
50
|
-
const { provider, pool, embedding, workspaceFs, model, utilityProvider, utilityModel, executeAnalysisWorkflow,
|
|
45
|
+
const { provider, pool, embedding, workspaceFs, model, utilityProvider, utilityModel, executeAnalysisWorkflow, runAuthorizer, runLauncher, bioKeys, chrome, resourcePolicy, hostTools, refStorePath, packagesFile, usageRecorder, citationResolver, } = deps;
|
|
51
46
|
const workingMemory = createWorkingMemory(pool);
|
|
52
47
|
const ncbi = createNcbiTools(bioKeys);
|
|
53
48
|
const chemDb = createChemDbTools(bioKeys, { ...(deps.logger ? { logger: deps.logger } : {}) });
|
|
@@ -114,21 +109,15 @@ export function createConversationAgent(deps) {
|
|
|
114
109
|
utilityModel,
|
|
115
110
|
...(deps.logger ? { logger: deps.logger } : {}),
|
|
116
111
|
}),
|
|
117
|
-
//
|
|
118
|
-
//
|
|
119
|
-
//
|
|
120
|
-
|
|
121
|
-
planReportTool,
|
|
122
|
-
createReportSubmitTool({
|
|
123
|
-
provider,
|
|
112
|
+
// The one report path. The tool starts a report thread as a child of the
|
|
113
|
+
// conversation, and the user composes the report there with the Report
|
|
114
|
+
// Builder.
|
|
115
|
+
createStartReportSessionTool({
|
|
124
116
|
pool,
|
|
125
|
-
resolveWorkspaceRoot,
|
|
126
|
-
model,
|
|
127
|
-
templatesDir,
|
|
128
|
-
skillsDir,
|
|
129
117
|
chrome,
|
|
130
|
-
|
|
131
|
-
|
|
118
|
+
anchorSession: deps.anchorReportSession,
|
|
119
|
+
...(deps.eyes ? { eyes: deps.eyes } : {}),
|
|
120
|
+
...(deps.logger ? { logger: deps.logger } : {}),
|
|
132
121
|
}),
|
|
133
122
|
// Display.
|
|
134
123
|
showUserTool,
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* `createReportSessionAgent` is the composition root of the report path. It gets
|
|
5
5
|
* the shared deps one time, and it hands each tool exactly what it needs. The
|
|
6
|
-
* authoring tools, the preview tool, the eyes tool, and the record
|
|
7
|
-
* session-state gateway, thus one assembled definition serves every
|
|
8
|
-
* per-session state stays behind the tool boundary.
|
|
6
|
+
* authoring tools, the listing tool, the preview tool, the eyes tool, and the record
|
|
7
|
+
* tool bind to the session-state gateway, thus one assembled definition serves every
|
|
8
|
+
* thread, and the per-session state stays behind the tool boundary.
|
|
9
9
|
*
|
|
10
10
|
* The roster is read-only toward the analysis. It holds the workspace read tools,
|
|
11
11
|
* the workspace search, the run inspection, and the data-profile inspection. It
|
|
@@ -13,6 +13,10 @@
|
|
|
13
13
|
* mutate surface. Thus no tool starts a run, and no tool changes an analysis. The
|
|
14
14
|
* roster omits those tools, and no runtime guard blocks them.
|
|
15
15
|
*
|
|
16
|
+
* The derivation tool is the one tool that runs a container, and it changes no
|
|
17
|
+
* analysis either. It mints no run id, it registers no artifact, and it writes under
|
|
18
|
+
* the directory of the session alone.
|
|
19
|
+
*
|
|
16
20
|
* The definition carries no per-session value. The system prompt composes through
|
|
17
21
|
* `composeSystemPrompt` with the identity part and the conversational part, the
|
|
18
22
|
* same composition as the conversation agent. Thus the prompt prefix stays constant
|
|
@@ -20,11 +24,15 @@
|
|
|
20
24
|
*/
|
|
21
25
|
import type { Pool } from "pg";
|
|
22
26
|
import type { AuthContext } from "../auth/types.js";
|
|
27
|
+
import type { RunAuthorizer } from "../execution/run-authorizer.js";
|
|
23
28
|
import type { AgentDefinition } from "../loop/types.js";
|
|
29
|
+
import type { SandboxClient } from "../sandbox/client.js";
|
|
30
|
+
import type { ReportSessionStateStore } from "../state/report-session-state.js";
|
|
24
31
|
import type { EmbeddingProvider } from "../providers/types.js";
|
|
25
32
|
import type { WorkspaceFilesystem } from "../workspace/filesystem.js";
|
|
26
33
|
import type { ResolveWorkspaceRoot } from "../workspace/paths.js";
|
|
27
34
|
import type { ChromeConfig } from "../lib/chrome.js";
|
|
35
|
+
import type { AcquireEyes } from "../lib/eyes.js";
|
|
28
36
|
import type { Logger } from "../lib/logger.js";
|
|
29
37
|
import type { ThreadStore } from "../memory/thread-store.js";
|
|
30
38
|
import type { ReferenceResolver } from "../report-model/reference-resolver.js";
|
|
@@ -48,16 +56,34 @@ export interface ReportSessionAgentDeps {
|
|
|
48
56
|
readonly embedding: EmbeddingProvider;
|
|
49
57
|
/** Workspace filesystem read seam -- the four read tools. */
|
|
50
58
|
readonly workspaceFs: WorkspaceFilesystem;
|
|
51
|
-
/** Session-state gateway -- the authoring tools, the preview tool, the eyes tool, and the record tool bind to it. */
|
|
59
|
+
/** Session-state gateway -- the authoring tools, the listing tool, the preview tool, the eyes tool, and the record tool bind to it. */
|
|
52
60
|
readonly gateway: ReportSessionStateGateway;
|
|
53
|
-
/** Workspace-root resolution seam -- the preview tool and the eyes tool resolve the
|
|
61
|
+
/** Workspace-root resolution seam -- the listing tool, the preview tool, and the eyes tool resolve the root per call. */
|
|
54
62
|
readonly resolveWorkspaceRoot: ResolveWorkspaceRoot;
|
|
55
63
|
/** Append-only version store -- the record tool gates the whole document first, then records one version. */
|
|
56
64
|
readonly store: ReportVersionStore;
|
|
65
|
+
/** Derivation ledger -- the derivation tool appends one record for each derived table. */
|
|
66
|
+
readonly derivations: Pick<ReportSessionStateStore, "appendDerivation">;
|
|
67
|
+
/**
|
|
68
|
+
* Sandbox seam -- the derivation tool runs one ephemeral container for each derived table. Omitted, the
|
|
69
|
+
* tool reports that the composition gives no sandbox, and it derives nothing.
|
|
70
|
+
*/
|
|
71
|
+
readonly sandboxClient?: SandboxClient;
|
|
72
|
+
/**
|
|
73
|
+
* Run-authorization seam -- the derivation tool authorizes the exec and revokes on every terminal path.
|
|
74
|
+
* Omitted, the tool derives nothing, the same as an absent sandbox client.
|
|
75
|
+
*/
|
|
76
|
+
readonly runAuthorizer?: RunAuthorizer;
|
|
57
77
|
/** Thread reader -- the record tool reads the anchor of the report thread. */
|
|
58
78
|
readonly threads: Pick<ThreadStore, "getThread">;
|
|
59
79
|
/** Headless-Chrome config -- the eyes tool opens the rendered page. */
|
|
60
80
|
readonly chrome: ChromeConfig;
|
|
81
|
+
/**
|
|
82
|
+
* Eyes seam -- where a browser comes from for one look. The eyes tool takes one lease for each look,
|
|
83
|
+
* and it releases the lease after the look. Omitted, the tool falls back to the chrome config, and a
|
|
84
|
+
* config that names no browser leaves the session with no look at all.
|
|
85
|
+
*/
|
|
86
|
+
readonly eyes?: AcquireEyes;
|
|
61
87
|
/**
|
|
62
88
|
* Reference-resolution factory -- absent until a realization lands; the preview tool and the record tool
|
|
63
89
|
* degrade as data. The factory binds one analysis, thus a tool makes the resolver over the scope of the call.
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* `createReportSessionAgent` is the composition root of the report path. It gets
|
|
5
5
|
* the shared deps one time, and it hands each tool exactly what it needs. The
|
|
6
|
-
* authoring tools, the preview tool, the eyes tool, and the record
|
|
7
|
-
* session-state gateway, thus one assembled definition serves every
|
|
8
|
-
* per-session state stays behind the tool boundary.
|
|
6
|
+
* authoring tools, the listing tool, the preview tool, the eyes tool, and the record
|
|
7
|
+
* tool bind to the session-state gateway, thus one assembled definition serves every
|
|
8
|
+
* thread, and the per-session state stays behind the tool boundary.
|
|
9
9
|
*
|
|
10
10
|
* The roster is read-only toward the analysis. It holds the workspace read tools,
|
|
11
11
|
* the workspace search, the run inspection, and the data-profile inspection. It
|
|
@@ -13,13 +13,17 @@
|
|
|
13
13
|
* mutate surface. Thus no tool starts a run, and no tool changes an analysis. The
|
|
14
14
|
* roster omits those tools, and no runtime guard blocks them.
|
|
15
15
|
*
|
|
16
|
+
* The derivation tool is the one tool that runs a container, and it changes no
|
|
17
|
+
* analysis either. It mints no run id, it registers no artifact, and it writes under
|
|
18
|
+
* the directory of the session alone.
|
|
19
|
+
*
|
|
16
20
|
* The definition carries no per-session value. The system prompt composes through
|
|
17
21
|
* `composeSystemPrompt` with the identity part and the conversational part, the
|
|
18
22
|
* same composition as the conversation agent. Thus the prompt prefix stays constant
|
|
19
23
|
* across threads, and the provider cache reuses it.
|
|
20
24
|
*/
|
|
21
25
|
import { createReportAuthoringTools } from "../tools/report-authoring/authoring-tools.js";
|
|
22
|
-
import { createExaminePageTool, createPreviewReportTool, createRecordVersionTool } from "../tools/report-session/index.js";
|
|
26
|
+
import { createDeriveTableTool, createExaminePageTool, createListPinnedArtifactsTool, createPreviewReportTool, createRecordVersionTool, } from "../tools/report-session/index.js";
|
|
23
27
|
import { createFileStatTool, createGrepTool, createListFilesTool, createReadFileTool, createWorkspaceSearchTool } from "../tools/workspace/index.js";
|
|
24
28
|
import { createInspectDataProfileTool, createInspectRunTool } from "../tools/research/index.js";
|
|
25
29
|
import { reportSessionPrompt } from "../prompts/report-session.js";
|
|
@@ -33,7 +37,8 @@ export const REPORT_SESSION_AGENT_ID = "report-session";
|
|
|
33
37
|
const REPORT_SESSION_MAX_ITERATIONS = 50;
|
|
34
38
|
/** Build the report `AgentDefinition` with every tool bound to its deps. */
|
|
35
39
|
export function createReportSessionAgent(deps) {
|
|
36
|
-
const { model, pool, embedding, workspaceFs, gateway, resolveWorkspaceRoot, store, threads, chrome, makeResolver, resolvePageAsset, logger } = deps;
|
|
40
|
+
const { model, pool, embedding, workspaceFs, gateway, resolveWorkspaceRoot, store, threads, chrome, eyes, makeResolver, resolvePageAsset, logger } = deps;
|
|
41
|
+
const { derivations, sandboxClient, runAuthorizer } = deps;
|
|
37
42
|
const authoring = createReportAuthoringTools(gateway);
|
|
38
43
|
const tools = [
|
|
39
44
|
// The read surface toward the analysis. It roams the tree read-only.
|
|
@@ -54,6 +59,23 @@ export function createReportSessionAgent(deps) {
|
|
|
54
59
|
authoring.read_outline,
|
|
55
60
|
authoring.read_block,
|
|
56
61
|
authoring.finish_draft,
|
|
62
|
+
// The orientation source of the pinned evidence. It reads the snapshot of the
|
|
63
|
+
// thread, and it resolves the workspace root per call for the header columns.
|
|
64
|
+
createListPinnedArtifactsTool({
|
|
65
|
+
gateway,
|
|
66
|
+
resolveWorkspaceRoot,
|
|
67
|
+
...(logger ? { logger } : {}),
|
|
68
|
+
}),
|
|
69
|
+
// The derivation tool. It reshapes the pinned evidence into one table under the
|
|
70
|
+
// session directory, on the sandbox rails of the value tier.
|
|
71
|
+
createDeriveTableTool({
|
|
72
|
+
gateway,
|
|
73
|
+
resolveWorkspaceRoot,
|
|
74
|
+
derivations,
|
|
75
|
+
...(sandboxClient ? { sandboxClient } : {}),
|
|
76
|
+
...(runAuthorizer ? { runAuthorizer } : {}),
|
|
77
|
+
...(logger ? { logger } : {}),
|
|
78
|
+
}),
|
|
57
79
|
// The render-and-preview tool. It resolves the page root per call.
|
|
58
80
|
createPreviewReportTool({
|
|
59
81
|
gateway,
|
|
@@ -67,13 +89,16 @@ export function createReportSessionAgent(deps) {
|
|
|
67
89
|
gateway,
|
|
68
90
|
resolveWorkspaceRoot,
|
|
69
91
|
chrome,
|
|
92
|
+
...(eyes ? { eyes } : {}),
|
|
70
93
|
...(logger ? { logger } : {}),
|
|
71
94
|
}),
|
|
72
|
-
// The record tool. It gates the whole document,
|
|
95
|
+
// The record tool. It gates the whole document, records one version, then prunes each
|
|
96
|
+
// derived table that the recorded document does not bind.
|
|
73
97
|
createRecordVersionTool({
|
|
74
98
|
gateway,
|
|
75
99
|
store,
|
|
76
100
|
threads,
|
|
101
|
+
resolveWorkspaceRoot,
|
|
77
102
|
...(makeResolver ? { makeResolver } : {}),
|
|
78
103
|
...(logger ? { logger } : {}),
|
|
79
104
|
}),
|
package/dist/app/chat-turn.js
CHANGED
|
@@ -36,7 +36,8 @@ export async function prepareChatTurn(deps, params) {
|
|
|
36
36
|
if (existing && existing.analysisId !== analysisId) {
|
|
37
37
|
return { kind: "not_found" };
|
|
38
38
|
}
|
|
39
|
-
// The type a caller resolves the turn's agent from
|
|
39
|
+
// The type a caller resolves the turn's agent from, and the type that the
|
|
40
|
+
// message assembly reads for its tail. An existing row carries
|
|
40
41
|
// its own. An absent one defaults to `conversation` — the store's own
|
|
41
42
|
// default — so a best-effort create that fails non-fatally still leaves a
|
|
42
43
|
// usable type; a successful create overrides it from the returned row.
|
|
@@ -67,6 +68,7 @@ export async function prepareChatTurn(deps, params) {
|
|
|
67
68
|
const history = createThreadHistory(pool);
|
|
68
69
|
const { messages, userMessage } = await assembleMessages({
|
|
69
70
|
threadId,
|
|
71
|
+
threadType,
|
|
70
72
|
analysisId,
|
|
71
73
|
userInput,
|
|
72
74
|
analysisContext: analysisState?.context ?? null,
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* [ ...loadRecent(threadId, budget) ← stable, cacheable prefix
|
|
7
7
|
* {user: cortex_analysis_state.context}, ← tail
|
|
8
8
|
* {user: runActivityContext}, ← tail
|
|
9
|
-
* {user: render(workingMemory)}, ← tail
|
|
9
|
+
* {user: render(workingMemory)}, ← tail, `conversation` thread only
|
|
10
10
|
* {user: normalizeUnicode(redactSecrets(input))} ] ← tail
|
|
11
11
|
*
|
|
12
12
|
* `system + tools + history` is the cacheable prefix — it only extends
|
|
@@ -14,6 +14,17 @@
|
|
|
14
14
|
* **tail** as `user` messages: they change every turn, so a system-message
|
|
15
15
|
* placement would bust the Anthropic cache prefix.
|
|
16
16
|
*
|
|
17
|
+
* A `report` thread does not get the working-memory tail. The spawn copies the
|
|
18
|
+
* working-memory render into the child transcript at the anchor. A live render
|
|
19
|
+
* sees state past that anchor, and that breaks the knowledge cap of a report
|
|
20
|
+
* session. The analysis context and the run activity stay on both thread types.
|
|
21
|
+
*
|
|
22
|
+
* The history window of a `report` thread also keeps the first turn. That turn
|
|
23
|
+
* is the seed, and it is the one record of the brief and of the copied render.
|
|
24
|
+
* The window evicts the oldest turn first, thus a long session would drop its
|
|
25
|
+
* own charter and keep only its tools. A `conversation` thread evicts as before,
|
|
26
|
+
* because its live tail carries the working memory on each turn.
|
|
27
|
+
*
|
|
17
28
|
* Sanitization (`redactSecrets`, `normalizeUnicode`) is applied **once**, to
|
|
18
29
|
* the new user input only — never to history, assistant messages, tool
|
|
19
30
|
* results, the analysis context, or the rendered working memory.
|
|
@@ -26,6 +37,7 @@
|
|
|
26
37
|
import type { ModelMessage } from "ai";
|
|
27
38
|
import type { LoopMessage } from "../loop/types.js";
|
|
28
39
|
import type { ThreadHistory } from "../memory/thread-history.js";
|
|
40
|
+
import type { ThreadType } from "../memory/thread-store.js";
|
|
29
41
|
import type { WorkingMemoryStore } from "../memory/working-memory.js";
|
|
30
42
|
/**
|
|
31
43
|
* Token budget for the `loadRecent` history window. Sized to leave headroom
|
|
@@ -36,6 +48,8 @@ export declare const DEFAULT_HISTORY_TOKEN_BUDGET = 120000;
|
|
|
36
48
|
export interface AssembleMessagesArgs {
|
|
37
49
|
/** The conversation thread — a UI-generated UUID, never the analysisId. */
|
|
38
50
|
readonly threadId: string;
|
|
51
|
+
/** The type of the thread. A `report` thread drops the working-memory tail, and its window keeps the seed. */
|
|
52
|
+
readonly threadType: ThreadType;
|
|
39
53
|
/** The analysis scope — keys working memory and (separately) the context. */
|
|
40
54
|
readonly analysisId: string;
|
|
41
55
|
/** The raw, untrusted user input for this turn. */
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* [ ...loadRecent(threadId, budget) ← stable, cacheable prefix
|
|
7
7
|
* {user: cortex_analysis_state.context}, ← tail
|
|
8
8
|
* {user: runActivityContext}, ← tail
|
|
9
|
-
* {user: render(workingMemory)}, ← tail
|
|
9
|
+
* {user: render(workingMemory)}, ← tail, `conversation` thread only
|
|
10
10
|
* {user: normalizeUnicode(redactSecrets(input))} ] ← tail
|
|
11
11
|
*
|
|
12
12
|
* `system + tools + history` is the cacheable prefix — it only extends
|
|
@@ -14,6 +14,17 @@
|
|
|
14
14
|
* **tail** as `user` messages: they change every turn, so a system-message
|
|
15
15
|
* placement would bust the Anthropic cache prefix.
|
|
16
16
|
*
|
|
17
|
+
* A `report` thread does not get the working-memory tail. The spawn copies the
|
|
18
|
+
* working-memory render into the child transcript at the anchor. A live render
|
|
19
|
+
* sees state past that anchor, and that breaks the knowledge cap of a report
|
|
20
|
+
* session. The analysis context and the run activity stay on both thread types.
|
|
21
|
+
*
|
|
22
|
+
* The history window of a `report` thread also keeps the first turn. That turn
|
|
23
|
+
* is the seed, and it is the one record of the brief and of the copied render.
|
|
24
|
+
* The window evicts the oldest turn first, thus a long session would drop its
|
|
25
|
+
* own charter and keep only its tools. A `conversation` thread evicts as before,
|
|
26
|
+
* because its live tail carries the working memory on each turn.
|
|
27
|
+
*
|
|
17
28
|
* Sanitization (`redactSecrets`, `normalizeUnicode`) is applied **once**, to
|
|
18
29
|
* the new user input only — never to history, assistant messages, tool
|
|
19
30
|
* results, the analysis context, or the rendered working memory.
|
|
@@ -37,7 +48,7 @@ export const DEFAULT_HISTORY_TOKEN_BUDGET = 120_000;
|
|
|
37
48
|
*/
|
|
38
49
|
export async function assembleMessages(args) {
|
|
39
50
|
const budget = args.tokenBudget ?? DEFAULT_HISTORY_TOKEN_BUDGET;
|
|
40
|
-
const history = unwrapOrThrow(await args.history.loadRecent(args.threadId, budget));
|
|
51
|
+
const history = unwrapOrThrow(await args.history.loadRecent(args.threadId, budget, { keepFirstTurn: args.threadType === "report" }));
|
|
41
52
|
// Sanitization — applied once, here, to the new user input only.
|
|
42
53
|
const userMessage = {
|
|
43
54
|
role: "user",
|
|
@@ -55,12 +66,15 @@ export async function assembleMessages(args) {
|
|
|
55
66
|
role: "user",
|
|
56
67
|
content: args.runActivityContext,
|
|
57
68
|
});
|
|
58
|
-
// Working memory — agent-authored
|
|
59
|
-
//
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
69
|
+
// Working memory — agent-authored and trusted. A `conversation` thread
|
|
70
|
+
// always gets it, because the render names each section even when it is
|
|
71
|
+
// empty. A `report` thread reads the frozen copy in its seed message.
|
|
72
|
+
if (args.threadType !== "report") {
|
|
73
|
+
tail.push({
|
|
74
|
+
role: "user",
|
|
75
|
+
content: unwrapOrThrow(await args.workingMemory.render(args.analysisId)),
|
|
76
|
+
});
|
|
77
|
+
}
|
|
64
78
|
tail.push(userMessage);
|
|
65
79
|
return { messages: [...history, ...tail], userMessage };
|
|
66
80
|
}
|
|
@@ -26,11 +26,17 @@
|
|
|
26
26
|
* thread and a wrong thread type are permanent, and a store or pin fault is
|
|
27
27
|
* transient. The persist is a compare-and-swap against the prior document that the
|
|
28
28
|
* load read, thus two concurrent turns cannot both land.
|
|
29
|
+
*
|
|
30
|
+
* The load serves the stored pin with the derivations of the session merged onto it.
|
|
31
|
+
* Thus a derived table binds, resolves, and validates the same way as a pinned one.
|
|
32
|
+
* The stored pin never changes, thus the anchor stays honest and the merge is
|
|
33
|
+
* recomputable from the row.
|
|
29
34
|
*/
|
|
30
35
|
import type { Pool } from "pg";
|
|
31
36
|
import type { Logger } from "../lib/logger.js";
|
|
32
|
-
import { type ReportSessionState as StoredSessionState } from "../state/report-session-state.js";
|
|
37
|
+
import { type ReportSessionState as StoredSessionState, type ReportSessionStateStore } from "../state/report-session-state.js";
|
|
33
38
|
import type { ReportSessionStateGateway } from "../tools/report-authoring/authoring-tools.js";
|
|
39
|
+
import type { ResolveWorkspaceRoot } from "../workspace/paths.js";
|
|
34
40
|
/**
|
|
35
41
|
* How a failed anchor ends. `absent-thread` and `wrong-thread-type` are permanent
|
|
36
42
|
* conditions, and `unavailable` is a transient store or pin fault. The gateway load
|
|
@@ -52,16 +58,27 @@ export type EnsureSessionStateResult = {
|
|
|
52
58
|
};
|
|
53
59
|
export interface ReportSessionRuntimeDeps {
|
|
54
60
|
readonly pool: Pool;
|
|
61
|
+
/**
|
|
62
|
+
* The workspace-root seam of the pin. The citation evidence of an analysis sits on disk under the
|
|
63
|
+
* root, thus a composition that binds no seam pins the artifact map alone.
|
|
64
|
+
*/
|
|
65
|
+
readonly resolveWorkspaceRoot?: ResolveWorkspaceRoot;
|
|
55
66
|
readonly logger?: Logger;
|
|
56
67
|
}
|
|
57
68
|
/**
|
|
58
69
|
* The report session-state runtime. The gateway serves the authoring tools, and
|
|
59
|
-
* `ensureSessionState` anchors the session. The
|
|
60
|
-
* `ensureSessionState` at the
|
|
61
|
-
*
|
|
70
|
+
* `ensureSessionState` anchors the session. The spawn of a report session runs
|
|
71
|
+
* `ensureSessionState` at the moment of the spawn, the serving path of a report
|
|
72
|
+
* turn runs it at the turn start, and the gateway `load` runs it too. Thus a tool
|
|
73
|
+
* call cannot arrive before the state exists.
|
|
62
74
|
*/
|
|
63
75
|
export interface ReportSessionRuntime {
|
|
64
76
|
readonly gateway: ReportSessionStateGateway;
|
|
77
|
+
/**
|
|
78
|
+
* The derivation ledger of the session state. The derivation tool appends one record for each
|
|
79
|
+
* derivation, and the gateway load serves each record as a member of the snapshot.
|
|
80
|
+
*/
|
|
81
|
+
readonly derivations: Pick<ReportSessionStateStore, "appendDerivation">;
|
|
65
82
|
ensureSessionState(threadId: string): Promise<EnsureSessionStateResult>;
|
|
66
83
|
}
|
|
67
84
|
/**
|
|
@@ -26,14 +26,47 @@
|
|
|
26
26
|
* thread and a wrong thread type are permanent, and a store or pin fault is
|
|
27
27
|
* transient. The persist is a compare-and-swap against the prior document that the
|
|
28
28
|
* load read, thus two concurrent turns cannot both land.
|
|
29
|
+
*
|
|
30
|
+
* The load serves the stored pin with the derivations of the session merged onto it.
|
|
31
|
+
* Thus a derived table binds, resolves, and validates the same way as a pinned one.
|
|
32
|
+
* The stored pin never changes, thus the anchor stays honest and the merge is
|
|
33
|
+
* recomputable from the row.
|
|
29
34
|
*/
|
|
30
35
|
import { createNoopLogger } from "../lib/console-logger.js";
|
|
31
36
|
import { describeDbError } from "../lib/db-result.js";
|
|
32
37
|
import { createThreadStore } from "../memory/thread-store.js";
|
|
33
38
|
import { pinReportSnapshot } from "../report-model/pin-snapshot.js";
|
|
34
|
-
import { createReportSessionStateStore } from "../state/report-session-state.js";
|
|
39
|
+
import { createReportSessionStateStore, } from "../state/report-session-state.js";
|
|
35
40
|
/** The empty draft of a fresh session. The pin writes the snapshot first, thus the document is empty here. */
|
|
36
41
|
const EMPTY_DRAFT = { title: "", sections: [] };
|
|
42
|
+
/**
|
|
43
|
+
* The served membership: the stored pin, with one entry for each derivation of the session.
|
|
44
|
+
*
|
|
45
|
+
* The tools read the served snapshot, thus a derived table binds the same way as a pinned one. The stored
|
|
46
|
+
* pin stays untouched, thus the merge runs again on each load and the row keeps the evidence of the pin
|
|
47
|
+
* alone.
|
|
48
|
+
*
|
|
49
|
+
* A derived entry carries the output hash alone. A file type states a role of the run ledger, and a
|
|
50
|
+
* derivation holds none. The map takes a null prototype, the same as the stored parse, thus a path such as
|
|
51
|
+
* `__proto__` stays an ordinary entry.
|
|
52
|
+
*
|
|
53
|
+
* The derivations land last, thus a record whose output path equals a pinned path would shadow the pin. No
|
|
54
|
+
* such record exists: the derivation tool refuses an output name that the served membership already holds,
|
|
55
|
+
* and the output path of a derivation sits under the session directory, which the pin never reaches.
|
|
56
|
+
*/
|
|
57
|
+
function serveMembership(snapshot, derivations) {
|
|
58
|
+
if (derivations.length === 0) {
|
|
59
|
+
return snapshot;
|
|
60
|
+
}
|
|
61
|
+
const artifacts = Object.create(null);
|
|
62
|
+
for (const [path, entry] of Object.entries(snapshot.artifacts)) {
|
|
63
|
+
artifacts[path] = entry;
|
|
64
|
+
}
|
|
65
|
+
for (const record of derivations) {
|
|
66
|
+
artifacts[record.outputPath] = { hash: record.outputHash };
|
|
67
|
+
}
|
|
68
|
+
return { ...snapshot, artifacts };
|
|
69
|
+
}
|
|
37
70
|
/**
|
|
38
71
|
* Build the report session-state runtime bound to a Postgres pool. The factory
|
|
39
72
|
* closure captures the pool and constructs the session-state store and the thread
|
|
@@ -61,12 +94,20 @@ export function createReportSessionRuntime(deps) {
|
|
|
61
94
|
* Pin the snapshot and write the row. A pin failure writes no row, thus a
|
|
62
95
|
* later run pins again. The write is insert-if-absent, thus two concurrent
|
|
63
96
|
* first runs make one row and both read the winner back.
|
|
97
|
+
*
|
|
98
|
+
* The pin takes the workspace-root seam for the citation evidence. An absent
|
|
99
|
+
* seam pins no citation, thus a citation block of the session resolves against
|
|
100
|
+
* an empty list. The warning names that condition one time for each session.
|
|
64
101
|
*/
|
|
65
102
|
async function pinAndWrite(threadId, analysisId) {
|
|
66
|
-
|
|
103
|
+
if (deps.resolveWorkspaceRoot === undefined) {
|
|
104
|
+
log.warn("the composition binds no workspace root, thus the pin carries no citation evidence", { threadId, analysisId });
|
|
105
|
+
}
|
|
106
|
+
const pinned = await pinReportSnapshot(pool, analysisId, deps.resolveWorkspaceRoot ? { resolveWorkspaceRoot: deps.resolveWorkspaceRoot } : {});
|
|
67
107
|
if (pinned.isErr()) {
|
|
68
|
-
log.error("the snapshot pin failed", { threadId, analysisId, ...log.errorFields(pinned.error.cause) });
|
|
69
|
-
|
|
108
|
+
log.error("the snapshot pin failed", { threadId, analysisId, kind: pinned.error.kind, ...log.errorFields(pinned.error.cause) });
|
|
109
|
+
const detail = pinned.error.kind === "run-listing-failed" ? "the run listing read failed" : "the artifact ledger read failed";
|
|
110
|
+
return { outcome: "failed", kind: "unavailable", detail };
|
|
70
111
|
}
|
|
71
112
|
const written = await store.writeSnapshot({ threadId, analysisId, snapshot: pinned.value });
|
|
72
113
|
return written.match((row) => ({ outcome: "ready", state: row }), (error) => storeFault(threadId, error));
|
|
@@ -104,6 +145,11 @@ export function createReportSessionRuntime(deps) {
|
|
|
104
145
|
* no document, thus the load gives the empty draft. The found load carries the
|
|
105
146
|
* stored analysis and the prior document as the concurrency token. A row with no
|
|
106
147
|
* snapshot cannot serve a tool, because the pin writes the snapshot first.
|
|
148
|
+
*
|
|
149
|
+
* The served snapshot is the stored pin with the derivations merged onto it, thus a
|
|
150
|
+
* tool reads one membership and it never merges again. The records ride the load
|
|
151
|
+
* beside the merged snapshot, because the chain of a derived path and the unused set
|
|
152
|
+
* both read the record and not the membership.
|
|
107
153
|
*/
|
|
108
154
|
function toLoad(state) {
|
|
109
155
|
if (state.snapshot === null) {
|
|
@@ -112,10 +158,11 @@ export function createReportSessionRuntime(deps) {
|
|
|
112
158
|
}
|
|
113
159
|
return {
|
|
114
160
|
outcome: "found",
|
|
115
|
-
state: { document: state.document ?? EMPTY_DRAFT, snapshot: state.snapshot },
|
|
161
|
+
state: { document: state.document ?? EMPTY_DRAFT, snapshot: serveMembership(state.snapshot, state.derivations) },
|
|
116
162
|
analysisId: state.analysisId,
|
|
117
163
|
token: state.document,
|
|
118
164
|
seenDocumentHash: state.seenDocumentHash,
|
|
165
|
+
derivations: state.derivations,
|
|
119
166
|
};
|
|
120
167
|
}
|
|
121
168
|
const gateway = {
|
|
@@ -179,5 +226,5 @@ export function createReportSessionRuntime(deps) {
|
|
|
179
226
|
});
|
|
180
227
|
},
|
|
181
228
|
};
|
|
182
|
-
return { gateway, ensureSessionState };
|
|
229
|
+
return { gateway, derivations: store, ensureSessionState };
|
|
183
230
|
}
|