@contractspec/example.policy-safe-knowledge-assistant 3.7.5 → 3.7.7

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.
@@ -1,229 +1,229 @@
1
1
  'use client';
2
2
 
3
- import { useCallback, useEffect, useMemo, useState } from 'react';
4
3
  import { useTemplateRuntime } from '@contractspec/lib.example-shared-ui';
4
+ import { useCallback, useEffect, useMemo, useState } from 'react';
5
5
 
6
6
  type AllowedScope = 'education_only' | 'generic_info' | 'escalation_required';
7
7
  type RiskLevel = 'low' | 'medium' | 'high';
8
8
 
9
9
  export interface UsePolicySafeKnowledgeAssistantState {
10
- context: {
11
- locale: string;
12
- jurisdiction: string;
13
- allowedScope: AllowedScope;
14
- kbSnapshotId: string | null;
15
- } | null;
16
- loading: boolean;
17
- error: Error | null;
18
- lastAnswer: {
19
- refused?: boolean;
20
- refusalReason?: string;
21
- sections: { heading: string; body: string }[];
22
- citations: {
23
- kbSnapshotId: string;
24
- sourceId: string;
25
- excerpt?: string;
26
- }[];
27
- } | null;
28
- lastRuleId: string | null;
29
- lastRuleVersionId: string | null;
30
- lastSnapshotId: string | null;
31
- lastReviewTaskId: string | null;
10
+ context: {
11
+ locale: string;
12
+ jurisdiction: string;
13
+ allowedScope: AllowedScope;
14
+ kbSnapshotId: string | null;
15
+ } | null;
16
+ loading: boolean;
17
+ error: Error | null;
18
+ lastAnswer: {
19
+ refused?: boolean;
20
+ refusalReason?: string;
21
+ sections: { heading: string; body: string }[];
22
+ citations: {
23
+ kbSnapshotId: string;
24
+ sourceId: string;
25
+ excerpt?: string;
26
+ }[];
27
+ } | null;
28
+ lastRuleId: string | null;
29
+ lastRuleVersionId: string | null;
30
+ lastSnapshotId: string | null;
31
+ lastReviewTaskId: string | null;
32
32
  }
33
33
 
34
34
  interface CitationLike {
35
- kbSnapshotId: string;
36
- sourceId: string;
37
- excerpt?: string;
35
+ kbSnapshotId: string;
36
+ sourceId: string;
37
+ excerpt?: string;
38
38
  }
39
39
  interface AnswerLike {
40
- refused?: boolean;
41
- refusalReason?: string;
42
- sections: { heading: string; body: string }[];
43
- citations: CitationLike[];
40
+ refused?: boolean;
41
+ refusalReason?: string;
42
+ sections: { heading: string; body: string }[];
43
+ citations: CitationLike[];
44
44
  }
45
45
 
46
46
  function isCitationLike(value: unknown): value is CitationLike {
47
- if (!value || typeof value !== 'object') return false;
48
- const v = value as Record<string, unknown>;
49
- return typeof v.kbSnapshotId === 'string' && typeof v.sourceId === 'string';
47
+ if (!value || typeof value !== 'object') return false;
48
+ const v = value as Record<string, unknown>;
49
+ return typeof v.kbSnapshotId === 'string' && typeof v.sourceId === 'string';
50
50
  }
51
51
 
52
52
  function toCitations(value: unknown): CitationLike[] {
53
- if (!Array.isArray(value)) return [];
54
- return value.filter(isCitationLike).map((c) => ({
55
- kbSnapshotId: c.kbSnapshotId,
56
- sourceId: c.sourceId,
57
- excerpt: c.excerpt,
58
- }));
53
+ if (!Array.isArray(value)) return [];
54
+ return value.filter(isCitationLike).map((c) => ({
55
+ kbSnapshotId: c.kbSnapshotId,
56
+ sourceId: c.sourceId,
57
+ excerpt: c.excerpt,
58
+ }));
59
59
  }
60
60
 
61
61
  import type { PolicySafeKnowledgeAssistantHandlers } from '../../handlers/policy-safe-knowledge-assistant.handlers';
62
62
 
63
63
  export function usePolicySafeKnowledgeAssistant() {
64
- const { handlers, projectId } = useTemplateRuntime<{
65
- policySafeKnowledgeAssistant: PolicySafeKnowledgeAssistantHandlers;
66
- }>();
67
- const api = handlers.policySafeKnowledgeAssistant;
68
-
69
- const [state, setState] = useState<UsePolicySafeKnowledgeAssistantState>({
70
- context: null,
71
- loading: true,
72
- error: null,
73
- lastAnswer: null,
74
- lastRuleId: null,
75
- lastRuleVersionId: null,
76
- lastSnapshotId: null,
77
- lastReviewTaskId: null,
78
- });
79
-
80
- const refreshContext = useCallback(async () => {
81
- try {
82
- setState((s) => ({ ...s, loading: true, error: null }));
83
- const ctx = await api.getUserContext({ projectId });
84
- setState((s) => ({
85
- ...s,
86
- context: {
87
- locale: ctx.locale,
88
- jurisdiction: ctx.jurisdiction,
89
- allowedScope: ctx.allowedScope,
90
- kbSnapshotId: ctx.kbSnapshotId,
91
- },
92
- loading: false,
93
- }));
94
- } catch (e) {
95
- setState((s) => ({
96
- ...s,
97
- loading: false,
98
- error: e instanceof Error ? e : new Error('Unknown error'),
99
- }));
100
- }
101
- }, [api, projectId]);
102
-
103
- useEffect(() => {
104
- refreshContext();
105
- }, [refreshContext]);
106
-
107
- const setContext = useCallback(
108
- async (input: {
109
- locale: string;
110
- jurisdiction: string;
111
- allowedScope: AllowedScope;
112
- }) => {
113
- const ctx = await api.setUserContext({ projectId, ...input });
114
- setState((s) => ({
115
- ...s,
116
- context: {
117
- locale: ctx.locale,
118
- jurisdiction: ctx.jurisdiction,
119
- allowedScope: ctx.allowedScope,
120
- kbSnapshotId: ctx.kbSnapshotId,
121
- },
122
- }));
123
- },
124
- [api, projectId]
125
- );
126
-
127
- const askAssistant = useCallback(
128
- async (question: string) => {
129
- const answerUnknown: unknown = await api.answer({ projectId, question });
130
- const answer = answerUnknown as AnswerLike;
131
- setState((s) => ({
132
- ...s,
133
- lastAnswer: {
134
- refused: answer.refused,
135
- refusalReason: answer.refusalReason,
136
- sections: answer.sections,
137
- citations: toCitations(
138
- (answerUnknown as { citations?: unknown }).citations
139
- ),
140
- },
141
- }));
142
- },
143
- [api, projectId]
144
- );
145
-
146
- const createDemoRule = useCallback(async () => {
147
- const rule = await api.createRule({
148
- projectId,
149
- jurisdiction: state.context?.jurisdiction ?? 'EU',
150
- topicKey: 'tax_reporting',
151
- });
152
- setState((s) => ({ ...s, lastRuleId: rule.id }));
153
- return rule.id as string;
154
- }, [api, projectId, state.context?.jurisdiction]);
155
-
156
- const upsertRuleVersion = useCallback(
157
- async (input: { ruleId: string; content: string }) => {
158
- const rv = await api.upsertRuleVersion({
159
- projectId,
160
- ruleId: input.ruleId,
161
- content: input.content,
162
- sourceRefs: [{ sourceDocumentId: 'src_demo', excerpt: 'demo excerpt' }],
163
- });
164
- setState((s) => ({ ...s, lastRuleVersionId: rv.id }));
165
- return rv.id as string;
166
- },
167
- [api, projectId]
168
- );
169
-
170
- const approveRuleVersion = useCallback(
171
- async (ruleVersionId: string) => {
172
- await api.approveRuleVersion({ ruleVersionId, approver: 'demo_expert' });
173
- },
174
- [api]
175
- );
176
-
177
- const publishSnapshot = useCallback(async () => {
178
- const snap = await api.publishSnapshot({
179
- projectId,
180
- jurisdiction: state.context?.jurisdiction ?? 'EU',
181
- asOfDate: new Date('2026-02-01T00:00:00.000Z'),
182
- });
183
- setState((s) => ({ ...s, lastSnapshotId: snap.id }));
184
- await refreshContext();
185
- return snap.id as string;
186
- }, [api, projectId, refreshContext, state.context?.jurisdiction]);
187
-
188
- const simulateHighRiskChangeAndApprove = useCallback(
189
- async (ruleVersionId: string) => {
190
- const cand = await api.createChangeCandidate({
191
- projectId,
192
- jurisdiction: state.context?.jurisdiction ?? 'EU',
193
- diffSummary: 'Simulated change (demo)',
194
- riskLevel: 'high' satisfies RiskLevel,
195
- proposedRuleVersionIds: [ruleVersionId],
196
- });
197
- const review = await api.createReviewTask({ changeCandidateId: cand.id });
198
- setState((s) => ({ ...s, lastReviewTaskId: review.id }));
199
- await api.submitDecision({
200
- reviewTaskId: review.id,
201
- decision: 'approve',
202
- decidedByRole: 'expert',
203
- decidedBy: 'demo_expert',
204
- });
205
- await api.publishIfReady({
206
- jurisdiction: state.context?.jurisdiction ?? 'EU',
207
- });
208
- return review.id as string;
209
- },
210
- [api, projectId, state.context?.jurisdiction]
211
- );
212
-
213
- const derived = useMemo(() => ({ projectId }), [projectId]);
214
-
215
- return {
216
- state,
217
- derived,
218
- actions: {
219
- refreshContext,
220
- setContext,
221
- askAssistant,
222
- createDemoRule,
223
- upsertRuleVersion,
224
- approveRuleVersion,
225
- publishSnapshot,
226
- simulateHighRiskChangeAndApprove,
227
- },
228
- };
64
+ const { handlers, projectId } = useTemplateRuntime<{
65
+ policySafeKnowledgeAssistant: PolicySafeKnowledgeAssistantHandlers;
66
+ }>();
67
+ const api = handlers.policySafeKnowledgeAssistant;
68
+
69
+ const [state, setState] = useState<UsePolicySafeKnowledgeAssistantState>({
70
+ context: null,
71
+ loading: true,
72
+ error: null,
73
+ lastAnswer: null,
74
+ lastRuleId: null,
75
+ lastRuleVersionId: null,
76
+ lastSnapshotId: null,
77
+ lastReviewTaskId: null,
78
+ });
79
+
80
+ const refreshContext = useCallback(async () => {
81
+ try {
82
+ setState((s) => ({ ...s, loading: true, error: null }));
83
+ const ctx = await api.getUserContext({ projectId });
84
+ setState((s) => ({
85
+ ...s,
86
+ context: {
87
+ locale: ctx.locale,
88
+ jurisdiction: ctx.jurisdiction,
89
+ allowedScope: ctx.allowedScope,
90
+ kbSnapshotId: ctx.kbSnapshotId,
91
+ },
92
+ loading: false,
93
+ }));
94
+ } catch (e) {
95
+ setState((s) => ({
96
+ ...s,
97
+ loading: false,
98
+ error: e instanceof Error ? e : new Error('Unknown error'),
99
+ }));
100
+ }
101
+ }, [api, projectId]);
102
+
103
+ useEffect(() => {
104
+ refreshContext();
105
+ }, [refreshContext]);
106
+
107
+ const setContext = useCallback(
108
+ async (input: {
109
+ locale: string;
110
+ jurisdiction: string;
111
+ allowedScope: AllowedScope;
112
+ }) => {
113
+ const ctx = await api.setUserContext({ projectId, ...input });
114
+ setState((s) => ({
115
+ ...s,
116
+ context: {
117
+ locale: ctx.locale,
118
+ jurisdiction: ctx.jurisdiction,
119
+ allowedScope: ctx.allowedScope,
120
+ kbSnapshotId: ctx.kbSnapshotId,
121
+ },
122
+ }));
123
+ },
124
+ [api, projectId]
125
+ );
126
+
127
+ const askAssistant = useCallback(
128
+ async (question: string) => {
129
+ const answerUnknown: unknown = await api.answer({ projectId, question });
130
+ const answer = answerUnknown as AnswerLike;
131
+ setState((s) => ({
132
+ ...s,
133
+ lastAnswer: {
134
+ refused: answer.refused,
135
+ refusalReason: answer.refusalReason,
136
+ sections: answer.sections,
137
+ citations: toCitations(
138
+ (answerUnknown as { citations?: unknown }).citations
139
+ ),
140
+ },
141
+ }));
142
+ },
143
+ [api, projectId]
144
+ );
145
+
146
+ const createDemoRule = useCallback(async () => {
147
+ const rule = await api.createRule({
148
+ projectId,
149
+ jurisdiction: state.context?.jurisdiction ?? 'EU',
150
+ topicKey: 'tax_reporting',
151
+ });
152
+ setState((s) => ({ ...s, lastRuleId: rule.id }));
153
+ return rule.id as string;
154
+ }, [api, projectId, state.context?.jurisdiction]);
155
+
156
+ const upsertRuleVersion = useCallback(
157
+ async (input: { ruleId: string; content: string }) => {
158
+ const rv = await api.upsertRuleVersion({
159
+ projectId,
160
+ ruleId: input.ruleId,
161
+ content: input.content,
162
+ sourceRefs: [{ sourceDocumentId: 'src_demo', excerpt: 'demo excerpt' }],
163
+ });
164
+ setState((s) => ({ ...s, lastRuleVersionId: rv.id }));
165
+ return rv.id as string;
166
+ },
167
+ [api, projectId]
168
+ );
169
+
170
+ const approveRuleVersion = useCallback(
171
+ async (ruleVersionId: string) => {
172
+ await api.approveRuleVersion({ ruleVersionId, approver: 'demo_expert' });
173
+ },
174
+ [api]
175
+ );
176
+
177
+ const publishSnapshot = useCallback(async () => {
178
+ const snap = await api.publishSnapshot({
179
+ projectId,
180
+ jurisdiction: state.context?.jurisdiction ?? 'EU',
181
+ asOfDate: new Date('2026-02-01T00:00:00.000Z'),
182
+ });
183
+ setState((s) => ({ ...s, lastSnapshotId: snap.id }));
184
+ await refreshContext();
185
+ return snap.id as string;
186
+ }, [api, projectId, refreshContext, state.context?.jurisdiction]);
187
+
188
+ const simulateHighRiskChangeAndApprove = useCallback(
189
+ async (ruleVersionId: string) => {
190
+ const cand = await api.createChangeCandidate({
191
+ projectId,
192
+ jurisdiction: state.context?.jurisdiction ?? 'EU',
193
+ diffSummary: 'Simulated change (demo)',
194
+ riskLevel: 'high' satisfies RiskLevel,
195
+ proposedRuleVersionIds: [ruleVersionId],
196
+ });
197
+ const review = await api.createReviewTask({ changeCandidateId: cand.id });
198
+ setState((s) => ({ ...s, lastReviewTaskId: review.id }));
199
+ await api.submitDecision({
200
+ reviewTaskId: review.id,
201
+ decision: 'approve',
202
+ decidedByRole: 'expert',
203
+ decidedBy: 'demo_expert',
204
+ });
205
+ await api.publishIfReady({
206
+ jurisdiction: state.context?.jurisdiction ?? 'EU',
207
+ });
208
+ return review.id as string;
209
+ },
210
+ [api, projectId, state.context?.jurisdiction]
211
+ );
212
+
213
+ const derived = useMemo(() => ({ projectId }), [projectId]);
214
+
215
+ return {
216
+ state,
217
+ derived,
218
+ actions: {
219
+ refreshContext,
220
+ setContext,
221
+ askAssistant,
222
+ createDemoRule,
223
+ upsertRuleVersion,
224
+ approveRuleVersion,
225
+ publishSnapshot,
226
+ simulateHighRiskChangeAndApprove,
227
+ },
228
+ };
229
229
  }
package/tsconfig.json CHANGED
@@ -1,19 +1,9 @@
1
1
  {
2
- "extends": "@contractspec/tool.typescript/react-library.json",
3
- "compilerOptions": {
4
- "outDir": "./dist",
5
- "rootDir": "./src"
6
- },
7
- "include": ["src/**/*"],
8
- "exclude": ["node_modules", "dist"]
2
+ "extends": "@contractspec/tool.typescript/react-library.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "rootDir": "./src"
6
+ },
7
+ "include": ["src/**/*"],
8
+ "exclude": ["node_modules", "dist"]
9
9
  }
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
package/tsdown.config.js CHANGED
@@ -1,16 +1,10 @@
1
- import { defineConfig, moduleLibrary, withDevExports } from '@contractspec/tool.bun';
1
+ import {
2
+ defineConfig,
3
+ moduleLibrary,
4
+ withDevExports,
5
+ } from '@contractspec/tool.bun';
2
6
 
3
7
  export default defineConfig(() => ({
4
- ...moduleLibrary,
5
- ...withDevExports,
8
+ ...moduleLibrary,
9
+ ...withDevExports,
6
10
  }));
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-