@gaunt-sloth/core 2.0.0-alpha.3 → 2.0.0-alpha.30
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/README.md +52 -20
- package/dist/config/colour.d.ts +38 -0
- package/dist/config/colour.js +36 -0
- package/dist/config/colour.js.map +1 -0
- package/dist/config/defaults.d.ts +84 -0
- package/dist/config/defaults.js +99 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/filesystem-tools.d.ts +41 -0
- package/dist/config/filesystem-tools.js +56 -0
- package/dist/config/filesystem-tools.js.map +1 -0
- package/dist/config/jsonc.d.ts +12 -0
- package/dist/config/jsonc.js +41 -0
- package/dist/config/jsonc.js.map +1 -0
- package/dist/config/loader.d.ts +246 -0
- package/dist/config/loader.js +1321 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/mouse.d.ts +50 -0
- package/dist/config/mouse.js +44 -0
- package/dist/config/mouse.js.map +1 -0
- package/dist/config/profiles.d.ts +68 -0
- package/dist/config/profiles.js +93 -0
- package/dist/config/profiles.js.map +1 -0
- package/dist/config/providerKeys.d.ts +69 -0
- package/dist/config/providerKeys.js +69 -0
- package/dist/config/providerKeys.js.map +1 -0
- package/dist/config/schema.d.ts +2999 -0
- package/dist/config/schema.js +1519 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/config/shell-policy.d.ts +896 -0
- package/dist/config/shell-policy.js +750 -0
- package/dist/config/shell-policy.js.map +1 -0
- package/dist/config/tool-descriptions.d.ts +211 -0
- package/dist/config/tool-descriptions.js +272 -0
- package/dist/config/tool-descriptions.js.map +1 -0
- package/dist/config/types.d.ts +760 -0
- package/dist/config/types.js +13 -0
- package/dist/config/types.js.map +1 -0
- package/dist/config.d.ts +34 -827
- package/dist/config.js +25 -657
- package/dist/config.js.map +1 -1
- package/dist/constants.d.ts +46 -0
- package/dist/constants.js +46 -0
- package/dist/constants.js.map +1 -1
- package/dist/core/GthAbstractAgent.d.ts +135 -2
- package/dist/core/GthAbstractAgent.js +496 -30
- package/dist/core/GthAbstractAgent.js.map +1 -1
- package/dist/core/GthAgentRunner.d.ts +568 -54
- package/dist/core/GthAgentRunner.js +1537 -136
- package/dist/core/GthAgentRunner.js.map +1 -1
- package/dist/core/GthLangChainAgent.d.ts +115 -0
- package/dist/core/GthLangChainAgent.js +644 -17
- package/dist/core/GthLangChainAgent.js.map +1 -1
- package/dist/core/approvals/annotations.d.ts +122 -0
- package/dist/core/approvals/annotations.js +137 -0
- package/dist/core/approvals/annotations.js.map +1 -0
- package/dist/core/approvals/grants.d.ts +216 -0
- package/dist/core/approvals/grants.js +469 -0
- package/dist/core/approvals/grants.js.map +1 -0
- package/dist/core/approvals/matcher.d.ts +202 -0
- package/dist/core/approvals/matcher.js +267 -0
- package/dist/core/approvals/matcher.js.map +1 -0
- package/dist/core/approvals/mcpSubjects.d.ts +40 -0
- package/dist/core/approvals/mcpSubjects.js +99 -0
- package/dist/core/approvals/mcpSubjects.js.map +1 -0
- package/dist/core/approvals/toolAnnotationSources.d.ts +105 -0
- package/dist/core/approvals/toolAnnotationSources.js +277 -0
- package/dist/core/approvals/toolAnnotationSources.js.map +1 -0
- package/dist/core/approvals/toolHost.d.ts +46 -0
- package/dist/core/approvals/toolHost.js +108 -0
- package/dist/core/approvals/toolHost.js.map +1 -0
- package/dist/core/debugCapture.d.ts +75 -0
- package/dist/core/debugCapture.js +101 -0
- package/dist/core/debugCapture.js.map +1 -0
- package/dist/core/gthLeanAgentFactory.d.ts +9 -0
- package/dist/core/gthLeanAgentFactory.js +10 -0
- package/dist/core/gthLeanAgentFactory.js.map +1 -0
- package/dist/core/launchBanner.d.ts +120 -0
- package/dist/core/launchBanner.js +418 -0
- package/dist/core/launchBanner.js.map +1 -0
- package/dist/core/plainToolIndication.d.ts +15 -0
- package/dist/core/plainToolIndication.js +174 -0
- package/dist/core/plainToolIndication.js.map +1 -0
- package/dist/core/reasoningBlocks.d.ts +60 -0
- package/dist/core/reasoningBlocks.js +98 -0
- package/dist/core/reasoningBlocks.js.map +1 -0
- package/dist/core/refusal.d.ts +53 -0
- package/dist/core/refusal.js +133 -0
- package/dist/core/refusal.js.map +1 -0
- package/dist/core/runStats.d.ts +52 -0
- package/dist/core/runStats.js +118 -0
- package/dist/core/runStats.js.map +1 -0
- package/dist/core/shell/ShellCommandFailedError.d.ts +54 -0
- package/dist/core/shell/ShellCommandFailedError.js +68 -0
- package/dist/core/shell/ShellCommandFailedError.js.map +1 -0
- package/dist/core/shell/abstention.d.ts +88 -0
- package/dist/core/shell/abstention.js +184 -0
- package/dist/core/shell/abstention.js.map +1 -0
- package/dist/core/shell/approvalCapture.d.ts +271 -0
- package/dist/core/shell/approvalCapture.js +108 -0
- package/dist/core/shell/approvalCapture.js.map +1 -0
- package/dist/core/shell/approvalStop.d.ts +84 -0
- package/dist/core/shell/approvalStop.js +119 -0
- package/dist/core/shell/approvalStop.js.map +1 -0
- package/dist/core/shell/arity.d.ts +6 -0
- package/dist/core/shell/arity.js +20 -6
- package/dist/core/shell/arity.js.map +1 -1
- package/dist/core/shell/denylist.d.ts +11 -0
- package/dist/core/shell/denylist.js +37 -0
- package/dist/core/shell/denylist.js.map +1 -0
- package/dist/core/shell/escalationSeverity.d.ts +141 -0
- package/dist/core/shell/escalationSeverity.js +89 -0
- package/dist/core/shell/escalationSeverity.js.map +1 -0
- package/dist/core/shell/framing.d.ts +190 -0
- package/dist/core/shell/framing.js +633 -0
- package/dist/core/shell/framing.js.map +1 -0
- package/dist/core/shell/hardline.d.ts +81 -0
- package/dist/core/shell/hardline.js +607 -0
- package/dist/core/shell/hardline.js.map +1 -0
- package/dist/core/shell/negotiation.d.ts +249 -0
- package/dist/core/shell/negotiation.js +355 -0
- package/dist/core/shell/negotiation.js.map +1 -0
- package/dist/core/shell/normalize.d.ts +44 -4
- package/dist/core/shell/normalize.js +61 -7
- package/dist/core/shell/normalize.js.map +1 -1
- package/dist/core/shell/openWorld.d.ts +263 -0
- package/dist/core/shell/openWorld.js +1188 -0
- package/dist/core/shell/openWorld.js.map +1 -0
- package/dist/core/shell/rater.d.ts +935 -0
- package/dist/core/shell/rater.js +1473 -0
- package/dist/core/shell/rater.js.map +1 -0
- package/dist/core/shell/raterModel.d.ts +41 -0
- package/dist/core/shell/raterModel.js +51 -0
- package/dist/core/shell/raterModel.js.map +1 -0
- package/dist/core/shell/rejection.d.ts +69 -0
- package/dist/core/shell/rejection.js +38 -0
- package/dist/core/shell/rejection.js.map +1 -0
- package/dist/core/toolCallRepair/grammar.d.ts +41 -0
- package/dist/core/toolCallRepair/grammar.js +116 -0
- package/dist/core/toolCallRepair/grammar.js.map +1 -0
- package/dist/core/toolCallRepair/index.d.ts +2 -0
- package/dist/core/toolCallRepair/index.js +7 -0
- package/dist/core/toolCallRepair/index.js.map +1 -0
- package/dist/core/toolCallRepair/payload.d.ts +36 -0
- package/dist/core/toolCallRepair/payload.js +341 -0
- package/dist/core/toolCallRepair/payload.js.map +1 -0
- package/dist/core/toolCallRepair/promote.d.ts +45 -0
- package/dist/core/toolCallRepair/promote.js +90 -0
- package/dist/core/toolCallRepair/promote.js.map +1 -0
- package/dist/core/toolDisplay.d.ts +123 -0
- package/dist/core/toolDisplay.js +451 -0
- package/dist/core/toolDisplay.js.map +1 -0
- package/dist/core/toolOutputChannel.d.ts +95 -0
- package/dist/core/toolOutputChannel.js +165 -0
- package/dist/core/toolOutputChannel.js.map +1 -0
- package/dist/core/types.d.ts +294 -12
- package/dist/core/types.js.map +1 -1
- package/dist/history/historyFormat.d.ts +28 -0
- package/dist/history/historyFormat.js +127 -0
- package/dist/history/historyFormat.js.map +1 -0
- package/dist/history/historyStore.d.ts +198 -0
- package/dist/history/historyStore.js +482 -0
- package/dist/history/historyStore.js.map +1 -0
- package/dist/history/recordSession.d.ts +37 -0
- package/dist/history/recordSession.js +56 -0
- package/dist/history/recordSession.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/providers/anthropic.d.ts +1 -1
- package/dist/providers/anthropic.js +5 -10
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/deepseek.d.ts +1 -1
- package/dist/providers/deepseek.js +5 -10
- package/dist/providers/deepseek.js.map +1 -1
- package/dist/providers/geminiSchemaSanitizer.d.ts +55 -0
- package/dist/providers/geminiSchemaSanitizer.js +347 -0
- package/dist/providers/geminiSchemaSanitizer.js.map +1 -0
- package/dist/providers/geminiThinking.d.ts +52 -0
- package/dist/providers/geminiThinking.js +72 -0
- package/dist/providers/geminiThinking.js.map +1 -0
- package/dist/providers/google-genai.d.ts +1 -1
- package/dist/providers/google-genai.js +12 -11
- package/dist/providers/google-genai.js.map +1 -1
- package/dist/providers/groq.d.ts +1 -1
- package/dist/providers/groq.js +5 -10
- package/dist/providers/groq.js.map +1 -1
- package/dist/providers/huggingface.d.ts +25 -0
- package/dist/providers/huggingface.js +69 -0
- package/dist/providers/huggingface.js.map +1 -0
- package/dist/providers/modelCatalog.d.ts +109 -0
- package/dist/providers/modelCatalog.js +245 -0
- package/dist/providers/modelCatalog.js.map +1 -0
- package/dist/providers/modelDiscovery.d.ts +153 -6
- package/dist/providers/modelDiscovery.js +295 -41
- package/dist/providers/modelDiscovery.js.map +1 -1
- package/dist/providers/ollama.d.ts +19 -5
- package/dist/providers/ollama.js +60 -52
- package/dist/providers/ollama.js.map +1 -1
- package/dist/providers/openai.d.ts +1 -1
- package/dist/providers/openai.js +39 -10
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/openrouter.d.ts +4 -5
- package/dist/providers/openrouter.js +20 -35
- package/dist/providers/openrouter.js.map +1 -1
- package/dist/providers/vertexai.d.ts +1 -1
- package/dist/providers/vertexai.js +12 -11
- package/dist/providers/vertexai.js.map +1 -1
- package/dist/providers/xai.d.ts +1 -1
- package/dist/providers/xai.js +5 -10
- package/dist/providers/xai.js.map +1 -1
- package/dist/runtime/askStructured.d.ts +105 -0
- package/dist/runtime/askStructured.js +120 -0
- package/dist/runtime/askStructured.js.map +1 -0
- package/dist/runtime/conversation.d.ts +60 -0
- package/dist/runtime/conversation.js +151 -0
- package/dist/runtime/conversation.js.map +1 -0
- package/dist/runtime/singleShot.d.ts +25 -5
- package/dist/runtime/singleShot.js +95 -36
- package/dist/runtime/singleShot.js.map +1 -1
- package/dist/runtime/structuredOutput.d.ts +104 -0
- package/dist/runtime/structuredOutput.js +393 -0
- package/dist/runtime/structuredOutput.js.map +1 -0
- package/dist/utils/ProgressIndicator.d.ts +21 -0
- package/dist/utils/ProgressIndicator.js +30 -3
- package/dist/utils/ProgressIndicator.js.map +1 -1
- package/dist/utils/aiignoreUtils.js.map +1 -1
- package/dist/utils/binaryOutputUtils.js.map +1 -1
- package/dist/utils/consoleUtils.d.ts +52 -0
- package/dist/utils/consoleUtils.js +72 -2
- package/dist/utils/consoleUtils.js.map +1 -1
- package/dist/utils/crashHandler.d.ts +87 -0
- package/dist/utils/crashHandler.js +128 -0
- package/dist/utils/crashHandler.js.map +1 -0
- package/dist/utils/debugDump.d.ts +134 -0
- package/dist/utils/debugDump.js +381 -0
- package/dist/utils/debugDump.js.map +1 -0
- package/dist/utils/debugUtils.d.ts +13 -4
- package/dist/utils/debugUtils.js +36 -13
- package/dist/utils/debugUtils.js.map +1 -1
- package/dist/utils/displayWidth.d.ts +53 -0
- package/dist/utils/displayWidth.js +195 -0
- package/dist/utils/displayWidth.js.map +1 -0
- package/dist/utils/fileUtils.d.ts +24 -2
- package/dist/utils/fileUtils.js +54 -12
- package/dist/utils/fileUtils.js.map +1 -1
- package/dist/utils/llmUtils.d.ts +39 -8
- package/dist/utils/llmUtils.js +76 -8
- package/dist/utils/llmUtils.js.map +1 -1
- package/dist/utils/redactSecrets.d.ts +63 -0
- package/dist/utils/redactSecrets.js +286 -0
- package/dist/utils/redactSecrets.js.map +1 -0
- package/dist/utils/systemPromptNotes.d.ts +225 -0
- package/dist/utils/systemPromptNotes.js +340 -0
- package/dist/utils/systemPromptNotes.js.map +1 -0
- package/dist/utils/systemUtils.d.ts +49 -1
- package/dist/utils/systemUtils.js +67 -3
- package/dist/utils/systemUtils.js.map +1 -1
- package/dist/utils/toolMatching.d.ts +30 -0
- package/dist/utils/toolMatching.js +44 -0
- package/dist/utils/toolMatching.js.map +1 -0
- package/dist/utils/untrustedText.d.ts +66 -0
- package/dist/utils/untrustedText.js +80 -0
- package/dist/utils/untrustedText.js.map +1 -0
- package/package.json +22 -6
- package/schema/gsloth-config.schema.json +3134 -0
- package/dist/core/shell/allowlist.d.ts +0 -75
- package/dist/core/shell/allowlist.js +0 -187
- package/dist/core/shell/allowlist.js.map +0 -1
- package/dist/core/shell/judge.d.ts +0 -161
- package/dist/core/shell/judge.js +0 -261
- package/dist/core/shell/judge.js.map +0 -1
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool-name pattern matching for allow/deny lists.
|
|
3
|
+
*
|
|
4
|
+
* Generic over any list of tool-name patterns — used by the `allowedTools` allow-list
|
|
5
|
+
* today, and reusable for other name-list gates (e.g. BATCH-10's `must_call` /
|
|
6
|
+
* `must_not_call`). Depends on nothing but the standard library.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Match a single tool `name` against a single `pattern`.
|
|
10
|
+
*
|
|
11
|
+
* - A pattern with **no** `*` is an **exact** match (`name === pattern`), preserving the
|
|
12
|
+
* original exact-name allow-list behavior.
|
|
13
|
+
* - A pattern containing `*` is treated **glob-style**: each `*` matches any run of
|
|
14
|
+
* characters (including none) and every other character is matched literally. The whole
|
|
15
|
+
* name must match — the pattern is anchored at both ends.
|
|
16
|
+
*
|
|
17
|
+
* Regex metacharacters in the literal segments are escaped, so a `.` or `+` in a pattern
|
|
18
|
+
* matches that character literally, never as a regex class.
|
|
19
|
+
*
|
|
20
|
+
* @example toolNameMatchesPattern('mcp__unimarket__buy', 'mcp__unimarket__*') // true
|
|
21
|
+
* @example toolNameMatchesPattern('read_file', '*_file') // true
|
|
22
|
+
* @example toolNameMatchesPattern('abcde', 'a*c*e') // true
|
|
23
|
+
* @example toolNameMatchesPattern('read_file', 'gh_pr') // false
|
|
24
|
+
*/
|
|
25
|
+
export function toolNameMatchesPattern(name, pattern) {
|
|
26
|
+
if (!pattern.includes('*')) {
|
|
27
|
+
return name === pattern;
|
|
28
|
+
}
|
|
29
|
+
// Split on '*' so each literal segment can be fully regex-escaped, then rejoin the
|
|
30
|
+
// segments with '.*' (any run of characters) and anchor the whole thing.
|
|
31
|
+
const regexBody = pattern
|
|
32
|
+
.split('*')
|
|
33
|
+
.map((segment) => segment.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))
|
|
34
|
+
.join('.*');
|
|
35
|
+
return new RegExp(`^${regexBody}$`).test(name);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* True iff `name` matches **any** of `patterns` (see {@link toolNameMatchesPattern}).
|
|
39
|
+
* An empty pattern list matches nothing.
|
|
40
|
+
*/
|
|
41
|
+
export function isToolAllowed(name, patterns) {
|
|
42
|
+
return patterns.some((pattern) => toolNameMatchesPattern(name, pattern));
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=toolMatching.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolMatching.js","sourceRoot":"","sources":["../../src/utils/toolMatching.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAAY,EAAE,OAAe;IAClE,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3B,OAAO,IAAI,KAAK,OAAO,CAAC;IAC1B,CAAC;IACD,mFAAmF;IACnF,yEAAyE;IACzE,MAAM,SAAS,GAAG,OAAO;SACtB,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;SAChE,IAAI,CAAC,IAAI,CAAC,CAAC;IACd,OAAO,IAAI,MAAM,CAAC,IAAI,SAAS,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACjD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,QAA2B;IACrE,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,sBAAsB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;AAC3E,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module utils/untrustedText
|
|
3
|
+
*
|
|
4
|
+
* **The structural delimiters gsloth wraps untrusted text in, and the one function that neutralizes
|
|
5
|
+
* a forged one.**
|
|
6
|
+
*
|
|
7
|
+
* Text that arrived from outside this process — an MCP server's discovery `instructions`, a command
|
|
8
|
+
* string the model composed from an issue body or a fetched page — is quoted into the model's
|
|
9
|
+
* context in several places. Wherever it is, the same two things have to be true:
|
|
10
|
+
*
|
|
11
|
+
* 1. the quoted text is visibly fenced, so the model can tell data from first-party instruction; and
|
|
12
|
+
* 2. **the quoted text cannot forge the fence** and escape it.
|
|
13
|
+
*
|
|
14
|
+
* (2) is the load-bearing half, and it is why the delimiters and the defang live together in one
|
|
15
|
+
* module rather than beside each consumer. A second defang written for a second consumer is how one
|
|
16
|
+
* of them comes to know about a delimiter the other emits: a forged `[END …]` token that the
|
|
17
|
+
* emitting site happens not to defang closes its fence early and the attacker's lines land OUTSIDE
|
|
18
|
+
* the boundary, reading as first-party text. {@link defangUntrustedDelimiters} knows **every**
|
|
19
|
+
* delimiter we emit, so every consumer is protected by every arm.
|
|
20
|
+
*
|
|
21
|
+
* **Defang BEFORE wrapping, always.** That ordering is the whole mechanism; wrapping first and
|
|
22
|
+
* sanitizing after would sanitize a string that already contains the real delimiters.
|
|
23
|
+
*/
|
|
24
|
+
/** The MCP discovery-instructions fence (EXT-32), emitted by `utils/systemPromptNotes.ts`. */
|
|
25
|
+
export declare const MCP_FENCE_BEGIN = "[BEGIN MCP SERVER-PROVIDED CONTEXT]";
|
|
26
|
+
export declare const MCP_FENCE_END = "[END MCP SERVER-PROVIDED CONTEXT]";
|
|
27
|
+
/**
|
|
28
|
+
* EXT-65 — the fence a refused command is quoted back inside, emitted by
|
|
29
|
+
* `core/shell/abstention.ts`. A command the gate could not parse is frequently a command the model
|
|
30
|
+
* assembled out of text it read somewhere, so quoting it back for the model to rewrite is quoting
|
|
31
|
+
* untrusted bytes into the model's context.
|
|
32
|
+
*/
|
|
33
|
+
export declare const QUOTED_COMMAND_FENCE_BEGIN = "[BEGIN QUOTED COMMAND TEXT]";
|
|
34
|
+
export declare const QUOTED_COMMAND_FENCE_END = "[END QUOTED COMMAND TEXT]";
|
|
35
|
+
/** How much of a refused command is quoted back. Generous; a realistic command is far shorter. */
|
|
36
|
+
export declare const QUOTED_COMMAND_MAX_CHARS = 2000;
|
|
37
|
+
/** Appended when {@link QUOTED_COMMAND_MAX_CHARS} actually clipped the quoted command. */
|
|
38
|
+
export declare const QUOTED_COMMAND_TRUNCATION_MARKER = "\u2026 [truncated]";
|
|
39
|
+
/**
|
|
40
|
+
* Neutralize every structural delimiter this codebase emits, inside UNTRUSTED text.
|
|
41
|
+
*
|
|
42
|
+
* The text is fully attacker-influenceable, so it may forge:
|
|
43
|
+
* - either fence's tokens (`[BEGIN|END MCP SERVER-PROVIDED CONTEXT]`,
|
|
44
|
+
* `[BEGIN|END QUOTED COMMAND TEXT]`) — the bracket run is collapsed so they can no longer be
|
|
45
|
+
* read as the real delimiter, while staying legible to a reader who wants to see what was
|
|
46
|
+
* attempted; and
|
|
47
|
+
* - a per-server label line `--- Server: …` (EXT-32) — the leading `---` run is broken so it
|
|
48
|
+
* cannot masquerade as one of ours.
|
|
49
|
+
*
|
|
50
|
+
* After this, the ONLY real delimiters in a composed block are the ones the caller emits. Names we
|
|
51
|
+
* put in our OWN labels come from trusted config keys and are not sanitized — only the untrusted
|
|
52
|
+
* CONTENT is.
|
|
53
|
+
*
|
|
54
|
+
* Whitespace-tolerant (`\s+`, optional bracket padding, `-{3,}`) so trivial spacing variants cannot
|
|
55
|
+
* slip a delimiter through, and case-insensitive so neither can a lowercase one.
|
|
56
|
+
*/
|
|
57
|
+
export declare function defangUntrustedDelimiters(text: string): string;
|
|
58
|
+
/**
|
|
59
|
+
* Truncate untrusted text at `maxChars`, SURROGATE-SAFE, appending `marker` only when text was
|
|
60
|
+
* actually clipped.
|
|
61
|
+
*
|
|
62
|
+
* A naive `slice(0, N)` can split a surrogate pair (e.g. an emoji) at the boundary and emit a lone
|
|
63
|
+
* half-code-unit. If the cut would land between a high and a low surrogate, back off one code unit
|
|
64
|
+
* so the pair is kept whole (dropped entirely rather than split).
|
|
65
|
+
*/
|
|
66
|
+
export declare function capUntrustedText(text: string, maxChars: number, marker: string): string;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module utils/untrustedText
|
|
3
|
+
*
|
|
4
|
+
* **The structural delimiters gsloth wraps untrusted text in, and the one function that neutralizes
|
|
5
|
+
* a forged one.**
|
|
6
|
+
*
|
|
7
|
+
* Text that arrived from outside this process — an MCP server's discovery `instructions`, a command
|
|
8
|
+
* string the model composed from an issue body or a fetched page — is quoted into the model's
|
|
9
|
+
* context in several places. Wherever it is, the same two things have to be true:
|
|
10
|
+
*
|
|
11
|
+
* 1. the quoted text is visibly fenced, so the model can tell data from first-party instruction; and
|
|
12
|
+
* 2. **the quoted text cannot forge the fence** and escape it.
|
|
13
|
+
*
|
|
14
|
+
* (2) is the load-bearing half, and it is why the delimiters and the defang live together in one
|
|
15
|
+
* module rather than beside each consumer. A second defang written for a second consumer is how one
|
|
16
|
+
* of them comes to know about a delimiter the other emits: a forged `[END …]` token that the
|
|
17
|
+
* emitting site happens not to defang closes its fence early and the attacker's lines land OUTSIDE
|
|
18
|
+
* the boundary, reading as first-party text. {@link defangUntrustedDelimiters} knows **every**
|
|
19
|
+
* delimiter we emit, so every consumer is protected by every arm.
|
|
20
|
+
*
|
|
21
|
+
* **Defang BEFORE wrapping, always.** That ordering is the whole mechanism; wrapping first and
|
|
22
|
+
* sanitizing after would sanitize a string that already contains the real delimiters.
|
|
23
|
+
*/
|
|
24
|
+
/** The MCP discovery-instructions fence (EXT-32), emitted by `utils/systemPromptNotes.ts`. */
|
|
25
|
+
export const MCP_FENCE_BEGIN = '[BEGIN MCP SERVER-PROVIDED CONTEXT]';
|
|
26
|
+
export const MCP_FENCE_END = '[END MCP SERVER-PROVIDED CONTEXT]';
|
|
27
|
+
/**
|
|
28
|
+
* EXT-65 — the fence a refused command is quoted back inside, emitted by
|
|
29
|
+
* `core/shell/abstention.ts`. A command the gate could not parse is frequently a command the model
|
|
30
|
+
* assembled out of text it read somewhere, so quoting it back for the model to rewrite is quoting
|
|
31
|
+
* untrusted bytes into the model's context.
|
|
32
|
+
*/
|
|
33
|
+
export const QUOTED_COMMAND_FENCE_BEGIN = '[BEGIN QUOTED COMMAND TEXT]';
|
|
34
|
+
export const QUOTED_COMMAND_FENCE_END = '[END QUOTED COMMAND TEXT]';
|
|
35
|
+
/** How much of a refused command is quoted back. Generous; a realistic command is far shorter. */
|
|
36
|
+
export const QUOTED_COMMAND_MAX_CHARS = 2000;
|
|
37
|
+
/** Appended when {@link QUOTED_COMMAND_MAX_CHARS} actually clipped the quoted command. */
|
|
38
|
+
export const QUOTED_COMMAND_TRUNCATION_MARKER = '… [truncated]';
|
|
39
|
+
/**
|
|
40
|
+
* Neutralize every structural delimiter this codebase emits, inside UNTRUSTED text.
|
|
41
|
+
*
|
|
42
|
+
* The text is fully attacker-influenceable, so it may forge:
|
|
43
|
+
* - either fence's tokens (`[BEGIN|END MCP SERVER-PROVIDED CONTEXT]`,
|
|
44
|
+
* `[BEGIN|END QUOTED COMMAND TEXT]`) — the bracket run is collapsed so they can no longer be
|
|
45
|
+
* read as the real delimiter, while staying legible to a reader who wants to see what was
|
|
46
|
+
* attempted; and
|
|
47
|
+
* - a per-server label line `--- Server: …` (EXT-32) — the leading `---` run is broken so it
|
|
48
|
+
* cannot masquerade as one of ours.
|
|
49
|
+
*
|
|
50
|
+
* After this, the ONLY real delimiters in a composed block are the ones the caller emits. Names we
|
|
51
|
+
* put in our OWN labels come from trusted config keys and are not sanitized — only the untrusted
|
|
52
|
+
* CONTENT is.
|
|
53
|
+
*
|
|
54
|
+
* Whitespace-tolerant (`\s+`, optional bracket padding, `-{3,}`) so trivial spacing variants cannot
|
|
55
|
+
* slip a delimiter through, and case-insensitive so neither can a lowercase one.
|
|
56
|
+
*/
|
|
57
|
+
export function defangUntrustedDelimiters(text) {
|
|
58
|
+
return text
|
|
59
|
+
.replace(/\[\s*(BEGIN|END)\s+MCP\s+SERVER-PROVIDED\s+CONTEXT\s*\]/gi, (_m, kw) => `(server text: ${kw.toUpperCase()} MCP SERVER-PROVIDED CONTEXT)`)
|
|
60
|
+
.replace(/\[\s*(BEGIN|END)\s+QUOTED\s+COMMAND\s+TEXT\s*\]/gi, (_m, kw) => `(quoted text: ${kw.toUpperCase()} QUOTED COMMAND TEXT)`)
|
|
61
|
+
.replace(/-{3,}(\s*Server\s*:)/gi, '- - -$1');
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Truncate untrusted text at `maxChars`, SURROGATE-SAFE, appending `marker` only when text was
|
|
65
|
+
* actually clipped.
|
|
66
|
+
*
|
|
67
|
+
* A naive `slice(0, N)` can split a surrogate pair (e.g. an emoji) at the boundary and emit a lone
|
|
68
|
+
* half-code-unit. If the cut would land between a high and a low surrogate, back off one code unit
|
|
69
|
+
* so the pair is kept whole (dropped entirely rather than split).
|
|
70
|
+
*/
|
|
71
|
+
export function capUntrustedText(text, maxChars, marker) {
|
|
72
|
+
if (text.length <= maxChars)
|
|
73
|
+
return text;
|
|
74
|
+
let end = maxChars;
|
|
75
|
+
const code = text.charCodeAt(end - 1);
|
|
76
|
+
if (code >= 0xd800 && code <= 0xdbff)
|
|
77
|
+
end -= 1; // don't split a surrogate pair
|
|
78
|
+
return `${text.slice(0, end).trimEnd()}\n${marker}`;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=untrustedText.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"untrustedText.js","sourceRoot":"","sources":["../../src/utils/untrustedText.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,8FAA8F;AAC9F,MAAM,CAAC,MAAM,eAAe,GAAG,qCAAqC,CAAC;AACrE,MAAM,CAAC,MAAM,aAAa,GAAG,mCAAmC,CAAC;AAEjE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,6BAA6B,CAAC;AACxE,MAAM,CAAC,MAAM,wBAAwB,GAAG,2BAA2B,CAAC;AAEpE,kGAAkG;AAClG,MAAM,CAAC,MAAM,wBAAwB,GAAG,IAAI,CAAC;AAE7C,0FAA0F;AAC1F,MAAM,CAAC,MAAM,gCAAgC,GAAG,eAAe,CAAC;AAEhE;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,yBAAyB,CAAC,IAAY;IACpD,OAAO,IAAI;SACR,OAAO,CACN,2DAA2D,EAC3D,CAAC,EAAE,EAAE,EAAU,EAAE,EAAE,CAAC,iBAAiB,EAAE,CAAC,WAAW,EAAE,+BAA+B,CACrF;SACA,OAAO,CACN,mDAAmD,EACnD,CAAC,EAAE,EAAE,EAAU,EAAE,EAAE,CAAC,iBAAiB,EAAE,CAAC,WAAW,EAAE,uBAAuB,CAC7E;SACA,OAAO,CAAC,wBAAwB,EAAE,SAAS,CAAC,CAAC;AAClD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,QAAgB,EAAE,MAAc;IAC7E,IAAI,IAAI,CAAC,MAAM,IAAI,QAAQ;QAAE,OAAO,IAAI,CAAC;IACzC,IAAI,GAAG,GAAG,QAAQ,CAAC;IACnB,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IACtC,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,IAAI,MAAM;QAAE,GAAG,IAAI,CAAC,CAAC,CAAC,+BAA+B;IAC/E,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,OAAO,EAAE,KAAK,MAAM,EAAE,CAAC;AACtD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gaunt-sloth/core",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.30",
|
|
4
4
|
"description": "Core utilities and types for Gaunt Sloth",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Andrew Kondratev",
|
|
@@ -30,17 +30,22 @@
|
|
|
30
30
|
"#src/*.js": "./dist/*.js"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@langchain/core": "^1.2.
|
|
34
|
-
"@langchain/langgraph": "^1.4.
|
|
35
|
-
"
|
|
36
|
-
"
|
|
33
|
+
"@langchain/core": "^1.2.3",
|
|
34
|
+
"@langchain/langgraph": "^1.4.8",
|
|
35
|
+
"jiti": "^2.7.0",
|
|
36
|
+
"jsonc-parser": "^3.3.1",
|
|
37
|
+
"langchain": "^1.5.4",
|
|
38
|
+
"string-width": "^8.2.2",
|
|
39
|
+
"zod": "^4.4.3"
|
|
37
40
|
},
|
|
38
41
|
"peerDependencies": {
|
|
39
42
|
"@langchain/anthropic": "^1.5.0",
|
|
40
43
|
"@langchain/deepseek": "^1.1.1",
|
|
41
44
|
"@langchain/google": "^0.2.0",
|
|
42
45
|
"@langchain/groq": "^1.3.0",
|
|
46
|
+
"@langchain/ollama": "^1.3.0",
|
|
43
47
|
"@langchain/openai": "^1.5.1",
|
|
48
|
+
"@langchain/openrouter": "^0.4.5",
|
|
44
49
|
"@langchain/xai": "^1.4.1"
|
|
45
50
|
},
|
|
46
51
|
"peerDependenciesMeta": {
|
|
@@ -56,21 +61,32 @@
|
|
|
56
61
|
"@langchain/groq": {
|
|
57
62
|
"optional": true
|
|
58
63
|
},
|
|
64
|
+
"@langchain/ollama": {
|
|
65
|
+
"optional": true
|
|
66
|
+
},
|
|
59
67
|
"@langchain/openai": {
|
|
60
68
|
"optional": true
|
|
61
69
|
},
|
|
70
|
+
"@langchain/openrouter": {
|
|
71
|
+
"optional": true
|
|
72
|
+
},
|
|
62
73
|
"@langchain/xai": {
|
|
63
74
|
"optional": true
|
|
64
75
|
}
|
|
65
76
|
},
|
|
66
77
|
"files": [
|
|
67
78
|
"./dist/*",
|
|
79
|
+
"./schema/*",
|
|
68
80
|
".gsloth.*.md"
|
|
69
81
|
],
|
|
70
82
|
"publishConfig": {
|
|
71
83
|
"tag": "alpha"
|
|
72
84
|
},
|
|
85
|
+
"devDependencies": {
|
|
86
|
+
"ajv": "8.20.0"
|
|
87
|
+
},
|
|
73
88
|
"scripts": {
|
|
74
|
-
"build": "tsc"
|
|
89
|
+
"build": "tsc",
|
|
90
|
+
"schema:generate": "node scripts/generate-config-schema.mjs"
|
|
75
91
|
}
|
|
76
92
|
}
|