Skip to content

Commit 9d39684

Browse files
author
Peter Kumberger
committed
Improve system prompt to find redaction suggestions
1 parent 1a98c9a commit 9d39684

3 files changed

Lines changed: 28 additions & 9 deletions

File tree

src/lib/chat-tools.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,8 @@ export function executeAskUser(args: Record<string, unknown>): { special: Specia
148148
}
149149
}
150150

151-
export function executeSuggestRedactions(args: Record<string, unknown>): { special: SpecialToolResult; toolResult: ToolResult } {
152-
const raw = args.suggestions as Array<Record<string, unknown>>
151+
export function executeSuggestRedactions(args: Record<string, unknown>): { special: SpecialToolResult | null; toolResult: ToolResult } {
152+
const raw = (args.suggestions as Array<Record<string, unknown>> | undefined) ?? []
153153
const suggestions: RedactionSuggestion[] = raw.map(s => ({
154154
documentKey: s.documentKey as string | undefined,
155155
text: s.text as string,
@@ -184,6 +184,18 @@ export function executeSuggestRedactions(args: Record<string, unknown>): { speci
184184
}))
185185
const remove = (args.remove as string[] | undefined) ?? []
186186
const total = suggestions.length + textRanges.length + pageRanges.length
187+
// An empty call is always a protocol error: a document with nothing to redact
188+
// is reported in prose instead of through this tool, so reaching here means
189+
// the arguments failed to serialise rather than that the document is clean.
190+
if (total === 0 && remove.length === 0) {
191+
return {
192+
special: null,
193+
toolResult: {
194+
success: false,
195+
error: 'This call carried no arguments, so nothing was applied. If the document genuinely contains nothing to redact, do not call this tool at all — say so in your reply instead. If you did intend to suggest redactions, repeat the call with "suggestions" (or "textRanges"/"pageRanges") populated; each entry needs documentKey, the exact text copied from the read_documents response, pageIndex, confidence, person and personGroup.',
196+
},
197+
}
198+
}
187199
return {
188200
special: { type: 'suggest_redactions', suggestions, textRanges, pageRanges, remove },
189201
toolResult: { success: true, data: `${total} Vorschläge hinzugefügt (${suggestions.length} Textstellen, ${textRanges.length} Textbereiche, ${pageRanges.length} Seitenbereiche), ${remove.length} entfernt.` },

src/lib/system-prompt.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,20 @@ export function buildSystemPrompt(opts: {
1818
}): string {
1919
const { redactionMode, foiJurisdiction, foiRules, locale } = opts
2020

21+
// `reason` is often just a restatement of `title` (e.g. "Personenbezogene Daten"),
22+
// so the statutory text carries the criteria the model actually needs to apply.
23+
const formatRule = (r: RedactionRule) => {
24+
const summary = r.reason && r.reason !== r.title ? r.reason : undefined
25+
const heading = `- **${r.title}**${r.reference ? ` (${r.reference})` : ''}${summary ? `: ${summary}` : ''}`
26+
const detail = r.full_text?.replace(/\s*\n+\s*/g, ' ').trim()
27+
return detail ? `${heading}\n ${detail}` : heading
28+
}
29+
2130
const foiSection = redactionMode === 'foi'
2231
? [
2332
'## FOI Mode',
2433
`Legal basis: ${foiJurisdiction ?? 'not selected'}`,
25-
foiRules?.length
26-
? foiRules.map(r => `- **${r.title}** (${r.reference ?? ''}): ${r.reason ?? r.full_text ?? ''}`).join('\n')
27-
: '',
34+
foiRules?.length ? foiRules.map(formatRule).join('\n') : '',
2835
].join('\n')
2936
: ''
3037

@@ -84,6 +91,8 @@ export function buildSystemPrompt(opts: {
8491
'',
8592
'Use "low" ONLY for genuinely ambiguous individual cases in the document, not as a blanket rating.',
8693
'',
94+
'If the document genuinely contains nothing that needs redacting, do NOT call `suggest_redactions` with empty arguments — say so in your reply instead.',
95+
'',
8796
'## Tool discipline',
8897
'',
8998
'- Execute **only one tool call** per response.',

src/middleware.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@ import { routing } from './i18n/routing'
44
export default createMiddleware(routing)
55

66
export const config = {
7-
// The `matcher` is relative to the `basePath`. The explicit '/' entry is
8-
// required so the middleware fires on the base-path root (e.g. `/easyredact/`);
9-
// Next.js does not trigger middleware on the root when a `basePath` is set and
10-
// the matcher uses a negative-lookahead regex. See vercel/next.js#50161.
7+
// Next.js skips the middleware on the base-path root when the matcher is a
8+
// negative-lookahead regex, so '/' has to be listed explicitly.
119
matcher: ['/', '/((?!api|_next|_vercel|.*\\..*).*)'],
1210
}

0 commit comments

Comments
 (0)