ollama-intern-mcp 1.0.1 → 1.0.2
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/errors.d.ts +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/guardrails/bannedPhrases.d.ts +38 -0
- package/dist/guardrails/bannedPhrases.d.ts.map +1 -0
- package/dist/guardrails/bannedPhrases.js +83 -0
- package/dist/guardrails/bannedPhrases.js.map +1 -0
- package/dist/guardrails/stringifiedArrayGuard.d.ts +45 -0
- package/dist/guardrails/stringifiedArrayGuard.d.ts.map +1 -0
- package/dist/guardrails/stringifiedArrayGuard.js +88 -0
- package/dist/guardrails/stringifiedArrayGuard.js.map +1 -0
- package/dist/tools/changeBrief.d.ts +2 -2
- package/dist/tools/classify.d.ts +14 -9
- package/dist/tools/classify.d.ts.map +1 -1
- package/dist/tools/classify.js +26 -13
- package/dist/tools/classify.js.map +1 -1
- package/dist/tools/draft.d.ts +4 -0
- package/dist/tools/draft.d.ts.map +1 -1
- package/dist/tools/draft.js +54 -1
- package/dist/tools/draft.js.map +1 -1
- package/dist/tools/extract.d.ts +13 -5
- package/dist/tools/extract.d.ts.map +1 -1
- package/dist/tools/extract.js +24 -9
- package/dist/tools/extract.js.map +1 -1
- package/dist/tools/incidentBrief.d.ts +2 -2
- package/dist/tools/packs/changePack.d.ts +3 -3
- package/dist/tools/packs/changePack.d.ts.map +1 -1
- package/dist/tools/packs/changePack.js +2 -1
- package/dist/tools/packs/changePack.js.map +1 -1
- package/dist/tools/packs/incidentPack.d.ts +3 -3
- package/dist/tools/packs/incidentPack.d.ts.map +1 -1
- package/dist/tools/packs/incidentPack.js +2 -1
- package/dist/tools/packs/incidentPack.js.map +1 -1
- package/dist/tools/research.d.ts +3 -3
- package/dist/tools/research.d.ts.map +1 -1
- package/dist/tools/research.js +2 -1
- package/dist/tools/research.js.map +1 -1
- package/dist/tools/summarizeDeep.d.ts +3 -3
- package/dist/tools/summarizeDeep.d.ts.map +1 -1
- package/dist/tools/summarizeDeep.js +2 -3
- package/dist/tools/summarizeDeep.js.map +1 -1
- package/dist/tools/triageLogs.d.ts +1 -1
- package/dist/tools/triageLogs.d.ts.map +1 -1
- package/dist/tools/triageLogs.js +2 -1
- package/dist/tools/triageLogs.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/errors.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Structured error shape — code / message / hint / retryable.
|
|
3
3
|
* Matches shipcheck hard gate B: no raw stacks, always a hint, always a retry signal.
|
|
4
4
|
*/
|
|
5
|
-
export type ErrorCode = "OLLAMA_UNREACHABLE" | "OLLAMA_MODEL_MISSING" | "OLLAMA_TIMEOUT" | "TIER_TIMEOUT" | "PROTECTED_PATH_WRITE" | "CITATION_INVALID" | "COMPILE_FAILED" | "EXTRACT_UNPARSEABLE" | "SOURCE_PATH_NOT_FOUND" | "SCHEMA_INVALID" | "INTERNAL";
|
|
5
|
+
export type ErrorCode = "OLLAMA_UNREACHABLE" | "OLLAMA_MODEL_MISSING" | "OLLAMA_TIMEOUT" | "TIER_TIMEOUT" | "PROTECTED_PATH_WRITE" | "CITATION_INVALID" | "COMPILE_FAILED" | "EXTRACT_UNPARSEABLE" | "SOURCE_PATH_NOT_FOUND" | "SCHEMA_INVALID" | "DRAFT_BANNED_PHRASE" | "INTERNAL";
|
|
6
6
|
export declare class InternError extends Error {
|
|
7
7
|
readonly code: ErrorCode;
|
|
8
8
|
readonly hint: string;
|
package/dist/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,SAAS,GACjB,oBAAoB,GACpB,sBAAsB,GACtB,gBAAgB,GAChB,cAAc,GACd,sBAAsB,GACtB,kBAAkB,GAClB,gBAAgB,GAChB,qBAAqB,GACrB,uBAAuB,GACvB,gBAAgB,GAChB,UAAU,CAAC;AAEf,qBAAa,WAAY,SAAQ,KAAK;aAElB,IAAI,EAAE,SAAS;aAEf,IAAI,EAAE,MAAM;aACZ,SAAS,EAAE,OAAO;gBAHlB,IAAI,EAAE,SAAS,EAC/B,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,MAAM,EACZ,SAAS,GAAE,OAAe;CAK7C;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,IAAI,CAAC;IACZ,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,UAAU,CAYrD"}
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,SAAS,GACjB,oBAAoB,GACpB,sBAAsB,GACtB,gBAAgB,GAChB,cAAc,GACd,sBAAsB,GACtB,kBAAkB,GAClB,gBAAgB,GAChB,qBAAqB,GACrB,uBAAuB,GACvB,gBAAgB,GAChB,qBAAqB,GACrB,UAAU,CAAC;AAEf,qBAAa,WAAY,SAAQ,KAAK;aAElB,IAAI,EAAE,SAAS;aAEf,IAAI,EAAE,MAAM;aACZ,SAAS,EAAE,OAAO;gBAHlB,IAAI,EAAE,SAAS,EAC/B,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,MAAM,EACZ,SAAS,GAAE,OAAe;CAK7C;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,IAAI,CAAC;IACZ,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,UAAU,CAYrD"}
|
package/dist/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAgBH,MAAM,OAAO,WAAY,SAAQ,KAAK;IAElB;IAEA;IACA;IAJlB,YACkB,IAAe,EAC/B,OAAe,EACC,IAAY,EACZ,YAAqB,KAAK;QAE1C,KAAK,CAAC,OAAO,CAAC,CAAC;QALC,SAAI,GAAJ,IAAI,CAAW;QAEf,SAAI,GAAJ,IAAI,CAAQ;QACZ,cAAS,GAAT,SAAS,CAAiB;QAG1C,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC5B,CAAC;CACF;AAUD,MAAM,UAAU,YAAY,CAAC,GAAY;IACvC,IAAI,GAAG,YAAY,WAAW,EAAE,CAAC;QAC/B,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,CAAC;IACzG,CAAC;IACD,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACjE,OAAO;QACL,KAAK,EAAE,IAAI;QACX,IAAI,EAAE,UAAU;QAChB,OAAO;QACP,IAAI,EAAE,kEAAkE;QACxE,SAAS,EAAE,KAAK;KACjB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bannedPhrases — marketing-sludge rejection list for `draft(style="doc")`.
|
|
3
|
+
*
|
|
4
|
+
* The draft-for-prose problem: even strong models generate hype words when
|
|
5
|
+
* asked for "doc" output. A post-generation regex pass catches the obvious
|
|
6
|
+
* sludge and triggers regeneration. Won't catch subtle bad prose, but
|
|
7
|
+
* cheapens the floor by rejecting the signal words that flag it.
|
|
8
|
+
*
|
|
9
|
+
* List is curated from the 2026-04-17 adoption pass and the repo-dataset
|
|
10
|
+
* marketing swarm — phrases that came back in brochure-voice drafts.
|
|
11
|
+
*
|
|
12
|
+
* Kept minimal on purpose. A bloated list starts rejecting legitimate
|
|
13
|
+
* technical prose ("robust error handling", "leverage caching"). Each entry
|
|
14
|
+
* here is one we'd reject 95%+ of the time as sludge.
|
|
15
|
+
*
|
|
16
|
+
* Match is case-insensitive, whole-word. Multi-word phrases match across
|
|
17
|
+
* whitespace; embedded punctuation is not normalized away (matches on
|
|
18
|
+
* natural prose boundaries only).
|
|
19
|
+
*/
|
|
20
|
+
export declare const BANNED_PHRASES: readonly string[];
|
|
21
|
+
export interface BannedPhraseMatch {
|
|
22
|
+
phrase: string;
|
|
23
|
+
index: number;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Scan `text` for any entry in `list`. Returns every match (case-insensitive,
|
|
27
|
+
* whole-word). Empty array means the text is clean.
|
|
28
|
+
*
|
|
29
|
+
* Whole-word match prevents false positives like "ecutting-edge" or
|
|
30
|
+
* "unlocksmith". Uses \b from the regex engine — which treats hyphen as a
|
|
31
|
+
* word boundary, so "cutting-edge" matches both "cutting-edge" (as a single
|
|
32
|
+
* token by its natural boundaries) and by falling back through the split
|
|
33
|
+
* "cutting" and "edge" variants already in the list.
|
|
34
|
+
*/
|
|
35
|
+
export declare function findBannedPhrases(text: string, list?: readonly string[]): BannedPhraseMatch[];
|
|
36
|
+
/** True iff any banned phrase is present. Cheap wrapper for handler use. */
|
|
37
|
+
export declare function containsBannedPhrase(text: string, list?: readonly string[]): boolean;
|
|
38
|
+
//# sourceMappingURL=bannedPhrases.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bannedPhrases.d.ts","sourceRoot":"","sources":["../../src/guardrails/bannedPhrases.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,eAAO,MAAM,cAAc,EAAE,SAAS,MAAM,EA+B1C,CAAC;AAEH,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,SAAS,MAAM,EAAmB,GACvC,iBAAiB,EAAE,CAgBrB;AAED,4EAA4E;AAC5E,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,SAAS,MAAM,EAAmB,GACvC,OAAO,CAET"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bannedPhrases — marketing-sludge rejection list for `draft(style="doc")`.
|
|
3
|
+
*
|
|
4
|
+
* The draft-for-prose problem: even strong models generate hype words when
|
|
5
|
+
* asked for "doc" output. A post-generation regex pass catches the obvious
|
|
6
|
+
* sludge and triggers regeneration. Won't catch subtle bad prose, but
|
|
7
|
+
* cheapens the floor by rejecting the signal words that flag it.
|
|
8
|
+
*
|
|
9
|
+
* List is curated from the 2026-04-17 adoption pass and the repo-dataset
|
|
10
|
+
* marketing swarm — phrases that came back in brochure-voice drafts.
|
|
11
|
+
*
|
|
12
|
+
* Kept minimal on purpose. A bloated list starts rejecting legitimate
|
|
13
|
+
* technical prose ("robust error handling", "leverage caching"). Each entry
|
|
14
|
+
* here is one we'd reject 95%+ of the time as sludge.
|
|
15
|
+
*
|
|
16
|
+
* Match is case-insensitive, whole-word. Multi-word phrases match across
|
|
17
|
+
* whitespace; embedded punctuation is not normalized away (matches on
|
|
18
|
+
* natural prose boundaries only).
|
|
19
|
+
*/
|
|
20
|
+
export const BANNED_PHRASES = Object.freeze([
|
|
21
|
+
"blazing fast",
|
|
22
|
+
"industry-leading",
|
|
23
|
+
"industry leading",
|
|
24
|
+
"the only",
|
|
25
|
+
"effortless",
|
|
26
|
+
"effortlessly",
|
|
27
|
+
"seamless",
|
|
28
|
+
"seamlessly",
|
|
29
|
+
"enhance",
|
|
30
|
+
"enhances",
|
|
31
|
+
"enhanced",
|
|
32
|
+
"streamline",
|
|
33
|
+
"streamlines",
|
|
34
|
+
"streamlined",
|
|
35
|
+
"leverage",
|
|
36
|
+
"leverages",
|
|
37
|
+
"leveraging",
|
|
38
|
+
"unlock",
|
|
39
|
+
"unlocks",
|
|
40
|
+
"unlocking",
|
|
41
|
+
"empower",
|
|
42
|
+
"empowers",
|
|
43
|
+
"empowering",
|
|
44
|
+
"robust",
|
|
45
|
+
"cutting-edge",
|
|
46
|
+
"cutting edge",
|
|
47
|
+
"next-generation",
|
|
48
|
+
"next generation",
|
|
49
|
+
"best-in-class",
|
|
50
|
+
"best in class",
|
|
51
|
+
]);
|
|
52
|
+
/**
|
|
53
|
+
* Scan `text` for any entry in `list`. Returns every match (case-insensitive,
|
|
54
|
+
* whole-word). Empty array means the text is clean.
|
|
55
|
+
*
|
|
56
|
+
* Whole-word match prevents false positives like "ecutting-edge" or
|
|
57
|
+
* "unlocksmith". Uses \b from the regex engine — which treats hyphen as a
|
|
58
|
+
* word boundary, so "cutting-edge" matches both "cutting-edge" (as a single
|
|
59
|
+
* token by its natural boundaries) and by falling back through the split
|
|
60
|
+
* "cutting" and "edge" variants already in the list.
|
|
61
|
+
*/
|
|
62
|
+
export function findBannedPhrases(text, list = BANNED_PHRASES) {
|
|
63
|
+
const matches = [];
|
|
64
|
+
const lower = text.toLowerCase();
|
|
65
|
+
for (const phrase of list) {
|
|
66
|
+
const lowerPhrase = phrase.toLowerCase();
|
|
67
|
+
// Escape regex metachars in the phrase, then bound on word chars.
|
|
68
|
+
const escaped = lowerPhrase.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
69
|
+
// Allow flexible whitespace inside multi-word phrases.
|
|
70
|
+
const pattern = escaped.replace(/\s+/g, "\\s+");
|
|
71
|
+
const re = new RegExp(`\\b${pattern}\\b`, "g");
|
|
72
|
+
let m;
|
|
73
|
+
while ((m = re.exec(lower)) !== null) {
|
|
74
|
+
matches.push({ phrase, index: m.index });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return matches;
|
|
78
|
+
}
|
|
79
|
+
/** True iff any banned phrase is present. Cheap wrapper for handler use. */
|
|
80
|
+
export function containsBannedPhrase(text, list = BANNED_PHRASES) {
|
|
81
|
+
return findBannedPhrases(text, list).length > 0;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=bannedPhrases.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bannedPhrases.js","sourceRoot":"","sources":["../../src/guardrails/bannedPhrases.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,CAAC,MAAM,cAAc,GAAsB,MAAM,CAAC,MAAM,CAAC;IAC7D,cAAc;IACd,kBAAkB;IAClB,kBAAkB;IAClB,UAAU;IACV,YAAY;IACZ,cAAc;IACd,UAAU;IACV,YAAY;IACZ,SAAS;IACT,UAAU;IACV,UAAU;IACV,YAAY;IACZ,aAAa;IACb,aAAa;IACb,UAAU;IACV,WAAW;IACX,YAAY;IACZ,QAAQ;IACR,SAAS;IACT,WAAW;IACX,SAAS;IACT,UAAU;IACV,YAAY;IACZ,QAAQ;IACR,cAAc;IACd,cAAc;IACd,iBAAiB;IACjB,iBAAiB;IACjB,eAAe;IACf,eAAe;CAChB,CAAC,CAAC;AAOH;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAC/B,IAAY,EACZ,OAA0B,cAAc;IAExC,MAAM,OAAO,GAAwB,EAAE,CAAC;IACxC,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IACjC,KAAK,MAAM,MAAM,IAAI,IAAI,EAAE,CAAC;QAC1B,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;QACzC,kEAAkE;QAClE,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;QACnE,uDAAuD;QACvD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAChD,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,MAAM,OAAO,KAAK,EAAE,GAAG,CAAC,CAAC;QAC/C,IAAI,CAAyB,CAAC;QAC9B,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YACrC,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,oBAAoB,CAClC,IAAY,EACZ,OAA0B,cAAc;IAExC,OAAO,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;AAClD,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* stringifiedArrayGuard — diagnostic schema helper.
|
|
3
|
+
*
|
|
4
|
+
* Problem:
|
|
5
|
+
* Some callers (observed in the repo-dataset marketing swarm, 2026-04-17)
|
|
6
|
+
* serialize nested array params as JSON strings before the MCP transport
|
|
7
|
+
* sees them. `source_paths: ["file.md"]` arrives at the server as
|
|
8
|
+
* `"[\"file.md\"]"` — a string. Strict `z.array(z.string())` then fails
|
|
9
|
+
* with a generic "expected array, received string", which hides the real
|
|
10
|
+
* cause (upstream stringification) behind a schema error the caller can't
|
|
11
|
+
* act on.
|
|
12
|
+
*
|
|
13
|
+
* Decision (user-directed, 2026-04-17):
|
|
14
|
+
* Keep the public contract strict — do NOT silently coerce. Instead, when
|
|
15
|
+
* a string arrives where an array is required, emit a diagnostic error
|
|
16
|
+
* that explicitly names the upstream-stringification case and tells the
|
|
17
|
+
* caller to fix their tool-call path. This keeps the product honest while
|
|
18
|
+
* giving the offending caller a fast signal. If later evidence shows
|
|
19
|
+
* multiple uncontrolled callers, a compatibility-coercion path can be
|
|
20
|
+
* added behind an explicit, warning-counted flag — but not yet.
|
|
21
|
+
*
|
|
22
|
+
* Parent doc: memory/ollama-intern-output-quality-report-2026-04-17.md
|
|
23
|
+
* Runbook: memory/ollama-intern-phase-a-runbook-2026-04-17.md
|
|
24
|
+
*/
|
|
25
|
+
import { z } from "zod";
|
|
26
|
+
export interface StrictStringArrayOpts {
|
|
27
|
+
min?: number;
|
|
28
|
+
max?: number;
|
|
29
|
+
minItemLen?: number;
|
|
30
|
+
fieldName?: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Strict array<string> schema with diagnostic for upstream-stringified input.
|
|
34
|
+
*
|
|
35
|
+
* Behavior:
|
|
36
|
+
* - array<string> matching min/max/minItemLen: pass
|
|
37
|
+
* - string (any shape): fail with specific diagnostic naming the
|
|
38
|
+
* stringification case when the string looks like a JSON array,
|
|
39
|
+
* or with a "wrap in array" hint otherwise
|
|
40
|
+
* - anything else: fail with zod's normal messages
|
|
41
|
+
*
|
|
42
|
+
* Output type is `string[]`. Chain `.optional()` for optional fields.
|
|
43
|
+
*/
|
|
44
|
+
export declare function strictStringArray(opts?: StrictStringArrayOpts): z.ZodType<string[]>;
|
|
45
|
+
//# sourceMappingURL=stringifiedArrayGuard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stringifiedArrayGuard.d.ts","sourceRoot":"","sources":["../../src/guardrails/stringifiedArrayGuard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,WAAW,qBAAqB;IACpC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA6BD;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,GAAE,qBAA0B,GAC/B,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAuCrB"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* stringifiedArrayGuard — diagnostic schema helper.
|
|
3
|
+
*
|
|
4
|
+
* Problem:
|
|
5
|
+
* Some callers (observed in the repo-dataset marketing swarm, 2026-04-17)
|
|
6
|
+
* serialize nested array params as JSON strings before the MCP transport
|
|
7
|
+
* sees them. `source_paths: ["file.md"]` arrives at the server as
|
|
8
|
+
* `"[\"file.md\"]"` — a string. Strict `z.array(z.string())` then fails
|
|
9
|
+
* with a generic "expected array, received string", which hides the real
|
|
10
|
+
* cause (upstream stringification) behind a schema error the caller can't
|
|
11
|
+
* act on.
|
|
12
|
+
*
|
|
13
|
+
* Decision (user-directed, 2026-04-17):
|
|
14
|
+
* Keep the public contract strict — do NOT silently coerce. Instead, when
|
|
15
|
+
* a string arrives where an array is required, emit a diagnostic error
|
|
16
|
+
* that explicitly names the upstream-stringification case and tells the
|
|
17
|
+
* caller to fix their tool-call path. This keeps the product honest while
|
|
18
|
+
* giving the offending caller a fast signal. If later evidence shows
|
|
19
|
+
* multiple uncontrolled callers, a compatibility-coercion path can be
|
|
20
|
+
* added behind an explicit, warning-counted flag — but not yet.
|
|
21
|
+
*
|
|
22
|
+
* Parent doc: memory/ollama-intern-output-quality-report-2026-04-17.md
|
|
23
|
+
* Runbook: memory/ollama-intern-phase-a-runbook-2026-04-17.md
|
|
24
|
+
*/
|
|
25
|
+
import { z } from "zod";
|
|
26
|
+
function buildStringDiagnostic(value, fieldName) {
|
|
27
|
+
const field = fieldName ?? "field";
|
|
28
|
+
const trimmed = value.trim();
|
|
29
|
+
const looksLikeJsonArray = trimmed.startsWith("[") && trimmed.endsWith("]");
|
|
30
|
+
const preview = trimmed.length > 80 ? `${trimmed.slice(0, 80)}...` : trimmed;
|
|
31
|
+
if (looksLikeJsonArray) {
|
|
32
|
+
return (`Stringified array detected on \`${field}\`. ` +
|
|
33
|
+
`Expected array<string>, received a string containing JSON: "${preview}". ` +
|
|
34
|
+
`The caller serialized the array before the MCP transport saw it — ` +
|
|
35
|
+
`fix the caller, not the server. ` +
|
|
36
|
+
`If you are a subagent, swarm, or custom tool-call path, ` +
|
|
37
|
+
`your serializer is JSON-encoding nested params; pass the array as a native array.`);
|
|
38
|
+
}
|
|
39
|
+
return (`Expected array<string> on \`${field}\`, got string "${preview}". ` +
|
|
40
|
+
`Wrap single values as an array: ["value"], not "value".`);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Strict array<string> schema with diagnostic for upstream-stringified input.
|
|
44
|
+
*
|
|
45
|
+
* Behavior:
|
|
46
|
+
* - array<string> matching min/max/minItemLen: pass
|
|
47
|
+
* - string (any shape): fail with specific diagnostic naming the
|
|
48
|
+
* stringification case when the string looks like a JSON array,
|
|
49
|
+
* or with a "wrap in array" hint otherwise
|
|
50
|
+
* - anything else: fail with zod's normal messages
|
|
51
|
+
*
|
|
52
|
+
* Output type is `string[]`. Chain `.optional()` for optional fields.
|
|
53
|
+
*/
|
|
54
|
+
export function strictStringArray(opts = {}) {
|
|
55
|
+
const min = opts.min ?? 1;
|
|
56
|
+
const max = opts.max;
|
|
57
|
+
const minItemLen = opts.minItemLen ?? 1;
|
|
58
|
+
const fieldName = opts.fieldName;
|
|
59
|
+
const real = (() => {
|
|
60
|
+
let s = z.array(z.string().min(minItemLen)).min(min);
|
|
61
|
+
if (max !== undefined)
|
|
62
|
+
s = s.max(max);
|
|
63
|
+
return s;
|
|
64
|
+
})();
|
|
65
|
+
return z
|
|
66
|
+
.any()
|
|
67
|
+
.transform((v, ctx) => {
|
|
68
|
+
if (typeof v === "string") {
|
|
69
|
+
// Log to stderr so MCP host captures the diagnostic event even
|
|
70
|
+
// though the handler never runs. Tagged for grep.
|
|
71
|
+
// eslint-disable-next-line no-console
|
|
72
|
+
console.error(`[ollama-intern:stringified-array-guard] field=${fieldName ?? "?"} received=string looks_like_json_array=${v.trim().startsWith("[") && v.trim().endsWith("]")}`);
|
|
73
|
+
ctx.addIssue({
|
|
74
|
+
code: z.ZodIssueCode.custom,
|
|
75
|
+
message: buildStringDiagnostic(v, fieldName),
|
|
76
|
+
});
|
|
77
|
+
return z.NEVER;
|
|
78
|
+
}
|
|
79
|
+
const res = real.safeParse(v);
|
|
80
|
+
if (!res.success) {
|
|
81
|
+
for (const issue of res.error.issues)
|
|
82
|
+
ctx.addIssue(issue);
|
|
83
|
+
return z.NEVER;
|
|
84
|
+
}
|
|
85
|
+
return res.data;
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=stringifiedArrayGuard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stringifiedArrayGuard.js","sourceRoot":"","sources":["../../src/guardrails/stringifiedArrayGuard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AASxB,SAAS,qBAAqB,CAC5B,KAAa,EACb,SAA6B;IAE7B,MAAM,KAAK,GAAG,SAAS,IAAI,OAAO,CAAC;IACnC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,MAAM,kBAAkB,GACtB,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IACnD,MAAM,OAAO,GACX,OAAO,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC;IAE/D,IAAI,kBAAkB,EAAE,CAAC;QACvB,OAAO,CACL,mCAAmC,KAAK,MAAM;YAC9C,+DAA+D,OAAO,KAAK;YAC3E,oEAAoE;YACpE,kCAAkC;YAClC,0DAA0D;YAC1D,mFAAmF,CACpF,CAAC;IACJ,CAAC;IACD,OAAO,CACL,+BAA+B,KAAK,mBAAmB,OAAO,KAAK;QACnE,yDAAyD,CAC1D,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,iBAAiB,CAC/B,OAA8B,EAAE;IAEhC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;IAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;IACrB,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,CAAC,CAAC;IACxC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;IAEjC,MAAM,IAAI,GAAG,CAAC,GAAG,EAAE;QACjB,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACrD,IAAI,GAAG,KAAK,SAAS;YAAE,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACtC,OAAO,CAAC,CAAC;IACX,CAAC,CAAC,EAAE,CAAC;IAEL,OAAO,CAAC;SACL,GAAG,EAAE;SACL,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAY,EAAE;QAC9B,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;YAC1B,+DAA+D;YAC/D,kDAAkD;YAClD,sCAAsC;YACtC,OAAO,CAAC,KAAK,CACX,iDACE,SAAS,IAAI,GACf,0CACE,CAAC,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,GAAG,CACnD,EAAE,CACH,CAAC;YACF,GAAG,CAAC,QAAQ,CAAC;gBACX,IAAI,EAAE,CAAC,CAAC,YAAY,CAAC,MAAM;gBAC3B,OAAO,EAAE,qBAAqB,CAAC,CAAC,EAAE,SAAS,CAAC;aAC7C,CAAC,CAAC;YACH,OAAO,CAAC,CAAC,KAAK,CAAC;QACjB,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QAC9B,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;YACjB,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM;gBAAE,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;YAC1D,OAAO,CAAC,CAAC,KAAK,CAAC;QACjB,CAAC;QACD,OAAO,GAAG,CAAC,IAAI,CAAC;IAClB,CAAC,CAAmC,CAAC;AACzC,CAAC"}
|
|
@@ -30,16 +30,16 @@ export declare const changeBriefSchema: z.ZodObject<{
|
|
|
30
30
|
max_breakpoints: z.ZodOptional<z.ZodNumber>;
|
|
31
31
|
max_validation_checks: z.ZodOptional<z.ZodNumber>;
|
|
32
32
|
}, "strip", z.ZodTypeAny, {
|
|
33
|
-
source_paths?: string[] | undefined;
|
|
34
33
|
per_file_max_chars?: number | undefined;
|
|
34
|
+
source_paths?: string[] | undefined;
|
|
35
35
|
corpus?: string | undefined;
|
|
36
36
|
corpus_query?: string | undefined;
|
|
37
37
|
diff_text?: string | undefined;
|
|
38
38
|
max_breakpoints?: number | undefined;
|
|
39
39
|
max_validation_checks?: number | undefined;
|
|
40
40
|
}, {
|
|
41
|
-
source_paths?: string[] | undefined;
|
|
42
41
|
per_file_max_chars?: number | undefined;
|
|
42
|
+
source_paths?: string[] | undefined;
|
|
43
43
|
corpus?: string | undefined;
|
|
44
44
|
corpus_query?: string | undefined;
|
|
45
45
|
diff_text?: string | undefined;
|
package/dist/tools/classify.d.ts
CHANGED
|
@@ -2,15 +2,14 @@
|
|
|
2
2
|
* ollama_classify — single-label classification with confidence.
|
|
3
3
|
* Tier: Instant.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* - `text`
|
|
7
|
-
* - `
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* completes and ok_count/error_count surface the split.
|
|
5
|
+
* Three input modes (exactly one):
|
|
6
|
+
* - `text` : single text, classified directly
|
|
7
|
+
* - `source_path` : single file, read + classified server-side — caller
|
|
8
|
+
* never pre-reads the file (context preservation)
|
|
9
|
+
* - `items` : batch of {id, text} — returns one batch envelope with
|
|
10
|
+
* per-item {id, ok, result|error}
|
|
12
11
|
*
|
|
13
|
-
* Exactly one of {text, items} must be provided.
|
|
12
|
+
* Exactly one of {text, source_path, items} must be provided.
|
|
14
13
|
*/
|
|
15
14
|
import { z } from "zod";
|
|
16
15
|
import type { Envelope } from "../envelope.js";
|
|
@@ -19,6 +18,7 @@ import { type ClassifyGuarded } from "../guardrails/confidence.js";
|
|
|
19
18
|
import type { RunContext } from "../runContext.js";
|
|
20
19
|
export declare const classifySchema: z.ZodObject<{
|
|
21
20
|
text: z.ZodOptional<z.ZodString>;
|
|
21
|
+
source_path: z.ZodOptional<z.ZodString>;
|
|
22
22
|
items: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
23
23
|
id: z.ZodString;
|
|
24
24
|
text: z.ZodString;
|
|
@@ -29,9 +29,10 @@ export declare const classifySchema: z.ZodObject<{
|
|
|
29
29
|
text: string;
|
|
30
30
|
id: string;
|
|
31
31
|
}>, "many">>;
|
|
32
|
-
labels: z.
|
|
32
|
+
labels: z.ZodType<string[], z.ZodTypeDef, string[]>;
|
|
33
33
|
allow_none: z.ZodOptional<z.ZodBoolean>;
|
|
34
34
|
threshold: z.ZodOptional<z.ZodNumber>;
|
|
35
|
+
per_file_max_chars: z.ZodOptional<z.ZodNumber>;
|
|
35
36
|
}, "strip", z.ZodTypeAny, {
|
|
36
37
|
labels: string[];
|
|
37
38
|
items?: {
|
|
@@ -39,8 +40,10 @@ export declare const classifySchema: z.ZodObject<{
|
|
|
39
40
|
id: string;
|
|
40
41
|
}[] | undefined;
|
|
41
42
|
text?: string | undefined;
|
|
43
|
+
source_path?: string | undefined;
|
|
42
44
|
allow_none?: boolean | undefined;
|
|
43
45
|
threshold?: number | undefined;
|
|
46
|
+
per_file_max_chars?: number | undefined;
|
|
44
47
|
}, {
|
|
45
48
|
labels: string[];
|
|
46
49
|
items?: {
|
|
@@ -48,8 +51,10 @@ export declare const classifySchema: z.ZodObject<{
|
|
|
48
51
|
id: string;
|
|
49
52
|
}[] | undefined;
|
|
50
53
|
text?: string | undefined;
|
|
54
|
+
source_path?: string | undefined;
|
|
51
55
|
allow_none?: boolean | undefined;
|
|
52
56
|
threshold?: number | undefined;
|
|
57
|
+
per_file_max_chars?: number | undefined;
|
|
53
58
|
}>;
|
|
54
59
|
export type ClassifyInput = z.infer<typeof classifySchema>;
|
|
55
60
|
export declare function handleClassify(input: ClassifyInput, ctx: RunContext): Promise<Envelope<ClassifyGuarded> | Envelope<BatchResult<ClassifyGuarded>>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"classify.d.ts","sourceRoot":"","sources":["../../src/tools/classify.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"classify.d.ts","sourceRoot":"","sources":["../../src/tools/classify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAG/C,OAAO,EAAY,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAA4B,KAAK,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAI7F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiBzB,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AA2C3D,wBAAsB,cAAc,CAClC,KAAK,EAAE,aAAa,EACpB,GAAG,EAAE,UAAU,GACd,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,GAAG,QAAQ,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC,CAAC,CA+C7E"}
|
package/dist/tools/classify.js
CHANGED
|
@@ -2,24 +2,26 @@
|
|
|
2
2
|
* ollama_classify — single-label classification with confidence.
|
|
3
3
|
* Tier: Instant.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* - `text`
|
|
7
|
-
* - `
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* completes and ok_count/error_count surface the split.
|
|
5
|
+
* Three input modes (exactly one):
|
|
6
|
+
* - `text` : single text, classified directly
|
|
7
|
+
* - `source_path` : single file, read + classified server-side — caller
|
|
8
|
+
* never pre-reads the file (context preservation)
|
|
9
|
+
* - `items` : batch of {id, text} — returns one batch envelope with
|
|
10
|
+
* per-item {id, ok, result|error}
|
|
12
11
|
*
|
|
13
|
-
* Exactly one of {text, items} must be provided.
|
|
12
|
+
* Exactly one of {text, source_path, items} must be provided.
|
|
14
13
|
*/
|
|
15
14
|
import { z } from "zod";
|
|
16
15
|
import { TEMPERATURE_BY_SHAPE } from "../tiers.js";
|
|
17
16
|
import { runTool } from "./runner.js";
|
|
18
17
|
import { runBatch } from "./batch.js";
|
|
19
18
|
import { applyConfidenceThreshold } from "../guardrails/confidence.js";
|
|
19
|
+
import { strictStringArray } from "../guardrails/stringifiedArrayGuard.js";
|
|
20
|
+
import { loadSources } from "../sources.js";
|
|
20
21
|
import { InternError } from "../errors.js";
|
|
21
22
|
export const classifySchema = z.object({
|
|
22
|
-
text: z.string().min(1).optional().describe("The single text to classify. Use this OR items
|
|
23
|
+
text: z.string().min(1).optional().describe("The single text to classify. Use this OR source_path OR items — exactly one."),
|
|
24
|
+
source_path: z.string().min(1).optional().describe("A single file path to read + classify server-side. Use this instead of `text` to save Claude context — the server reads the file, Claude never sees its contents."),
|
|
23
25
|
items: z
|
|
24
26
|
.array(z.object({
|
|
25
27
|
id: z.string().min(1).describe("Caller-provided, unique within the batch."),
|
|
@@ -28,9 +30,10 @@ export const classifySchema = z.object({
|
|
|
28
30
|
.min(1)
|
|
29
31
|
.optional()
|
|
30
32
|
.describe("Batch of texts to classify. Each needs a stable caller-provided id so results join back to source inputs cleanly. Returns one batch envelope with per-item {id, ok, result|error} entries."),
|
|
31
|
-
labels:
|
|
33
|
+
labels: strictStringArray({ min: 2, fieldName: "labels" }).describe("Candidate labels — the model picks exactly one, or null if allow_none."),
|
|
32
34
|
allow_none: z.boolean().optional().describe("If true and confidence < threshold, return label=null instead of a weak guess."),
|
|
33
35
|
threshold: z.number().min(0).max(1).optional().describe("Confidence floor (default 0.7)."),
|
|
36
|
+
per_file_max_chars: z.number().int().min(1000).max(200_000).optional().describe("Chars to read when source_path is used (default 40k)."),
|
|
34
37
|
});
|
|
35
38
|
function buildPromptFor(text, input) {
|
|
36
39
|
const labels = input.labels.map((l) => `"${l}"`).join(", ");
|
|
@@ -58,9 +61,11 @@ function parseClassify(raw) {
|
|
|
58
61
|
}
|
|
59
62
|
}
|
|
60
63
|
function assertExactlyOneInput(input) {
|
|
61
|
-
const given = (input.text !== undefined ? 1 : 0) +
|
|
64
|
+
const given = (input.text !== undefined ? 1 : 0) +
|
|
65
|
+
(input.source_path !== undefined ? 1 : 0) +
|
|
66
|
+
(input.items !== undefined ? 1 : 0);
|
|
62
67
|
if (given !== 1) {
|
|
63
|
-
throw new InternError("SCHEMA_INVALID", `ollama_classify: provide exactly one of "text" or "items" (given ${given}).`, "Pass text for a single call, or items:[{id,text}] for a batch.
|
|
68
|
+
throw new InternError("SCHEMA_INVALID", `ollama_classify: provide exactly one of "text", "source_path", or "items" (given ${given}).`, "Pass text for a single call, source_path to read a file server-side, or items:[{id,text}] for a batch.", false);
|
|
64
69
|
}
|
|
65
70
|
}
|
|
66
71
|
export async function handleClassify(input, ctx) {
|
|
@@ -83,7 +88,15 @@ export async function handleClassify(input, ctx) {
|
|
|
83
88
|
}),
|
|
84
89
|
});
|
|
85
90
|
}
|
|
86
|
-
|
|
91
|
+
let text;
|
|
92
|
+
if (input.source_path !== undefined) {
|
|
93
|
+
const perFileMax = input.per_file_max_chars ?? 40_000;
|
|
94
|
+
const [loaded] = await loadSources([input.source_path], perFileMax);
|
|
95
|
+
text = loaded.body;
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
text = input.text;
|
|
99
|
+
}
|
|
87
100
|
return runTool({
|
|
88
101
|
tool: "ollama_classify",
|
|
89
102
|
tier: "instant",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"classify.js","sourceRoot":"","sources":["../../src/tools/classify.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"classify.js","sourceRoot":"","sources":["../../src/tools/classify.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/draft.d.ts
CHANGED
|
@@ -33,6 +33,10 @@ export interface DraftResult {
|
|
|
33
33
|
draft: string;
|
|
34
34
|
is_draft: true;
|
|
35
35
|
compile_check?: CompileCheckResult;
|
|
36
|
+
/** Number of regeneration rounds triggered by the banned-phrase guard (style="doc" only). 0 means the first attempt passed. */
|
|
37
|
+
regenerations_triggered?: number;
|
|
38
|
+
/** Phrases detected in rejected attempts, deduped in order of first appearance. */
|
|
39
|
+
detected_phrases?: string[];
|
|
36
40
|
}
|
|
37
41
|
export declare function handleDraft(input: DraftInput, ctx: RunContext): Promise<Envelope<DraftResult>>;
|
|
38
42
|
//# sourceMappingURL=draft.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"draft.d.ts","sourceRoot":"","sources":["../../src/tools/draft.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAI/C,OAAO,EAAgB,KAAK,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"draft.d.ts","sourceRoot":"","sources":["../../src/tools/draft.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAI/C,OAAO,EAAgB,KAAK,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAItF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAInD,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;EAStB,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAErD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,IAAI,CAAC;IACf,aAAa,CAAC,EAAE,kBAAkB,CAAC;IACnC,+HAA+H;IAC/H,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,mFAAmF;IACnF,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC7B;AAeD,wBAAsB,WAAW,CAC/B,KAAK,EAAE,UAAU,EACjB,GAAG,EAAE,UAAU,GACd,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAuFhC"}
|
package/dist/tools/draft.js
CHANGED
|
@@ -10,7 +10,10 @@ import { TEMPERATURE_BY_SHAPE } from "../tiers.js";
|
|
|
10
10
|
import { runTool } from "./runner.js";
|
|
11
11
|
import { assertWriteAllowed } from "../guardrails/writeConfirm.js";
|
|
12
12
|
import { compileCheck } from "../guardrails/compileCheck.js";
|
|
13
|
+
import { findBannedPhrases } from "../guardrails/bannedPhrases.js";
|
|
14
|
+
import { InternError } from "../errors.js";
|
|
13
15
|
import { timestamp } from "../observability.js";
|
|
16
|
+
const DOC_MAX_ATTEMPTS = 3;
|
|
14
17
|
export const draftSchema = z.object({
|
|
15
18
|
prompt: z.string().min(1).describe("What to draft. Be concrete."),
|
|
16
19
|
language: z
|
|
@@ -48,7 +51,7 @@ export async function handleDraft(input, ctx) {
|
|
|
48
51
|
});
|
|
49
52
|
throw err;
|
|
50
53
|
}
|
|
51
|
-
const
|
|
54
|
+
const runOnce = async () => runTool({
|
|
52
55
|
tool: "ollama_draft",
|
|
53
56
|
tier: "workhorse",
|
|
54
57
|
ctx,
|
|
@@ -59,6 +62,56 @@ export async function handleDraft(input, ctx) {
|
|
|
59
62
|
}),
|
|
60
63
|
parse: (raw) => ({ draft: stripCodeFence(raw), is_draft: true }),
|
|
61
64
|
});
|
|
65
|
+
let envelope;
|
|
66
|
+
const detectedPhraseLog = [];
|
|
67
|
+
let regenerations = 0;
|
|
68
|
+
if (input.style === "doc") {
|
|
69
|
+
let attempt = 0;
|
|
70
|
+
let lastMatches = [];
|
|
71
|
+
envelope = await runOnce();
|
|
72
|
+
attempt = 1;
|
|
73
|
+
lastMatches = findBannedPhrases(envelope.result.draft);
|
|
74
|
+
while (lastMatches.length > 0 && attempt < DOC_MAX_ATTEMPTS) {
|
|
75
|
+
for (const m of lastMatches) {
|
|
76
|
+
if (!detectedPhraseLog.includes(m.phrase))
|
|
77
|
+
detectedPhraseLog.push(m.phrase);
|
|
78
|
+
}
|
|
79
|
+
await ctx.logger.log({
|
|
80
|
+
kind: "guardrail",
|
|
81
|
+
ts: timestamp(),
|
|
82
|
+
tool: "ollama_draft",
|
|
83
|
+
rule: "bannedPhrases",
|
|
84
|
+
action: "regenerated",
|
|
85
|
+
detail: { attempt, detected: lastMatches.map((m) => m.phrase) },
|
|
86
|
+
});
|
|
87
|
+
regenerations += 1;
|
|
88
|
+
envelope = await runOnce();
|
|
89
|
+
attempt += 1;
|
|
90
|
+
lastMatches = findBannedPhrases(envelope.result.draft);
|
|
91
|
+
}
|
|
92
|
+
if (lastMatches.length > 0) {
|
|
93
|
+
for (const m of lastMatches) {
|
|
94
|
+
if (!detectedPhraseLog.includes(m.phrase))
|
|
95
|
+
detectedPhraseLog.push(m.phrase);
|
|
96
|
+
}
|
|
97
|
+
await ctx.logger.log({
|
|
98
|
+
kind: "guardrail",
|
|
99
|
+
ts: timestamp(),
|
|
100
|
+
tool: "ollama_draft",
|
|
101
|
+
rule: "bannedPhrases",
|
|
102
|
+
action: "blocked",
|
|
103
|
+
detail: { attempts: attempt, detected: detectedPhraseLog },
|
|
104
|
+
});
|
|
105
|
+
throw new InternError("DRAFT_BANNED_PHRASE", `draft(style="doc") produced banned marketing phrases after ${attempt} attempts: ${detectedPhraseLog.join(", ")}`, `Rewrite the prompt to demand concrete, falsifiable claims — e.g. "name a specific capability and a measurable outcome; avoid words like 'seamless', 'effortless', 'leverage'". Consider style="concise" if brevity matters more than tone.`, true);
|
|
106
|
+
}
|
|
107
|
+
if (regenerations > 0)
|
|
108
|
+
envelope.result.regenerations_triggered = regenerations;
|
|
109
|
+
if (detectedPhraseLog.length > 0)
|
|
110
|
+
envelope.result.detected_phrases = detectedPhraseLog;
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
envelope = await runOnce();
|
|
114
|
+
}
|
|
62
115
|
if (input.language) {
|
|
63
116
|
envelope.result.compile_check = await compileCheck(envelope.result.draft, input.language);
|
|
64
117
|
}
|
package/dist/tools/draft.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"draft.js","sourceRoot":"","sources":["../../src/tools/draft.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EAAE,YAAY,EAA2B,MAAM,+BAA+B,CAAC;AACtF,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGhD,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,6BAA6B,CAAC;IACjE,QAAQ,EAAE,CAAC;SACR,IAAI,CAAC,CAAC,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;SAC1D,QAAQ,EAAE;SACV,QAAQ,CAAC,wEAAwE,CAAC;IACrF,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sDAAsD,CAAC;IAC7G,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2FAA2F,CAAC;IACxI,aAAa,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,uDAAuD,CAAC;CACxG,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"draft.js","sourceRoot":"","sources":["../../src/tools/draft.ts"],"names":[],"mappings":"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"}
|