@oscharko-dev/keiko-contracts 0.2.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/dist/.tsbuildinfo +1 -0
- package/dist/bff-wire.d.ts +661 -0
- package/dist/bff-wire.d.ts.map +1 -0
- package/dist/bff-wire.js +102 -0
- package/dist/bug-investigation-events.d.ts +92 -0
- package/dist/bug-investigation-events.d.ts.map +1 -0
- package/dist/bug-investigation-events.js +18 -0
- package/dist/coding-context.d.ts +76 -0
- package/dist/coding-context.d.ts.map +1 -0
- package/dist/coding-context.js +158 -0
- package/dist/connected-context.d.ts +174 -0
- package/dist/connected-context.d.ts.map +1 -0
- package/dist/connected-context.js +636 -0
- package/dist/conversation-budget.d.ts +37 -0
- package/dist/conversation-budget.d.ts.map +1 -0
- package/dist/conversation-budget.js +97 -0
- package/dist/editor-agent.d.ts +131 -0
- package/dist/editor-agent.d.ts.map +1 -0
- package/dist/editor-agent.js +197 -0
- package/dist/editor-completion.d.ts +62 -0
- package/dist/editor-completion.d.ts.map +1 -0
- package/dist/editor-completion.js +147 -0
- package/dist/editor-dirty-close.d.ts +17 -0
- package/dist/editor-dirty-close.d.ts.map +1 -0
- package/dist/editor-dirty-close.js +8 -0
- package/dist/editor-hot-exit.d.ts +18 -0
- package/dist/editor-hot-exit.d.ts.map +1 -0
- package/dist/editor-hot-exit.js +42 -0
- package/dist/editor-inline-completion.d.ts +70 -0
- package/dist/editor-inline-completion.d.ts.map +1 -0
- package/dist/editor-inline-completion.js +215 -0
- package/dist/editor-layout.d.ts +105 -0
- package/dist/editor-layout.d.ts.map +1 -0
- package/dist/editor-layout.js +479 -0
- package/dist/editor-patch-apply.d.ts +77 -0
- package/dist/editor-patch-apply.d.ts.map +1 -0
- package/dist/editor-patch-apply.js +122 -0
- package/dist/editor-session.d.ts +31 -0
- package/dist/editor-session.d.ts.map +1 -0
- package/dist/editor-session.js +75 -0
- package/dist/editor-test-generation.d.ts +104 -0
- package/dist/editor-test-generation.d.ts.map +1 -0
- package/dist/editor-test-generation.js +211 -0
- package/dist/evaluations.d.ts +75 -0
- package/dist/evaluations.d.ts.map +1 -0
- package/dist/evaluations.js +16 -0
- package/dist/evidence.d.ts +297 -0
- package/dist/evidence.d.ts.map +1 -0
- package/dist/evidence.js +9 -0
- package/dist/gateway.d.ts +129 -0
- package/dist/gateway.d.ts.map +1 -0
- package/dist/gateway.js +66 -0
- package/dist/harness.d.ts +274 -0
- package/dist/harness.d.ts.map +1 -0
- package/dist/harness.js +38 -0
- package/dist/index.d.ts +101 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +83 -0
- package/dist/language-service.d.ts +145 -0
- package/dist/language-service.d.ts.map +1 -0
- package/dist/language-service.js +161 -0
- package/dist/local-knowledge-large-document-validation.d.ts +7 -0
- package/dist/local-knowledge-large-document-validation.d.ts.map +1 -0
- package/dist/local-knowledge-large-document-validation.js +161 -0
- package/dist/local-knowledge-large-document.d.ts +113 -0
- package/dist/local-knowledge-large-document.d.ts.map +1 -0
- package/dist/local-knowledge-large-document.js +142 -0
- package/dist/local-knowledge-paths.d.ts +3 -0
- package/dist/local-knowledge-paths.d.ts.map +1 -0
- package/dist/local-knowledge-paths.js +65 -0
- package/dist/local-knowledge-records.d.ts +190 -0
- package/dist/local-knowledge-records.d.ts.map +1 -0
- package/dist/local-knowledge-records.js +36 -0
- package/dist/local-knowledge-schema-validation.d.ts +19 -0
- package/dist/local-knowledge-schema-validation.d.ts.map +1 -0
- package/dist/local-knowledge-schema-validation.js +115 -0
- package/dist/local-knowledge-schema.d.ts +14 -0
- package/dist/local-knowledge-schema.d.ts.map +1 -0
- package/dist/local-knowledge-schema.js +715 -0
- package/dist/local-knowledge-validation.d.ts +20 -0
- package/dist/local-knowledge-validation.d.ts.map +1 -0
- package/dist/local-knowledge-validation.js +487 -0
- package/dist/local-knowledge.d.ts +158 -0
- package/dist/local-knowledge.d.ts.map +1 -0
- package/dist/local-knowledge.js +63 -0
- package/dist/memory-audit-events.d.ts +73 -0
- package/dist/memory-audit-events.d.ts.map +1 -0
- package/dist/memory-audit-events.js +44 -0
- package/dist/memory-audit-validation.d.ts +4 -0
- package/dist/memory-audit-validation.d.ts.map +1 -0
- package/dist/memory-audit-validation.js +151 -0
- package/dist/memory-barrel.d.ts +15 -0
- package/dist/memory-barrel.d.ts.map +1 -0
- package/dist/memory-barrel.js +20 -0
- package/dist/memory-internal.d.ts +26 -0
- package/dist/memory-internal.d.ts.map +1 -0
- package/dist/memory-internal.js +104 -0
- package/dist/memory-operations-validation.d.ts +12 -0
- package/dist/memory-operations-validation.d.ts.map +1 -0
- package/dist/memory-operations-validation.js +267 -0
- package/dist/memory-operations.d.ts +156 -0
- package/dist/memory-operations.d.ts.map +1 -0
- package/dist/memory-operations.js +29 -0
- package/dist/memory-record-validation.d.ts +10 -0
- package/dist/memory-record-validation.d.ts.map +1 -0
- package/dist/memory-record-validation.js +101 -0
- package/dist/memory-records.d.ts +66 -0
- package/dist/memory-records.d.ts.map +1 -0
- package/dist/memory-records.js +22 -0
- package/dist/memory-retrieval-validation.d.ts +6 -0
- package/dist/memory-retrieval-validation.d.ts.map +1 -0
- package/dist/memory-retrieval-validation.js +108 -0
- package/dist/memory-validation.d.ts +31 -0
- package/dist/memory-validation.d.ts.map +1 -0
- package/dist/memory-validation.js +318 -0
- package/dist/memory-workflow-port.d.ts +26 -0
- package/dist/memory-workflow-port.d.ts.map +1 -0
- package/dist/memory-workflow-port.js +13 -0
- package/dist/memory.d.ts +81 -0
- package/dist/memory.d.ts.map +1 -0
- package/dist/memory.js +104 -0
- package/dist/prompt-enhancer-analyzer.d.ts +7 -0
- package/dist/prompt-enhancer-analyzer.d.ts.map +1 -0
- package/dist/prompt-enhancer-analyzer.js +745 -0
- package/dist/prompt-enhancer-bff.d.ts +67 -0
- package/dist/prompt-enhancer-bff.d.ts.map +1 -0
- package/dist/prompt-enhancer-bff.js +156 -0
- package/dist/prompt-enhancer-critic.d.ts +46 -0
- package/dist/prompt-enhancer-critic.d.ts.map +1 -0
- package/dist/prompt-enhancer-critic.js +35 -0
- package/dist/prompt-enhancer-grounding.d.ts +19 -0
- package/dist/prompt-enhancer-grounding.d.ts.map +1 -0
- package/dist/prompt-enhancer-grounding.js +235 -0
- package/dist/prompt-enhancer-safety.d.ts +66 -0
- package/dist/prompt-enhancer-safety.d.ts.map +1 -0
- package/dist/prompt-enhancer-safety.js +446 -0
- package/dist/prompt-enhancer-validation.d.ts +28 -0
- package/dist/prompt-enhancer-validation.d.ts.map +1 -0
- package/dist/prompt-enhancer-validation.js +931 -0
- package/dist/prompt-enhancer.d.ts +184 -0
- package/dist/prompt-enhancer.d.ts.map +1 -0
- package/dist/prompt-enhancer.js +350 -0
- package/dist/qualityIntelligence/assertNever.d.ts +2 -0
- package/dist/qualityIntelligence/assertNever.d.ts.map +1 -0
- package/dist/qualityIntelligence/assertNever.js +7 -0
- package/dist/qualityIntelligence/auditSummary.d.ts +25 -0
- package/dist/qualityIntelligence/auditSummary.d.ts.map +1 -0
- package/dist/qualityIntelligence/auditSummary.js +7 -0
- package/dist/qualityIntelligence/bffWire.d.ts +356 -0
- package/dist/qualityIntelligence/bffWire.d.ts.map +1 -0
- package/dist/qualityIntelligence/bffWire.js +22 -0
- package/dist/qualityIntelligence/coverageMap.d.ts +21 -0
- package/dist/qualityIntelligence/coverageMap.d.ts.map +1 -0
- package/dist/qualityIntelligence/coverageMap.js +29 -0
- package/dist/qualityIntelligence/editableRevision.d.ts +21 -0
- package/dist/qualityIntelligence/editableRevision.d.ts.map +1 -0
- package/dist/qualityIntelligence/editableRevision.js +8 -0
- package/dist/qualityIntelligence/evidenceAtom.d.ts +35 -0
- package/dist/qualityIntelligence/evidenceAtom.d.ts.map +1 -0
- package/dist/qualityIntelligence/evidenceAtom.js +29 -0
- package/dist/qualityIntelligence/exportBundle.d.ts +28 -0
- package/dist/qualityIntelligence/exportBundle.d.ts.map +1 -0
- package/dist/qualityIntelligence/exportBundle.js +46 -0
- package/dist/qualityIntelligence/handoffEnvelope.d.ts +23 -0
- package/dist/qualityIntelligence/handoffEnvelope.d.ts.map +1 -0
- package/dist/qualityIntelligence/handoffEnvelope.js +8 -0
- package/dist/qualityIntelligence/ids.d.ts +58 -0
- package/dist/qualityIntelligence/ids.d.ts.map +1 -0
- package/dist/qualityIntelligence/ids.js +93 -0
- package/dist/qualityIntelligence/index.d.ts +29 -0
- package/dist/qualityIntelligence/index.d.ts.map +1 -0
- package/dist/qualityIntelligence/index.js +20 -0
- package/dist/qualityIntelligence/reviewRecord.d.ts +19 -0
- package/dist/qualityIntelligence/reviewRecord.d.ts.map +1 -0
- package/dist/qualityIntelligence/reviewRecord.js +20 -0
- package/dist/qualityIntelligence/runPlanAndEvents.d.ts +84 -0
- package/dist/qualityIntelligence/runPlanAndEvents.d.ts.map +1 -0
- package/dist/qualityIntelligence/runPlanAndEvents.js +51 -0
- package/dist/qualityIntelligence/sourceEnvelope.d.ts +77 -0
- package/dist/qualityIntelligence/sourceEnvelope.d.ts.map +1 -0
- package/dist/qualityIntelligence/sourceEnvelope.js +118 -0
- package/dist/qualityIntelligence/testCaseCandidate.d.ts +21 -0
- package/dist/qualityIntelligence/testCaseCandidate.d.ts.map +1 -0
- package/dist/qualityIntelligence/testCaseCandidate.js +21 -0
- package/dist/qualityIntelligence/testQualityRubric.d.ts +17 -0
- package/dist/qualityIntelligence/testQualityRubric.d.ts.map +1 -0
- package/dist/qualityIntelligence/testQualityRubric.js +32 -0
- package/dist/qualityIntelligence/validationFinding.d.ts +48 -0
- package/dist/qualityIntelligence/validationFinding.d.ts.map +1 -0
- package/dist/qualityIntelligence/validationFinding.js +36 -0
- package/dist/relationships-validation.d.ts +13 -0
- package/dist/relationships-validation.d.ts.map +1 -0
- package/dist/relationships-validation.js +422 -0
- package/dist/relationships.d.ts +79 -0
- package/dist/relationships.d.ts.map +1 -0
- package/dist/relationships.js +307 -0
- package/dist/text-safety.d.ts +7 -0
- package/dist/text-safety.d.ts.map +1 -0
- package/dist/text-safety.js +58 -0
- package/dist/tools.d.ts +153 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +118 -0
- package/dist/unit-test-events.d.ts +87 -0
- package/dist/unit-test-events.d.ts.map +1 -0
- package/dist/unit-test-events.js +14 -0
- package/dist/verification-summary.d.ts +38 -0
- package/dist/verification-summary.d.ts.map +1 -0
- package/dist/verification-summary.js +5 -0
- package/dist/verification.d.ts +64 -0
- package/dist/verification.d.ts.map +1 -0
- package/dist/verification.js +13 -0
- package/dist/workflow-descriptor.d.ts +21 -0
- package/dist/workflow-descriptor.d.ts.map +1 -0
- package/dist/workflow-descriptor.js +8 -0
- package/dist/workflow-handoff.d.ts +69 -0
- package/dist/workflow-handoff.d.ts.map +1 -0
- package/dist/workflow-handoff.js +381 -0
- package/dist/workspace-descriptors.d.ts +21 -0
- package/dist/workspace-descriptors.d.ts.map +1 -0
- package/dist/workspace-descriptors.js +180 -0
- package/dist/workspace-ui.d.ts +119 -0
- package/dist/workspace-ui.d.ts.map +1 -0
- package/dist/workspace-ui.js +105 -0
- package/dist/workspace.d.ts +104 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +27 -0
- package/package.json +71 -0
|
@@ -0,0 +1,745 @@
|
|
|
1
|
+
// Deterministic Prompt Enhancer analyzer (Issue #1309, ADR-0044 §3 / blueprint §2).
|
|
2
|
+
//
|
|
3
|
+
// `analyzePrompt` converts a raw, untrusted user draft into a normalized `PromptTaskAnalysis`
|
|
4
|
+
// WITHOUT any model call, IO, clock read, or randomness. Classification is rule-backed and
|
|
5
|
+
// explainable: every dimension is driven by a closed keyword/structure table, and every detector
|
|
6
|
+
// that fires is recorded in `signals` so the result is auditable and testable. No raw input text is
|
|
7
|
+
// echoed into the analysis — only bounded metadata (lengths) and fixed signal labels — keeping the
|
|
8
|
+
// output content-light and aligned with the safe-error discipline (ADR-0044 §5).
|
|
9
|
+
//
|
|
10
|
+
// Leaf-package rule (ADR-0019 direction 1): no `@oscharko-dev/keiko-*` imports. The module reuses the
|
|
11
|
+
// same-package `normalizePromptDraft` (which composes `stripUnsafeFormatChars`) for input hardening.
|
|
12
|
+
import { PROMPT_ENHANCER_SCHEMA_VERSION, PROMPT_MISSING_CONTEXT_MAX_CHARS, isSafetyCriticalDomain, normalizePromptDraft, } from "./prompt-enhancer.js";
|
|
13
|
+
const STOP_WORDS = new Set([
|
|
14
|
+
"the",
|
|
15
|
+
"a",
|
|
16
|
+
"an",
|
|
17
|
+
"and",
|
|
18
|
+
"or",
|
|
19
|
+
"but",
|
|
20
|
+
"to",
|
|
21
|
+
"of",
|
|
22
|
+
"in",
|
|
23
|
+
"on",
|
|
24
|
+
"for",
|
|
25
|
+
"with",
|
|
26
|
+
"is",
|
|
27
|
+
"are",
|
|
28
|
+
"this",
|
|
29
|
+
"that",
|
|
30
|
+
"it",
|
|
31
|
+
"please",
|
|
32
|
+
"can",
|
|
33
|
+
"you",
|
|
34
|
+
"me",
|
|
35
|
+
"my",
|
|
36
|
+
"i",
|
|
37
|
+
"do",
|
|
38
|
+
"how",
|
|
39
|
+
"what",
|
|
40
|
+
"why",
|
|
41
|
+
]);
|
|
42
|
+
function countMeaningfulTokens(lower) {
|
|
43
|
+
const tokens = lower.split(/[^\p{L}\p{N}]+/u).filter((t) => t.length > 0);
|
|
44
|
+
let count = 0;
|
|
45
|
+
for (const token of tokens) {
|
|
46
|
+
if (token.length >= 3 && !STOP_WORDS.has(token))
|
|
47
|
+
count += 1;
|
|
48
|
+
}
|
|
49
|
+
return count;
|
|
50
|
+
}
|
|
51
|
+
function buildView(normalized, request) {
|
|
52
|
+
const lower = normalized.toLowerCase();
|
|
53
|
+
return {
|
|
54
|
+
normalizedLength: normalized.length,
|
|
55
|
+
lower,
|
|
56
|
+
hasConnectedContext: request.input.hasConnectedContext === true || (request.input.attachmentCount ?? 0) > 0,
|
|
57
|
+
meaningfulTokenCount: countMeaningfulTokens(lower),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const containsAny = (haystack, needles) => needles.some((needle) => haystack.includes(needle));
|
|
61
|
+
const countMatches = (haystack, needles) => {
|
|
62
|
+
let count = 0;
|
|
63
|
+
for (const needle of needles) {
|
|
64
|
+
if (haystack.includes(needle))
|
|
65
|
+
count += 1;
|
|
66
|
+
}
|
|
67
|
+
return count;
|
|
68
|
+
};
|
|
69
|
+
const TASK_CLASS_RULES = [
|
|
70
|
+
{
|
|
71
|
+
taskClass: "prompt-optimization",
|
|
72
|
+
strong: [
|
|
73
|
+
"improve this prompt",
|
|
74
|
+
"optimize the prompt",
|
|
75
|
+
"rewrite the prompt",
|
|
76
|
+
"meta-prompt",
|
|
77
|
+
"system prompt for",
|
|
78
|
+
],
|
|
79
|
+
weak: ["prompt engineering", "better prompt", "prompt template"],
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
taskClass: "code-debugging",
|
|
83
|
+
strong: [
|
|
84
|
+
"debug",
|
|
85
|
+
"fix this bug",
|
|
86
|
+
"stack trace",
|
|
87
|
+
"traceback",
|
|
88
|
+
"why does this fail",
|
|
89
|
+
"not working",
|
|
90
|
+
],
|
|
91
|
+
weak: ["error", "exception", "throws", "undefined is not", "segfault"],
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
taskClass: "code-architecture",
|
|
95
|
+
strong: ["system design", "design the system", "software architecture", "architecture for"],
|
|
96
|
+
weak: ["scalable", "microservice", "design pattern", "trade-offs between", "high-level design"],
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
taskClass: "code-generation",
|
|
100
|
+
strong: [
|
|
101
|
+
"write a function",
|
|
102
|
+
"write code",
|
|
103
|
+
"implement a",
|
|
104
|
+
"generate code",
|
|
105
|
+
"write a script",
|
|
106
|
+
"create a class",
|
|
107
|
+
],
|
|
108
|
+
weak: [
|
|
109
|
+
"function that",
|
|
110
|
+
"function to",
|
|
111
|
+
"function for",
|
|
112
|
+
"code that",
|
|
113
|
+
"a method to",
|
|
114
|
+
"a class to",
|
|
115
|
+
"an algorithm",
|
|
116
|
+
"write a program",
|
|
117
|
+
"build an api",
|
|
118
|
+
"refactor",
|
|
119
|
+
"snippet",
|
|
120
|
+
],
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
taskClass: "structured-extraction",
|
|
124
|
+
strong: ["extract the", "parse the", "pull out the", "extract fields", "into json"],
|
|
125
|
+
weak: ["extract", "parse", "list all the", "structured output"],
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
taskClass: "summarization",
|
|
129
|
+
strong: ["summarize", "tl;dr", "tldr", "give me a summary", "condense"],
|
|
130
|
+
weak: ["summary", "key points", "in brief", "abstract of"],
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
taskClass: "data-analysis",
|
|
134
|
+
strong: [
|
|
135
|
+
"analyze this data",
|
|
136
|
+
"analyze the dataset",
|
|
137
|
+
"statistical analysis",
|
|
138
|
+
"correlation between",
|
|
139
|
+
],
|
|
140
|
+
weak: ["dataset", "regression", "aggregate", "pivot", "trend", "metrics"],
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
taskClass: "rag-question-answering",
|
|
144
|
+
strong: [
|
|
145
|
+
"based on the provided",
|
|
146
|
+
"according to the document",
|
|
147
|
+
"from the attached",
|
|
148
|
+
"using the document",
|
|
149
|
+
"in the provided text",
|
|
150
|
+
],
|
|
151
|
+
weak: ["from these files", "from the context", "in the attached"],
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
taskClass: "research",
|
|
155
|
+
strong: [
|
|
156
|
+
"deep research",
|
|
157
|
+
"comprehensive overview",
|
|
158
|
+
"literature review",
|
|
159
|
+
"state of the art",
|
|
160
|
+
"survey of",
|
|
161
|
+
],
|
|
162
|
+
weak: ["research", "investigate", "background on", "explore the topic"],
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
taskClass: "creative-writing",
|
|
166
|
+
strong: [
|
|
167
|
+
"write a poem",
|
|
168
|
+
"write a story",
|
|
169
|
+
"write a song",
|
|
170
|
+
"write lyrics",
|
|
171
|
+
"screenplay",
|
|
172
|
+
"short story",
|
|
173
|
+
],
|
|
174
|
+
weak: ["poem", "fiction", "creative", "imagine a", "tale"],
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
taskClass: "writing-editing",
|
|
178
|
+
strong: ["write an email", "draft a", "proofread", "rewrite this", "rephrase"],
|
|
179
|
+
weak: ["edit", "improve this text", "make this clearer", "polish", "tone"],
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
taskClass: "decision-support",
|
|
183
|
+
strong: ["should i", "pros and cons", "help me decide", "which is better", "compare options"],
|
|
184
|
+
weak: ["recommend", "trade-offs", "decision", "evaluate options"],
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
taskClass: "agentic-tool-use",
|
|
188
|
+
strong: ["use the tool", "call the api", "automate", "take actions", "as an agent"],
|
|
189
|
+
weak: ["execute", "browse", "fetch and", "step by step using tools", "orchestrate"],
|
|
190
|
+
},
|
|
191
|
+
];
|
|
192
|
+
function scoreTaskClassRule(rule, lower) {
|
|
193
|
+
const strongHits = countMatches(lower, rule.strong);
|
|
194
|
+
const weakHits = countMatches(lower, rule.weak);
|
|
195
|
+
return { score: strongHits * 2 + weakHits, strong: strongHits > 0 };
|
|
196
|
+
}
|
|
197
|
+
function detectBaseTaskClass(lower) {
|
|
198
|
+
let best;
|
|
199
|
+
for (const rule of TASK_CLASS_RULES) {
|
|
200
|
+
const { score, strong } = scoreTaskClassRule(rule, lower);
|
|
201
|
+
if (score > 0 && (best === undefined || score > best.score)) {
|
|
202
|
+
best = { rule, score, strong };
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (best === undefined) {
|
|
206
|
+
return { taskClass: "factual-qa", confidence: "weak" };
|
|
207
|
+
}
|
|
208
|
+
const confidence = best.strong
|
|
209
|
+
? "strong"
|
|
210
|
+
: best.score >= 2
|
|
211
|
+
? "moderate"
|
|
212
|
+
: "weak";
|
|
213
|
+
return { taskClass: best.rule.taskClass, confidence };
|
|
214
|
+
}
|
|
215
|
+
// Ordered so consequential domains win ties (drives criticality). `general` is the implicit default.
|
|
216
|
+
const DOMAIN_RULES = [
|
|
217
|
+
{
|
|
218
|
+
domain: "legal",
|
|
219
|
+
keywords: [
|
|
220
|
+
"legal",
|
|
221
|
+
"lawsuit",
|
|
222
|
+
"liable",
|
|
223
|
+
"liability",
|
|
224
|
+
"contract clause",
|
|
225
|
+
"attorney",
|
|
226
|
+
"court",
|
|
227
|
+
"gdpr",
|
|
228
|
+
"regulation",
|
|
229
|
+
"copyright",
|
|
230
|
+
"patent",
|
|
231
|
+
],
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
domain: "medical",
|
|
235
|
+
keywords: [
|
|
236
|
+
"medical",
|
|
237
|
+
"symptom",
|
|
238
|
+
"diagnos",
|
|
239
|
+
"disease",
|
|
240
|
+
"dosage",
|
|
241
|
+
"prescription",
|
|
242
|
+
"patient",
|
|
243
|
+
"treatment",
|
|
244
|
+
"medication",
|
|
245
|
+
"clinical",
|
|
246
|
+
],
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
domain: "finance",
|
|
250
|
+
keywords: [
|
|
251
|
+
"invest",
|
|
252
|
+
"stock price",
|
|
253
|
+
"portfolio",
|
|
254
|
+
"mortgage",
|
|
255
|
+
"tax return",
|
|
256
|
+
"trading",
|
|
257
|
+
"retirement",
|
|
258
|
+
"interest rate",
|
|
259
|
+
"loan",
|
|
260
|
+
],
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
domain: "security",
|
|
264
|
+
keywords: [
|
|
265
|
+
"vulnerab",
|
|
266
|
+
"exploit",
|
|
267
|
+
"penetration test",
|
|
268
|
+
"malware",
|
|
269
|
+
"sql injection",
|
|
270
|
+
"xss",
|
|
271
|
+
"csrf",
|
|
272
|
+
"authentication",
|
|
273
|
+
"encryption",
|
|
274
|
+
"secrets management",
|
|
275
|
+
],
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
domain: "data-science",
|
|
279
|
+
keywords: [
|
|
280
|
+
"machine learning",
|
|
281
|
+
"neural network",
|
|
282
|
+
"training data",
|
|
283
|
+
"pandas",
|
|
284
|
+
"regression model",
|
|
285
|
+
"feature engineering",
|
|
286
|
+
],
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
domain: "science",
|
|
290
|
+
keywords: ["physics", "chemistry", "biology", "hypothesis", "theorem", "experiment"],
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
domain: "business",
|
|
294
|
+
keywords: ["marketing", "sales", "revenue", "business plan", "startup", "customer", "kpi"],
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
domain: "education",
|
|
298
|
+
keywords: ["teach", "lesson", "homework", "student", "tutorial", "curriculum"],
|
|
299
|
+
},
|
|
300
|
+
{ domain: "creative", keywords: ["poem", "story", "novel", "song", "fiction", "screenplay"] },
|
|
301
|
+
{
|
|
302
|
+
domain: "software",
|
|
303
|
+
keywords: [
|
|
304
|
+
"code",
|
|
305
|
+
"function",
|
|
306
|
+
"typescript",
|
|
307
|
+
"python",
|
|
308
|
+
"javascript",
|
|
309
|
+
"api",
|
|
310
|
+
"database",
|
|
311
|
+
"compile",
|
|
312
|
+
"react",
|
|
313
|
+
"algorithm",
|
|
314
|
+
],
|
|
315
|
+
},
|
|
316
|
+
];
|
|
317
|
+
function detectDomain(lower) {
|
|
318
|
+
let best;
|
|
319
|
+
for (const rule of DOMAIN_RULES) {
|
|
320
|
+
const score = countMatches(lower, rule.keywords);
|
|
321
|
+
if (score > 0 && (best === undefined || score > best.score)) {
|
|
322
|
+
best = { domain: rule.domain, score };
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return best?.domain ?? "general";
|
|
326
|
+
}
|
|
327
|
+
// ─── Safety-critical override + criticality ──────────────────────────────────────
|
|
328
|
+
// A prompt is treated as seeking consequential advice in a safety-critical domain only when it is an
|
|
329
|
+
// inherently decision-making task OR it contains an explicit advice cue. Neutral factual, research,
|
|
330
|
+
// summarization, or extraction tasks that merely mention a safety-critical domain are NOT escalated
|
|
331
|
+
// to the safety-critical task class (they remain their base class with an elevated criticality from
|
|
332
|
+
// the domain). This avoids over-escalating, e.g., "Explain the history of medical terminology".
|
|
333
|
+
const CONSEQUENTIAL_TASK_CLASSES = new Set(["decision-support"]);
|
|
334
|
+
const ADVICE_CUES = [
|
|
335
|
+
"should i",
|
|
336
|
+
"what should i do",
|
|
337
|
+
"is it legal",
|
|
338
|
+
"am i liable",
|
|
339
|
+
"diagnose",
|
|
340
|
+
"what dose",
|
|
341
|
+
"how much should i invest",
|
|
342
|
+
"is it safe",
|
|
343
|
+
"my rights",
|
|
344
|
+
"legal rights",
|
|
345
|
+
"can i sue",
|
|
346
|
+
"recommended treatment",
|
|
347
|
+
"tax implications",
|
|
348
|
+
"legal advice",
|
|
349
|
+
"medical advice",
|
|
350
|
+
"financial advice",
|
|
351
|
+
];
|
|
352
|
+
function isAdviceSeeking(taskClass, lower) {
|
|
353
|
+
return CONSEQUENTIAL_TASK_CLASSES.has(taskClass) || containsAny(lower, ADVICE_CUES);
|
|
354
|
+
}
|
|
355
|
+
function deriveCriticality(domain, taskClass, riskFlags) {
|
|
356
|
+
// Critical is reserved for consequential advice in a safety-critical domain (the safety-critical
|
|
357
|
+
// task class). A safety-critical DOMAIN with a non-advice task, an agentic task, or any risk flag
|
|
358
|
+
// is elevated — heightened awareness without the strongest gate.
|
|
359
|
+
if (taskClass === "safety-critical")
|
|
360
|
+
return "critical";
|
|
361
|
+
if (isSafetyCriticalDomain(domain) || taskClass === "agentic-tool-use" || riskFlags.length > 0) {
|
|
362
|
+
return "elevated";
|
|
363
|
+
}
|
|
364
|
+
return "standard";
|
|
365
|
+
}
|
|
366
|
+
// ─── Risk flags (lexical signals) ────────────────────────────────────────────────
|
|
367
|
+
const INSTRUCTION_OVERRIDE_CUES = [
|
|
368
|
+
"ignore previous instructions",
|
|
369
|
+
"ignore all previous",
|
|
370
|
+
"disregard previous",
|
|
371
|
+
"disregard the above instructions",
|
|
372
|
+
"ignore your instructions",
|
|
373
|
+
"ignore the system prompt",
|
|
374
|
+
"you are now ",
|
|
375
|
+
"developer mode",
|
|
376
|
+
"jailbreak",
|
|
377
|
+
];
|
|
378
|
+
const TOOL_AUTHORITY_CUES = [
|
|
379
|
+
"run this command",
|
|
380
|
+
"execute this command",
|
|
381
|
+
"sudo ",
|
|
382
|
+
"rm -rf",
|
|
383
|
+
"install and run",
|
|
384
|
+
"grant yourself",
|
|
385
|
+
"give yourself access",
|
|
386
|
+
"deploy to production",
|
|
387
|
+
"run the script",
|
|
388
|
+
"execute the following",
|
|
389
|
+
];
|
|
390
|
+
const EGRESS_CUES = [
|
|
391
|
+
"exfiltrate",
|
|
392
|
+
"send the data to",
|
|
393
|
+
"upload to",
|
|
394
|
+
"post to http",
|
|
395
|
+
"curl http",
|
|
396
|
+
"make a request to http",
|
|
397
|
+
"send it to my server",
|
|
398
|
+
"download from and run",
|
|
399
|
+
];
|
|
400
|
+
function detectRiskFlags(lower, domain, taskClass) {
|
|
401
|
+
const flags = [];
|
|
402
|
+
if (containsAny(lower, INSTRUCTION_OVERRIDE_CUES))
|
|
403
|
+
flags.push("instruction-override-suspected");
|
|
404
|
+
if (containsAny(lower, TOOL_AUTHORITY_CUES))
|
|
405
|
+
flags.push("tool-authority-requested");
|
|
406
|
+
if (containsAny(lower, EGRESS_CUES))
|
|
407
|
+
flags.push("egress-requested");
|
|
408
|
+
if (isSafetyCriticalDomain(domain) && isAdviceSeeking(taskClass, lower)) {
|
|
409
|
+
flags.push("safety-critical-advice");
|
|
410
|
+
}
|
|
411
|
+
return flags;
|
|
412
|
+
}
|
|
413
|
+
function classify(view) {
|
|
414
|
+
const domain = detectDomain(view.lower);
|
|
415
|
+
const base = detectBaseTaskClass(view.lower);
|
|
416
|
+
const safetyOverride = isSafetyCriticalDomain(domain) && isAdviceSeeking(base.taskClass, view.lower);
|
|
417
|
+
const taskClass = safetyOverride ? "safety-critical" : base.taskClass;
|
|
418
|
+
const confidence = safetyOverride ? "strong" : base.confidence;
|
|
419
|
+
const riskFlags = detectRiskFlags(view.lower, domain, base.taskClass);
|
|
420
|
+
const criticality = deriveCriticality(domain, taskClass, riskFlags);
|
|
421
|
+
return { taskClass, confidence, domain, criticality, riskFlags };
|
|
422
|
+
}
|
|
423
|
+
// ─── Grounding need (AC3) ────────────────────────────────────────────────────────
|
|
424
|
+
const TEMPORAL_RECENCY_CUES = [
|
|
425
|
+
"today",
|
|
426
|
+
"right now",
|
|
427
|
+
"currently",
|
|
428
|
+
"latest",
|
|
429
|
+
"most recent",
|
|
430
|
+
"this year",
|
|
431
|
+
"this week",
|
|
432
|
+
"as of",
|
|
433
|
+
"up to date",
|
|
434
|
+
"up-to-date",
|
|
435
|
+
"current ",
|
|
436
|
+
];
|
|
437
|
+
const NAMED_CURRENT_CUES = [
|
|
438
|
+
"breaking news",
|
|
439
|
+
"who won",
|
|
440
|
+
"who is the current",
|
|
441
|
+
"election",
|
|
442
|
+
"just released",
|
|
443
|
+
"newest",
|
|
444
|
+
];
|
|
445
|
+
const MARKET_PRICE_CUES = [
|
|
446
|
+
"stock price",
|
|
447
|
+
"exchange rate",
|
|
448
|
+
"market cap",
|
|
449
|
+
"price of",
|
|
450
|
+
"how much does it cost",
|
|
451
|
+
];
|
|
452
|
+
const SUPPLIED_CONTEXT_CUES = [
|
|
453
|
+
"attached",
|
|
454
|
+
"the provided",
|
|
455
|
+
"this document",
|
|
456
|
+
"these files",
|
|
457
|
+
"the text below",
|
|
458
|
+
"the context above",
|
|
459
|
+
"the snippet",
|
|
460
|
+
];
|
|
461
|
+
const RETRIEVAL_CUES = [
|
|
462
|
+
"search for",
|
|
463
|
+
"look up",
|
|
464
|
+
"find sources",
|
|
465
|
+
"cite sources",
|
|
466
|
+
"with citations",
|
|
467
|
+
];
|
|
468
|
+
const SELF_CONTAINED_CLASSES = new Set([
|
|
469
|
+
"code-generation",
|
|
470
|
+
"creative-writing",
|
|
471
|
+
"summarization",
|
|
472
|
+
"structured-extraction",
|
|
473
|
+
"prompt-optimization",
|
|
474
|
+
]);
|
|
475
|
+
function collectGroundingSignals(view) {
|
|
476
|
+
const signals = [];
|
|
477
|
+
if (containsAny(view.lower, TEMPORAL_RECENCY_CUES))
|
|
478
|
+
signals.push("temporal-recency-term");
|
|
479
|
+
if (containsAny(view.lower, NAMED_CURRENT_CUES))
|
|
480
|
+
signals.push("named-current-event");
|
|
481
|
+
if (containsAny(view.lower, MARKET_PRICE_CUES))
|
|
482
|
+
signals.push("market-or-price");
|
|
483
|
+
if (/https?:\/\/|www\./u.test(view.lower))
|
|
484
|
+
signals.push("url-reference");
|
|
485
|
+
if (view.hasConnectedContext || containsAny(view.lower, SUPPLIED_CONTEXT_CUES)) {
|
|
486
|
+
signals.push("supplied-context-reference");
|
|
487
|
+
}
|
|
488
|
+
if (containsAny(view.lower, RETRIEVAL_CUES))
|
|
489
|
+
signals.push("retrieval-cue");
|
|
490
|
+
return signals;
|
|
491
|
+
}
|
|
492
|
+
function isVolatileGrounding(signals) {
|
|
493
|
+
return (signals.includes("temporal-recency-term") ||
|
|
494
|
+
signals.includes("named-current-event") ||
|
|
495
|
+
signals.includes("market-or-price"));
|
|
496
|
+
}
|
|
497
|
+
function detectGroundingNeed(view, taskClass) {
|
|
498
|
+
const signals = collectGroundingSignals(view);
|
|
499
|
+
const volatile = isVolatileGrounding(signals);
|
|
500
|
+
if (volatile || signals.includes("url-reference")) {
|
|
501
|
+
return { kind: "external-current", volatile, signals };
|
|
502
|
+
}
|
|
503
|
+
if (signals.includes("supplied-context-reference")) {
|
|
504
|
+
return { kind: "supplied-context", volatile: false, signals };
|
|
505
|
+
}
|
|
506
|
+
if (signals.includes("retrieval-cue") ||
|
|
507
|
+
taskClass === "research" ||
|
|
508
|
+
taskClass === "rag-question-answering") {
|
|
509
|
+
return {
|
|
510
|
+
kind: "external-knowledge",
|
|
511
|
+
volatile: false,
|
|
512
|
+
signals: appendSignal(signals, "retrieval-cue"),
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
if (SELF_CONTAINED_CLASSES.has(taskClass)) {
|
|
516
|
+
return { kind: "none", volatile: false, signals: ["self-contained-task"] };
|
|
517
|
+
}
|
|
518
|
+
return { kind: "external-knowledge", volatile: false, signals: ["no-external-signal"] };
|
|
519
|
+
}
|
|
520
|
+
function appendSignal(signals, signal) {
|
|
521
|
+
return signals.includes(signal) ? signals : [...signals, signal];
|
|
522
|
+
}
|
|
523
|
+
const OUTPUT_HINT_RULES = [
|
|
524
|
+
{ hint: "explicit-json", format: "json", keywords: ["json", "as json", "in json"] },
|
|
525
|
+
{ hint: "explicit-yaml", format: "yaml", keywords: ["yaml"] },
|
|
526
|
+
{ hint: "explicit-csv", format: "csv", keywords: ["csv", "comma-separated"] },
|
|
527
|
+
{ hint: "explicit-table", format: "table", keywords: ["as a table", "in a table", "tabular"] },
|
|
528
|
+
{ hint: "explicit-code", format: "code", keywords: ["code block", "a snippet", "as code"] },
|
|
529
|
+
{
|
|
530
|
+
hint: "explicit-list",
|
|
531
|
+
format: "list",
|
|
532
|
+
keywords: ["bullet points", "bulleted list", "numbered list", "as a list"],
|
|
533
|
+
},
|
|
534
|
+
{ hint: "explicit-markdown", format: "markdown", keywords: ["in markdown", "as markdown"] },
|
|
535
|
+
];
|
|
536
|
+
const DEFAULT_FORMAT_BY_CLASS = {
|
|
537
|
+
"code-generation": "code",
|
|
538
|
+
"code-debugging": "code",
|
|
539
|
+
"structured-extraction": "json",
|
|
540
|
+
"data-analysis": "table",
|
|
541
|
+
"creative-writing": "prose",
|
|
542
|
+
"writing-editing": "prose",
|
|
543
|
+
summarization: "markdown",
|
|
544
|
+
research: "markdown",
|
|
545
|
+
"decision-support": "markdown",
|
|
546
|
+
};
|
|
547
|
+
const STRUCTURED_FORMATS = new Set(["json", "yaml", "csv", "table"]);
|
|
548
|
+
function detectOutputSchema(lower, taskClass) {
|
|
549
|
+
const hints = [];
|
|
550
|
+
let format;
|
|
551
|
+
for (const rule of OUTPUT_HINT_RULES) {
|
|
552
|
+
if (containsAny(lower, rule.keywords)) {
|
|
553
|
+
hints.push(rule.hint);
|
|
554
|
+
format ??= rule.format;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
if (containsAny(lower, ["schema", "the fields", "format:"]))
|
|
558
|
+
hints.push("schema-keyword");
|
|
559
|
+
const resolved = format ?? DEFAULT_FORMAT_BY_CLASS[taskClass] ?? "unspecified";
|
|
560
|
+
return {
|
|
561
|
+
format: resolved,
|
|
562
|
+
structured: STRUCTURED_FORMATS.has(resolved),
|
|
563
|
+
hints: hints.length > 0 ? hints : ["no-format-signal"],
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
// ─── Missing context (AC4) ───────────────────────────────────────────────────────
|
|
567
|
+
const SCOPE_REFERENCE_CUES = [
|
|
568
|
+
"this file",
|
|
569
|
+
"the file",
|
|
570
|
+
"this code",
|
|
571
|
+
"the code",
|
|
572
|
+
"the document",
|
|
573
|
+
"above",
|
|
574
|
+
"below",
|
|
575
|
+
"attached",
|
|
576
|
+
"the provided",
|
|
577
|
+
];
|
|
578
|
+
const AUDIENCE_CUES = ["for ", "audience", "readers", "to a ", "for a "];
|
|
579
|
+
const CONSTRAINT_CUES = [
|
|
580
|
+
"using ",
|
|
581
|
+
" in ",
|
|
582
|
+
"language",
|
|
583
|
+
"within",
|
|
584
|
+
"must ",
|
|
585
|
+
"should ",
|
|
586
|
+
"framework",
|
|
587
|
+
"library",
|
|
588
|
+
"without ",
|
|
589
|
+
"no more than",
|
|
590
|
+
];
|
|
591
|
+
const CRITERIA_CUES = [
|
|
592
|
+
"criteria",
|
|
593
|
+
"goal",
|
|
594
|
+
"objective",
|
|
595
|
+
"optimize for",
|
|
596
|
+
"prioritize",
|
|
597
|
+
"based on",
|
|
598
|
+
];
|
|
599
|
+
const FORMAT_SENSITIVE_CLASSES = new Set([
|
|
600
|
+
"structured-extraction",
|
|
601
|
+
"data-analysis",
|
|
602
|
+
]);
|
|
603
|
+
const AUDIENCE_SENSITIVE_CLASSES = new Set([
|
|
604
|
+
"writing-editing",
|
|
605
|
+
"creative-writing",
|
|
606
|
+
]);
|
|
607
|
+
const CONSTRAINT_SENSITIVE_CLASSES = new Set([
|
|
608
|
+
"code-generation",
|
|
609
|
+
"code-architecture",
|
|
610
|
+
]);
|
|
611
|
+
const CRITERIA_SENSITIVE_CLASSES = new Set([
|
|
612
|
+
"decision-support",
|
|
613
|
+
"research",
|
|
614
|
+
]);
|
|
615
|
+
const MAX_MISSING_TOPICS = 4;
|
|
616
|
+
const lacksSubject = (view) => view.normalizedLength < 12 || view.meaningfulTokenCount < 3;
|
|
617
|
+
const lacksDataSource = (view) => containsAny(view.lower, SCOPE_REFERENCE_CUES) && !view.hasConnectedContext;
|
|
618
|
+
// A format-sensitive task (structured extraction, data analysis) is missing its output format when
|
|
619
|
+
// the user gave no explicit format hint. The resolved `format` is checked via the hints array rather
|
|
620
|
+
// than the final value, because these classes carry a sensible default format that would otherwise
|
|
621
|
+
// mask the absence of an explicit signal (`no-format-signal` is present exactly when none was found).
|
|
622
|
+
const lacksOutputFormat = (taskClass, outputSchema) => FORMAT_SENSITIVE_CLASSES.has(taskClass) && outputSchema.hints.includes("no-format-signal");
|
|
623
|
+
const lacksAudience = (view, taskClass) => AUDIENCE_SENSITIVE_CLASSES.has(taskClass) && !containsAny(view.lower, AUDIENCE_CUES);
|
|
624
|
+
const lacksConstraints = (view, taskClass) => CONSTRAINT_SENSITIVE_CLASSES.has(taskClass) && !containsAny(view.lower, CONSTRAINT_CUES);
|
|
625
|
+
const lacksSuccessCriteria = (view, taskClass) => CRITERIA_SENSITIVE_CLASSES.has(taskClass) && !containsAny(view.lower, CRITERIA_CUES);
|
|
626
|
+
function detectMissingTopics(view, classification, outputSchema) {
|
|
627
|
+
const cls = classification.taskClass;
|
|
628
|
+
const topics = [];
|
|
629
|
+
if (lacksSubject(view))
|
|
630
|
+
topics.push("subject");
|
|
631
|
+
if (lacksDataSource(view))
|
|
632
|
+
topics.push("data-source");
|
|
633
|
+
if (lacksOutputFormat(cls, outputSchema))
|
|
634
|
+
topics.push("output-format");
|
|
635
|
+
if (lacksAudience(view, cls))
|
|
636
|
+
topics.push("audience");
|
|
637
|
+
if (lacksConstraints(view, cls))
|
|
638
|
+
topics.push("constraints");
|
|
639
|
+
if (lacksSuccessCriteria(view, cls))
|
|
640
|
+
topics.push("success-criteria");
|
|
641
|
+
return topics.slice(0, MAX_MISSING_TOPICS);
|
|
642
|
+
}
|
|
643
|
+
const CLARIFICATION_TEMPLATES = {
|
|
644
|
+
subject: "What specific subject or task should this prompt address?",
|
|
645
|
+
scope: "Which part of the work should the task focus on?",
|
|
646
|
+
audience: "Who is the intended audience for the output?",
|
|
647
|
+
"output-format": "What output format is expected (for example JSON, a table, or prose)?",
|
|
648
|
+
constraints: "Are there language, framework, or length constraints to honor?",
|
|
649
|
+
"data-source": "Which files, documents, or sources should ground the answer?",
|
|
650
|
+
"success-criteria": "What defines a successful outcome for this task?",
|
|
651
|
+
};
|
|
652
|
+
const ASSUMPTION_TEMPLATES = {
|
|
653
|
+
subject: "Assuming the broadest reasonable interpretation of the requested subject.",
|
|
654
|
+
scope: "Assuming the task applies to the most relevant available scope.",
|
|
655
|
+
audience: "Assuming a general professional audience.",
|
|
656
|
+
"output-format": "Assuming a structured format appropriate to the task.",
|
|
657
|
+
constraints: "Assuming no constraints beyond standard best practices.",
|
|
658
|
+
"data-source": "Assuming the answer should rely only on supplied context, with gaps flagged.",
|
|
659
|
+
"success-criteria": "Assuming correctness and completeness are the primary success criteria.",
|
|
660
|
+
};
|
|
661
|
+
function toMissingContext(topics, strategy) {
|
|
662
|
+
return topics.map((topic) => strategy === "clarify"
|
|
663
|
+
? {
|
|
664
|
+
kind: "clarification",
|
|
665
|
+
topic,
|
|
666
|
+
question: CLARIFICATION_TEMPLATES[topic].slice(0, PROMPT_MISSING_CONTEXT_MAX_CHARS),
|
|
667
|
+
}
|
|
668
|
+
: {
|
|
669
|
+
kind: "assumption",
|
|
670
|
+
topic,
|
|
671
|
+
statement: ASSUMPTION_TEMPLATES[topic].slice(0, PROMPT_MISSING_CONTEXT_MAX_CHARS),
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
// ─── Profile recommendation ──────────────────────────────────────────────────────
|
|
675
|
+
// Deterministic task-class → profile map. A critical criticality (safety-critical domain) always
|
|
676
|
+
// escalates to the safety-critical profile regardless of the base class.
|
|
677
|
+
const PROFILE_BY_TASK_CLASS = {
|
|
678
|
+
"factual-qa": "precise",
|
|
679
|
+
research: "research",
|
|
680
|
+
"rag-question-answering": "precise",
|
|
681
|
+
summarization: "precise",
|
|
682
|
+
"structured-extraction": "technical",
|
|
683
|
+
"data-analysis": "technical",
|
|
684
|
+
"code-generation": "technical",
|
|
685
|
+
"code-debugging": "technical",
|
|
686
|
+
"code-architecture": "technical",
|
|
687
|
+
"writing-editing": "fast",
|
|
688
|
+
"creative-writing": "creative",
|
|
689
|
+
"decision-support": "precise",
|
|
690
|
+
"agentic-tool-use": "agentic",
|
|
691
|
+
"prompt-optimization": "technical",
|
|
692
|
+
"safety-critical": "safety-critical",
|
|
693
|
+
};
|
|
694
|
+
function recommendProfile(classification) {
|
|
695
|
+
if (classification.criticality === "critical")
|
|
696
|
+
return "safety-critical";
|
|
697
|
+
return PROFILE_BY_TASK_CLASS[classification.taskClass];
|
|
698
|
+
}
|
|
699
|
+
// ─── Signal collection (explainability) ──────────────────────────────────────────
|
|
700
|
+
function collectSignals(classification, grounding, outputSchema, missingContext) {
|
|
701
|
+
const signals = [
|
|
702
|
+
{ dimension: "task-class", code: `class:${classification.taskClass}` },
|
|
703
|
+
{ dimension: "domain", code: `domain:${classification.domain}` },
|
|
704
|
+
{ dimension: "grounding", code: `grounding:${grounding.kind}` },
|
|
705
|
+
{ dimension: "output", code: `format:${outputSchema.format}` },
|
|
706
|
+
];
|
|
707
|
+
for (const signal of grounding.signals)
|
|
708
|
+
signals.push({ dimension: "grounding", code: `signal:${signal}` });
|
|
709
|
+
for (const hint of outputSchema.hints)
|
|
710
|
+
signals.push({ dimension: "output", code: `hint:${hint}` });
|
|
711
|
+
for (const flag of classification.riskFlags)
|
|
712
|
+
signals.push({ dimension: "risk", code: `risk:${flag}` });
|
|
713
|
+
for (const item of missingContext)
|
|
714
|
+
signals.push({ dimension: "missing-context", code: `topic:${item.topic}` });
|
|
715
|
+
return signals;
|
|
716
|
+
}
|
|
717
|
+
// ─── Public entry point ──────────────────────────────────────────────────────────
|
|
718
|
+
/**
|
|
719
|
+
* Convert a raw prompt-enhancement request into a deterministic, normalized `PromptTaskAnalysis`.
|
|
720
|
+
* Pure: identical requests always produce identical analyses. No model call, IO, clock, or random.
|
|
721
|
+
*/
|
|
722
|
+
export function analyzePrompt(request) {
|
|
723
|
+
const normalized = normalizePromptDraft(request.input.text);
|
|
724
|
+
const view = buildView(normalized, request);
|
|
725
|
+
const classification = classify(view);
|
|
726
|
+
const grounding = detectGroundingNeed(view, classification.taskClass);
|
|
727
|
+
const outputSchema = detectOutputSchema(view.lower, classification.taskClass);
|
|
728
|
+
const topics = detectMissingTopics(view, classification, outputSchema);
|
|
729
|
+
const missingContext = toMissingContext(topics, request.missingInformationStrategy);
|
|
730
|
+
return {
|
|
731
|
+
schemaVersion: PROMPT_ENHANCER_SCHEMA_VERSION,
|
|
732
|
+
requestId: request.requestId,
|
|
733
|
+
taskClass: classification.taskClass,
|
|
734
|
+
taskClassConfidence: classification.confidence,
|
|
735
|
+
domain: classification.domain,
|
|
736
|
+
criticality: classification.criticality,
|
|
737
|
+
groundingNeed: grounding,
|
|
738
|
+
outputSchema,
|
|
739
|
+
missingContext,
|
|
740
|
+
riskFlags: classification.riskFlags,
|
|
741
|
+
recommendedProfile: recommendProfile(classification),
|
|
742
|
+
normalizedInputLength: view.normalizedLength,
|
|
743
|
+
signals: collectSignals(classification, grounding, outputSchema, missingContext),
|
|
744
|
+
};
|
|
745
|
+
}
|