@e-llm-studio/cognitive-assessment
v1.0.41
Published
Cognitive assessment library for e-llm-studio
Downloads
4,208
Readme
@e-llm-studio/cognitive-assessment
React library for integrating Cognitive Assessment flows (assessment/workflow) with:
- left chat panel
- right workflow/assessment screens
- API-driven actions and autosave flow
- GPT / web citation on workflow result steps
Installation
npm install @e-llm-studio/cognitive-assessmentPeer Dependencies
Make sure your app provides these:
npm install react react-dom @mui/material @mui/icons-material @emotion/react @emotion/styled @tanstack/react-queryIntegration Patterns
This package supports two host integration styles. Pick the one that matches how your mode is structured.
| Pattern | When to use | Host owns |
| --- | --- | --- |
| Screen composition (recommended for modes) | You render individual screens (SelectAssessmentScreen, ResultScreen, etc.) inside your own router/wrapper | API auth, routing, user context, web citation API calls |
| CognitiveWorkspace | You want the full bundled workspace with minimal wiring | Mostly config + layout sizing |
The screen composition pattern is how remote_template integrates this library today via CognitiveAssessmentWrapper.
Mode / Host Integration (Screen Composition)
Use this when your app (mode shell, micro-frontend remote, etc.) owns routing and auth — similar to:
remote_template/src/RemoteWrappers/CognitiveAssessmentWrapper/
├── CognitiveAssessmentWrapper.tsx # Router + QueryClientProvider
├── screen/
│ ├── CognitiveAssessment.tsx # Main flow (select → run → result)
│ └── RunScreen.tsx # Deep-link run result view
└── shared/
└── useHostWebCitationIntegration.ts1. Wrap with providers
Your mode wrapper should provide:
QueryClientProvider(if you use the bundled TanStack hooks in your host)BrowserRouterwith the correctbasenamefor nested mode routes
2. Render screens from the package
Import screens and types directly:
import {
SelectAssessmentScreen,
RunAssessmentScreen,
ResultScreen,
WelcomeScreen,
type AssessmentMode,
type AssessmentScreen,
} from "@e-llm-studio/cognitive-assessment";Wire navigation with local state (or your own context). The library does not require CognitiveWorkspace when you compose screens yourself.
3. Pass host-owned API credentials
Your host should pass bearer tokens / user info into your own service hooks (see remote_template cognitiveAssessment.hooks.ts). The library screens accept data and callbacks — they do not read your auth store directly.
4. Web citation (required wiring for ResultScreen)
Web citation API calls must happen in the host, not inside ResultScreen.
Host screen (CognitiveAssessment.tsx / RunScreen.tsx)
→ useWebCitationIntegration (or host wrapper)
→ ResultScreen (pass-through only)
→ WorkflowResultCard (WebCitationProvider)
→ CitationRender → GptWebCitationPanel → GptWebCitationHost responsibilities
- Track
resultExtraMetafrom the workflow run. - Call
useWebCitationIntegrationwithworkflowComposerId+extraMeta+ user context. - Pass
webCitationDataMap,onFetchWebCitation, andonResultExtraMetaChangeintoResultScreen.
Minimal example (live run → result)
import { useMemo, useState } from "react";
import {
ResultScreen,
buildResultScreenDataFromWorkflowRun,
useWebCitationIntegration,
type AssessmentMode,
} from "@e-llm-studio/cognitive-assessment";
function RunResultView({
mode,
workflowRun,
userContext,
}: {
mode: AssessmentMode;
workflowRun: WorkflowRunApiResponse;
userContext: { userId?: string; userEmail?: string; userName?: string };
}) {
const { resultData, resultExtraMeta } = useMemo(
() => buildResultScreenDataFromWorkflowRun(workflowRun),
[workflowRun],
);
const { webCitationDataMap, onFetchWebCitation } = useWebCitationIntegration({
workflowComposerId: workflowRun.workflowComposerId,
extraMeta: resultExtraMeta,
userContext,
});
return (
<ResultScreen
mode={mode}
showFooter={false}
resultData={resultData}
resultExtraMeta={resultExtraMeta}
workflowComposerId={workflowRun.workflowComposerId}
webCitationDataMap={webCitationDataMap}
onFetchWebCitation={onFetchWebCitation}
/>
);
}Minimal example (streaming result screen inside main flow)
When ResultScreen runs the workflow itself (chat stream), the host must also listen for extraMeta updates:
const [resultExtraMeta, setResultExtraMeta] = useState<Record<string, unknown> | null>(null);
const { webCitationDataMap, onFetchWebCitation } = useWebCitationIntegration({
workflowComposerId: selectedAssessmentId,
extraMeta: resultExtraMeta,
userContext: {
userId: user._id,
userEmail: user.email,
userName: `${user.firstname} ${user.lastname}`.trim(),
},
});
<ResultScreen
mode={mode}
workflowComposerId={selectedAssessmentId}
streamConfig={streamConfig}
user={resultUser}
onResultExtraMetaChange={setResultExtraMeta}
webCitationDataMap={webCitationDataMap}
onFetchWebCitation={onFetchWebCitation}
onBack={...}
/>Reusable host hook (recommended)
Copy or adapt useHostWebCitationIntegration from remote_template so every mode passes the same user context shape:
import { useHostWebCitationIntegration } from "./shared/useHostWebCitationIntegration";
const { webCitationDataMap, onFetchWebCitation } = useHostWebCitationIntegration({
workflowComposerId: selectedAssessmentId,
extraMeta: resultExtraMeta,
});5. Environment variables (host app)
Add these to your host .env and expose them through your bundler (webpack.DefinePlugin, Vite define, etc.):
REACT_APP_API_BASE_URL=<your_api_base_url>
REACT_APP_API_TOKEN=<bearer token for workflow APIs>
REACT_APP_WEB_CITATION_API_KEY=<api-key for get_citation>
REACT_APP_ASSISTANT_URL=<assistant websocket/http base>
REACT_APP_ORGANIZATION_NAME=techolution
REACT_APP_CHAT_ASSISTANT_NAME=cognitiveassessment
# Optional — used when env-based user context is needed
REACT_APP_USER_ID=
REACT_APP_USER_EMAIL=
REACT_APP_USER_FIRST_NAME=
REACT_APP_USER_LAST_NAME=
# Optional — disable dev proxy if your API already allows CORS
REACT_APP_USE_DEV_API_PROXY=falseREACT_APP_WEB_CITATION_API_KEY is required for web citation. Requests go to:
POST /utility/ca-workflow-composer-agent/get_citation
6. Dev-server proxy (CORS)
Browsers block the api-key header on cross-origin requests. In local development, proxy the citation endpoint through your dev server.
Webpack (remote_template pattern):
devServer: {
proxy: [{
context: ["/utility/ca-workflow-composer-agent"],
target: process.env.REACT_APP_API_BASE_URL,
changeOrigin: true,
secure: true,
}],
},CRACO (package local npm run dev): see cognitive-assessment/craco.config.js.
In development the library posts to a relative /utility/... URL when NODE_ENV=development and REACT_APP_USE_DEV_API_PROXY is not false.
For production deployments, ensure the API allows CORS for api-key or proxy the route at your gateway.
7. Deep-link result routes
Expose standalone result URLs in your mode router (assessment vs workflow):
<Route path="/run-assessment" element={<RunScreen mode="assessment" />} />
<Route path="/run-workflow" element={<RunScreen mode="workflow" />} />RunScreen should poll GET /api/workflow-composer/runs/:id, map with buildResultScreenDataFromWorkflowRun, then pass citation props to ResultScreen.
Quick Start (CognitiveWorkspace)
Use this when you want the all-in-one workspace widget with minimal host code:
import React, { useMemo } from "react";
import {
CognitiveWorkspace,
CognitiveAssessmentClient,
type AssessmentApiConfig,
type AssessmentMode,
} from "@e-llm-studio/cognitive-assessment";
const apiConfig: AssessmentApiConfig = {
baseUrl: "https://your-api-host",
auth: {
type: "bearer",
value: "YOUR_TOKEN",
},
};
export default function AssessmentWidget() {
const client = useMemo(() => new CognitiveAssessmentClient(), []);
const mode: AssessmentMode = "workflow";
return (
<div style={{ width: "100%", height: "100%" }}>
<CognitiveWorkspace
assessment={{
client,
apiConfig,
mode,
initialScreen: "select-assessment",
streamConfig: {
assistantUrl: "wss://your-assistant-endpoint",
organizationName: "your-org",
chatAssistantName: "your-assistant",
},
user: {
email: "[email protected]",
firstName: "First",
lastName: "Last",
},
onClose: () => {},
}}
/>
</div>
);
}Exported APIs
Screens & workspace
import {
CognitiveWorkspace,
CognitiveAssessmentService,
SelectAssessmentScreen,
RunAssessmentScreen,
ResultScreen,
WelcomeScreen,
buildResultScreenDataFromWorkflowRun,
} from "@e-llm-studio/cognitive-assessment";Web citation (host integration)
import {
useWebCitationIntegration,
createFetchWebCitationHandler,
fetchWebCitation,
getDefaultWebCitationUserContext,
} from "@e-llm-studio/cognitive-assessment";
import type {
WebCitationDataMap,
FetchWebCitationFn,
IWebCitationUserContext,
CitationUiConfig,
} from "@e-llm-studio/cognitive-assessment";
import {
DEFAULT_CITATION_UI_CONFIG,
DEFAULT_GPT_WEB_CITATION_STYLES,
} from "@e-llm-studio/cognitive-assessment";Client / API helpers
import {
CognitiveAssessmentClient,
createAssessmentApiActions,
createAssessmentApiClient,
useAssessmentContext,
} from "@e-llm-studio/cognitive-assessment";ResultScreen citation props
| Prop | Owner | Purpose |
| --- | --- | --- |
| workflowComposerId | Host | Sent in get_citation payload |
| resultExtraMeta | Host (or from buildResultScreenDataFromWorkflowRun) | Contains gpt_citations metadata |
| onResultExtraMetaChange | Host | Called when streaming run produces new extraMeta |
| webCitationDataMap | Host | Cached API responses keyed by gpt_citation$N |
| onFetchWebCitation | Host | Invoked when user clicks View Web Citation |
| citationUiConfig | Host (optional) | Layout overrides for GptWebCitation and scanned-doc citation — see GptWebCitation |
Citation IDs in the API payload use citation_uuid from extraMeta, not the display key gpt_citation$1.
GptWebCitation (@e-llm-studio/citation)
The UI for GPT ↔ Web citation toggle comes from GptWebCitation in the citation package:
import GptWebCitation from "@e-llm-studio/citation/GptWebCitation";In cognitive-assessment you usually do not mount GptWebCitation yourself. The library wires it for you:
ResultScreen
→ WorkflowResultCard (WebCitationProvider)
→ CitationRender
→ GptWebCitationPanel
→ useGptCitationState + GptWebCitationGptWebCitationPanel and useGptCitationState mirror the contract used in the citation library’s GptWebCitationTest.tsx — same props, same controlled-state split.
Preview in the citation package
To explore the component without a backend, run the citation dev server with GptWebCitationTest mounted in citation/src/index.tsx. That harness:
- Builds a default
gptCitationfromCognitiveInternalgptReasoningTestdummy data - Simulates a 2s API delay when View Web Citation is clicked
- Ships
defaultDemoStylesso GPT and web panels share matched heights
GptWebCitation props
| Prop | Required | Who sets it in CA | Purpose |
| --- | --- | --- | --- |
| gptCitation | Yes | useGptCitationState | GPT reasoning panel (item, headerTitle, iconsConfig, bodyHeight, optional DocumentTitle) |
| isWebCitation | No (default false) | useGptCitationState | true when citation.citationType === "web" — shows toggle + web view |
| webCitationData | No | Host cache + mergeWebCitationData | API response: content, imageMetadata, citationUrl |
| showWebCitation | No | useGptCitationState via WebCitationContext | false = GPT view, true = web view. Always passed in CA (controlled) |
| onToggleCitationView | No | useGptCitationState | Fired when user clicks View Web Citation or View GPT Citation. Parent flips showWebCitation |
| onGenerateWebCitation | No | useGptCitationState | Fired when web view opens and no cached data exists — triggers onFetchWebCitation |
| isWebCitationLoading | No | useGptCitationState | Skeleton while fetching (skipped if image URL already cached) |
| topic | No | useGptCitationState | Web header topic (from paraphrase / label; auto-extracted from content if omitted) |
| sourceLabel | No | useGptCitationState | Web header label, e.g. Source: Web Citation > … |
| learnedFrom | No | useGptCitationState | Footer “Learned From …” (auto-derived from citationUrl if omitted) |
| showExpandImageButton | No | citationUiConfig | Full-screen expand on screenshot (default false in CA) |
| showGptMaximizeButton | No | citationUiConfig | GPT header maximize icon (default false in CA) |
| styles | No | citationUiConfig | Inline layout overrides — see below |
Why onToggleCitationView and onGenerateWebCitation are separate
GptWebCitation does not fetch data itself. The parent owns state:
onToggleCitationView— switch GPT ↔ web (showWebCitation). If cached data exists, just flip the view.onGenerateWebCitation— called only when the user opens web view and there is no cachedwebCitationDatayet. Parent sets loading and calls the API.
In GptWebCitationTest, when showWebCitation is passed from outside (controlled), onToggleCitationView is omitted so the parent owns the toggle. In cognitive-assessment, useGptCitationState always provides both handlers.
Optional props — when you need them
| Prop | Omit when | Pass when |
| --- | --- | --- |
| learnedFrom | citationUrl is present (hostname is auto-derived) | You want a custom footer label |
| topic / sourceLabel | Defaults from citation model are fine | Custom header copy per mode |
| showExpandImageButton | Default (false in CA) is fine | Users need full-screen screenshot |
| showGptMaximizeButton | Default (false in CA) is fine | Users need GPT fullscreen expand |
| styles | Package defaults (DEFAULT_GPT_WEB_CITATION_STYLES) are fine | You need matched panel heights or mode-specific layout |
Customizing layout via citationUiConfig
Pass citationUiConfig on ResultScreen (or WorkflowResultCard). It flows through WebCitationProvider → CitationRender → GptWebCitationPanel → GptWebCitation.styles.
This mirrors defaultDemoStyles from GptWebCitationTest.tsx in the citation package:
const sharedPanelHeight = "520px";
const sharedContentHeight = "450px";
const demoStyles = {
container: { maxWidth: 900 },
gptCitation: {
wrapper: {
minHeight: sharedPanelHeight,
border: "1px solid #e5e7eb",
borderRadius: 8,
},
footerAction: { left: "1.5rem" },
toggleButton: { minWidth: 180, fontSize: 14 },
},
webCitation: {
panel: {
minHeight: sharedPanelHeight,
border: "1px solid #e5e7eb",
borderRadius: 8,
},
header: { padding: "8px 16px" },
content: {
minHeight: sharedContentHeight,
maxHeight: sharedContentHeight,
overflowY: "auto",
},
footer: { padding: "8px 16px" },
toggleButton: { minWidth: 180, fontSize: 14 },
learnedFrom: { fontSize: 13 },
},
};
<ResultScreen
mode={mode}
workflowComposerId={workflowComposerId}
webCitationDataMap={webCitationDataMap}
onFetchWebCitation={onFetchWebCitation}
citationUiConfig={{
gptWebCitation: {
headerTitle: "Summary Citations",
bodyHeight: sharedContentHeight, // match GPT body to webCitation.content height
showGptMaximizeButton: true,
showExpandImageButton: true,
styles: demoStyles,
},
}}
/>styles keys (maps to GptWebCitation internals)
| Key | Applies to |
| --- | --- |
| container | Outer wrapper (GPT overlay + web panel root) |
| gptCitation.wrapper | GPT citation card border / minHeight |
| gptCitation.footerAction | View Web Citation button row in GPT footer |
| gptCitation.toggleButton | View Web Citation button |
| webCitation.panel | Web citation card |
| webCitation.header | Source label + pagination + score badge |
| webCitation.content | Screenshot / markdown / skeleton area |
| webCitation.footer | View GPT Citation + Learned From row |
| webCitation.toggleButton | View GPT Citation button |
| webCitation.learnedFrom | “Learned From …” text |
Custom values merge with DEFAULT_GPT_WEB_CITATION_STYLES when passed via citationUiConfig.gptWebCitation.styles (see citationUiConfig.utils.ts). Set bodyHeight on gptWebCitation together with webCitation.content.minHeight / maxHeight so both views align.
Direct usage (advanced)
If you build a custom screen outside ResultScreen, reproduce the GptWebCitationTest pattern:
import { useState } from "react";
import GptWebCitation from "@e-llm-studio/citation/GptWebCitation";
function MyCitationPanel() {
const [showWebCitation, setShowWebCitation] = useState(false);
const [webCitationData, setWebCitationData] = useState(undefined);
const [isLoading, setIsLoading] = useState(false);
return (
<GptWebCitation
gptCitation={gptCitationConfig}
isWebCitation={true}
webCitationData={webCitationData}
showWebCitation={showWebCitation}
isWebCitationLoading={isLoading}
onToggleCitationView={() => setShowWebCitation((prev) => !prev)}
onGenerateWebCitation={async () => {
setShowWebCitation(true);
setIsLoading(true);
const data = await fetchWebCitation(...);
setWebCitationData(data);
setIsLoading(false);
}}
styles={demoStyles}
/>
);
}For production in this package, prefer useWebCitationIntegration + ResultScreen so fetch, cache, and UI state stay consistent.
webCitationData API shape
{
citationId: string;
content?: string; // HTML/markdown fallback when no image
citationType: "web";
citationUrl?: string; // required for "Visit Link" below screenshot
imageMetadata?: {
signed_url?: string; // preferred — renders screenshot
gs_uri?: string;
blob_path?: string;
};
}When imageMetadata.signed_url is present, the web view shows a screenshot. Otherwise it renders content as markdown/HTML.
Styling Notes
- Styles are injected by the package runtime. You do not need to import package CSS manually.
- Container sizing should be controlled by parent layout. Prefer giving parent containers explicit
width/heightvalues.
Troubleshooting
1) Web citation works in Postman but not in the browser
Add a dev-server proxy for /utility/ca-workflow-composer-agent or fix API CORS for the api-key header. Verify REACT_APP_WEB_CITATION_API_KEY is defined in the host bundle.
2) Clicking View Web Citation flips back to GPT view
Ensure you pass stable webCitationDataMap / onFetchWebCitation from a host hook (do not recreate inline handlers on every render without memoization). Use useWebCitationIntegration.
3) mode: "workflow" not taking effect
Use a package version that includes mode support in AssessmentProvider.
4) Build errors resolving lucide-react or uuid
Reinstall after updating the package version:
rm -rf node_modules package-lock.json
npm install5) Warning from pdf-collaborative-tool dynamic dependency
Transitive warning from citation/pdf tooling. Typically non-blocking unless your bundler treats warnings as errors.
Local package development
cd cognitive-assessment
npm i --legacy-peer-deps
npm run dev # local preview (CRACO + proxy)
npm run typecheck
npm run build # outputs dist/
npm pack # create .tgz for file: install in host modesTo consume a local build from a mode host, copy both tarballs into your host cognitive-assessment-package/ folder:
e-llm-studio-cognitive-assessment-<version>.tgze-llm-studio-citation-0.0.198.tgz(required nested dependency)
"@e-llm-studio/cognitive-assessment": "file:cognitive-assessment-package/e-llm-studio-cognitive-assessment-1.0.2.tgz",
"@e-llm-studio/citation": "file:cognitive-assessment-package/e-llm-studio-citation-0.0.198.tgz"Add an npm overrides entry so nested file: citation resolves from the host package folder:
"overrides": {
"@e-llm-studio/citation": "file:cognitive-assessment-package/e-llm-studio-citation-0.0.198.tgz"
}