@yadsh/dsh-qa-surface 0.15.4 → 0.15.6
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/lib/access/model-policy.js +124 -0
- package/lib/access/model-policy.js.map +1 -0
- package/lib/access/model.js +5 -0
- package/lib/access/model.js.map +1 -1
- package/lib/access/service.js +77 -3
- package/lib/access/service.js.map +1 -1
- package/lib/admin/service.js +6 -0
- package/lib/admin/service.js.map +1 -1
- package/lib/client/admin/ModelPolicyEditor.js +52 -0
- package/lib/client/admin/ModelPolicyEditor.js.map +1 -0
- package/lib/client/admin/QaAdmin.js +4 -2
- package/lib/client/admin/QaAdmin.js.map +1 -1
- package/lib/client/admin/pages/Users.js +18 -2
- package/lib/client/admin/pages/Users.js.map +1 -1
- package/lib/client/admin/shared.js +3 -0
- package/lib/client/admin/shared.js.map +1 -1
- package/lib/client/components/QaChangelog.js +33 -1
- package/lib/client/components/QaChangelog.js.map +1 -1
- package/lib/client/index.js +1 -0
- package/lib/client/index.js.map +1 -1
- package/lib/client/settings/sections/session.js +2 -2
- package/lib/client/settings/sections/session.js.map +1 -1
- package/lib/client/types.js.map +1 -1
- package/lib/client.js +367 -93
- package/lib/client.js.map +1 -1
- package/lib/index.js +32 -17
- package/lib/index.js.map +1 -1
- package/lib/integration/host-runner.js +2 -10
- package/lib/integration/host-runner.js.map +1 -1
- package/lib/secure-session.js +16 -7
- package/lib/secure-session.js.map +1 -1
- package/lib/session-model.js +40 -0
- package/lib/session-model.js.map +1 -0
- package/lib/typert.host.js +211 -80
- package/lib/typert.remote-client.d.ts +3 -1
- package/lib/typert.remote-client.js +184 -75
- package/lib/types/access/model-policy.d.ts +95 -0
- package/lib/types/access/service.d.ts +41 -4
- package/lib/types/client/admin/ModelPolicyEditor.d.ts +23 -0
- package/lib/types/client/types.d.ts +3 -1
- package/lib/types/index.d.ts +20 -4
- package/lib/types/secure-session.d.ts +14 -1
- package/lib/types/session-model.d.ts +24 -0
- package/lib/types/types.d.ts +35 -0
- package/package.json +3 -3
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { QaModelCatalogEntry, QaModelPair, ResolvedQaSurfaceConfig } from "../types.js";
|
|
2
|
+
/** The layer a resolved pair came from; the journal names it with the pair. */
|
|
3
|
+
export type QaModelPolicyLayer = "account" | "subrole" | "deployment";
|
|
4
|
+
/**
|
|
5
|
+
* The model policy of one session: the pair its chats open on and the layer
|
|
6
|
+
* that fixed it.
|
|
7
|
+
*
|
|
8
|
+
* That pair is what the fixed-model lockdown holds the session to. It is no
|
|
9
|
+
* longer the deployment's pair, and it is not the model the visitor picked: a
|
|
10
|
+
* role with a pair of its own is served by that pair, while a chat left on a
|
|
11
|
+
* layer some policy has since replaced is outside its policy — exactly as a chat
|
|
12
|
+
* left off the single global pair used to be.
|
|
13
|
+
*/
|
|
14
|
+
export interface QaSessionModelPolicy {
|
|
15
|
+
readonly pair: QaModelPair | undefined;
|
|
16
|
+
readonly layer: QaModelPolicyLayer | undefined;
|
|
17
|
+
}
|
|
18
|
+
/** The session fields of the resolved config, as the policy reads them. */
|
|
19
|
+
type SessionSlice = ResolvedQaSurfaceConfig["session"];
|
|
20
|
+
/**
|
|
21
|
+
* Normalize one configured pair.
|
|
22
|
+
*
|
|
23
|
+
* Provider and model are named together or not at all, because the Host
|
|
24
|
+
* refuses either alone; an empty pair is no pair, so a role that names nothing
|
|
25
|
+
* defers to the layer below it instead of failing the configuration.
|
|
26
|
+
* @param value - the pair as stored, or nothing.
|
|
27
|
+
* @param label - prefix for the refusal, naming the field the operator edited.
|
|
28
|
+
*/
|
|
29
|
+
export declare function normalizeModelPair(value: QaModelPair | null | undefined, label: string): QaModelPair | undefined;
|
|
30
|
+
/** The deployment-wide pair, as the policy's last layer. */
|
|
31
|
+
export declare function deploymentModelPair(session: Pick<SessionSlice, "provider" | "model" | "reasoningEffort"> | undefined): QaModelPair | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* Fold the named layers into one session policy.
|
|
34
|
+
*
|
|
35
|
+
* The first complete pair wins outright rather than merging field by field: an
|
|
36
|
+
* account that overrides a role says which model it means, and half of a pair
|
|
37
|
+
* from one layer over half of another is a combination no operator wrote.
|
|
38
|
+
* @param layers - the layers in priority order, `undefined` where a layer keeps
|
|
39
|
+
* no opinion.
|
|
40
|
+
*/
|
|
41
|
+
export declare function resolveModelPolicy(layers: Partial<Record<QaModelPolicyLayer, QaModelPair | undefined>>): QaSessionModelPolicy;
|
|
42
|
+
/**
|
|
43
|
+
* The provider, model and reasoning effort a live agent carries, as the
|
|
44
|
+
* lockdown reads them off `agent.options`.
|
|
45
|
+
*/
|
|
46
|
+
export interface ModelSelectionFacts {
|
|
47
|
+
readonly provider?: string;
|
|
48
|
+
readonly model?: string;
|
|
49
|
+
readonly reasoningEffort?: string;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Whether one agent's selection sits inside the session's model policy.
|
|
53
|
+
*
|
|
54
|
+
* A pair that names no effort constrains provider and model only, so a chat
|
|
55
|
+
* that switches effort inside its own model is not mistaken for a move to
|
|
56
|
+
* another policy — which is the reading the single-pair check already had. A
|
|
57
|
+
* policy that names no pair at all constrains nothing: there is no operator
|
|
58
|
+
* decision for the session to have left.
|
|
59
|
+
*/
|
|
60
|
+
export declare function modelPolicySatisfied(policy: QaSessionModelPolicy, selection: ModelSelectionFacts): boolean;
|
|
61
|
+
/** The catalog shape this module projects, as the harness reports it. */
|
|
62
|
+
export interface HarnessModelCatalog {
|
|
63
|
+
readonly groups: readonly {
|
|
64
|
+
readonly id: string;
|
|
65
|
+
readonly name?: string;
|
|
66
|
+
readonly models: readonly {
|
|
67
|
+
readonly id: string;
|
|
68
|
+
readonly name?: string;
|
|
69
|
+
readonly reasoning?: {
|
|
70
|
+
readonly efforts?: readonly {
|
|
71
|
+
readonly id: string;
|
|
72
|
+
}[];
|
|
73
|
+
};
|
|
74
|
+
}[];
|
|
75
|
+
}[];
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Project the harness catalog into the pairs the administration surface lists.
|
|
79
|
+
* @param catalog - the host's model catalog.
|
|
80
|
+
*/
|
|
81
|
+
export declare function projectModelCatalog(catalog: HarnessModelCatalog): readonly QaModelCatalogEntry[];
|
|
82
|
+
/**
|
|
83
|
+
* Refuse a pair the Host cannot serve, in the words an operator reads in the
|
|
84
|
+
* settings surface.
|
|
85
|
+
*
|
|
86
|
+
* Without this a stand accepts a typo and then fails on the first question of
|
|
87
|
+
* every chat that policy opens, which names neither the pair nor where it came
|
|
88
|
+
* from. An empty catalog is not a refusal: a Host whose catalog read failed
|
|
89
|
+
* answers with no entries, and the policy is then checked when the chat starts.
|
|
90
|
+
* @param pair - the pair being saved.
|
|
91
|
+
* @param catalog - the projected catalog, or `undefined` to skip the check.
|
|
92
|
+
*/
|
|
93
|
+
export declare function assertModelPairAvailable(pair: QaModelPair | undefined, catalog: readonly QaModelCatalogEntry[] | undefined): void;
|
|
94
|
+
export {};
|
|
95
|
+
//# sourceMappingURL=model-policy.d.ts.map
|
|
@@ -3,8 +3,9 @@ import type { Context } from "@deepseek-ai/cordis";
|
|
|
3
3
|
import type { PluginLogger } from "@yadsh/dsh-plugin-log";
|
|
4
4
|
import type { QaAccounts } from "../accounts/store.js";
|
|
5
5
|
import type { QaAgentToolGrants } from "../enforcement/tool-grants.js";
|
|
6
|
-
import type { QaAccessAdminSnapshot, QaAccountUserPublic, QaCapabilityConfig, QaCapabilityDescriptor, QaCapabilitySelection, QaClaimResult, QaCurrentAccess, QaEffectiveCapabilityPolicy, QaSessionAccess, QaSkillActivationRecord, QaSkillAssignmentOverride, QaSubrole, QaUserAccess, ResolvedQaSurfaceConfig } from "../types.js";
|
|
6
|
+
import type { QaAccessAdminSnapshot, QaAccountUserPublic, QaCapabilityConfig, QaCapabilityDescriptor, QaCapabilitySelection, QaClaimResult, QaCurrentAccess, QaEffectiveCapabilityPolicy, QaModelCatalogEntry, QaModelPair, QaSessionAccess, QaSkillActivationRecord, QaSkillAssignmentOverride, QaSubrole, QaUserAccess, ResolvedQaSurfaceConfig } from "../types.js";
|
|
7
7
|
import type { QaSessionLogReader } from "../admin/session-log.js";
|
|
8
|
+
import { type QaSessionModelPolicy } from "./model-policy.js";
|
|
8
9
|
import { QaCapabilityCatalog, type CapabilityCatalogSnapshot, type QaPresetScopeLease } from "./capability-catalog.js";
|
|
9
10
|
import { QaRoleRepository } from "./role-repository.js";
|
|
10
11
|
export interface QaResolvedSessionPolicy {
|
|
@@ -193,11 +194,47 @@ export declare class QaAccessService {
|
|
|
193
194
|
adminSnapshot(token: string): Promise<QaAccessAdminSnapshot>;
|
|
194
195
|
/** Replace or clear one skill's administrator overlay. */
|
|
195
196
|
updateSkillOverride(token: string, input: QaSkillAssignmentOverride): readonly QaSkillAssignmentOverride[];
|
|
196
|
-
|
|
197
|
-
|
|
197
|
+
/**
|
|
198
|
+
* The provider/model pairs this Host can serve right now, for the surface
|
|
199
|
+
* that writes a policy.
|
|
200
|
+
*
|
|
201
|
+
* The operator picks out of this list rather than typing a pair: a policy
|
|
202
|
+
* that names a model the deployment does not offer does not fail when it is
|
|
203
|
+
* saved, it fails on the first question of every chat that policy opens.
|
|
204
|
+
* @param token - the administrator's browser token.
|
|
205
|
+
*/
|
|
206
|
+
modelCatalog(token: string): Promise<readonly QaModelCatalogEntry[]>;
|
|
207
|
+
/**
|
|
208
|
+
* The model policy of one session: the pair its chats open on, and the layer
|
|
209
|
+
* that fixed it.
|
|
210
|
+
*
|
|
211
|
+
* Read from the role the chat was reserved under, so the answer is the same
|
|
212
|
+
* for the browser path and for the integration API, which addressed the same
|
|
213
|
+
* account through a service token. Without an account behind the chat only
|
|
214
|
+
* the deployment layer can speak, which is what a stand without accounts
|
|
215
|
+
* asked for before roles had opinions about models.
|
|
216
|
+
* @param sessionId - the chat being opened.
|
|
217
|
+
*/
|
|
218
|
+
modelPolicyFor(sessionId: string): QaSessionModelPolicy;
|
|
219
|
+
/**
|
|
220
|
+
* Refuse a policy the Host cannot serve before it is stored.
|
|
221
|
+
* @param pair - the pair as edited, before normalization.
|
|
222
|
+
* @param label - the field the operator edited, for the refusal.
|
|
223
|
+
*/
|
|
224
|
+
assertPairServable(pair: QaModelPair | null | undefined, label: string): Promise<void>;
|
|
225
|
+
/**
|
|
226
|
+
* Ask the Host's catalog about one named pair.
|
|
227
|
+
*
|
|
228
|
+
* Called only where a pair was actually named: an assignment or a role that
|
|
229
|
+
* says nothing about models is written the moment it was written, without
|
|
230
|
+
* waiting on a catalog read it has no use for.
|
|
231
|
+
*/
|
|
232
|
+
private requireServablePair;
|
|
233
|
+
createSubrole(token: string, input: QaSubrole): Promise<QaSubrole>;
|
|
234
|
+
updateSubrole(token: string, id: string, input: QaSubrole): Promise<QaSubrole>;
|
|
198
235
|
deleteSubrole(token: string, id: string, replacementId: string | null): void;
|
|
199
236
|
updateCommon(token: string, input: QaCapabilitySelection): QaCapabilitySelection;
|
|
200
|
-
updateAssignment(token: string, userId: string, input: QaUserAccess): QaUserAccess
|
|
237
|
+
updateAssignment(token: string, userId: string, input: QaUserAccess): Promise<QaUserAccess>;
|
|
201
238
|
/** The accounts store, or the refusal this operation names. */
|
|
202
239
|
private requireAccounts;
|
|
203
240
|
/**
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { QaAccessApi } from "../types.js";
|
|
2
|
+
import type { QaModelPair } from "../../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* The provider and model one policy fixes, written by picking a pair this Host
|
|
5
|
+
* actually serves.
|
|
6
|
+
*
|
|
7
|
+
* Free text was the trap: a pair nobody can serve does not fail when it is
|
|
8
|
+
* saved, it fails on the first question of every chat that policy opens, in
|
|
9
|
+
* words that name neither the pair nor the role that asked for it. So the
|
|
10
|
+
* operator chooses from the harness catalog, and a pair already stored but no
|
|
11
|
+
* longer offered stays in the list, marked as such — an editor that cannot see
|
|
12
|
+
* it would otherwise drop it while the operator was changing something else.
|
|
13
|
+
*/
|
|
14
|
+
export declare function ModelPolicyEditor(props: {
|
|
15
|
+
readonly api: QaAccessApi;
|
|
16
|
+
readonly token: string;
|
|
17
|
+
readonly value: QaModelPair | undefined;
|
|
18
|
+
readonly disabled: boolean;
|
|
19
|
+
/** Prefix of the test ids, so one component serves both editors. */
|
|
20
|
+
readonly testId: string;
|
|
21
|
+
readonly onChange: (value: QaModelPair | undefined) => void;
|
|
22
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
23
|
+
//# sourceMappingURL=ModelPolicyEditor.d.ts.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ClientRemote } from "@deepseek-ai/dsh-api-gateway/client";
|
|
2
2
|
import type { ISessions, SessionFace } from "@deepseek-ai/dsh-api-session-controller/client";
|
|
3
3
|
import type { UiConversation } from "@deepseek-ai/dsh-client-ui-conversation/client";
|
|
4
|
-
import type { QaAccountNotificationsInput, QaAccountProfileInput, QaAccountSession, QaAccountStartersInput, QaAccountStarter, QaAccountUserPublic, QaAccessAdminSnapshot, QaApprovalDecision, QaClaimResult, QaLockdownProof, QaOwnershipEntry, QaPasswordResetRequest, QaPendingApproval, QaPendingQuestion, QaQuestionAnswerItem, QaQueueStatus, QaIssuedServiceToken, QaServiceTokenCreateInput, QaServiceTokenSummary, QaSessionState, QaSkillDocument, QaSkillDraftInput, QaSkillRemoval, QaSkillSummary, QaSkillToolDescriptor, QaSkillValidation, QaSourceFilePreview, QaTurnSources, QaWhoamiResult, QaDocumentPreview, QaWorkspaceFile, QaWorkspaceListing, QaCapabilitySelection, QaCurrentAccess, QaSessionAccess, QaSkillActivationRecord, QaSkillAssignmentOverride, QaSubrole, QaUserAccess, QaAdminAuditEvent, QaAdminOverview, QaAdminPage, QaAdminSkillScope, QaAdminSkillsView, QaAdminUserDetail, QaAdminUserRow, QaAdminUserUpdate, QaAuditQuery, QaConversationDetail, QaConversationDeletion, QaConversationQuery, QaConversationReview, QaConversationReviewInput, QaConversationSummary, QaExpertMemoryDraft, QaExpertMemoryPage, QaExpertMemoryRecord, QaExpertMemoryScope, QaFeedbackQuery, QaFeedbackRow, QaMessageFeedback, QaMessageFeedbackInput, QaQualityMetrics, QaReviewQueueItem, QaReviewQueueRow, QaSlashCatalog, QaSlashExecution, QaSlashSubmitAttachment, QaUserQuery } from "../types.js";
|
|
4
|
+
import type { QaAccountNotificationsInput, QaAccountProfileInput, QaAccountSession, QaAccountStartersInput, QaAccountStarter, QaAccountUserPublic, QaAccessAdminSnapshot, QaApprovalDecision, QaClaimResult, QaLockdownProof, QaModelCatalogEntry, QaOwnershipEntry, QaPasswordResetRequest, QaPendingApproval, QaPendingQuestion, QaQuestionAnswerItem, QaQueueStatus, QaIssuedServiceToken, QaServiceTokenCreateInput, QaServiceTokenSummary, QaSessionState, QaSkillDocument, QaSkillDraftInput, QaSkillRemoval, QaSkillSummary, QaSkillToolDescriptor, QaSkillValidation, QaSourceFilePreview, QaTurnSources, QaWhoamiResult, QaDocumentPreview, QaWorkspaceFile, QaWorkspaceListing, QaCapabilitySelection, QaCurrentAccess, QaSessionAccess, QaSkillActivationRecord, QaSkillAssignmentOverride, QaSubrole, QaUserAccess, QaAdminAuditEvent, QaAdminOverview, QaAdminPage, QaAdminSkillScope, QaAdminSkillsView, QaAdminUserDetail, QaAdminUserRow, QaAdminUserUpdate, QaAuditQuery, QaConversationDetail, QaConversationDeletion, QaConversationQuery, QaConversationReview, QaConversationReviewInput, QaConversationSummary, QaExpertMemoryDraft, QaExpertMemoryPage, QaExpertMemoryRecord, QaExpertMemoryScope, QaFeedbackQuery, QaFeedbackRow, QaMessageFeedback, QaMessageFeedbackInput, QaQualityMetrics, QaReviewQueueItem, QaReviewQueueRow, QaSlashCatalog, QaSlashExecution, QaSlashSubmitAttachment, QaUserQuery } from "../types.js";
|
|
5
5
|
/** Wire content one prompt carries: text plus base64 image uploads. */
|
|
6
6
|
export type QaPromptContent = Parameters<SessionFace["prompt"]>[0];
|
|
7
7
|
/** DSH session runtime surface the QA controller is allowed to touch. */
|
|
@@ -48,6 +48,8 @@ export interface QaAccessApi {
|
|
|
48
48
|
}>>;
|
|
49
49
|
updateCommon(token: string, input: QaCapabilitySelection): Promise<RemoteResult<QaCapabilitySelection>>;
|
|
50
50
|
updateAssignment(token: string, userId: string, input: QaUserAccess): Promise<RemoteResult<QaUserAccess>>;
|
|
51
|
+
/** The pairs the Host can serve, for writing a model policy by picking one. */
|
|
52
|
+
modelCatalog(token: string): Promise<RemoteResult<readonly QaModelCatalogEntry[]>>;
|
|
51
53
|
updateSkillOverride(token: string, input: QaSkillAssignmentOverride): Promise<RemoteResult<readonly QaSkillAssignmentOverride[]>>;
|
|
52
54
|
skillActivations(token: string, sessionId: string): Promise<RemoteResult<readonly QaSkillActivationRecord[]>>;
|
|
53
55
|
}
|
package/lib/types/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { Context } from "@deepseek-ai/cordis";
|
|
|
3
3
|
import type { QaSurfaceConfigRefs } from "./config.js";
|
|
4
4
|
import type { QaAccountNotificationsInput } from "./types.js";
|
|
5
5
|
import type { QaTurnSources } from "./provenance/types.js";
|
|
6
|
-
import type { QaAccountProfileInput, QaAccountSession, QaAccountStartersInput, QaAccountUserPublic, QaApprovalDecision, QaClaimResult, QaDocumentPreview, QaIssuedServiceToken, QaLockdownProof, QaOwnershipEntry, QaPasswordResetRequest, QaPendingApproval, QaPendingQuestion, QaQuestionAnswerItem, QaQueueStatus, QaServiceTokenCreateInput, QaServiceTokenSummary, ResolvedQaSurfaceConfig, QaAdminSkillScope, QaAdminSkillsView, QaExpertMemoryDraft, QaExpertMemoryPage, QaExpertMemoryRecord, QaExpertMemoryScope, QaSkillDocument, QaSkillDraftInput, QaSkillRemoval, QaSkillSummary, QaSkillToolDescriptor, QaSkillValidation, QaSourceFilePreview, QaWhoamiResult, QaWorkspaceFile, QaWorkspaceListing, QaPrincipal, QaAccessAdminSnapshot, QaAdminAuditEvent, QaAdminOverview, QaAdminPage, QaAdminUserDetail, QaAdminUserRow, QaAdminUserUpdate, QaAuditQuery, QaCapabilitySelection, QaConversationDetail, QaConversationDeletion, QaConversationQuery, QaConversationReview, QaConversationReviewInput, QaConversationSummary, QaCurrentAccess, QaFeedbackHarvestEntry, QaFeedbackHarvestResult, QaFeedbackQuery, QaFeedbackRow, QaMessageFeedback, QaMessageFeedbackInput, QaQualityMetrics, QaReviewQueueItem, QaReviewQueueRow, QaSessionAccess, QaSlashCatalog, QaSlashExecution, QaSlashSubmitAttachment, QaSkillActivationRecord, QaSkillAssignmentOverride, QaSubrole, QaUserAccess, QaUserQuery } from "./types.js";
|
|
6
|
+
import type { QaAccountProfileInput, QaAccountSession, QaAccountStartersInput, QaAccountUserPublic, QaApprovalDecision, QaClaimResult, QaDocumentPreview, QaIssuedServiceToken, QaLockdownProof, QaOwnershipEntry, QaPasswordResetRequest, QaPendingApproval, QaPendingQuestion, QaQuestionAnswerItem, QaQueueStatus, QaServiceTokenCreateInput, QaServiceTokenSummary, ResolvedQaSurfaceConfig, QaAdminSkillScope, QaAdminSkillsView, QaExpertMemoryDraft, QaExpertMemoryPage, QaExpertMemoryRecord, QaExpertMemoryScope, QaSkillDocument, QaSkillDraftInput, QaSkillRemoval, QaSkillSummary, QaSkillToolDescriptor, QaSkillValidation, QaSourceFilePreview, QaWhoamiResult, QaWorkspaceFile, QaWorkspaceListing, QaPrincipal, QaAccessAdminSnapshot, QaAdminAuditEvent, QaAdminOverview, QaAdminPage, QaAdminUserDetail, QaAdminUserRow, QaAdminUserUpdate, QaAuditQuery, QaCapabilitySelection, QaConversationDetail, QaConversationDeletion, QaConversationQuery, QaConversationReview, QaConversationReviewInput, QaConversationSummary, QaCurrentAccess, QaFeedbackHarvestEntry, QaFeedbackHarvestResult, QaFeedbackQuery, QaFeedbackRow, QaMessageFeedback, QaMessageFeedbackInput, QaModelCatalogEntry, QaModelPair, QaQualityMetrics, QaReviewQueueItem, QaReviewQueueRow, QaSessionAccess, QaSlashCatalog, QaSlashExecution, QaSlashSubmitAttachment, QaSkillActivationRecord, QaSkillAssignmentOverride, QaSubrole, QaUserAccess, QaUserQuery } from "./types.js";
|
|
7
7
|
export declare const name = "qa-surface";
|
|
8
8
|
export declare const inject: string[];
|
|
9
9
|
import { QA_SURFACE_SETTINGS_NAMESPACE } from "./shared/settings.js";
|
|
@@ -97,6 +97,20 @@ export declare class QaSurface extends TypertRemoteService {
|
|
|
97
97
|
principalForSession(sessionId: string): QaPrincipal | undefined;
|
|
98
98
|
/** Admit tools that independently enforce the same QA principal boundary. */
|
|
99
99
|
registerPrincipalScopedTools(names: readonly string[]): () => void;
|
|
100
|
+
/**
|
|
101
|
+
* The provider and model the QA policy fixes for one chat, for a plugin that
|
|
102
|
+
* launches work out of it.
|
|
103
|
+
*
|
|
104
|
+
* A delegated run composes its model from its own profile, and a profile that
|
|
105
|
+
* names nothing inherits the parent — which used to mean the model some
|
|
106
|
+
* visitor had picked. This answers with the pair the role was given instead,
|
|
107
|
+
* so a delegation follows the policy of the chat it serves rather than the
|
|
108
|
+
* selection made inside it. `undefined` is the deployment naming no pair at
|
|
109
|
+
* all, which leaves the caller's own configuration in force.
|
|
110
|
+
*
|
|
111
|
+
* @param sessionId - the chat the work is delegated from.
|
|
112
|
+
*/
|
|
113
|
+
modelPolicyForSession(sessionId: string): QaModelPair | undefined;
|
|
100
114
|
getConfig(): ResolvedQaSurfaceConfig;
|
|
101
115
|
/**
|
|
102
116
|
* Ownership plus the role's user-skill grant for one slash read.
|
|
@@ -228,13 +242,15 @@ export declare class QaSurface extends TypertRemoteService {
|
|
|
228
242
|
accessSession(token: string, sessionId: string): QaSessionAccess;
|
|
229
243
|
/** Complete administrator projection; authorization is checked before discovery. */
|
|
230
244
|
accessAdminSnapshot(token: string): Promise<QaAccessAdminSnapshot>;
|
|
231
|
-
accessCreateSubrole(token: string, input: QaSubrole): QaSubrole
|
|
232
|
-
accessUpdateSubrole(token: string, id: string, input: QaSubrole): QaSubrole
|
|
245
|
+
accessCreateSubrole(token: string, input: QaSubrole): Promise<QaSubrole>;
|
|
246
|
+
accessUpdateSubrole(token: string, id: string, input: QaSubrole): Promise<QaSubrole>;
|
|
247
|
+
/** The pairs this Host can serve, for the surface that writes a policy. */
|
|
248
|
+
accessModelCatalog(token: string): Promise<readonly QaModelCatalogEntry[]>;
|
|
233
249
|
accessDeleteSubrole(token: string, id: string, replacementId: string | null): {
|
|
234
250
|
readonly deleted: boolean;
|
|
235
251
|
};
|
|
236
252
|
accessUpdateCommon(token: string, input: QaCapabilitySelection): QaCapabilitySelection;
|
|
237
|
-
accessUpdateAssignment(token: string, userId: string, input: QaUserAccess): QaUserAccess
|
|
253
|
+
accessUpdateAssignment(token: string, userId: string, input: QaUserAccess): Promise<QaUserAccess>;
|
|
238
254
|
/** Layer one administrator assignment over what a SKILL.md declares. */
|
|
239
255
|
accessUpdateSkillOverride(token: string, input: QaSkillAssignmentOverride): readonly QaSkillAssignmentOverride[];
|
|
240
256
|
/** What each skill activation actually granted in this session. */
|
|
@@ -3,6 +3,7 @@ import type { Context } from "@deepseek-ai/cordis";
|
|
|
3
3
|
import type { PluginLogger } from "@yadsh/dsh-plugin-log";
|
|
4
4
|
import { type QaSessionFacts } from "./accounts/store.js";
|
|
5
5
|
import type { QaResolvedSessionPolicy } from "./access/service.js";
|
|
6
|
+
import { type QaSessionModelPolicy } from "./access/model-policy.js";
|
|
6
7
|
import type { QaLockdownProof, ResolvedQaSurfaceConfig } from "./types.js";
|
|
7
8
|
/**
|
|
8
9
|
* The accounts half of admission, resolved per call by the entry (accounts
|
|
@@ -45,6 +46,12 @@ export declare class QaPolicyAdmission {
|
|
|
45
46
|
private readonly capabilityPolicy?;
|
|
46
47
|
/** Scope-local catalog entries may be known before they are activated. */
|
|
47
48
|
private readonly knownDynamicToolNames;
|
|
49
|
+
/**
|
|
50
|
+
* The session's model policy, which is what the fixed-model lockdown holds
|
|
51
|
+
* the chat to. Without a resolver the deployment pair is the whole of it —
|
|
52
|
+
* the answer a stand that keeps roles elsewhere still gets.
|
|
53
|
+
*/
|
|
54
|
+
private readonly modelPolicy?;
|
|
48
55
|
private readonly appliedPolicies;
|
|
49
56
|
/** Host-trusted principal-scoped plugin tools enabled outside static config. */
|
|
50
57
|
private readonly principalScopedTools;
|
|
@@ -83,7 +90,13 @@ export declare class QaPolicyAdmission {
|
|
|
83
90
|
readonly id: string;
|
|
84
91
|
} | undefined, sessionId: string, agent: Agent) => Promise<QaResolvedSessionPolicy | undefined>) | undefined,
|
|
85
92
|
/** Scope-local catalog entries may be known before they are activated. */
|
|
86
|
-
knownDynamicToolNames?: () => readonly string[]
|
|
93
|
+
knownDynamicToolNames?: () => readonly string[],
|
|
94
|
+
/**
|
|
95
|
+
* The session's model policy, which is what the fixed-model lockdown holds
|
|
96
|
+
* the chat to. Without a resolver the deployment pair is the whole of it —
|
|
97
|
+
* the answer a stand that keeps roles elsewhere still gets.
|
|
98
|
+
*/
|
|
99
|
+
modelPolicy?: ((sessionId: string) => QaSessionModelPolicy) | undefined);
|
|
87
100
|
/**
|
|
88
101
|
* Add tools whose own executor resolves the QA principal server-side.
|
|
89
102
|
* Enabling the contributing plugin is the operator decision; model arguments
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Context } from "@deepseek-ai/cordis";
|
|
2
|
+
import type { SessionId } from "@deepseek-ai/dsh-session/types";
|
|
3
|
+
import type { PluginLogger } from "@yadsh/dsh-plugin-log";
|
|
4
|
+
import { type QaSessionModelPolicy } from "./access/model-policy.js";
|
|
5
|
+
import type { QaModelPair } from "./types.js";
|
|
6
|
+
/**
|
|
7
|
+
* Put one fresh session on the pair its model policy names.
|
|
8
|
+
*
|
|
9
|
+
* The check runs here rather than after the selection because the Host answers
|
|
10
|
+
* an unknown model by failing the first question of the chat, in words that
|
|
11
|
+
* name neither the pair nor the policy it came from. Refusing at the door keeps
|
|
12
|
+
* the chat uncreated and the operator's journal on the same line as the reason.
|
|
13
|
+
*
|
|
14
|
+
* Absent pair means no layer of the policy spoke: the session keeps whatever
|
|
15
|
+
* the Host's own default composition gives it.
|
|
16
|
+
*
|
|
17
|
+
* @param ctx - the Host context, for the model catalog and the selection.
|
|
18
|
+
* @param sessionId - the session the Host just created.
|
|
19
|
+
* @param policy - the resolved policy of this session.
|
|
20
|
+
* @param logger - where the applied pair is recorded, with its layer.
|
|
21
|
+
* @returns the pair the session was put on, or `undefined` when none applied.
|
|
22
|
+
*/
|
|
23
|
+
export declare function applySessionModelPolicy(ctx: Context, sessionId: SessionId, policy: QaSessionModelPolicy, logger: PluginLogger): Promise<QaModelPair | undefined>;
|
|
24
|
+
//# sourceMappingURL=session-model.d.ts.map
|
package/lib/types/types.d.ts
CHANGED
|
@@ -173,6 +173,16 @@ export interface QaSkillActivationRecord {
|
|
|
173
173
|
readonly deniedTools: readonly string[];
|
|
174
174
|
readonly reason?: string;
|
|
175
175
|
}
|
|
176
|
+
/**
|
|
177
|
+
* One provider and model pair, fixed by policy rather than chosen in the
|
|
178
|
+
* interface. `provider` and `model` are named together or not at all, because
|
|
179
|
+
* the Host refuses either of them alone.
|
|
180
|
+
*/
|
|
181
|
+
export interface QaModelPair {
|
|
182
|
+
readonly provider: string;
|
|
183
|
+
readonly model: string;
|
|
184
|
+
readonly reasoningEffort?: string;
|
|
185
|
+
}
|
|
176
186
|
/** One agent capability profile. It never grants administrative access. */
|
|
177
187
|
export interface QaSubrole {
|
|
178
188
|
readonly id: string;
|
|
@@ -180,6 +190,12 @@ export interface QaSubrole {
|
|
|
180
190
|
readonly description?: string;
|
|
181
191
|
readonly enabled: boolean;
|
|
182
192
|
readonly capabilities: QaCapabilitySelection;
|
|
193
|
+
/**
|
|
194
|
+
* The pair every chat of this role is opened on, whatever the visitor picks
|
|
195
|
+
* in the interface. Absent means the role keeps no opinion and the
|
|
196
|
+
* deployment's pair serves it.
|
|
197
|
+
*/
|
|
198
|
+
readonly model?: QaModelPair;
|
|
183
199
|
readonly ui?: {
|
|
184
200
|
readonly icon?: string;
|
|
185
201
|
readonly accent?: string;
|
|
@@ -193,10 +209,29 @@ export interface QaCapabilityConfig {
|
|
|
193
209
|
/** Administrator assignments layered over what each skill declares. */
|
|
194
210
|
readonly skillOverrides: readonly QaSkillAssignmentOverride[];
|
|
195
211
|
}
|
|
212
|
+
/**
|
|
213
|
+
* One pair the Host can serve right now, as the administration surface lists
|
|
214
|
+
* it. A projection of the harness catalog, so the browser never learns the
|
|
215
|
+
* provider's own catalog shape and a policy can only be written by picking one
|
|
216
|
+
* of these.
|
|
217
|
+
*/
|
|
218
|
+
export interface QaModelCatalogEntry {
|
|
219
|
+
readonly provider: string;
|
|
220
|
+
readonly model: string;
|
|
221
|
+
/** The catalog's display name for the model, or its id when it has none. */
|
|
222
|
+
readonly label: string;
|
|
223
|
+
readonly reasoningEfforts: readonly string[];
|
|
224
|
+
}
|
|
196
225
|
/** The QA profiles one account may choose, independently of its access role. */
|
|
197
226
|
export interface QaUserAccess {
|
|
198
227
|
readonly allowedSubroles: readonly string[];
|
|
199
228
|
readonly defaultSubrole: string;
|
|
229
|
+
/**
|
|
230
|
+
* The pair this account is opened on, ahead of what its role says: a support
|
|
231
|
+
* desk runs on the local model even when it borrows a role the rest of the
|
|
232
|
+
* deployment shares. Absent means the account keeps no opinion.
|
|
233
|
+
*/
|
|
234
|
+
readonly model?: QaModelPair;
|
|
200
235
|
}
|
|
201
236
|
export type QaCapabilitySourceKind = "core" | "plugin" | "mcp" | "filesystem" | "runtime";
|
|
202
237
|
/** One capability currently installed, or retained as a missing selection. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yadsh/dsh-qa-surface",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.6",
|
|
4
4
|
"description": "A focused end-user QA surface backed by native DeepSeek Harness sessions",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -137,9 +137,9 @@
|
|
|
137
137
|
"zod": "^4.4.3",
|
|
138
138
|
"@yadsh/dsh-audit-ui": "^0.1.2",
|
|
139
139
|
"@yadsh/dsh-audit-core": "^0.1.1",
|
|
140
|
-
"@yadsh/dsh-plugin-kit": "^0.5.0",
|
|
141
140
|
"@yadsh/dsh-plugin-log": "^0.4.1",
|
|
142
|
-
"@yadsh/dsh-
|
|
141
|
+
"@yadsh/dsh-plugin-kit": "^0.5.0",
|
|
142
|
+
"@yadsh/dsh-documents": "^0.6.3"
|
|
143
143
|
},
|
|
144
144
|
"devDependencies": {
|
|
145
145
|
"@deepseek-ai/cordis": "4.0.4",
|