Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
133 lines
4.8 KiB
TypeScript
133 lines
4.8 KiB
TypeScript
import { sdk } from '../sdk'
|
|
import { configFile } from '../file-models/config'
|
|
|
|
const { InputSpec, Value } = sdk
|
|
|
|
const inputSpec = InputSpec.of({
|
|
reviewInstructions: Value.textarea({
|
|
name: 'Review Rubric',
|
|
description:
|
|
'What every reviewer should look for and produce. Layered above each ' +
|
|
'reviewer\'s persona. Be concrete about the structure you want back.',
|
|
required: true,
|
|
default: null,
|
|
minRows: 5,
|
|
maxRows: 20,
|
|
placeholder:
|
|
'Review the attached document(s). Produce: a short summary, key findings, ' +
|
|
'risks/red flags, open questions, and recommendations. Cite the document and ' +
|
|
'section for each point. Never invent facts not present in the documents.',
|
|
}),
|
|
networkMode: Value.select({
|
|
name: 'Network Mode',
|
|
description:
|
|
'Air-gapped: reviewers reach ONLY the on-Spark model proxy — zero internet, ' +
|
|
'documents never leave your hardware (models must be pre-pulled into the ' +
|
|
'Spark HF cache, all on the head Spark). Local services: reviewers may also ' +
|
|
'reach LAN services like SearXNG and the second Spark (this network has ' +
|
|
'egress unless you firewall it).',
|
|
default: 'airgapped',
|
|
values: {
|
|
airgapped: 'Air-gapped (no network, recommended)',
|
|
local_services: 'Local services (SearXNG / 2nd Spark)',
|
|
},
|
|
}),
|
|
searxngUrl: Value.text({
|
|
name: 'SearXNG URL (local-services only)',
|
|
description: 'JSON-search endpoint to give reviewers a web_search tool. Ignored in air-gapped mode. Empty = no web search.',
|
|
required: false,
|
|
default: null,
|
|
placeholder: 'https://searxng.local',
|
|
}),
|
|
synthesisEnabled: Value.toggle({
|
|
name: 'Synthesize a Consolidated Report',
|
|
description:
|
|
'After the panel finishes, run a local "lead reviewer" that reads all the ' +
|
|
'individual reports and writes one consolidated report (themes, conflicts, ' +
|
|
'consensus, recommendation). No frontier model — stays on the Sparks.',
|
|
default: true,
|
|
}),
|
|
synthesisModel: Value.text({
|
|
name: 'Lead Reviewer Model (optional)',
|
|
description: 'Catalog alias of the model that writes the consolidated report. Empty = use the first model.',
|
|
required: false,
|
|
default: null,
|
|
placeholder: 'reviewer-a',
|
|
}),
|
|
synthesisPersona: Value.textarea({
|
|
name: 'Lead Reviewer Instructions (optional)',
|
|
description: 'Override how the consolidated report is written. Empty = a sensible built-in default.',
|
|
required: false,
|
|
default: null,
|
|
minRows: 3,
|
|
maxRows: 14,
|
|
}),
|
|
wipeRemoteDocs: Value.toggle({
|
|
name: 'Wipe Documents From Sparks After Review',
|
|
description:
|
|
'Delete the extracted document text from the Sparks when a job finishes. ' +
|
|
'Reports are always kept on this StartOS box. Recommended for confidential material.',
|
|
default: true,
|
|
}),
|
|
autoRunOnDrop: Value.toggle({
|
|
name: 'Auto-run When Documents Are Dropped',
|
|
description:
|
|
'Start a review automatically (after a short debounce) whenever new files ' +
|
|
'land in the inbox. Off by default so you trigger reviews explicitly.',
|
|
default: false,
|
|
}),
|
|
})
|
|
|
|
export const configureReview = sdk.Action.withInput(
|
|
'configure-review',
|
|
|
|
async ({ effects }) => ({
|
|
name: 'Configure Review',
|
|
description: 'Set the rubric, air-gap mode, synthesis, and document retention.',
|
|
warning: null,
|
|
allowedStatuses: 'any',
|
|
group: null,
|
|
visibility: 'enabled',
|
|
}),
|
|
|
|
inputSpec,
|
|
|
|
async ({ effects }) => {
|
|
const cfg = await configFile.read().const(effects)
|
|
if (!cfg) return {}
|
|
return {
|
|
reviewInstructions: cfg.reviewInstructions,
|
|
networkMode: cfg.networkMode,
|
|
searxngUrl: cfg.searxngUrl || undefined,
|
|
synthesisEnabled: cfg.synthesisEnabled,
|
|
synthesisModel: cfg.synthesisModel || undefined,
|
|
synthesisPersona: cfg.synthesisPersona || undefined,
|
|
wipeRemoteDocs: cfg.wipeRemoteDocs,
|
|
autoRunOnDrop: cfg.autoRunOnDrop,
|
|
}
|
|
},
|
|
|
|
async ({ effects, input }) => {
|
|
await configFile.merge(effects, {
|
|
reviewInstructions: input.reviewInstructions,
|
|
networkMode: input.networkMode,
|
|
searxngUrl: input.searxngUrl ?? '',
|
|
synthesisEnabled: input.synthesisEnabled,
|
|
synthesisModel: input.synthesisModel ?? '',
|
|
synthesisPersona: input.synthesisPersona ?? '',
|
|
wipeRemoteDocs: input.wipeRemoteDocs,
|
|
autoRunOnDrop: input.autoRunOnDrop,
|
|
})
|
|
|
|
return {
|
|
version: '1',
|
|
title: 'Review Settings Saved',
|
|
message:
|
|
input.networkMode === 'airgapped'
|
|
? 'Saved. Reviewers will run air-gapped (no internet). Ensure all models are on the head Spark and pre-pulled into its HF cache.'
|
|
: 'Saved. Reviewers run in local-services mode and may reach the network — make sure that is acceptable for these documents.',
|
|
result: { type: 'single', value: input.networkMode, copyable: false, qr: false, masked: false },
|
|
}
|
|
},
|
|
)
|