@yadsh/dsh-qa-surface 0.3.0 → 0.5.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/README.md +192 -15
- package/cordis.patch.yml +8 -0
- package/lib/account-remotes.js +100 -0
- package/lib/account-remotes.js.map +1 -0
- package/lib/accounts/credentials.js +35 -0
- package/lib/accounts/credentials.js.map +1 -0
- package/lib/accounts/errors.js +9 -0
- package/lib/accounts/errors.js.map +1 -0
- package/lib/accounts/file.js +101 -0
- package/lib/accounts/file.js.map +1 -0
- package/lib/accounts/store.js +159 -161
- package/lib/accounts/store.js.map +1 -1
- package/lib/accounts/token.js +61 -0
- package/lib/accounts/token.js.map +1 -0
- package/lib/approvals.js +179 -0
- package/lib/approvals.js.map +1 -0
- package/lib/attachment-rules.js +111 -0
- package/lib/attachment-rules.js.map +1 -0
- package/lib/cli.js +132 -9
- package/lib/cli.js.map +1 -1
- package/lib/client/QaAccountsController.js +32 -2
- package/lib/client/QaAccountsController.js.map +1 -1
- package/lib/client/QaSessionController.js +140 -65
- package/lib/client/QaSessionController.js.map +1 -1
- package/lib/client/QaSurface.js +134 -107
- package/lib/client/QaSurface.js.map +1 -1
- package/lib/client/QaTranscriptAdapter.js +71 -6
- package/lib/client/QaTranscriptAdapter.js.map +1 -1
- package/lib/client/approvals.js +104 -0
- package/lib/client/approvals.js.map +1 -0
- package/lib/client/attachments.js +150 -0
- package/lib/client/attachments.js.map +1 -0
- package/lib/client/attestation.js +4 -1
- package/lib/client/attestation.js.map +1 -1
- package/lib/client/base64.js +16 -0
- package/lib/client/base64.js.map +1 -0
- package/lib/client/chat-files.js +48 -0
- package/lib/client/chat-files.js.map +1 -0
- package/lib/client/components/Markdown.js +1 -1
- package/lib/client/components/Markdown.js.map +1 -1
- package/lib/client/components/QaApproval.js +23 -0
- package/lib/client/components/QaApproval.js.map +1 -0
- package/lib/client/components/QaChangelog.js +62 -19
- package/lib/client/components/QaChangelog.js.map +1 -1
- package/lib/client/components/QaComposer.js +56 -74
- package/lib/client/components/QaComposer.js.map +1 -1
- package/lib/client/components/QaFileAttachment.js +19 -0
- package/lib/client/components/QaFileAttachment.js.map +1 -0
- package/lib/client/components/QaFilesPanel.js +45 -0
- package/lib/client/components/QaFilesPanel.js.map +1 -0
- package/lib/client/components/QaHeader.js +34 -0
- package/lib/client/components/QaHeader.js.map +1 -0
- package/lib/client/components/QaMessage.js +17 -4
- package/lib/client/components/QaMessage.js.map +1 -1
- package/lib/client/components/QaModal.js +31 -0
- package/lib/client/components/QaModal.js.map +1 -0
- package/lib/client/components/QaProfile.js +64 -0
- package/lib/client/components/QaProfile.js.map +1 -0
- package/lib/client/components/QaQuestions.js +96 -0
- package/lib/client/components/QaQuestions.js.map +1 -0
- package/lib/client/components/QaRightRail.js +15 -0
- package/lib/client/components/QaRightRail.js.map +1 -0
- package/lib/client/components/QaSidebar.js +6 -1
- package/lib/client/components/QaSidebar.js.map +1 -1
- package/lib/client/components/{QaSourcesDrawer.js → QaSourcesPanel.js} +3 -3
- package/lib/client/components/QaSourcesPanel.js.map +1 -0
- package/lib/client/components/QaTurnRail.js +15 -0
- package/lib/client/components/QaTurnRail.js.map +1 -1
- package/lib/client/components/QaWidthHandle.js +25 -20
- package/lib/client/components/QaWidthHandle.js.map +1 -1
- package/lib/client/components/QaWorkGroup.js +19 -20
- package/lib/client/components/QaWorkGroup.js.map +1 -1
- package/lib/client/components/surface-utils.js +28 -0
- package/lib/client/components/surface-utils.js.map +1 -0
- package/lib/client/components/thinking-phrases.js +24 -0
- package/lib/client/components/thinking-phrases.js.map +1 -0
- package/lib/client/create-session.js +7 -32
- package/lib/client/create-session.js.map +1 -1
- package/lib/client/failure-copy.js +63 -0
- package/lib/client/failure-copy.js.map +1 -0
- package/lib/client/index.js +49 -7
- package/lib/client/index.js.map +1 -1
- package/lib/client/project-session-state.js +5 -3
- package/lib/client/project-session-state.js.map +1 -1
- package/lib/client/prompt-content.js +54 -0
- package/lib/client/prompt-content.js.map +1 -0
- package/lib/client/questions.js +114 -0
- package/lib/client/questions.js.map +1 -0
- package/lib/client/settings/card.js +143 -0
- package/lib/client/settings/card.js.map +1 -0
- package/lib/client/settings/fields.js +145 -0
- package/lib/client/settings/fields.js.map +1 -0
- package/lib/client/settings/format.js +255 -0
- package/lib/client/settings/format.js.map +1 -0
- package/lib/client/settings/sections/access.js +25 -0
- package/lib/client/settings/sections/access.js.map +1 -0
- package/lib/client/settings/sections/accounts.js +47 -0
- package/lib/client/settings/sections/accounts.js.map +1 -0
- package/lib/client/settings/sections/attachments.js +46 -0
- package/lib/client/settings/sections/attachments.js.map +1 -0
- package/lib/client/settings/sections/branding.js +28 -0
- package/lib/client/settings/sections/branding.js.map +1 -0
- package/lib/client/settings/sections/common.js +20 -0
- package/lib/client/settings/sections/common.js.map +1 -0
- package/lib/client/settings/sections/embedding.js +19 -0
- package/lib/client/settings/sections/embedding.js.map +1 -0
- package/lib/client/settings/sections/interface.js +60 -0
- package/lib/client/settings/sections/interface.js.map +1 -0
- package/lib/client/settings/sections/lockdown.js +82 -0
- package/lib/client/settings/sections/lockdown.js.map +1 -0
- package/lib/client/settings/sections/session.js +53 -0
- package/lib/client/settings/sections/session.js.map +1 -0
- package/lib/client/settings/sections/sources.js +74 -0
- package/lib/client/settings/sections/sources.js.map +1 -0
- package/lib/client/settings/sections/status.js +37 -0
- package/lib/client/settings/sections/status.js.map +1 -0
- package/lib/client/settings/sections.js +23 -0
- package/lib/client/settings/sections.js.map +1 -0
- package/lib/client/settings/styles.js +57 -0
- package/lib/client/settings/styles.js.map +1 -0
- package/lib/client/stream-publisher.js +47 -0
- package/lib/client/stream-publisher.js.map +1 -0
- package/lib/client/styles.js +127 -19
- package/lib/client/styles.js.map +1 -1
- package/lib/client/types.js +2 -0
- package/lib/client/types.js.map +1 -1
- package/lib/client/use-right-rail.js +96 -0
- package/lib/client/use-right-rail.js.map +1 -0
- package/lib/client/use-session-ui-state.js +26 -19
- package/lib/client/use-session-ui-state.js.map +1 -1
- package/lib/client.js +5694 -813
- package/lib/client.js.map +1 -1
- package/lib/config-resolvers/accounts.js +60 -0
- package/lib/config-resolvers/accounts.js.map +1 -0
- package/lib/config-resolvers/attachments.js +28 -0
- package/lib/config-resolvers/attachments.js.map +1 -0
- package/lib/config-resolvers/basics.js +61 -0
- package/lib/config-resolvers/basics.js.map +1 -0
- package/lib/config-resolvers/defaults.js +136 -0
- package/lib/config-resolvers/defaults.js.map +1 -0
- package/lib/config-resolvers/lockdown.js +90 -0
- package/lib/config-resolvers/lockdown.js.map +1 -0
- package/lib/config-resolvers/session.js +42 -0
- package/lib/config-resolvers/session.js.map +1 -0
- package/lib/config-resolvers/shared.js +51 -0
- package/lib/config-resolvers/shared.js.map +1 -0
- package/lib/config-resolvers/sources.js +83 -0
- package/lib/config-resolvers/sources.js.map +1 -0
- package/lib/config-resolvers/ui.js +20 -0
- package/lib/config-resolvers/ui.js.map +1 -0
- package/lib/config.js +76 -6
- package/lib/config.js.map +1 -1
- package/lib/entry-redirect.js +2 -1
- package/lib/entry-redirect.js.map +1 -1
- package/lib/index.js +198 -79
- package/lib/index.js.map +1 -1
- package/lib/profile.js +214 -0
- package/lib/profile.js.map +1 -0
- package/lib/prompt-notes.js +231 -0
- package/lib/prompt-notes.js.map +1 -0
- package/lib/provenance/host-store.js +25 -9
- package/lib/provenance/host-store.js.map +1 -1
- package/lib/provenance/reported.js +37 -12
- package/lib/provenance/reported.js.map +1 -1
- package/lib/questions.js +185 -0
- package/lib/questions.js.map +1 -0
- package/lib/resolve-config.js +35 -410
- package/lib/resolve-config.js.map +1 -1
- package/lib/secure-session.js +139 -21
- package/lib/secure-session.js.map +1 -1
- package/lib/session-ownership.js +55 -0
- package/lib/session-ownership.js.map +1 -0
- package/lib/shared/session-key.js +18 -0
- package/lib/shared/session-key.js.map +1 -0
- package/lib/shared/settings.js +10 -0
- package/lib/shared/settings.js.map +1 -0
- package/lib/thinking-phrases.js +68 -0
- package/lib/thinking-phrases.js.map +1 -0
- package/lib/typert.host.js +506 -21
- package/lib/typert.remote-client.d.ts +15 -1
- package/lib/typert.remote-client.js +407 -15
- package/lib/types/account-remotes.d.ts +42 -0
- package/lib/types/accounts/credentials.d.ts +20 -0
- package/lib/types/accounts/errors.d.ts +11 -0
- package/lib/types/accounts/file.d.ts +82 -0
- package/lib/types/accounts/store.d.ts +74 -43
- package/lib/types/accounts/token.d.ts +31 -0
- package/lib/types/approvals.d.ts +65 -0
- package/lib/types/attachment-rules.d.ts +44 -0
- package/lib/types/cli.d.ts +2 -2
- package/lib/types/client/QaAccountsController.d.ts +8 -1
- package/lib/types/client/QaSessionController.d.ts +53 -16
- package/lib/types/client/QaSurface.d.ts +14 -1
- package/lib/types/client/approvals.d.ts +39 -0
- package/lib/types/client/attachments.d.ts +54 -0
- package/lib/types/client/base64.d.ts +10 -0
- package/lib/types/client/chat-files.d.ts +30 -0
- package/lib/types/client/components/QaApproval.d.ts +13 -0
- package/lib/types/client/components/QaChangelog.d.ts +1 -1
- package/lib/types/client/components/QaComposer.d.ts +8 -4
- package/lib/types/client/components/QaFileAttachment.d.ts +14 -0
- package/lib/types/client/components/QaFilesPanel.d.ts +15 -0
- package/lib/types/client/components/QaHeader.d.ts +41 -0
- package/lib/types/client/components/QaMessage.d.ts +3 -1
- package/lib/types/client/components/QaModal.d.ts +26 -0
- package/lib/types/client/components/QaProfile.d.ts +25 -0
- package/lib/types/client/components/QaQuestions.d.ts +13 -0
- package/lib/types/client/components/QaRightRail.d.ts +23 -0
- package/lib/types/client/components/QaSidebar.d.ts +14 -0
- package/lib/types/client/components/{QaSourcesDrawer.d.ts → QaSourcesPanel.d.ts} +7 -4
- package/lib/types/client/components/QaTurnRail.d.ts +6 -0
- package/lib/types/client/components/QaWidthHandle.d.ts +14 -7
- package/lib/types/client/components/QaWorkGroup.d.ts +5 -3
- package/lib/types/client/components/surface-utils.d.ts +11 -0
- package/lib/types/client/components/thinking-phrases.d.ts +9 -0
- package/lib/types/client/create-session.d.ts +6 -9
- package/lib/types/client/failure-copy.d.ts +19 -0
- package/lib/types/client/project-session-state.d.ts +8 -1
- package/lib/types/client/prompt-content.d.ts +30 -0
- package/lib/types/client/questions.d.ts +45 -0
- package/lib/types/client/settings/card.d.ts +23 -0
- package/lib/types/client/settings/fields.d.ts +139 -0
- package/lib/types/client/settings/format.d.ts +108 -0
- package/lib/types/client/settings/sections/access.d.ts +9 -0
- package/lib/types/client/settings/sections/accounts.d.ts +9 -0
- package/lib/types/client/settings/sections/attachments.d.ts +15 -0
- package/lib/types/client/settings/sections/branding.d.ts +8 -0
- package/lib/types/client/settings/sections/common.d.ts +28 -0
- package/lib/types/client/settings/sections/embedding.d.ts +8 -0
- package/lib/types/client/settings/sections/interface.d.ts +9 -0
- package/lib/types/client/settings/sections/lockdown.d.ts +9 -0
- package/lib/types/client/settings/sections/session.d.ts +9 -0
- package/lib/types/client/settings/sections/sources.d.ts +9 -0
- package/lib/types/client/settings/sections/status.d.ts +22 -0
- package/lib/types/client/settings/sections.d.ts +25 -0
- package/lib/types/client/settings/styles.d.ts +8 -0
- package/lib/types/client/stream-publisher.d.ts +28 -0
- package/lib/types/client/types.d.ts +76 -1
- package/lib/types/client/use-right-rail.d.ts +56 -0
- package/lib/types/client/use-session-ui-state.d.ts +13 -7
- package/lib/types/config-resolvers/accounts.d.ts +15 -0
- package/lib/types/config-resolvers/attachments.d.ts +6 -0
- package/lib/types/config-resolvers/basics.d.ts +8 -0
- package/lib/types/config-resolvers/defaults.d.ts +4 -0
- package/lib/types/config-resolvers/lockdown.d.ts +10 -0
- package/lib/types/config-resolvers/session.d.ts +6 -0
- package/lib/types/config-resolvers/shared.d.ts +23 -0
- package/lib/types/config-resolvers/sources.d.ts +6 -0
- package/lib/types/config-resolvers/ui.d.ts +6 -0
- package/lib/types/index.d.ts +48 -15
- package/lib/types/profile.d.ts +76 -0
- package/lib/types/prompt-notes.d.ts +110 -0
- package/lib/types/provenance/reported.d.ts +9 -1
- package/lib/types/questions.d.ts +83 -0
- package/lib/types/resolve-config.d.ts +8 -3
- package/lib/types/secure-session.d.ts +46 -2
- package/lib/types/session-ownership.d.ts +30 -0
- package/lib/types/shared/session-key.d.ts +23 -0
- package/lib/types/shared/settings.d.ts +10 -0
- package/lib/types/thinking-phrases.d.ts +17 -0
- package/lib/types/types.d.ts +203 -9
- package/lib/types/user-workspace.d.ts +42 -0
- package/lib/user-workspace.js +246 -0
- package/lib/user-workspace.js.map +1 -0
- package/package.json +15 -8
- package/CHANGELOG.md +0 -176
- package/SPEC-dsh-qa-surface.md +0 -2425
- package/docs/ARCHITECTURE.md +0 -66
- package/docs/COMPATIBILITY.md +0 -14
- package/docs/CONFIGURATION.md +0 -199
- package/docs/EMBEDDING.md +0 -13
- package/docs/SOURCES-MIGRATION.md +0 -28
- package/docs/SOURCES-PROVENANCE-AUDIT.md +0 -88
- package/docs/SPEC-dsh-qa-surface-accounts.md +0 -219
- package/docs/SPEC-dsh-qa-surface-sources-provenance.md +0 -1692
- package/lib/client/components/QaSourcesDrawer.js.map +0 -1
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { type Dispatch, type SetStateAction } from "react";
|
|
2
|
-
import type {
|
|
2
|
+
import type { QaAttachmentDraft, QaSource, QaTurnSources } from "../types.js";
|
|
3
3
|
/** Snapshot completeness captured when a drawer was opened from a message. */
|
|
4
4
|
export interface QaDrawerCompleteness {
|
|
5
5
|
readonly complete: boolean;
|
|
6
6
|
readonly incompleteOrigins?: QaTurnSources["incompleteOrigins"];
|
|
7
7
|
}
|
|
8
|
+
/** The rail tab ids; the agents drawer has not become a tab yet. */
|
|
9
|
+
export type QaRailTab = "sources" | "files";
|
|
8
10
|
export interface QaSessionUiState {
|
|
9
11
|
/** Per group: how many answers back from the newest is shown (0 = newest). */
|
|
10
12
|
readonly variantOffsets: Record<string, number>;
|
|
@@ -14,22 +16,26 @@ export interface QaSessionUiState {
|
|
|
14
16
|
readonly setActiveTurn: Dispatch<SetStateAction<number | null>>;
|
|
15
17
|
readonly agentsOpen: boolean;
|
|
16
18
|
readonly setAgentsOpen: Dispatch<SetStateAction<boolean>>;
|
|
17
|
-
|
|
18
|
-
readonly
|
|
19
|
+
/** Whether the right rail column is shown. */
|
|
20
|
+
readonly railOpen: boolean;
|
|
21
|
+
readonly setRailOpen: Dispatch<SetStateAction<boolean>>;
|
|
22
|
+
/** Which rail tab is active; meaningful only while the rail is open. */
|
|
23
|
+
readonly railTab: QaRailTab;
|
|
24
|
+
readonly setRailTab: Dispatch<SetStateAction<QaRailTab>>;
|
|
19
25
|
readonly drawerSources: readonly QaSource[] | null;
|
|
20
26
|
readonly setDrawerSources: Dispatch<SetStateAction<readonly QaSource[] | null>>;
|
|
21
27
|
readonly drawerCompleteness: QaDrawerCompleteness | null;
|
|
22
28
|
readonly setDrawerCompleteness: Dispatch<SetStateAction<QaDrawerCompleteness | null>>;
|
|
23
29
|
readonly drawerDetail: QaSource | null;
|
|
24
30
|
readonly setDrawerDetail: Dispatch<SetStateAction<QaSource | null>>;
|
|
25
|
-
readonly
|
|
26
|
-
readonly
|
|
31
|
+
readonly pendingAttachments: readonly QaAttachmentDraft[];
|
|
32
|
+
readonly setPendingAttachments: (next: readonly QaAttachmentDraft[]) => void;
|
|
27
33
|
}
|
|
28
34
|
/**
|
|
29
35
|
* Per-chat UI state: composer attachments, variant offsets, the rail mark and
|
|
30
36
|
* the drawers. Everything here describes the chat it was made in, so a
|
|
31
|
-
* session change clears it instead of leaking a draft, an
|
|
32
|
-
* from one conversation into the next.
|
|
37
|
+
* session change clears it instead of leaking a draft, an attachment or a
|
|
38
|
+
* drawer from one conversation into the next.
|
|
33
39
|
*/
|
|
34
40
|
export declare function useSessionUiState(sessionId: string | null): QaSessionUiState;
|
|
35
41
|
//# sourceMappingURL=use-session-ui-state.d.ts.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { QaSurfaceConfig, ResolvedQaSurfaceConfig } from "../types.js";
|
|
2
|
+
type AccountsSlice = ResolvedQaSurfaceConfig["accounts"];
|
|
3
|
+
/** Resolved neighbors the per-user workspace boundary is checked against. */
|
|
4
|
+
export interface AccountsDependencies {
|
|
5
|
+
readonly session: ResolvedQaSurfaceConfig["session"];
|
|
6
|
+
readonly lockdown: ResolvedQaSurfaceConfig["lockdown"];
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Resolve the accounts domain. The per-user workspace boundary spans session
|
|
10
|
+
* and lockdown, so their resolved slices arrive as dependencies and the
|
|
11
|
+
* boundary checks run here, next to the flag they guard.
|
|
12
|
+
*/
|
|
13
|
+
export declare function resolveAccounts(input: QaSurfaceConfig, dependencies: AccountsDependencies): AccountsSlice;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=accounts.d.ts.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { QaSurfaceConfig, ResolvedQaSurfaceConfig } from "../types.js";
|
|
2
|
+
type AttachmentsSlice = ResolvedQaSurfaceConfig["attachments"];
|
|
3
|
+
/** Resolve the attachments domain: intake toggles and byte/line bounds. */
|
|
4
|
+
export declare function resolveAttachments(input: QaSurfaceConfig): AttachmentsSlice;
|
|
5
|
+
export {};
|
|
6
|
+
//# sourceMappingURL=attachments.d.ts.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { QaSurfaceConfig, ResolvedQaSurfaceConfig } from "../types.js";
|
|
2
|
+
export declare function normalizeRoutePath(value: string): string;
|
|
3
|
+
/** The scalar domains that carry no table-shaped or cross-domain rules. */
|
|
4
|
+
type BasicsSlice = Pick<ResolvedQaSurfaceConfig, "enabled" | "route" | "branding" | "embedding" | "entry" | "interaction">;
|
|
5
|
+
/** Resolve the master switch, route, branding, embedding, and entry domains. */
|
|
6
|
+
export declare function resolveBasics(input: QaSurfaceConfig): BasicsSlice;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=basics.d.ts.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { QaSurfaceConfig, ResolvedQaSurfaceConfig } from "../types.js";
|
|
2
|
+
type LockdownSlice = ResolvedQaSurfaceConfig["lockdown"];
|
|
3
|
+
/**
|
|
4
|
+
* Resolve the lockdown domain. The capability flags are clamped shut, and
|
|
5
|
+
* showing the reset control needs an explicit authorization here, so the
|
|
6
|
+
* resolved UI slice arrives as a neighbor.
|
|
7
|
+
*/
|
|
8
|
+
export declare function resolveLockdown(input: QaSurfaceConfig, ui: ResolvedQaSurfaceConfig["ui"]): LockdownSlice;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=lockdown.d.ts.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { QaSurfaceConfig, ResolvedQaSurfaceConfig } from "../types.js";
|
|
2
|
+
type SessionSlice = ResolvedQaSurfaceConfig["session"];
|
|
3
|
+
/** Resolve the session domain: policy, pinning, and model selection. */
|
|
4
|
+
export declare function resolveSession(input: QaSurfaceConfig): SessionSlice;
|
|
5
|
+
export {};
|
|
6
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Trim an optional string; a blank value collapses to null. */
|
|
2
|
+
export declare function optionalText(value: string | null | undefined): string | null;
|
|
3
|
+
/**
|
|
4
|
+
* Whether a configured directory is absolute. The rule reads a drive-letter
|
|
5
|
+
* path as absolute on every platform, like `session.cwd` does: a deployment
|
|
6
|
+
* profile is authored on one machine and may be read on another, so a
|
|
7
|
+
* Windows-style root is not a mistake to reject on a POSIX host.
|
|
8
|
+
*/
|
|
9
|
+
export declare function isAbsoluteDirectoryPath(value: string): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Shared numeric guard for operator-tuned limits: the value has to be a safe
|
|
12
|
+
* integer inside [min, max], and every rejection carries the same message.
|
|
13
|
+
*/
|
|
14
|
+
export declare function assertIntInRange(name: string, value: number, min: number, max: number): void;
|
|
15
|
+
/** Deduplicate and trim the operator's quick questions. */
|
|
16
|
+
export declare function uniqueQuestions(values: readonly string[]): readonly string[];
|
|
17
|
+
/**
|
|
18
|
+
* Normalize the operator's phrase list. Unlike quick questions, an empty list
|
|
19
|
+
* cannot mean "hide the control": the running indicator has to say something,
|
|
20
|
+
* so emptiness restores the built-in phrases.
|
|
21
|
+
*/
|
|
22
|
+
export declare function uniquePhrases(values: readonly string[]): readonly string[];
|
|
23
|
+
//# sourceMappingURL=shared.d.ts.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { QaSurfaceConfig, ResolvedQaSurfaceConfig } from "../types.js";
|
|
2
|
+
type SourcesSlice = ResolvedQaSurfaceConfig["sources"];
|
|
3
|
+
/** Resolve the sources domain: collection, display, and preview bounds. */
|
|
4
|
+
export declare function resolveSources(input: QaSurfaceConfig): SourcesSlice;
|
|
5
|
+
export {};
|
|
6
|
+
//# sourceMappingURL=sources.d.ts.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { QaSurfaceConfig, ResolvedQaSurfaceConfig } from "../types.js";
|
|
2
|
+
type UiSlice = ResolvedQaSurfaceConfig["ui"];
|
|
3
|
+
/** Resolve the UI domain: widget visibility and the content width floor. */
|
|
4
|
+
export declare function resolveUi(input: QaSurfaceConfig): UiSlice;
|
|
5
|
+
export {};
|
|
6
|
+
//# sourceMappingURL=ui.d.ts.map
|
package/lib/types/index.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
|
|
2
2
|
import type { Context } from "@deepseek-ai/cordis";
|
|
3
3
|
import type { QaTurnSources } from "./provenance/types.js";
|
|
4
|
-
import type { QaAccountSession, QaClaimResult, QaLockdownProof, QaOwnershipEntry, QaSurfaceConfig, ResolvedQaSurfaceConfig, QaSourceFilePreview, QaWhoamiResult } from "./types.js";
|
|
4
|
+
import type { QaAccountProfileInput, QaAccountSession, QaAccountUserPublic, QaApprovalDecision, QaClaimResult, QaLockdownProof, QaOwnershipEntry, QaPendingApproval, QaPendingQuestion, QaQuestionAnswerItem, QaSurfaceConfig, ResolvedQaSurfaceConfig, QaSourceFilePreview, QaWhoamiResult } from "./types.js";
|
|
5
5
|
export declare const name = "qa-surface";
|
|
6
6
|
export declare const inject: string[];
|
|
7
|
-
|
|
7
|
+
import { QA_SURFACE_SETTINGS_NAMESPACE } from "./shared/settings.js";
|
|
8
|
+
export { QA_SURFACE_SETTINGS_NAMESPACE };
|
|
8
9
|
export declare const Config: import("@deepseek-ai/schemastery").default<QaSurfaceConfig>;
|
|
9
10
|
declare module "@deepseek-ai/cordis" {
|
|
10
11
|
interface Context {
|
|
@@ -18,24 +19,18 @@ export declare class QaSurface extends TypertRemoteService {
|
|
|
18
19
|
private source;
|
|
19
20
|
private readonly logger;
|
|
20
21
|
private readonly admission;
|
|
22
|
+
private readonly approvals;
|
|
23
|
+
private readonly userQuestions;
|
|
21
24
|
private readonly provenance;
|
|
22
|
-
private
|
|
23
|
-
|
|
25
|
+
private readonly notes;
|
|
26
|
+
/** Account-remote bodies; the wire signatures stay on this class. */
|
|
27
|
+
private readonly accountRemotes;
|
|
24
28
|
private readonly launchToken;
|
|
25
29
|
private webServer;
|
|
26
30
|
private disposeRoute;
|
|
27
31
|
private routeKey;
|
|
28
32
|
constructor(ctx: Context, entry?: QaSurfaceConfig);
|
|
29
33
|
getConfig(): ResolvedQaSurfaceConfig;
|
|
30
|
-
/**
|
|
31
|
-
* The accounts store behind the runtime toggle. Rebuilt only when the
|
|
32
|
-
* account-affecting options change; the file is shared across rebuilds.
|
|
33
|
-
*/
|
|
34
|
-
private accountsFor;
|
|
35
|
-
/** The accounts store, or the disabled refusal the browser maps to copy. */
|
|
36
|
-
private requireAccounts;
|
|
37
|
-
/** Account failures ride the shared `(reason: <code>)` wire marker. */
|
|
38
|
-
private accountsRemote;
|
|
39
34
|
/**
|
|
40
35
|
* Self-service signup; the first account ever created becomes admin. The
|
|
41
36
|
* display name derives from the email: the generated client enforces exact
|
|
@@ -59,6 +54,13 @@ export declare class QaSurface extends TypertRemoteService {
|
|
|
59
54
|
accountsListOwnership(token: string): {
|
|
60
55
|
readonly entries: readonly QaOwnershipEntry[];
|
|
61
56
|
};
|
|
57
|
+
/**
|
|
58
|
+
* Replace the caller's own self-declared profile. The token is the only
|
|
59
|
+
* identity the wire carries: a browser can never name a profile but its own,
|
|
60
|
+
* and the deployment's declared fields and length limits are enforced in the
|
|
61
|
+
* store before anything is written.
|
|
62
|
+
*/
|
|
63
|
+
accountsUpdateProfile(token: string, input: QaAccountProfileInput): QaAccountUserPublic;
|
|
62
64
|
/**
|
|
63
65
|
* Serve the effective QA configuration to the browser. The DSH gateway pins
|
|
64
66
|
* settings RPCs to loopback, so a browser served over the LAN always sees
|
|
@@ -67,10 +69,40 @@ export declare class QaSurface extends TypertRemoteService {
|
|
|
67
69
|
* boundary stays in {@link secureSession}.
|
|
68
70
|
*/
|
|
69
71
|
describe(): ResolvedQaSurfaceConfig;
|
|
72
|
+
/**
|
|
73
|
+
* Create a QA session from Host-owned inputs. With account workspaces on,
|
|
74
|
+
* cwd is `<configured workspace>/.qa-users/<account UUID>` and the child is
|
|
75
|
+
* intentionally not registered or attached as another DSH workspace.
|
|
76
|
+
*/
|
|
77
|
+
createSession(token: string): Promise<string>;
|
|
70
78
|
/** Pin and attest the effective policy. The browser supplies identity only. */
|
|
71
|
-
secureSession(token: string, sessionId: string): QaLockdownProof
|
|
79
|
+
secureSession(token: string, sessionId: string): Promise<QaLockdownProof>;
|
|
72
80
|
/** Return canonical Host snapshots; replay is rebuilt from qa/sources events. */
|
|
73
|
-
sources(token: string, sessionId: string): readonly QaTurnSources[]
|
|
81
|
+
sources(token: string, sessionId: string): Promise<readonly QaTurnSources[]>;
|
|
82
|
+
/**
|
|
83
|
+
* The tool calls of one chat that wait for the operator. Read-only: a
|
|
84
|
+
* deployment with blocked approvals answers with an empty list.
|
|
85
|
+
*/
|
|
86
|
+
pendingApprovals(token: string, sessionId: string): Promise<readonly QaPendingApproval[]>;
|
|
87
|
+
/**
|
|
88
|
+
* Apply the operator's answer to one parked call. The id must belong to a
|
|
89
|
+
* request of this chat; an answer that lost the race (the turn was stopped,
|
|
90
|
+
* the agent went away) is refused with `false`.
|
|
91
|
+
*/
|
|
92
|
+
answerApproval(token: string, sessionId: string, requestId: string, decision: QaApprovalDecision): Promise<boolean>;
|
|
93
|
+
/**
|
|
94
|
+
* The questions of one chat that wait for the operator. Read-only: a
|
|
95
|
+
* deployment with unsupported questions answers with an empty list.
|
|
96
|
+
*/
|
|
97
|
+
pendingQuestions(token: string, sessionId: string): Promise<readonly QaPendingQuestion[]>;
|
|
98
|
+
/**
|
|
99
|
+
* Apply the operator's answers to one parked question request. Every question
|
|
100
|
+
* of the request must be present in `answers`; one the browser omits reads as
|
|
101
|
+
* a skip.
|
|
102
|
+
*/
|
|
103
|
+
answerQuestion(token: string, sessionId: string, requestId: string, answers: readonly QaQuestionAnswerItem[]): Promise<boolean>;
|
|
104
|
+
/** Close a parked question request without answering it. */
|
|
105
|
+
cancelQuestion(token: string, sessionId: string, requestId: string): Promise<boolean>;
|
|
74
106
|
/** Narrow read-only preview capability for files already present as sources. */
|
|
75
107
|
readSourceFile(token: string, sessionId: string, sourcePath: string): Promise<QaSourceFilePreview>;
|
|
76
108
|
private refreshRoute;
|
|
@@ -83,6 +115,7 @@ export { entryRedirectRow, entryRedirectScript } from "./entry-redirect.js";
|
|
|
83
115
|
export { registerQaNavigationRoute } from "./host-route.js";
|
|
84
116
|
export { qaToolDenial, qaToolPolicyPlan } from "./lockdown-policy.js";
|
|
85
117
|
export { QaPolicyAdmission } from "./secure-session.js";
|
|
118
|
+
export { QaPromptNotes, renderUserIdentity, QA_IDENTITY_NOTE, QA_SOURCES_NOTE, } from "./prompt-notes.js";
|
|
86
119
|
export * from "./provenance/index.js";
|
|
87
120
|
export type * from "./types.js";
|
|
88
121
|
export default QaSurface;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { QaAccountIdentityField, QaAccountProfile } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Profile shape, limits, and the normalization both halves of the plugin
|
|
4
|
+
* agree on. Deliberately free of Node built-ins: the configuration resolver
|
|
5
|
+
* and the browser-side form import these same limits, and a Host-only import
|
|
6
|
+
* here would drag the accounts store into the client bundle.
|
|
7
|
+
*/
|
|
8
|
+
/** Longest accepted full name. */
|
|
9
|
+
export declare const QA_PROFILE_MAX_FULL_NAME = 200;
|
|
10
|
+
/** Longest accepted value of one external-system handle. */
|
|
11
|
+
export declare const QA_PROFILE_MAX_IDENTITY_VALUE = 200;
|
|
12
|
+
/** Most handles one profile may carry. */
|
|
13
|
+
export declare const QA_PROFILE_MAX_IDENTITIES = 16;
|
|
14
|
+
/** Handle keys are lowercase labels; the deployment declares which ones exist. */
|
|
15
|
+
export declare const QA_PROFILE_IDENTITY_KEY: RegExp;
|
|
16
|
+
/** Longest accepted display label of one declared handle field. */
|
|
17
|
+
export declare const QA_PROFILE_MAX_IDENTITY_LABEL = 40;
|
|
18
|
+
/** Most handle fields one deployment may declare. */
|
|
19
|
+
export declare const QA_PROFILE_MAX_IDENTITY_FIELDS = 8;
|
|
20
|
+
/** Default cap on the user's free-form agent guidance. */
|
|
21
|
+
export declare const QA_PROFILE_DEFAULT_INSTRUCTIONS_MAX = 2000;
|
|
22
|
+
/** Bounds within which a deployment may set that cap. */
|
|
23
|
+
export declare const QA_PROFILE_INSTRUCTIONS_MAX_MIN = 200;
|
|
24
|
+
export declare const QA_PROFILE_INSTRUCTIONS_MAX_MAX = 20000;
|
|
25
|
+
/** The profile of an account that never filled one in. */
|
|
26
|
+
export declare function emptyProfile(): QaAccountProfile;
|
|
27
|
+
/**
|
|
28
|
+
* Read one stored (or wire-delivered) profile into its public shape. Unknown
|
|
29
|
+
* or hand-edited input degrades to the readable subset instead of throwing:
|
|
30
|
+
* a malformed profile must never cost the account its session. Overlong text
|
|
31
|
+
* is truncated here — the write path rejects it with a message instead.
|
|
32
|
+
*/
|
|
33
|
+
export declare function normalizeProfile(value: unknown): QaAccountProfile;
|
|
34
|
+
/** Validated profile values, before the store stamps `updatedAt`. */
|
|
35
|
+
export interface QaProfileWrite {
|
|
36
|
+
readonly fullName: string;
|
|
37
|
+
readonly identities: Readonly<Record<string, string>>;
|
|
38
|
+
readonly instructions: string;
|
|
39
|
+
}
|
|
40
|
+
export type QaProfileWriteResult = {
|
|
41
|
+
readonly ok: true;
|
|
42
|
+
readonly value: QaProfileWrite;
|
|
43
|
+
} | {
|
|
44
|
+
readonly ok: false;
|
|
45
|
+
readonly message: string;
|
|
46
|
+
};
|
|
47
|
+
export interface QaProfileWriteOptions {
|
|
48
|
+
readonly instructionsMaxLength: number;
|
|
49
|
+
/**
|
|
50
|
+
* Fields the deployment declares; a write may name only these keys. Omit to
|
|
51
|
+
* check the key shape alone — the operator CLI path, where the writer is the
|
|
52
|
+
* same person who owns the configuration.
|
|
53
|
+
*/
|
|
54
|
+
readonly identities?: readonly QaAccountIdentityField[];
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Validate one full-replace profile write. Values are cleaned the same way
|
|
58
|
+
* the read path cleans them, so what a caller sends is what the prompt will
|
|
59
|
+
* later render; limits are refused with a message instead of truncated, so a
|
|
60
|
+
* user pasting an essay learns why it was not stored.
|
|
61
|
+
*/
|
|
62
|
+
export declare function validateProfileWrite(input: unknown, options: QaProfileWriteOptions): QaProfileWriteResult;
|
|
63
|
+
export type QaIdentityFieldsResult = {
|
|
64
|
+
readonly ok: true;
|
|
65
|
+
readonly value: readonly QaAccountIdentityField[];
|
|
66
|
+
} | {
|
|
67
|
+
readonly ok: false;
|
|
68
|
+
readonly message: string;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Validate the deployment's declared handle fields: the profile form renders
|
|
72
|
+
* one input per entry and the prompt names exactly these, so a typo in a key
|
|
73
|
+
* becomes a refusal at configuration time rather than a silent no-op.
|
|
74
|
+
*/
|
|
75
|
+
export declare function validateIdentityFields(value: unknown): QaIdentityFieldsResult;
|
|
76
|
+
//# sourceMappingURL=profile.d.ts.map
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import type { Context } from "@deepseek-ai/cordis";
|
|
2
|
+
import type { PluginLogger } from "@yadsh/dsh-plugin-log";
|
|
3
|
+
import type { QaAccounts } from "./accounts/store.js";
|
|
4
|
+
import type { QaAccountIdentityField, QaAccountProfile, ResolvedQaSurfaceConfig } from "./types.js";
|
|
5
|
+
/**
|
|
6
|
+
* Plugin marker on every injected message. The chat projection turns a
|
|
7
|
+
* plugin-sourced user message into injected context rather than a chat
|
|
8
|
+
* bubble, and the QA transcript keeps exactly those hidden.
|
|
9
|
+
*/
|
|
10
|
+
export declare const QA_NOTES_PLUGIN = "qa-surface";
|
|
11
|
+
/** Note name carrying who the assistant is talking to. */
|
|
12
|
+
export declare const QA_IDENTITY_NOTE = "dsh-qa-surface:user-identity";
|
|
13
|
+
/** Note name carrying the deployment's rule about source provenance. */
|
|
14
|
+
export declare const QA_SOURCES_NOTE = "dsh-qa-surface:structured-sources";
|
|
15
|
+
export interface QaIdentityRenderInput {
|
|
16
|
+
/** The owner's account address; the one fact accounts always provide. */
|
|
17
|
+
readonly email: string;
|
|
18
|
+
readonly profile: QaAccountProfile;
|
|
19
|
+
/** Handle fields the deployment declares, in its configured order. */
|
|
20
|
+
readonly identities: readonly QaAccountIdentityField[];
|
|
21
|
+
}
|
|
22
|
+
/** The two identity parts one user resolves to; either may be empty. */
|
|
23
|
+
export interface QaRenderedIdentity {
|
|
24
|
+
readonly identity: string;
|
|
25
|
+
readonly instructions: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Render the identity text for one attested user.
|
|
29
|
+
*
|
|
30
|
+
* The wording is deliberately explicit about provenance: these are the user's
|
|
31
|
+
* own claims, so the model is told to name the identifier it searched by and
|
|
32
|
+
* to ask when the results contradict the request. A wrong handle that the
|
|
33
|
+
* model trusts silently is the failure mode this text exists to prevent.
|
|
34
|
+
*/
|
|
35
|
+
export declare function renderUserIdentity(input: QaIdentityRenderInput): QaRenderedIdentity;
|
|
36
|
+
/** One named block the injector can add to a step. */
|
|
37
|
+
export interface QaPromptNote {
|
|
38
|
+
/** Source-section name, and the marker that finds the note again. */
|
|
39
|
+
readonly name: string;
|
|
40
|
+
readonly text: string;
|
|
41
|
+
}
|
|
42
|
+
export interface QaPromptNotesOptions {
|
|
43
|
+
readonly config: () => ResolvedQaSurfaceConfig;
|
|
44
|
+
/** The live accounts store, or undefined while accounts are disabled. */
|
|
45
|
+
readonly accounts: () => QaAccounts | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Whether one session belongs to the QA surface. The admission answers it:
|
|
48
|
+
* only an attested session reaches the QA audience the notes are written
|
|
49
|
+
* for, and delegated children resolve through their root session.
|
|
50
|
+
*/
|
|
51
|
+
readonly isQaSession: (sessionId: string) => boolean;
|
|
52
|
+
readonly logger: PluginLogger;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Delivers the QA surface's ambient notes to the agent: who the assistant is
|
|
56
|
+
* talking to, and what the deployment expects around source provenance.
|
|
57
|
+
*
|
|
58
|
+
* A system-prompt section would be the natural home for both, and this plugin
|
|
59
|
+
* used one for each. Neither survives the QA deployment's own preset: the
|
|
60
|
+
* `qa-research` persona registers with `complete: true` (the persona IS the
|
|
61
|
+
* whole system prompt, so every other section is discarded) and
|
|
62
|
+
* `includeRuntimeContext: false` (which drops every context contribution as
|
|
63
|
+
* well). The preset says so outright — no plugin adds prompt text.
|
|
64
|
+
*
|
|
65
|
+
* What stays open is the conversation: a plugin-sourced user message is
|
|
66
|
+
* admitted to the request as injected context, survives both switches, and
|
|
67
|
+
* the transcript projection already hides every non-`subagent` context note
|
|
68
|
+
* from the QA audience. Each note is written once per text rather than once
|
|
69
|
+
* per step — the session's own surface is the state, so a resume or a plugin
|
|
70
|
+
* reload never duplicates a note — and written again only when its text
|
|
71
|
+
* actually changes.
|
|
72
|
+
*
|
|
73
|
+
* The notes are advisory text, never authority: nothing here is enforced by
|
|
74
|
+
* the model's compliance. The lockdown (allow-list, guards, permission
|
|
75
|
+
* preset) is host-side and holds whatever the conversation says.
|
|
76
|
+
*/
|
|
77
|
+
export declare class QaPromptNotes {
|
|
78
|
+
private readonly ctx;
|
|
79
|
+
private readonly options;
|
|
80
|
+
/** `${agentId}:${noteName}` → the text the note already carries. */
|
|
81
|
+
private readonly carried;
|
|
82
|
+
private readonly disposePreStep;
|
|
83
|
+
private disposed;
|
|
84
|
+
constructor(ctx: Context, options: QaPromptNotesOptions);
|
|
85
|
+
dispose(): void;
|
|
86
|
+
/** Append every note whose text this step does not already carry. */
|
|
87
|
+
private inject;
|
|
88
|
+
/** Who is asking: the owner's name, handles and their own instructions. */
|
|
89
|
+
private identityNotes;
|
|
90
|
+
/** What the deployment expects around the sources the surface collects. */
|
|
91
|
+
private sourcesNotes;
|
|
92
|
+
private carriedKey;
|
|
93
|
+
/**
|
|
94
|
+
* The text one note already carries in this agent's conversation. Process
|
|
95
|
+
* memory answers it after the first step; a cold read walks the durable
|
|
96
|
+
* surface so a resumed session or a reloaded plugin does not write twice.
|
|
97
|
+
*/
|
|
98
|
+
private carriedText;
|
|
99
|
+
/**
|
|
100
|
+
* The session a chat started from. Delegated children are joined to their
|
|
101
|
+
* preset's standing scope rather than to their parent agent, so the chain
|
|
102
|
+
* has to be walked through the durable session headers; an unresolvable link
|
|
103
|
+
* (a resumed session whose parent is no longer loaded) degrades to the
|
|
104
|
+
* farthest ancestor known at that moment.
|
|
105
|
+
*/
|
|
106
|
+
private rootSessionId;
|
|
107
|
+
/** The owner's email and profile, or nothing while the chat is anonymous. */
|
|
108
|
+
private identityOf;
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=prompt-notes.d.ts.map
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { canonicalizeUrl } from "./normalize.js";
|
|
2
2
|
import type { QaReportedSource, QaSourceOrigin, QaSourceReference } from "./types.js";
|
|
3
|
+
export interface ReportedSourceOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Whether a reported source must carry an address to be recorded. With
|
|
6
|
+
* `false`, a source the model wrote without a usable path or URL keeps its
|
|
7
|
+
* own type, title and snippet instead of being dropped.
|
|
8
|
+
*/
|
|
9
|
+
readonly validate?: boolean;
|
|
10
|
+
}
|
|
3
11
|
/** Normalize a source explicitly reported by a delegated provider. */
|
|
4
|
-
export declare function normalizeReportedSource(source: QaReportedSource, origin: QaSourceOrigin, workspaceRoot?: string, urlOptions?: Parameters<typeof canonicalizeUrl>[1]): QaSourceReference | null;
|
|
12
|
+
export declare function normalizeReportedSource(source: QaReportedSource, origin: QaSourceOrigin, workspaceRoot?: string, urlOptions?: Parameters<typeof canonicalizeUrl>[1], options?: ReportedSourceOptions): QaSourceReference | null;
|
|
5
13
|
//# sourceMappingURL=reported.d.ts.map
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { Agent } from "@deepseek-ai/dsh-agent";
|
|
2
|
+
import type { Context } from "@deepseek-ai/cordis";
|
|
3
|
+
import type { PluginLogger } from "@yadsh/dsh-plugin-log";
|
|
4
|
+
import type { QaSessionOwnership } from "./session-ownership.js";
|
|
5
|
+
import type { QaPendingQuestion, QaQuestionAnswerItem } from "./types.js";
|
|
6
|
+
/**
|
|
7
|
+
* The harness user-questions contract this seam reads and writes, declared
|
|
8
|
+
* structurally on purpose: the plugin neither mounts the service nor depends on
|
|
9
|
+
* its package, so it stays loadable in a deployment that composes no questions
|
|
10
|
+
* at all. Shapes follow `@deepseek-ai/dsh-user-questions` `src/types.ts` at the
|
|
11
|
+
* tested harness release (`AskUserQuestionItem` / `AskUserQuestionAnswer`).
|
|
12
|
+
*/
|
|
13
|
+
export interface QaQuestionOption {
|
|
14
|
+
readonly label: string;
|
|
15
|
+
readonly description?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface QaQuestionItem {
|
|
18
|
+
readonly id: string;
|
|
19
|
+
readonly question: string;
|
|
20
|
+
readonly detail?: string;
|
|
21
|
+
readonly header?: string;
|
|
22
|
+
readonly options?: readonly QaQuestionOption[];
|
|
23
|
+
readonly multiSelect?: boolean;
|
|
24
|
+
}
|
|
25
|
+
export interface QaQuestionRequest {
|
|
26
|
+
readonly questions: readonly QaQuestionItem[];
|
|
27
|
+
readonly agent?: Agent;
|
|
28
|
+
readonly signal?: AbortSignal;
|
|
29
|
+
}
|
|
30
|
+
/** What the answerer waterfall accepts as its value. */
|
|
31
|
+
export interface QaQuestionAnswer {
|
|
32
|
+
readonly answers: readonly QaQuestionAnswerItem[];
|
|
33
|
+
}
|
|
34
|
+
/** What the model reads when the deployment does not answer questions. */
|
|
35
|
+
export declare const QA_QUESTIONS_UNSUPPORTED = "questions are not answered in this assistant view; ask the user in plain text instead";
|
|
36
|
+
/**
|
|
37
|
+
* User questions in the QA view.
|
|
38
|
+
*
|
|
39
|
+
* `ask_user_question` reaches the browser through the harness answerer
|
|
40
|
+
* waterfall, and the stock DSH web bundle mounts its own answerer in every
|
|
41
|
+
* page. Behind the QA overlay that answerer is unreachable, so a question asked
|
|
42
|
+
* of a QA chat would sit in front of nobody. This gate claims the request for
|
|
43
|
+
* attested chats before the generic browser bridge sees it:
|
|
44
|
+
*
|
|
45
|
+
* - `interaction.questions: interactive` parks the request until the operator
|
|
46
|
+
* answers or closes it in the QA view, and the answer becomes the waterfall's
|
|
47
|
+
* value.
|
|
48
|
+
* - `unsupported` (default) refuses with a reason the model can act on, rather
|
|
49
|
+
* than letting the turn stall on a card no one can see.
|
|
50
|
+
*
|
|
51
|
+
* Nothing is ever answered on the operator's behalf, and a request from a
|
|
52
|
+
* session this deployment did not attest is handed back to the chain untouched.
|
|
53
|
+
*/
|
|
54
|
+
export declare class QaQuestionGate {
|
|
55
|
+
private readonly ctx;
|
|
56
|
+
private readonly interactive;
|
|
57
|
+
private readonly ownership;
|
|
58
|
+
private readonly logger;
|
|
59
|
+
private readonly pending;
|
|
60
|
+
private readonly disposers;
|
|
61
|
+
constructor(ctx: Context, interactive: () => boolean, ownership: QaSessionOwnership, logger: PluginLogger);
|
|
62
|
+
/** Claim question requests for the chats this deployment answers. */
|
|
63
|
+
install(): void;
|
|
64
|
+
/** Questions of one chat, oldest first: what the QA view renders. */
|
|
65
|
+
list(sessionId: string): readonly QaPendingQuestion[];
|
|
66
|
+
/**
|
|
67
|
+
* Apply the operator's answers; an unknown or foreign id is refused. The
|
|
68
|
+
* parked request is authoritative: a label the question never offered is
|
|
69
|
+
* dropped, and a free-text answer replaces the choice in a single-select
|
|
70
|
+
* rather than accompanying it, so the model only ever reads a real answer.
|
|
71
|
+
*/
|
|
72
|
+
answer(sessionId: string, requestId: string, answers: readonly QaQuestionAnswerItem[]): boolean;
|
|
73
|
+
/** Close a request without answering it. */
|
|
74
|
+
cancel(sessionId: string, requestId: string): boolean;
|
|
75
|
+
/** Detach the listener and fail every parked request. Wired as an effect. */
|
|
76
|
+
dispose(): void;
|
|
77
|
+
private handle;
|
|
78
|
+
/** Park one request until the operator answers it, or the turn ends. */
|
|
79
|
+
private park;
|
|
80
|
+
/** Fail the questions one session's agent owns; a disposed agent cannot ask. */
|
|
81
|
+
private settleOwner;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=questions.d.ts.map
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
import { normalizeRoutePath } from "./config-resolvers/basics.js";
|
|
2
|
+
import { DEFAULT_QA_SURFACE_CONFIG } from "./config-resolvers/defaults.js";
|
|
1
3
|
import type { QaSurfaceConfig, ResolvedQaSurfaceConfig } from "./types.js";
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
export { DEFAULT_QA_SURFACE_CONFIG, normalizeRoutePath };
|
|
5
|
+
/**
|
|
6
|
+
* Materialize defaults and enforce route/session/model safety constraints by
|
|
7
|
+
* running one resolver per config domain — in the order the checks have
|
|
8
|
+
* always fired — and assembling the frozen result.
|
|
9
|
+
*/
|
|
5
10
|
export declare function resolveConfig(input?: QaSurfaceConfig): ResolvedQaSurfaceConfig;
|
|
6
11
|
//# sourceMappingURL=resolve-config.d.ts.map
|
|
@@ -7,7 +7,10 @@ import type { QaLockdownProof, ResolvedQaSurfaceConfig } from "./types.js";
|
|
|
7
7
|
* pair or throw the coarse `QaAttestationError`; see {@link QaAccounts}.
|
|
8
8
|
*/
|
|
9
9
|
export interface QaAccountsGate {
|
|
10
|
-
enforceSessionAccess(token: string, sessionId: string):
|
|
10
|
+
enforceSessionAccess(token: string, sessionId: string): {
|
|
11
|
+
readonly id: string;
|
|
12
|
+
} | undefined;
|
|
13
|
+
userWorkspace(userId: string, registeredWorkspacePath: string): string;
|
|
11
14
|
}
|
|
12
15
|
/**
|
|
13
16
|
* Host-side QA policy admission boundary — the only browser-callable operation
|
|
@@ -23,8 +26,49 @@ export declare class QaPolicyAdmission {
|
|
|
23
26
|
private readonly logger;
|
|
24
27
|
private readonly accounts?;
|
|
25
28
|
private readonly appliedPolicies;
|
|
29
|
+
/**
|
|
30
|
+
* Sessions the QA surface has attested. The provenance note is written for
|
|
31
|
+
* exactly these, and a delegated child resolves through its root session, so
|
|
32
|
+
* one set answers for the whole chat.
|
|
33
|
+
*/
|
|
34
|
+
private readonly attested;
|
|
35
|
+
private readonly workspaceAccess;
|
|
36
|
+
private readonly disposeWorkspaceGuard;
|
|
26
37
|
constructor(ctx: Context, config: () => ResolvedQaSurfaceConfig, logger: PluginLogger, accounts?: QaAccountsGate | undefined);
|
|
27
|
-
|
|
38
|
+
/**
|
|
39
|
+
* The mounted attachment store's verbatim root, when the backend exposes
|
|
40
|
+
* one. It sits outside every workspace, so the per-user fence would
|
|
41
|
+
* otherwise deny the model the exact file an upload produced and the prompt
|
|
42
|
+
* points it at. A backend without a resolvable root simply keeps the fence
|
|
43
|
+
* closed — attachments then only work where reads are not fenced per user.
|
|
44
|
+
*/
|
|
45
|
+
private attachmentRoot;
|
|
46
|
+
/**
|
|
47
|
+
* The live agent for one session, resuming a Session the Host has not
|
|
48
|
+
* materialized in this process.
|
|
49
|
+
*
|
|
50
|
+
* DSH builds an agent on demand: a session's journal opens straight from
|
|
51
|
+
* persistence (`session/page` reads the durable log), and only Agent-bound
|
|
52
|
+
* operations — a prompt, a model selection, renaming, an upload — resolve or
|
|
53
|
+
* resume one. So a chat from an earlier Host run has a readable transcript
|
|
54
|
+
* and no agent at all, and attestation, which pins the tool policy ON that
|
|
55
|
+
* agent, is the first thing here that needs one. Refusing instead would make
|
|
56
|
+
* every restored chat unopenable until something else in the Host happened
|
|
57
|
+
* to wake it.
|
|
58
|
+
*
|
|
59
|
+
* The resume composes the session's OWN recorded preset — the same
|
|
60
|
+
* composition a stock prompt would produce — so a session composed outside
|
|
61
|
+
* the QA preset still lands on the mismatch refusals below ("composition
|
|
62
|
+
* mismatch"), and the adoption and permission checks stay the gate.
|
|
63
|
+
*/
|
|
64
|
+
private liveAgent;
|
|
65
|
+
secureSession(token: string, sessionId: string): Promise<QaLockdownProof>;
|
|
66
|
+
/**
|
|
67
|
+
* Whether one session went through this boundary. The provenance note is
|
|
68
|
+
* written only for attested sessions, which is what keeps a deployment's
|
|
69
|
+
* source rules out of unrelated chats served by the same process.
|
|
70
|
+
*/
|
|
71
|
+
knowsSession(sessionId: string): boolean;
|
|
28
72
|
/** Detach every pinned tool policy; wired as a disposal effect by the entry. */
|
|
29
73
|
dispose(): void;
|
|
30
74
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Context } from "@deepseek-ai/cordis";
|
|
2
|
+
/**
|
|
3
|
+
* Which sessions belong to this deployment.
|
|
4
|
+
*
|
|
5
|
+
* The admission boundary attests chat roots. A delegated child never appears
|
|
6
|
+
* there — its scope chain does not reach the chat's own agent context — so it
|
|
7
|
+
* inherits its chat from the session that created it. Both interactive seams
|
|
8
|
+
* (tool approvals and user questions) read ownership from here, which is what
|
|
9
|
+
* keeps one chat answered by exactly one surface.
|
|
10
|
+
*/
|
|
11
|
+
export declare class QaSessionOwnership {
|
|
12
|
+
private readonly isAttested;
|
|
13
|
+
/** Child session → the attested chat that owns it. */
|
|
14
|
+
private readonly inherited;
|
|
15
|
+
private disposeListener;
|
|
16
|
+
private installed;
|
|
17
|
+
constructor(isAttested: (sessionId: string) => boolean);
|
|
18
|
+
/** Listen for the children of an attested chat; safe to call from each seam. */
|
|
19
|
+
install(ctx: Context): void;
|
|
20
|
+
/** The attested chat behind a session: itself, or the root it inherited. */
|
|
21
|
+
rootOf(sessionId: string): string | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Drop one session's inheritance. Called when its agent is gone; the chat's
|
|
24
|
+
* own claim needs no bookkeeping here, because it resolves through the
|
|
25
|
+
* admission's attested set, which owns that lifetime.
|
|
26
|
+
*/
|
|
27
|
+
forget(sessionId: string): void;
|
|
28
|
+
dispose(): void;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=session-ownership.d.ts.map
|