@gaunt-sloth/core 2.0.0-alpha.23 → 2.0.0-alpha.25

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.
Files changed (154) hide show
  1. package/README.md +43 -18
  2. package/dist/config/colour.d.ts +38 -0
  3. package/dist/config/colour.js +36 -0
  4. package/dist/config/colour.js.map +1 -0
  5. package/dist/config/defaults.d.ts +6 -7
  6. package/dist/config/defaults.js +4 -8
  7. package/dist/config/defaults.js.map +1 -1
  8. package/dist/config/loader.d.ts +50 -3
  9. package/dist/config/loader.js +345 -29
  10. package/dist/config/loader.js.map +1 -1
  11. package/dist/config/mouse.d.ts +50 -0
  12. package/dist/config/mouse.js +44 -0
  13. package/dist/config/mouse.js.map +1 -0
  14. package/dist/config/profiles.d.ts +68 -0
  15. package/dist/config/profiles.js +93 -0
  16. package/dist/config/profiles.js.map +1 -0
  17. package/dist/config/schema.d.ts +2441 -116
  18. package/dist/config/schema.js +930 -19
  19. package/dist/config/schema.js.map +1 -1
  20. package/dist/config/shell-policy.d.ts +466 -116
  21. package/dist/config/shell-policy.js +273 -62
  22. package/dist/config/shell-policy.js.map +1 -1
  23. package/dist/config/tool-descriptions.d.ts +165 -0
  24. package/dist/config/tool-descriptions.js +229 -0
  25. package/dist/config/tool-descriptions.js.map +1 -0
  26. package/dist/config/types.d.ts +139 -6
  27. package/dist/config/types.js.map +1 -1
  28. package/dist/config.d.ts +4 -0
  29. package/dist/config.js +4 -0
  30. package/dist/config.js.map +1 -1
  31. package/dist/core/GthAbstractAgent.d.ts +85 -2
  32. package/dist/core/GthAbstractAgent.js +194 -1
  33. package/dist/core/GthAbstractAgent.js.map +1 -1
  34. package/dist/core/GthAgentRunner.d.ts +341 -58
  35. package/dist/core/GthAgentRunner.js +857 -149
  36. package/dist/core/GthAgentRunner.js.map +1 -1
  37. package/dist/core/GthLangChainAgent.d.ts +99 -0
  38. package/dist/core/GthLangChainAgent.js +388 -3
  39. package/dist/core/GthLangChainAgent.js.map +1 -1
  40. package/dist/core/approvals/annotations.d.ts +122 -0
  41. package/dist/core/approvals/annotations.js +137 -0
  42. package/dist/core/approvals/annotations.js.map +1 -0
  43. package/dist/core/approvals/grants.d.ts +216 -0
  44. package/dist/core/approvals/grants.js +469 -0
  45. package/dist/core/approvals/grants.js.map +1 -0
  46. package/dist/core/approvals/matcher.d.ts +202 -0
  47. package/dist/core/approvals/matcher.js +267 -0
  48. package/dist/core/approvals/matcher.js.map +1 -0
  49. package/dist/core/approvals/mcpSubjects.d.ts +40 -0
  50. package/dist/core/approvals/mcpSubjects.js +99 -0
  51. package/dist/core/approvals/mcpSubjects.js.map +1 -0
  52. package/dist/core/approvals/toolAnnotationSources.d.ts +105 -0
  53. package/dist/core/approvals/toolAnnotationSources.js +277 -0
  54. package/dist/core/approvals/toolAnnotationSources.js.map +1 -0
  55. package/dist/core/approvals/toolHost.d.ts +46 -0
  56. package/dist/core/approvals/toolHost.js +108 -0
  57. package/dist/core/approvals/toolHost.js.map +1 -0
  58. package/dist/core/debugCapture.d.ts +16 -0
  59. package/dist/core/debugCapture.js.map +1 -1
  60. package/dist/core/launchBanner.d.ts +120 -0
  61. package/dist/core/launchBanner.js +399 -0
  62. package/dist/core/launchBanner.js.map +1 -0
  63. package/dist/core/plainToolIndication.js +61 -35
  64. package/dist/core/plainToolIndication.js.map +1 -1
  65. package/dist/core/refusal.d.ts +53 -0
  66. package/dist/core/refusal.js +129 -0
  67. package/dist/core/refusal.js.map +1 -0
  68. package/dist/core/shell/approvalStop.d.ts +75 -0
  69. package/dist/core/shell/approvalStop.js +108 -0
  70. package/dist/core/shell/approvalStop.js.map +1 -0
  71. package/dist/core/shell/arity.d.ts +6 -0
  72. package/dist/core/shell/arity.js +20 -6
  73. package/dist/core/shell/arity.js.map +1 -1
  74. package/dist/core/shell/denylist.d.ts +11 -0
  75. package/dist/core/shell/denylist.js +37 -0
  76. package/dist/core/shell/denylist.js.map +1 -0
  77. package/dist/core/shell/normalize.d.ts +41 -1
  78. package/dist/core/shell/normalize.js +58 -4
  79. package/dist/core/shell/normalize.js.map +1 -1
  80. package/dist/core/shell/openWorld.d.ts +138 -0
  81. package/dist/core/shell/openWorld.js +523 -0
  82. package/dist/core/shell/openWorld.js.map +1 -0
  83. package/dist/core/shell/rater.d.ts +560 -0
  84. package/dist/core/shell/rater.js +895 -0
  85. package/dist/core/shell/rater.js.map +1 -0
  86. package/dist/core/shell/raterModel.d.ts +41 -0
  87. package/dist/core/shell/raterModel.js +51 -0
  88. package/dist/core/shell/raterModel.js.map +1 -0
  89. package/dist/core/shell/rejection.d.ts +66 -0
  90. package/dist/core/shell/rejection.js +38 -0
  91. package/dist/core/shell/rejection.js.map +1 -0
  92. package/dist/core/toolCallRepair/grammar.d.ts +41 -0
  93. package/dist/core/toolCallRepair/grammar.js +116 -0
  94. package/dist/core/toolCallRepair/grammar.js.map +1 -0
  95. package/dist/core/toolCallRepair/index.d.ts +2 -0
  96. package/dist/core/toolCallRepair/index.js +7 -0
  97. package/dist/core/toolCallRepair/index.js.map +1 -0
  98. package/dist/core/toolCallRepair/payload.d.ts +36 -0
  99. package/dist/core/toolCallRepair/payload.js +341 -0
  100. package/dist/core/toolCallRepair/payload.js.map +1 -0
  101. package/dist/core/toolCallRepair/promote.d.ts +45 -0
  102. package/dist/core/toolCallRepair/promote.js +90 -0
  103. package/dist/core/toolCallRepair/promote.js.map +1 -0
  104. package/dist/core/toolDisplay.d.ts +14 -1
  105. package/dist/core/toolDisplay.js +69 -12
  106. package/dist/core/toolDisplay.js.map +1 -1
  107. package/dist/core/toolOutputChannel.d.ts +33 -6
  108. package/dist/core/toolOutputChannel.js +61 -8
  109. package/dist/core/toolOutputChannel.js.map +1 -1
  110. package/dist/core/types.d.ts +71 -9
  111. package/dist/core/types.js.map +1 -1
  112. package/dist/providers/geminiSchemaSanitizer.d.ts +6 -3
  113. package/dist/providers/geminiSchemaSanitizer.js +152 -6
  114. package/dist/providers/geminiSchemaSanitizer.js.map +1 -1
  115. package/dist/providers/modelDiscovery.d.ts +18 -4
  116. package/dist/providers/modelDiscovery.js +67 -17
  117. package/dist/providers/modelDiscovery.js.map +1 -1
  118. package/dist/providers/openai.js +34 -0
  119. package/dist/providers/openai.js.map +1 -1
  120. package/dist/runtime/askStructured.d.ts +8 -7
  121. package/dist/runtime/askStructured.js +8 -7
  122. package/dist/runtime/askStructured.js.map +1 -1
  123. package/dist/runtime/conversation.js +89 -76
  124. package/dist/runtime/conversation.js.map +1 -1
  125. package/dist/runtime/singleShot.js +71 -60
  126. package/dist/runtime/singleShot.js.map +1 -1
  127. package/dist/utils/ProgressIndicator.d.ts +21 -0
  128. package/dist/utils/ProgressIndicator.js +30 -3
  129. package/dist/utils/ProgressIndicator.js.map +1 -1
  130. package/dist/utils/consoleUtils.d.ts +30 -0
  131. package/dist/utils/consoleUtils.js +27 -2
  132. package/dist/utils/consoleUtils.js.map +1 -1
  133. package/dist/utils/crashHandler.d.ts +87 -0
  134. package/dist/utils/crashHandler.js +128 -0
  135. package/dist/utils/crashHandler.js.map +1 -0
  136. package/dist/utils/debugDump.d.ts +58 -0
  137. package/dist/utils/debugDump.js +149 -15
  138. package/dist/utils/debugDump.js.map +1 -1
  139. package/dist/utils/llmUtils.d.ts +22 -8
  140. package/dist/utils/llmUtils.js +48 -8
  141. package/dist/utils/llmUtils.js.map +1 -1
  142. package/dist/utils/redactSecrets.js +68 -20
  143. package/dist/utils/redactSecrets.js.map +1 -1
  144. package/dist/utils/systemUtils.d.ts +17 -0
  145. package/dist/utils/systemUtils.js +17 -0
  146. package/dist/utils/systemUtils.js.map +1 -1
  147. package/package.json +5 -2
  148. package/schema/gsloth-config.schema.json +1484 -466
  149. package/dist/core/shell/allowlist.d.ts +0 -75
  150. package/dist/core/shell/allowlist.js +0 -187
  151. package/dist/core/shell/allowlist.js.map +0 -1
  152. package/dist/core/shell/judge.d.ts +0 -161
  153. package/dist/core/shell/judge.js +0 -261
  154. package/dist/core/shell/judge.js.map +0 -1
@@ -0,0 +1,229 @@
1
+ /**
2
+ * §4.5's table, **verbatim**. The wordings are normative copy the model reads; do not paraphrase,
3
+ * re-punctuate or "improve" them.
4
+ *
5
+ * - `read-only` and `write` share one sentence: at both rungs a non-granted call goes to the human,
6
+ * so the user's approval is a certainty, not a possibility.
7
+ * - `auto-safe` softens `will` to `MAY`: the rater approves what it rates safe, so only some calls
8
+ * reach the user.
9
+ * - `full-auto` gets its **own** wording because the consequence differs — the user is not asked
10
+ * there, so promising the user's approval would be false. What can happen is a refusal by the
11
+ * rater.
12
+ * - `bypass` appends nothing to anything: no gate, so no sentence could be true.
13
+ */
14
+ export const RUNG_TOOL_DESCRIPTION_SUFFIXES = {
15
+ 'read-only': "Calling this tool will require the user's approval. Only use it when the result cannot be " +
16
+ 'achieved with the other provided tools.',
17
+ write: "Calling this tool will require the user's approval. Only use it when the result cannot be " +
18
+ 'achieved with the other provided tools.',
19
+ 'auto-safe': "Calling this tool MAY require the user's approval if it does not look safe. Only use it when " +
20
+ 'it is impossible to achieve the result with the other provided tools.',
21
+ 'full-auto': 'Calling this tool MAY be refused by the auto-rater if it does not look safe. Only use it ' +
22
+ 'when it is impossible to achieve the result with the other provided tools.',
23
+ bypass: null,
24
+ };
25
+ /** The distinct suffix strings, for {@link stripRungToolDescriptionSuffix}'s idempotency check. */
26
+ const ALL_SUFFIXES = Array.from(new Set(Object.values(RUNG_TOOL_DESCRIPTION_SUFFIXES).filter((s) => s !== null)));
27
+ /**
28
+ * Access class per built-in tool name. Covers BOTH backends' names: gsloth's own
29
+ * `GthFileSystemToolkit` (lean) and deepagents' filesystem tools (`ls`/`glob`/`grep`, deep) — the
30
+ * two sets overlap on `read_file`/`write_file`/`edit_file`, which is exactly why one flat table
31
+ * keyed by name serves both.
32
+ *
33
+ * Deliberately absent: `run_shell_command`, the fixed dev-command tools, `gth_web_fetch`,
34
+ * `gth_checklist`, `gth_status_update`, `show_a2ui_surface`, MCP/custom/A2A tools. None of them is
35
+ * "reading or writing files in the working folder", so none is granted by a rung's access class.
36
+ * (They are still *granted today* — the gate does not gate them — which {@link isGrantedAtRung}
37
+ * decides on the gated set, not on this table.)
38
+ */
39
+ export const BUILT_IN_TOOL_ACCESS = {
40
+ // gsloth GthFileSystemToolkit (lean backend)
41
+ read_file: 'read',
42
+ read_multiple_files: 'read',
43
+ gth_read_binary: 'read',
44
+ list_directory: 'read',
45
+ list_directory_with_sizes: 'read',
46
+ directory_tree: 'read',
47
+ search_files: 'read',
48
+ get_file_info: 'read',
49
+ list_allowed_directories: 'read',
50
+ write_file: 'write',
51
+ edit_file: 'write',
52
+ create_directory: 'write',
53
+ move_file: 'write',
54
+ delete_file: 'write',
55
+ delete_directory: 'write',
56
+ // deepagents filesystem tools (deep backend) not already named above
57
+ ls: 'read',
58
+ glob: 'read',
59
+ grep: 'read',
60
+ // gsloth built-ins that read file contents in the working folder
61
+ gth_grep: 'read',
62
+ };
63
+ /**
64
+ * §4.3/§4.4 — the one-line descriptions handed to the rater with the granted tools' names.
65
+ *
66
+ * **Authored here on purpose.** §4.3 admits this list as *"trusted, locally-generated text, not
67
+ * part of the fenced block"*, so it may not be assembled from tool `description` fields at large:
68
+ * an MCP server's tool description is attacker-influenceable text, and placing it outside the
69
+ * fenced block would open an injection channel straight past the rater's untrusted-input preamble.
70
+ * Only tools named in THIS table are ever offered, so an MCP, custom or A2A tool can never
71
+ * contribute text to the rater prompt.
72
+ *
73
+ * Restricted to tools that could plausibly stand in for a shell command — the file tools, content
74
+ * search, and the fixed dev-command tools (whose command is human-authored config, so suggesting
75
+ * `run_tests` over `npm test` is exactly the trade this section exists to make). `gth_checklist`,
76
+ * `gth_status_update` and `show_a2ui_surface` are omitted: they substitute for nothing a model
77
+ * would otherwise shell out for, and a suggestion list is only useful while it is short.
78
+ *
79
+ * **`gth_web_fetch` is deliberately NOT here**, though it is ungated at every rung. §4.5's
80
+ * justification for disclosing the posture at all is that the granted tools are "by construction,
81
+ * the constrained ones confined to the working folder" — a network fetch is not. Offering it would
82
+ * let a refused `curl`/`wget` come back as a suggestion whose §7 clause tells the model, verbatim,
83
+ * that the alternative "will not interrupt the user": a refused egress turned into a free one,
84
+ * through the rater rather than through the gate. An `attack` halts before any message reaches the
85
+ * model, but a merely `destructive` fetch would not. Same reasoning excludes MCP and custom tools,
86
+ * which additionally supply text we did not author.
87
+ */
88
+ export const BUILT_IN_TOOL_SUMMARIES = {
89
+ read_file: 'Read one file in the working folder.',
90
+ read_multiple_files: 'Read several files in the working folder in one call.',
91
+ gth_read_binary: 'Read an image or other binary file in the working folder.',
92
+ list_directory: 'List the entries of a directory in the working folder.',
93
+ list_directory_with_sizes: 'List a directory in the working folder with entry sizes.',
94
+ directory_tree: 'Show a recursive tree of a directory in the working folder.',
95
+ search_files: 'Find files in the working folder by name pattern.',
96
+ get_file_info: 'Show size, timestamps and type of a file in the working folder.',
97
+ list_allowed_directories: 'List the directories the file tools are allowed to touch.',
98
+ write_file: 'Create or overwrite a file in the working folder.',
99
+ edit_file: 'Apply a targeted edit to a file in the working folder.',
100
+ create_directory: 'Create a directory in the working folder.',
101
+ move_file: 'Move or rename a file in the working folder.',
102
+ delete_file: 'Delete a file in the working folder.',
103
+ delete_directory: 'Delete a directory in the working folder.',
104
+ ls: 'List the entries of a directory in the working folder.',
105
+ glob: 'Find files in the working folder by glob pattern.',
106
+ grep: 'Search file contents in the working folder by regular expression.',
107
+ gth_grep: 'Search file contents in the working folder by regular expression.',
108
+ run_tests: "Run the project's configured test command.",
109
+ run_single_test: "Run one test file with the project's configured test command.",
110
+ run_lint: "Run the project's configured lint command.",
111
+ run_build: "Run the project's configured build command.",
112
+ };
113
+ /** The sentence §4.5 appends at this rung, or `null` when the rung appends nothing (`bypass`). */
114
+ export function getRungToolDescriptionSuffix(rung) {
115
+ return RUNG_TOOL_DESCRIPTION_SUFFIXES[rung] ?? null;
116
+ }
117
+ /**
118
+ * Is `toolName` auto-approved (granted, free, no prompt and no rating) at `rung`?
119
+ *
120
+ * @param toolName The registered tool name.
121
+ * @param rung The rung in force for the session.
122
+ * @param gatedTools The names the gate actually wires into the approval interrupt. **This is the
123
+ * parameter that keeps the descriptions honest**: a tool the gate does not gate cannot require
124
+ * approval, whatever a rung's table row says about tool classes, so it is granted. Both backends
125
+ * pass the same set they hand to `interruptOn` / `humanInTheLoopMiddleware`.
126
+ *
127
+ * Order:
128
+ * 1. `bypass` grants everything (§2.5) — the gate is off.
129
+ * 2. A tool the gate does not gate is granted at every rung (§4.3's scope boundary).
130
+ * 3. A gated tool is granted only where the rung's own grant covers its access class: read tools
131
+ * from `read-only` up (§2.1), write tools from `write` up (§2.2, and §2.3/§2.4 which grant
132
+ * "everything `write` grants"). A gated tool with no access class — the shell, a network call,
133
+ * an MCP tool — is granted at no rung but `bypass`.
134
+ */
135
+ export function isGrantedAtRung(toolName, rung, gatedTools) {
136
+ if (rung === 'bypass')
137
+ return true;
138
+ if (!gatedTools.includes(toolName))
139
+ return true;
140
+ const access = BUILT_IN_TOOL_ACCESS[toolName];
141
+ if (access === 'read')
142
+ return true;
143
+ if (access === 'write')
144
+ return rung !== 'read-only';
145
+ return false;
146
+ }
147
+ /**
148
+ * Remove a previously-appended §4.5 suffix (any rung's), returning the tool's own description.
149
+ *
150
+ * Makes {@link applyRungAwareToolDescriptions} idempotent and re-appliable at a different rung —
151
+ * which matters because a resolver may hand back the SAME tool instance on a re-init (an MCP
152
+ * client caches its tool objects), and a second pass would otherwise stack sentences.
153
+ */
154
+ export function stripRungToolDescriptionSuffix(description) {
155
+ let result = description;
156
+ // Loop: a description that was appended to twice by an older build still ends up clean.
157
+ let changed = true;
158
+ while (changed) {
159
+ changed = false;
160
+ for (const suffix of ALL_SUFFIXES) {
161
+ if (result.endsWith(suffix)) {
162
+ result = result.slice(0, -suffix.length).replace(/\s+$/, '');
163
+ changed = true;
164
+ }
165
+ }
166
+ }
167
+ return result;
168
+ }
169
+ /**
170
+ * §4.5 — at tool-registration time, append the rung's sentence to the description of every tool
171
+ * that is NOT auto-approved at that rung, and leave every granted tool's description untouched.
172
+ *
173
+ * Mutates in place (and returns the same array): the tools are about to be handed to
174
+ * `createAgent`/`createDeepAgent`, and the array is freshly resolved per init. Idempotent — any
175
+ * previously-appended suffix is stripped first, so re-registration at a different rung replaces
176
+ * the sentence rather than stacking one.
177
+ *
178
+ * A tool with no name is left alone (provider-native "magic object" tools carry no name and cannot
179
+ * be classified); a tool with an empty description gets the suffix as its whole description rather
180
+ * than a leading space.
181
+ */
182
+ export function applyRungAwareToolDescriptions(tools, options) {
183
+ const suffix = getRungToolDescriptionSuffix(options.rung);
184
+ for (const tool of tools) {
185
+ if (!tool || typeof tool.name !== 'string' || tool.name.length === 0)
186
+ continue;
187
+ if (typeof tool.description !== 'string')
188
+ continue;
189
+ const base = stripRungToolDescriptionSuffix(tool.description);
190
+ // A granted tool carries NO sentence — its absence is what marks it free (§4.5).
191
+ if (suffix === null || isGrantedAtRung(tool.name, options.rung, options.gatedTools)) {
192
+ tool.description = base;
193
+ continue;
194
+ }
195
+ tool.description = base.length > 0 ? `${base} ${suffix}` : suffix;
196
+ }
197
+ return tools;
198
+ }
199
+ /**
200
+ * §4.3/§4.4 — the names and one-line descriptions of the built-in tools already granted at `rung`,
201
+ * for the rater prompt.
202
+ *
203
+ * Filtered three ways, each of which matters:
204
+ * - to tools **actually registered** in this session (a suggestion naming a tool the model does not
205
+ * have is worse than no suggestion);
206
+ * - to tools in {@link BUILT_IN_TOOL_SUMMARIES}, so only locally-authored text ever reaches the
207
+ * rater prompt (never an MCP/custom tool's own description);
208
+ * - to tools **granted at the rung** — suggesting a tool that would itself need approval defeats
209
+ * the point.
210
+ *
211
+ * Order follows the registration order so the prompt is stable across runs.
212
+ */
213
+ export function describeGrantedBuiltInTools(registeredToolNames, rung, gatedTools) {
214
+ const seen = new Set();
215
+ const summaries = [];
216
+ for (const name of registeredToolNames) {
217
+ if (seen.has(name))
218
+ continue;
219
+ seen.add(name);
220
+ const description = BUILT_IN_TOOL_SUMMARIES[name];
221
+ if (!description)
222
+ continue;
223
+ if (!isGrantedAtRung(name, rung, gatedTools))
224
+ continue;
225
+ summaries.push({ name, description });
226
+ }
227
+ return summaries;
228
+ }
229
+ //# sourceMappingURL=tool-descriptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-descriptions.js","sourceRoot":"","sources":["../../src/config/tool-descriptions.ts"],"names":[],"mappings":"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"}
@@ -7,7 +7,47 @@
7
7
  import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
8
8
  import type { BaseToolkit, StructuredToolInterface } from '@langchain/core/tools';
9
9
  import type { StatusLevel } from '#src/core/types.js';
10
- import type { BuiltInToolsSetting } from '#src/config/shell-policy.js';
10
+ import type { ApprovalsConfig, BuiltInToolsSetting } from '#src/config/shell-policy.js';
11
+ /**
12
+ * GS2-43 — the seven configurable prompt segments. Each maps to a prompt file with a
13
+ * well-known default name (`.gsloth.backstory.md`, `.gsloth.guidelines.md`,
14
+ * `.gsloth.system.md`, `.gsloth.chat.md`, `.gsloth.code.md`, `.gsloth.exec.md`,
15
+ * `.gsloth.review.md`) and can be retargeted / disabled / composed via
16
+ * {@link GthConfig.prompts}.
17
+ */
18
+ export type PromptSegmentName = 'backstory' | 'guidelines' | 'system' | 'chat' | 'code' | 'exec' | 'review';
19
+ /**
20
+ * GS2-43 — configuration for one prompt segment.
21
+ */
22
+ export interface PromptSegmentConfig {
23
+ /**
24
+ * File to read for this segment. Resolved like every prompt file: the config dir
25
+ * (`.gsloth/.gsloth-settings[/<profile>]/`) first, then relative to the project root.
26
+ */
27
+ path?: string;
28
+ /**
29
+ * `false` drops the segment entirely — even its bundled default. Default `true`.
30
+ */
31
+ enabled?: boolean;
32
+ /**
33
+ * `'replace'` (default): the {@link path} file replaces the built-in segment content.
34
+ * `'append'`: the file content is appended after the built-in content.
35
+ */
36
+ mode?: 'replace' | 'append';
37
+ }
38
+ /**
39
+ * GS2-43 — one segment's setting: a `string` path (shorthand for `{ path }`) or a
40
+ * {@link PromptSegmentConfig} object.
41
+ */
42
+ export type PromptSegmentSetting = string | PromptSegmentConfig;
43
+ /**
44
+ * GS2-43 — the unified `prompts` config object. Replaces the removed flat
45
+ * `projectGuidelines` / `projectReviewInstructions` keys and makes all seven prompt
46
+ * segments retargetable through config. Sibling keys are trivially addable (GS2-44 will
47
+ * add `agents` for AGENTS.md auto-discovery), so keep segment names and future siblings
48
+ * in this one flat namespace.
49
+ */
50
+ export type PromptsConfig = Partial<Record<PromptSegmentName, PromptSegmentSetting>>;
11
51
  /**
12
52
  * Shared per-command tooling configuration (the knobs every actionable command carries).
13
53
  * Reused across the per-command types in {@link GthConfig.commands} and by
@@ -19,11 +59,38 @@ import type { BuiltInToolsSetting } from '#src/config/shell-policy.js';
19
59
  export interface CommandToolingConfig {
20
60
  filesystem?: string[] | 'all' | 'read' | 'none';
21
61
  builtInTools?: BuiltInToolsSetting;
62
+ /**
63
+ * §9.1 — per-command approvals posture. It overrides only the fields it NAMES: `mode`,
64
+ * `rater`, `raterTimeoutMs` and `allow` replace the root's, while `deny` and `escalate`
65
+ * concatenate with it. See {@link GthConfig.approvals}.
66
+ */
67
+ approvals?: ApprovalsConfig;
22
68
  customTools?: CustomToolsConfig | false;
23
69
  /** See {@link GthConfig.allowedTools}. */
24
70
  allowedTools?: string[];
25
71
  binaryFormats?: false | BinaryFormatConfig[];
26
72
  }
73
+ /**
74
+ * GS2-33 — one profile-backed subagent declaration. When the parent agent spawns this subagent
75
+ * (the deepagents `task` tool), the CHILD resolves the named config {@link profile} through the
76
+ * GS2-1 cascade, so it runs under THAT profile's model + tools + prompt (e.g. a cheap flash-lite
77
+ * profile for recall/search subagents while the parent runs on a strong model).
78
+ *
79
+ * The `profile` is a named profile block created by `gth config profile create <name>` — a
80
+ * `.gsloth/.gsloth-settings/<name>/` config dir, the same discovery convention `--profile` /
81
+ * `--identity-profile` resolve.
82
+ */
83
+ export interface SubagentProfileSpec {
84
+ /** Identifier the model selects this subagent by (the task-tool subagent name). */
85
+ name: string;
86
+ /** Description shown to the model when it chooses a subagent. Defaults to a profile note. */
87
+ description?: string;
88
+ /**
89
+ * Named config profile whose model + tools + prompt the CHILD resolves. Threaded through the
90
+ * subagent-spawn config resolution as {@link CommandLineConfigOverrides.identityProfile}.
91
+ */
92
+ profile: string;
93
+ }
27
94
  /**
28
95
  * This is a processed Gaunt Sloth config ready to be passed down into components.
29
96
  *
@@ -80,11 +147,12 @@ export interface GthConfig {
80
147
  */
81
148
  requirementSource: string;
82
149
  /**
83
- * Path to project-specific guidelines.
84
- * The default is `.gsloth.guidelines.md`; this config may be used to point Gaunt Sloth to a different file,
85
- * for example, to AGENTS.md
150
+ * GS2-43 the unified prompt-segment config (see {@link PromptsConfig}). Each of the seven
151
+ * segments (`backstory | guidelines | system | chat | code | exec | review`) accepts a string
152
+ * path (e.g. `"guidelines": "AGENTS.md"`) or an object (`{ path?, enabled?, mode? }`). When a
153
+ * segment is omitted its default-named file / bundled default applies unchanged.
86
154
  */
87
- projectGuidelines: string;
155
+ prompts?: PromptsConfig;
88
156
  /**
89
157
  * Separate identity profile.
90
158
  * May include separate identity, guidelines and command protocol,
@@ -108,7 +176,6 @@ export interface GthConfig {
108
176
  locale?: string;
109
177
  timezone?: string;
110
178
  };
111
- projectReviewInstructions: string;
112
179
  /**
113
180
  * If true, only use user-provided system prompts. Do not fall back to the
114
181
  * bundled `.gsloth.*.md` prompt files shipped with the installation.
@@ -126,6 +193,22 @@ export interface GthConfig {
126
193
  * a per-command value replaces the top-level one.
127
194
  */
128
195
  builtInTools?: BuiltInToolsSetting;
196
+ /**
197
+ * CFG-27 — the tool-approval **ladder**: one of the five rungs (`read-only` · `write` ·
198
+ * `auto-safe` · `full-auto` · `bypass`), written either as the bare rung name or as an object
199
+ * carrying the rater's identity profile and the declared allow/deny lists. Each rung fully
200
+ * determines behaviour — there are no severity thresholds, no strictness levels and no
201
+ * independent rater switch.
202
+ *
203
+ * Settable at the root or per command (`commands.<command>.approvals`). §9.1 — a per-command
204
+ * value overrides only the fields it NAMES. `mode`, `rater` and `raterTimeoutMs` replace the
205
+ * root's; `deny` and `escalate` CONCATENATE across every scope, so a per-command rung can never
206
+ * discard the root's prohibitions; `allow` is REPLACED when the command states its own and
207
+ * inherited when it does not, so a scope may narrow what runs unprompted and may never widen
208
+ * what is prohibited (§3.1: a too-broad allow entry runs unrated, a missed deny entry does not).
209
+ * Absent = `auto-safe`, resolved by `resolveApprovals`.
210
+ */
211
+ approvals?: ApprovalsConfig;
129
212
  tools?: StructuredToolInterface[] | BaseToolkit[] | ServerTool[];
130
213
  /**
131
214
  * Restrict the agent to this allow-list of tool names, applied after every tool source
@@ -201,6 +284,13 @@ export interface GthConfig {
201
284
  * Use colour in output
202
285
  */
203
286
  useColour: boolean;
287
+ /**
288
+ * Enable terminal mouse reporting in the Ink TUI, making its affordances clickable.
289
+ * On by default in an interactive terminal. While it is on the terminal's own text selection
290
+ * needs a modifier (Shift, or Option in some macOS terminals) — set this to `false`, or set
291
+ * `GTH_NO_MOUSE`, to get unmodified selection back.
292
+ */
293
+ useMouse: boolean;
204
294
  /**
205
295
  * Stream session log instead of writing it when inference streaming is complete.
206
296
  * (only works when {@link streamOutput} is true)
@@ -290,6 +380,12 @@ export interface GthConfig {
290
380
  api?: {
291
381
  filesystem?: string[] | 'all' | 'read' | 'none';
292
382
  builtInTools?: BuiltInToolsSetting;
383
+ /**
384
+ * §9.1 — per-command approvals posture. It overrides only the fields it NAMES: `mode`,
385
+ * `rater`, `raterTimeoutMs` and `allow` replace the root's, while `deny` and `escalate`
386
+ * concatenate with it. See {@link GthConfig.approvals}.
387
+ */
388
+ approvals?: ApprovalsConfig;
293
389
  port?: number;
294
390
  cors?: {
295
391
  allowOrigin?: string;
@@ -374,6 +470,27 @@ export interface GthConfig {
374
470
  output?: {
375
471
  header?: boolean;
376
472
  };
473
+ /**
474
+ * EXT-36 — the tool-loop guard: a repeated-identical-`(tool, args)` / no-progress detector that
475
+ * runs as a lean-backend `beforeModel` middleware, the orthogonal sibling of GS2-36's
476
+ * consecutive-tool-ERROR budget. It catches the case GS2-36 leaves open — a model re-issuing the
477
+ * SAME call verbatim, whether it keeps erroring or keeps "succeeding" with the same result.
478
+ *
479
+ * - `false` disables it entirely.
480
+ * - `true` / omitted → WARN on, HALT off, default threshold ({@link DEFAULT_TOOL_LOOP_THRESHOLD}).
481
+ * - object → per-field: `warn` (default ON) injects a control-flow-free nudge at the threshold;
482
+ * `halt` (default OFF, opt-in) ends the run cleanly (`jumpTo:'end'`, never a throw) at the
483
+ * threshold; `threshold` is the number of consecutive identical calls that trip it.
484
+ *
485
+ * WARN is provably harmless (no routing effect, one nudge per signature per streak). The WARN-on
486
+ * default is applied at the read site (not in {@link DEFAULT_CONFIG}) to avoid churning the
487
+ * effective-config snapshot.
488
+ */
489
+ toolLoopGuard?: boolean | {
490
+ warn?: boolean;
491
+ halt?: boolean;
492
+ threshold?: number;
493
+ };
377
494
  /**
378
495
  * BATCH-19 — custom `gth eval` reporters, keyed by the NAME they are selected under
379
496
  * (`gth eval … --reporter <name>`). Each value is a MODULE PATH, resolved relative to the project
@@ -384,6 +501,15 @@ export interface GthConfig {
384
501
  * it is the user's own config, which already executes arbitrary JS.
385
502
  */
386
503
  reporters?: Record<string, string>;
504
+ /**
505
+ * GS2-33 — profile-backed subagents. Each entry names a subagent and the {@link
506
+ * SubagentProfileSpec.profile named config profile} the CHILD resolves when the parent spawns it,
507
+ * so a subagent can run under a different model/tools/prompt than the parent (a cheap profile for
508
+ * recall/search while the parent runs on a strong model). Honored by the deep (deepagents) backend
509
+ * — its `task` tool gains one selectable subagent per entry; the lean backend's own subagent
510
+ * primitive lands in GS2-25.
511
+ */
512
+ subagents?: SubagentProfileSpec[];
387
513
  }
388
514
  /**
389
515
  * `gth pr` command configuration.
@@ -417,6 +543,13 @@ export type ConsoleLevelInput = StatusLevel | keyof typeof StatusLevel | Lowerca
417
543
  export interface RawGthConfig extends Omit<GthConfig, 'llm' | 'consoleLevel'> {
418
544
  llm: LLMConfig;
419
545
  consoleLevel?: ConsoleLevelInput;
546
+ /**
547
+ * GS2-41 — profile composition. When set on a NAMED profile config, this profile inherits from
548
+ * the named base profile: the base resolves first, then this profile's fields merge on top
549
+ * (last-wins). Raw-config-only — resolved and consumed at load time (`resolveConfigExtends`), so
550
+ * it never appears on the resolved {@link GthConfig}.
551
+ */
552
+ extends?: string;
420
553
  }
421
554
  export type BinaryFormatType = 'image' | 'file' | 'audio' | 'video' | 'binary';
422
555
  export interface BinaryFormatConfig {
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"AAiiBA,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,UAAU;IACV,WAAW;IACX,MAAM;IACN,UAAU;IACV,QAAQ;IACR,cAAc;IACd,KAAK;IACL,YAAY;IACZ,aAAa;IACb,QAAQ;CACA,CAAC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"AAwqBA,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,UAAU;IACV,WAAW;IACX,MAAM;IACN,UAAU;IACV,QAAQ;IACR,cAAc;IACd,KAAK;IACL,YAAY;IACZ,aAAa;IACb,QAAQ;CACA,CAAC"}
package/dist/config.d.ts CHANGED
@@ -15,11 +15,15 @@
15
15
  * - `config/defaults.ts` — {@link DEFAULT_CONFIG}.
16
16
  * - `config/loader.ts` — discovery + the layered load/merge pipeline.
17
17
  * - `config/schema.ts` — the Zod schema (single source of truth) + JSON-Schema generator.
18
+ * - `config/tool-descriptions.ts` — EXT-58: the rung-aware tool-description suffixes (§4.5) and
19
+ * the granted-built-in table the rater's alternative suggestion draws on (§4.4).
18
20
  *
19
21
  * Every name that was previously exported from `config.ts` is re-exported here, so the
20
22
  * public import path `@gaunt-sloth/core/config.js` (and `#src/config.js`) is unchanged.
21
23
  */
22
24
  export * from '#src/config/types.js';
23
25
  export * from '#src/config/shell-policy.js';
26
+ export * from '#src/config/tool-descriptions.js';
24
27
  export * from '#src/config/defaults.js';
25
28
  export * from '#src/config/loader.js';
29
+ export * from '#src/config/profiles.js';
package/dist/config.js CHANGED
@@ -15,12 +15,16 @@
15
15
  * - `config/defaults.ts` — {@link DEFAULT_CONFIG}.
16
16
  * - `config/loader.ts` — discovery + the layered load/merge pipeline.
17
17
  * - `config/schema.ts` — the Zod schema (single source of truth) + JSON-Schema generator.
18
+ * - `config/tool-descriptions.ts` — EXT-58: the rung-aware tool-description suffixes (§4.5) and
19
+ * the granted-built-in table the rater's alternative suggestion draws on (§4.4).
18
20
  *
19
21
  * Every name that was previously exported from `config.ts` is re-exported here, so the
20
22
  * public import path `@gaunt-sloth/core/config.js` (and `#src/config.js`) is unchanged.
21
23
  */
22
24
  export * from '#src/config/types.js';
23
25
  export * from '#src/config/shell-policy.js';
26
+ export * from '#src/config/tool-descriptions.js';
24
27
  export * from '#src/config/defaults.js';
25
28
  export * from '#src/config/loader.js';
29
+ export * from '#src/config/profiles.js';
26
30
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,cAAc,sBAAsB,CAAC;AACrC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,cAAc,sBAAsB,CAAC;AACrC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,kCAAkC,CAAC;AACjD,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC"}
@@ -1,11 +1,13 @@
1
- import { GthConfig, ServerTool } from '#src/config.js';
1
+ import { GthConfig, ServerTool, type ApprovalRung, type DescribableTool } from '#src/config.js';
2
2
  import { AgentResolvers, AgentStreamEvent, GthAgentInterface, GthCommand, GthCompiledGraph, GthRunStats, Message, PendingToolInterrupt, StatusUpdateCallback } from '#src/core/types.js';
3
- import type { DebugCapture } from '#src/core/debugCapture.js';
3
+ import type { DeclaredToolAnnotations } from '#src/core/approvals/annotations.js';
4
+ import type { DebugCapture, DebugRequestExtras, LastModelRequest } from '#src/core/debugCapture.js';
4
5
  import { AIMessageChunk, BaseMessage } from '@langchain/core/messages';
5
6
  import { RunnableConfig } from '@langchain/core/runnables';
6
7
  import { BaseToolkit, StructuredToolInterface } from '@langchain/core/tools';
7
8
  import { IterableReadableStream } from '@langchain/core/utils/stream';
8
9
  import { BaseCheckpointSaver } from '@langchain/langgraph';
10
+ import { type RefusalInfo } from '#src/core/refusal.js';
9
11
  /**
10
12
  * TUI-C29 — return a chunk fit for `concat`-aggregation with OpenRouter's raw response stripped.
11
13
  *
@@ -51,6 +53,22 @@ export declare abstract class GthAbstractAgent implements GthAgentInterface {
51
53
  * server / non-TUI callers simply never set it, so those contracts are unchanged.
52
54
  */
53
55
  debugCapture: DebugCapture | undefined;
56
+ /**
57
+ * GS2-56 — the ALWAYS-ON snapshot of the most recent model request (extras + the as-sent,
58
+ * post-summarization messages), populated UNCONDITIONALLY at each backend's `wrapModelCall` feed
59
+ * site — NOT gated on {@link debugCapture} being attached. This is what lets `/debug-dump` render
60
+ * the full model input even when the TUI `/debug` panel was never opened and on non-TUI surfaces
61
+ * (the sink only ever fed the live `/debug` panel). O(1): a single overwritten reference retaining
62
+ * only the LAST call — no accumulation, so the "pay nothing until you need it" intent is kept.
63
+ */
64
+ lastModelRequest: LastModelRequest | undefined;
65
+ /**
66
+ * GS2-56 — stash the last model request (the as-sent messages + {@link DebugRequestExtras}).
67
+ * Called unconditionally from each backend's capture middleware, independent of the debug sink,
68
+ * so the snapshot is available to `/debug-dump` on every surface. Overwrites (retains only the
69
+ * most recent call). Callers already guard the invocation; kept trivial so it can never throw.
70
+ */
71
+ protected setLastModelRequest(messages: BaseMessage[], extras?: DebugRequestExtras): void;
54
72
  /**
55
73
  * GS2-16 — per-run analytics tally (token usage + invoked tool names) folded from the messages
56
74
  * flowing through {@link invoke} / the streaming paths. Reset at each turn boundary via
@@ -58,6 +76,22 @@ export declare abstract class GthAbstractAgent implements GthAgentInterface {
58
76
  * fully fail-soft (accumulation is guarded and never throws into a run).
59
77
  */
60
78
  private runStatsAcc;
79
+ /**
80
+ * EXT-58 — the names of the tools registered with the graph at the last {@link init}, recorded by
81
+ * {@link registerApprovalsAwareTools}. Read by `GthAgentRunner` to build the rater's
82
+ * granted-built-in list (§4.4), so a suggestion can only ever name a tool the model actually has.
83
+ */
84
+ private registeredToolNames;
85
+ /**
86
+ * EXT-70 §4.7.1 — what the connected MCP servers DECLARED about their own tools, captured from
87
+ * the same registration hook as {@link registeredToolNames} and keyed by the registered tool
88
+ * name. Read by `GthAgentRunner` as the `mcp` half of a `DeclaredToolAnnotationLookup`.
89
+ *
90
+ * It is a record of claims, never of decisions: no trust is applied here (that is
91
+ * `createEffectiveToolAnnotationSource`'s only job), and an absent tool yields the fail-closed
92
+ * defaults rather than "declared nothing".
93
+ */
94
+ private declaredMcpToolAnnotations;
61
95
  constructor(statusUpdate: StatusUpdateCallback, resolvers?: AgentResolvers);
62
96
  /**
63
97
  * GS2-63 — emit one line of the technical run-header preamble (the Workdir/Model/Tools/Middleware
@@ -68,6 +102,47 @@ export declare abstract class GthAbstractAgent implements GthAgentInterface {
68
102
  * output, warnings and errors keep using {@link statusUpdate} directly.
69
103
  */
70
104
  protected headerStatus(message: string): void;
105
+ /**
106
+ * EXT-58 (spec §4.5) — the ONE tool-registration hook both backends call with their final tool
107
+ * array, just before handing it to the graph builder. It does two things:
108
+ *
109
+ * 1. Appends the rung's approval sentence to every tool that is **not** auto-approved at that
110
+ * rung, and leaves every granted tool's description untouched (the absence of the sentence is
111
+ * what marks a tool free). See {@link applyRungAwareToolDescriptions}.
112
+ * 2. Records the registered tool names for {@link getRegisteredToolNames}, which feeds the
113
+ * rater's granted-alternative list (§4.4).
114
+ * 3. EXT-70 §4.7.1 — records what the MCP servers declared about their own tools, for
115
+ * {@link getDeclaredMcpToolAnnotations}. This is the ONE place a `tools/list` annotation
116
+ * enters the approvals stack, and it enters as a claim: nothing here decides whether it is
117
+ * believed.
118
+ *
119
+ * `gatedTools` MUST be the same set the caller wires into the approval interrupt
120
+ * (`humanInTheLoopMiddleware`'s `interruptOn` on lean, deepagents' `interruptOn` on deep). That
121
+ * shared parameter is what makes it impossible for a description to promise an approval the gate
122
+ * will not ask for — §4.5's "a description that disagrees with what the gate will actually do is
123
+ * worse than no description at all".
124
+ *
125
+ * `additionalToolNames` covers tools the graph builder registers itself and that therefore never
126
+ * appear in `tools` — deepagents' own filesystem tools on the deep backend. Their descriptions
127
+ * are deepagents', not ours, so they cannot be suffixed here; they are recorded only so the
128
+ * rater's suggestion list reflects what the deep model actually has.
129
+ */
130
+ protected registerApprovalsAwareTools<T extends DescribableTool>(tools: T[], options: {
131
+ rung: ApprovalRung;
132
+ gatedTools: readonly string[];
133
+ additionalToolNames?: readonly string[];
134
+ }): T[];
135
+ /**
136
+ * EXT-58 — the tool names registered with the graph at the last {@link init} (empty before it).
137
+ * The runner intersects these with the built-in summaries table to build the rater's
138
+ * granted-alternative list, so the rater can never name a tool this session does not have.
139
+ */
140
+ getRegisteredToolNames(): string[];
141
+ /**
142
+ * EXT-70 §4.7.1 — what the MCP servers declared for their tools at the last {@link init}, keyed
143
+ * by registered tool name (empty before it, and on a session with no MCP servers).
144
+ */
145
+ getDeclaredMcpToolAnnotations(): ReadonlyMap<string, DeclaredToolAnnotations>;
71
146
  /**
72
147
  * GS2-16 — clear the per-run analytics tally so the next turn starts from zero. The runner
73
148
  * calls this at each turn boundary because it (and this agent) are reused across turns in an
@@ -90,6 +165,14 @@ export declare abstract class GthAbstractAgent implements GthAgentInterface {
90
165
  * part that differs between the lean and deep agents.
91
166
  */
92
167
  abstract init(command: GthCommand | undefined, configIn: GthConfig, checkpointer?: BaseCheckpointSaver | undefined): Promise<void>;
168
+ /**
169
+ * EXT-37 — surface a detected content-policy refusal: emit the clear, user-facing explanation at
170
+ * WARNING level (an empty-content refusal streams nothing, so without this the console shows
171
+ * nothing) and return the same message so it becomes the turn's terminal answer. Shared by the
172
+ * non-streaming {@link invoke} and streaming {@link streamFromInput} paths so both render a
173
+ * refusal identically. A refusal is a *successful* (if declined) response — never a retry.
174
+ */
175
+ protected surfaceRefusal(info: RefusalInfo): string;
93
176
  /**
94
177
  * Invoke LLM with a message and runnable config.
95
178
  * For streaming use {@link #stream} method, streaming is preferred if model API supports it.