@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,165 @@
|
|
|
1
|
+
import { displayError, displayInfo, displayWarning } from '#src/utils/consoleUtils.js';
|
|
2
|
+
import { stdout } from '#src/utils/systemUtils.js';
|
|
3
|
+
let activeListener = null;
|
|
4
|
+
/**
|
|
5
|
+
* TUI-C31 (d): true while a surface owns the terminal frame (the mounted Ink TUI) but no
|
|
6
|
+
* per-turn subscriber is attached — i.e. BETWEEN turns. In that window a straggler child that
|
|
7
|
+
* outlived the kill grace must NOT reach raw stdout (it would corrupt Ink's managed frame), so
|
|
8
|
+
* the default sink drops it instead. Off by default, so every headless surface is unaffected.
|
|
9
|
+
*/
|
|
10
|
+
let suppressed = false;
|
|
11
|
+
/**
|
|
12
|
+
* Subscribe to live tool output, replacing the default stdout/`displayInfo` sink for as long
|
|
13
|
+
* as the subscription is active. Returns an unsubscribe function. Last subscriber wins; the
|
|
14
|
+
* returned unsubscribe only clears its OWN registration (a stale unsubscribe can never detach
|
|
15
|
+
* a newer subscriber).
|
|
16
|
+
*/
|
|
17
|
+
export function subscribeToolOutput(listener) {
|
|
18
|
+
activeListener = listener;
|
|
19
|
+
return () => {
|
|
20
|
+
if (activeListener === listener) {
|
|
21
|
+
activeListener = null;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* TUI-C31 (d): mark whether a terminal-owning surface (the Ink TUI) is mounted. While mounted,
|
|
27
|
+
* the default sink SUPPRESSES output that has no per-turn subscriber (a post-turn straggler)
|
|
28
|
+
* rather than writing it raw over the managed frame. The TUI session sets this `true` around the
|
|
29
|
+
* whole session (`render()` … `waitUntilExit()`) and back to `false` on unmount, so once the TUI
|
|
30
|
+
* is gone the default (headless) stdout sink is fully restored. An active per-turn subscriber
|
|
31
|
+
* always takes precedence, so legitimate in-turn output is untouched.
|
|
32
|
+
*/
|
|
33
|
+
export function setToolOutputSuppressed(value) {
|
|
34
|
+
suppressed = value;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Emit one piece of live tool output. Routed to the active subscriber when present (the Ink
|
|
38
|
+
* TUI), otherwise to the DEFAULT SINK, which reproduces the pre-TUI-C17 behaviour exactly:
|
|
39
|
+
* the notice via `displayInfo` with its historical leading newline, chunks via `stdout.write`,
|
|
40
|
+
* a warning via `displayWarning` and an error via `displayError` (TUI-C31 a). While the TUI is
|
|
41
|
+
* mounted but no subscriber is attached (between turns), a no-subscriber emit is SUPPRESSED
|
|
42
|
+
* rather than written raw over the managed frame (TUI-C31 d).
|
|
43
|
+
*/
|
|
44
|
+
export function emitToolOutput(chunk) {
|
|
45
|
+
if (activeListener) {
|
|
46
|
+
activeListener(chunk);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (suppressed) {
|
|
50
|
+
// TUI mounted, between turns: drop the straggler instead of corrupting the managed frame.
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
switch (chunk.kind) {
|
|
54
|
+
case 'notice':
|
|
55
|
+
displayInfo(`\n${chunk.text}`);
|
|
56
|
+
break;
|
|
57
|
+
case 'warning':
|
|
58
|
+
displayWarning(chunk.text);
|
|
59
|
+
break;
|
|
60
|
+
case 'error':
|
|
61
|
+
displayError(chunk.text);
|
|
62
|
+
break;
|
|
63
|
+
default:
|
|
64
|
+
stdout.write(chunk.text);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/** Convert one channel chunk into its typed {@link AgentStreamEvent} representation. */
|
|
68
|
+
function toEvent(chunk) {
|
|
69
|
+
return {
|
|
70
|
+
type: 'tool_output',
|
|
71
|
+
...(chunk.toolCallId !== undefined ? { id: chunk.toolCallId } : {}),
|
|
72
|
+
name: chunk.toolName,
|
|
73
|
+
chunk: chunk.text,
|
|
74
|
+
// A `notice` is chrome; a failure-path `warning`/`error` is also chrome relative to the child's
|
|
75
|
+
// own stdout/stderr `output`, so it lands on the view-model's separate `notice` field (never
|
|
76
|
+
// counted as a raw output line) rather than styled as command output.
|
|
77
|
+
...(chunk.kind === 'notice' || chunk.kind === 'warning' || chunk.kind === 'error'
|
|
78
|
+
? { isNotice: true }
|
|
79
|
+
: {}),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Merge live tool output into an agent event stream: subscribes to the channel for the
|
|
84
|
+
* lifetime of `inner` and yields each emitted chunk as a `tool_output` event, interleaved
|
|
85
|
+
* with `inner`'s own events in arrival order. Because tool child output arrives WHILE the
|
|
86
|
+
* graph stream is awaiting its next message, the merge is push-based (a woken queue), so a
|
|
87
|
+
* long-running command's output streams into the consumer live rather than batching until
|
|
88
|
+
* the tool finishes.
|
|
89
|
+
*
|
|
90
|
+
* Used by the TUI session around `processMessagesWithEvents`; always unsubscribes (restoring
|
|
91
|
+
* the default stdout sink) when the inner stream completes, throws, or the consumer stops
|
|
92
|
+
* early. Errors from `inner` (including aborts) propagate unchanged after the queue drains.
|
|
93
|
+
*/
|
|
94
|
+
export async function* mergeToolOutputIntoEvents(inner) {
|
|
95
|
+
const queue = [];
|
|
96
|
+
let wake = null;
|
|
97
|
+
let done = false;
|
|
98
|
+
let error;
|
|
99
|
+
let failed = false;
|
|
100
|
+
const notify = () => {
|
|
101
|
+
const w = wake;
|
|
102
|
+
wake = null;
|
|
103
|
+
w?.();
|
|
104
|
+
};
|
|
105
|
+
const unsubscribe = subscribeToolOutput((chunk) => {
|
|
106
|
+
queue.push(toEvent(chunk));
|
|
107
|
+
notify();
|
|
108
|
+
});
|
|
109
|
+
// Pump the inner stream into the same queue so both sources serialize in arrival order.
|
|
110
|
+
const pump = (async () => {
|
|
111
|
+
try {
|
|
112
|
+
for await (const event of inner) {
|
|
113
|
+
queue.push(event);
|
|
114
|
+
notify();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
catch (e) {
|
|
118
|
+
failed = true;
|
|
119
|
+
error = e;
|
|
120
|
+
}
|
|
121
|
+
finally {
|
|
122
|
+
done = true;
|
|
123
|
+
notify();
|
|
124
|
+
}
|
|
125
|
+
})();
|
|
126
|
+
try {
|
|
127
|
+
for (;;) {
|
|
128
|
+
while (queue.length > 0) {
|
|
129
|
+
yield queue.shift();
|
|
130
|
+
}
|
|
131
|
+
if (done)
|
|
132
|
+
break;
|
|
133
|
+
await new Promise((resolve) => {
|
|
134
|
+
wake = resolve;
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
await pump;
|
|
138
|
+
// TUI-C31 (b): the subscriber is still attached at this point, so a straggler chunk can be
|
|
139
|
+
// pushed in the microwindow between the loop's last drain and the unsubscribe (the child
|
|
140
|
+
// flushed one final line as the turn ended). Detach the subscriber FIRST — after which no
|
|
141
|
+
// further chunk can be queued — THEN drain whatever is already queued, so nothing enqueued is
|
|
142
|
+
// silently dropped.
|
|
143
|
+
unsubscribe();
|
|
144
|
+
while (queue.length > 0) {
|
|
145
|
+
yield queue.shift();
|
|
146
|
+
}
|
|
147
|
+
if (failed)
|
|
148
|
+
throw error;
|
|
149
|
+
}
|
|
150
|
+
finally {
|
|
151
|
+
// TUI-C31 (c): also reached on early-stop — a consumer `return()`/`throw` into this generator
|
|
152
|
+
// while it is suspended (e.g. at a yield, the way a `for await` aborts). Make that path clean:
|
|
153
|
+
// unsubscribe (idempotent — a stale unsubscribe is a no-op) so the subscription never leaks,
|
|
154
|
+
// settle any pending wake resolver, and best-effort release the inner stream. This is
|
|
155
|
+
// deliberately fire-and-forget: `inner` may be parked on an await that its own `return()`
|
|
156
|
+
// cannot interrupt, and AWAITING the pump here would hang the consumer's `return()` on exactly
|
|
157
|
+
// that unresolvable inner — so we release and let go rather than block.
|
|
158
|
+
unsubscribe();
|
|
159
|
+
notify();
|
|
160
|
+
if (!done) {
|
|
161
|
+
void inner.return?.(undefined).catch(() => { });
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=toolOutputChannel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolOutputChannel.js","sourceRoot":"","sources":["../../src/core/toolOutputChannel.ts"],"names":[],"mappings":"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"}
|
package/dist/core/types.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { GthConfig } from '#src/config.js';
|
|
2
|
-
import type {
|
|
2
|
+
import type { DeclaredToolAnnotations } from '#src/core/approvals/annotations.js';
|
|
3
|
+
import type { RaterNegotiationRound, ShellSafetyVerdict } from '#src/core/shell/rater.js';
|
|
3
4
|
import type { BaseMessage } from '@langchain/core/messages';
|
|
4
5
|
import type { RunnableConfig } from '@langchain/core/runnables';
|
|
5
6
|
import type { StructuredToolInterface } from '@langchain/core/tools';
|
|
@@ -22,6 +23,45 @@ export declare enum StatusLevel {
|
|
|
22
23
|
STREAM = 6
|
|
23
24
|
}
|
|
24
25
|
export type GthCommand = 'ask' | 'pr' | 'review' | 'chat' | 'code' | 'api' | 'exec';
|
|
26
|
+
/**
|
|
27
|
+
* GS2-16 — per-run analytics harvested from a finished agent turn, threaded into the opt-in
|
|
28
|
+
* history recorder ({@link recordSessionSafe}) so `gth insights` reports real numbers instead of
|
|
29
|
+
* zeros. All fields are best-effort: token counts are only present when the provider actually
|
|
30
|
+
* reported `usage_metadata` (otherwise omitted so the recorder stores NULL and the insights
|
|
31
|
+
* formatter suppresses the misleading `0`), and `tools` lists the names of tools invoked during
|
|
32
|
+
* the run (deduplicated, order-insensitive). There is no `costUsd` — cost requires a reliable
|
|
33
|
+
* price table this project does not carry, so it is deliberately never invented here.
|
|
34
|
+
*/
|
|
35
|
+
export interface GthRunStats {
|
|
36
|
+
/** Total prompt/input tokens across the run's LLM calls, when the provider reported usage. */
|
|
37
|
+
tokensInput?: number;
|
|
38
|
+
/** Total completion/output tokens across the run's LLM calls, when the provider reported usage. */
|
|
39
|
+
tokensOutput?: number;
|
|
40
|
+
/** Names of tools invoked during the run (deduplicated); empty when no tools were used. */
|
|
41
|
+
tools: string[];
|
|
42
|
+
/**
|
|
43
|
+
* BATCH-21 — one record per executed tool result (`ToolMessage`) observed during the run, in
|
|
44
|
+
* arrival order and NOT deduplicated (a tool called twice yields two records), so `gth eval`'s
|
|
45
|
+
* tool-RESULT assertions (`must_error` / `tool_result_json_path`) can grade what a tool
|
|
46
|
+
* *returned*, not just that it was called. Optional (additive): producers that predate the field
|
|
47
|
+
* simply omit it; {@link runStats.js finalizeRunStats} always sets it.
|
|
48
|
+
*/
|
|
49
|
+
toolResults?: GthToolResult[];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* BATCH-21 — one executed tool call's result, harvested from its `ToolMessage` by the GS2-16
|
|
53
|
+
* run-stats accumulator (`core/runStats.ts`). Fail-soft like everything else there: `content` is
|
|
54
|
+
* omitted when no text payload could be derived, and is size-capped
|
|
55
|
+
* ({@link runStats.js TOOL_RESULT_CONTENT_CAP}) so a giant payload can't bloat run stats.
|
|
56
|
+
*/
|
|
57
|
+
export interface GthToolResult {
|
|
58
|
+
/** The tool that produced the result (`ToolMessage.name`). */
|
|
59
|
+
name: string;
|
|
60
|
+
/** `true` iff the result carried LangChain's real error signal (`ToolMessage.status === 'error'`). */
|
|
61
|
+
isError: boolean;
|
|
62
|
+
/** The result payload as text (a non-string payload is JSON-stringified), capped in length. */
|
|
63
|
+
content?: string;
|
|
64
|
+
}
|
|
25
65
|
/**
|
|
26
66
|
* Typed events emitted by the agent's {@link GthAgentInterface#streamWithEvents} path.
|
|
27
67
|
* This is the renderer contract shared by every consumer of an agent run — the AG-UI
|
|
@@ -49,10 +89,45 @@ export type AgentStreamEvent = {
|
|
|
49
89
|
} | {
|
|
50
90
|
type: 'tool_end';
|
|
51
91
|
id: string;
|
|
92
|
+
} | {
|
|
93
|
+
/**
|
|
94
|
+
* TUI-C17 — one live output chunk from an EXECUTING tool (a custom/dev toolkit child
|
|
95
|
+
* process's stdout/stderr, or its "Executing …" announcement), surfaced through the managed
|
|
96
|
+
* event stream instead of raw `process.stdout` so a renderer (the Ink TUI) can fold it into
|
|
97
|
+
* its view-model. Emitted by the tool-output channel merge
|
|
98
|
+
* (see `core/toolOutputChannel.js#mergeToolOutputIntoEvents`), NOT by `processEventStream`
|
|
99
|
+
* itself — consumers that don't opt into the merge (e.g. the AG-UI SSE encoder) never see it
|
|
100
|
+
* and the toolkits keep writing to stdout for them (today's headless behaviour).
|
|
101
|
+
*/
|
|
102
|
+
type: 'tool_output';
|
|
103
|
+
/**
|
|
104
|
+
* The tool call this chunk belongs to (LangChain's `ToolRunnableConfig.toolCall.id`,
|
|
105
|
+
* threaded through the toolkits), so a renderer can nest output under the exact call —
|
|
106
|
+
* TUI-C30 consumes this for per-call output previews. Optional only defensively: absent
|
|
107
|
+
* when the executing framework did not supply a tool call, in which case consumers should
|
|
108
|
+
* fall back to `name` attribution.
|
|
109
|
+
*/
|
|
110
|
+
id?: string;
|
|
111
|
+
/** The gth tool name (e.g. `run_shell_command`, a custom tool's name). Always known. */
|
|
112
|
+
name: string;
|
|
113
|
+
/** One verbatim streamed chunk of the child's stdout/stderr (or the notice text). */
|
|
114
|
+
chunk: string;
|
|
115
|
+
/**
|
|
116
|
+
* True when this chunk is the "🔧 Executing …" announcement rather than child output, so
|
|
117
|
+
* a richer renderer (TUI-C30) can style or strip it when previewing raw output lines.
|
|
118
|
+
*/
|
|
119
|
+
isNotice?: boolean;
|
|
52
120
|
} | {
|
|
53
121
|
type: 'tool_result';
|
|
54
122
|
id: string;
|
|
55
123
|
content: string;
|
|
124
|
+
/**
|
|
125
|
+
* True when the underlying `ToolMessage.status` is `'error'` (LangChain's real
|
|
126
|
+
* tool-result error signal). Absent/undefined means success — consumers must not
|
|
127
|
+
* sniff the result text to infer failure. Optional for backward compatibility with
|
|
128
|
+
* producers that predate the field.
|
|
129
|
+
*/
|
|
130
|
+
isError?: boolean;
|
|
56
131
|
};
|
|
57
132
|
/**
|
|
58
133
|
* The minimal structural surface of a compiled LangGraph agent that the shared agent
|
|
@@ -84,29 +159,126 @@ export interface PendingToolInterrupt {
|
|
|
84
159
|
name: string;
|
|
85
160
|
args: Record<string, unknown>;
|
|
86
161
|
/**
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
* can show
|
|
90
|
-
*
|
|
162
|
+
* CFG-26 — when the AI rater escalated this `run_shell_command` to the human (rather than
|
|
163
|
+
* approving it or bouncing it back to the model), the rater's verdict is attached here so the
|
|
164
|
+
* approval surface can show an "AI rater (<tier>): <reason>" notice. Absent when the rater is
|
|
165
|
+
* off, or when the command reached the human without being rated.
|
|
91
166
|
*/
|
|
92
167
|
safetyVerdict?: ShellSafetyVerdict;
|
|
168
|
+
/**
|
|
169
|
+
* EXT-71 §3.2 — when this call reached the human because a declared `approvals.escalate` entry
|
|
170
|
+
* matched it, the entry that fired, rendered for display. It is the provenance the prompt shows:
|
|
171
|
+
* an escalation the user cannot trace to the line they wrote reads as the gate malfunctioning.
|
|
172
|
+
* Absent whenever the escalation came from the rung or the rater instead.
|
|
173
|
+
*/
|
|
174
|
+
escalatedBy?: string;
|
|
175
|
+
/**
|
|
176
|
+
* EXT-71 §6 — **what a sticky choice will store**, rendered in the object form the user would
|
|
177
|
+
* write in a config file, e.g. `{ "type": "shell", "matcher": "exact", "pattern": "npm test" }`.
|
|
178
|
+
* The menu MUST show this at the moment of the choice, on every surface: the user is shown the
|
|
179
|
+
* thing they are agreeing to rather than a generalization of it, which is what makes the display
|
|
180
|
+
* honest and cheap at once.
|
|
181
|
+
*
|
|
182
|
+
* **For a tool call the stored thing is the tool, not the arguments** (§4.7.4), so this reads
|
|
183
|
+
* e.g. `{ "type": "mcpTool", "server": "fetcher", "matcher": "exact", "pattern": "fetch_url",
|
|
184
|
+
* "host": "docs.internal.example" }`. That is the one place a grant is deliberately broader than
|
|
185
|
+
* what the human was shown, which is why the display carries the most weight there.
|
|
186
|
+
*
|
|
187
|
+
* Absent exactly where no sticky grant is on offer — a `catastrophic` outcome (§4.2 withdraws
|
|
188
|
+
* the persistent grants), a rung that remembers nothing, a command that does not statically
|
|
189
|
+
* resolve, or a tool call naming more than one host (which has no honest single-host entry) — so
|
|
190
|
+
* a prompt never advertises a control that has already been withdrawn.
|
|
191
|
+
*/
|
|
192
|
+
grantPreview?: string;
|
|
193
|
+
/**
|
|
194
|
+
* §6 — **the same grant in the words a menu control is written in**: `npm test` for a shell
|
|
195
|
+
* command, `tool gth_web_fetch (host docs.internal.example)` or `mcpTool jira/create_issue` for a
|
|
196
|
+
* tool call. It is what the *always approve* control names, so the control reads as
|
|
197
|
+
* *always approve this tool for this host* rather than as a bare key.
|
|
198
|
+
*
|
|
199
|
+
* It is rendered by `describeApprovalEntry` — the one-liner every other provenance message uses,
|
|
200
|
+
* including the §4.7.4 notice that later withdraws the grant. Sharing the renderer is the point:
|
|
201
|
+
* a menu that describes a grant differently from the notice that withdraws it is how a user stops
|
|
202
|
+
* trusting either.
|
|
203
|
+
*
|
|
204
|
+
* Present exactly when {@link grantPreview} is, since both are rendered from the one entry
|
|
205
|
+
* `recordApproval` would write.
|
|
206
|
+
*/
|
|
207
|
+
grantSummary?: string;
|
|
208
|
+
/**
|
|
209
|
+
* [[TUI-C26]] §6 — **what the menu's *always reject* choice will record**, in the object form the
|
|
210
|
+
* user would write in a config file. The deny mirror of {@link grantPreview}, shown at the moment
|
|
211
|
+
* of the choice for the same reason: a control that does not say what it stores is one the user
|
|
212
|
+
* has to guess at.
|
|
213
|
+
*
|
|
214
|
+
* **Its availability is NOT the grant's**, and reading one off the other is the mistake this
|
|
215
|
+
* field exists to prevent. The matcher's own rule is *undecidable → no match on the allow side, a
|
|
216
|
+
* match on the deny side*, so a command the gate cannot statically resolve **can** be refused
|
|
217
|
+
* permanently even though it can never be allowed permanently. `always reject` also stays offered
|
|
218
|
+
* on a `catastrophic` verdict, where §4.2 withdraws every sticky grant: sticky refusal is safe in
|
|
219
|
+
* every direction, and it is only the grant that is ever made harder.
|
|
220
|
+
*
|
|
221
|
+
* Absent only where the entry grammar cannot hold one at all — today, an MCP call whose server
|
|
222
|
+
* could not be attributed (the grammar's `server` cannot be empty). Absent means the control is
|
|
223
|
+
* **not offered**, never offered-and-disabled.
|
|
224
|
+
*/
|
|
225
|
+
denyPreview?: string;
|
|
226
|
+
/**
|
|
227
|
+
* §6 — the same deny entry in the words the control is written in, through the one-liner every
|
|
228
|
+
* other provenance message uses. Present exactly when {@link denyPreview} is, since both are
|
|
229
|
+
* rendered from the one entry the runner would record.
|
|
230
|
+
*/
|
|
231
|
+
denySummary?: string;
|
|
232
|
+
/**
|
|
233
|
+
* [[EXT-29]] §6 — **every round of the §5 negotiation that preceded this escalation**, oldest
|
|
234
|
+
* first, when one did.
|
|
235
|
+
*
|
|
236
|
+
* The user is not asked to rule on the final command in isolation: *that the agent proposed
|
|
237
|
+
* `git reset --hard origin/main` three times unchanged, against two rejections that each told it
|
|
238
|
+
* what to fix, is itself the most important thing on the screen, and it is invisible if only the
|
|
239
|
+
* last attempt is shown.* `core/shell/negotiation.ts`'s `renderNegotiationTranscript` is the
|
|
240
|
+
* shared renderer, so two surfaces cannot describe one exchange two ways.
|
|
241
|
+
*
|
|
242
|
+
* Absent for every escalation that had no negotiation — `catastrophic` (§4.2 gives it no rounds
|
|
243
|
+
* at all), a declared `approvals.escalate` entry, an unrated rung, a tool subject.
|
|
244
|
+
*/
|
|
245
|
+
negotiationRounds?: readonly RaterNegotiationRound[];
|
|
93
246
|
}
|
|
94
247
|
/**
|
|
95
|
-
* Persistence scope for an `approve` decision (
|
|
248
|
+
* Persistence scope for an `approve` decision (spec §6):
|
|
96
249
|
* - `once` — run this single invocation only; remember nothing (the default).
|
|
97
|
-
* - `session` — remember
|
|
98
|
-
* instance, so
|
|
99
|
-
*
|
|
250
|
+
* - `session` — remember **this command**, as an `exact` entry (§3.1), for the life of this runner
|
|
251
|
+
* instance, so the same command stops re-prompting. A longer variant of it still asks: the menu
|
|
252
|
+
* never widens, and breadth is something a human writes in a config file.
|
|
253
|
+
* - `always` — additionally persist that entry to the project store
|
|
100
254
|
* (`.gsloth/.gsloth-settings/shell-allowlist.json`) so it survives across runs.
|
|
101
255
|
*/
|
|
102
256
|
export type ToolApprovalScope = 'once' | 'session' | 'always';
|
|
257
|
+
/**
|
|
258
|
+
* §6 — persistence scope for a `reject` decision, the *always reject* half of the escalation menu:
|
|
259
|
+
* - `once` — refuse this single invocation; remember nothing (the default).
|
|
260
|
+
* - `session` — additionally record a **deny** entry for this call, in the one entry grammar, for
|
|
261
|
+
* the life of this runner instance. The matcher consults it before anything else, so the next
|
|
262
|
+
* identical call is refused without reaching a person at all.
|
|
263
|
+
*
|
|
264
|
+
* **There is deliberately no `always`.** An `approve` can persist because there is a project store
|
|
265
|
+
* to persist it to; there is no persisted deny store, and inventing one is a decision about a file
|
|
266
|
+
* users will have to live with rather than a rendering choice. So the scopes here are the ones the
|
|
267
|
+
* gate can actually honour, and a control that promised more would be §6's own failure mode — an
|
|
268
|
+
* affordance offered and then quietly refused.
|
|
269
|
+
*/
|
|
270
|
+
export type ToolRejectScope = 'once' | 'session';
|
|
103
271
|
/**
|
|
104
272
|
* A consumer-supplied decision on a {@link PendingToolInterrupt}: approve runs the tool,
|
|
105
273
|
* reject feeds the model a tool-rejected message (with the optional reason).
|
|
106
274
|
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
275
|
+
* Each arm carries an optional scope; when absent it means `once` (backward compatible — a bare
|
|
276
|
+
* `{ type: 'approve' }` or `{ type: 'reject' }` still type-checks and behaves as the single-shot
|
|
277
|
+
* decision that persists nothing).
|
|
278
|
+
*
|
|
279
|
+
* The two scopes are **different types on purpose**. Sharing {@link ToolApprovalScope} would let a
|
|
280
|
+
* surface send `{ type: 'reject', scope: 'always' }`, which type-checks, promises a persistence
|
|
281
|
+
* nothing implements, and degrades to a session refusal with no diagnostic.
|
|
110
282
|
*/
|
|
111
283
|
export type ToolApprovalDecision = {
|
|
112
284
|
type: 'approve';
|
|
@@ -114,6 +286,7 @@ export type ToolApprovalDecision = {
|
|
|
114
286
|
} | {
|
|
115
287
|
type: 'reject';
|
|
116
288
|
message?: string;
|
|
289
|
+
scope?: ToolRejectScope;
|
|
117
290
|
};
|
|
118
291
|
/**
|
|
119
292
|
* Callback the {@link GthAgentRunner} invokes when a run suspends on a tool-approval
|
|
@@ -122,6 +295,42 @@ export type ToolApprovalDecision = {
|
|
|
122
295
|
* silently hang or auto-approve.
|
|
123
296
|
*/
|
|
124
297
|
export type ToolApprovalCallback = (pending: PendingToolInterrupt) => Promise<ToolApprovalDecision> | ToolApprovalDecision;
|
|
298
|
+
/**
|
|
299
|
+
* [[TUI-C68]] §6.1 — what the **attack banner** is about: the command whose own structure the
|
|
300
|
+
* rater called hostile, and the rater's explanation of what it saw. Both are untrusted text and a
|
|
301
|
+
* surface must paint them through `core/shell/framing`.
|
|
302
|
+
*
|
|
303
|
+
* A separate shape from {@link PendingToolInterrupt} because it is a separate question. An approval
|
|
304
|
+
* prompt asks *may this run*, and every control on its menu is a legitimate answer carrying a
|
|
305
|
+
* scope; this asks *do you believe the rating is wrong*, has exactly one way through, and offers no
|
|
306
|
+
* scope at all — so a surface cannot reach for a menu control that does not exist here.
|
|
307
|
+
*/
|
|
308
|
+
export interface PendingAttackHalt {
|
|
309
|
+
/** The command the rater rated an attack, as the model wrote it. Untrusted text. */
|
|
310
|
+
command: string;
|
|
311
|
+
/** The rater's own explanation of what the command's structure showed. Untrusted text. */
|
|
312
|
+
reason: string;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* §6.1 — the human's answer at the attack banner.
|
|
316
|
+
*
|
|
317
|
+
* **A string union rather than a boolean, and the polarity is deliberate.** `run-anyway` is the
|
|
318
|
+
* only value that runs anything; every other value — one a future surface invents, or `undefined`
|
|
319
|
+
* from a surface that forgot to return — stops the run. A boolean would put the irreversible answer
|
|
320
|
+
* one inverted comparison away, and there is nothing here worth being one typo from.
|
|
321
|
+
*/
|
|
322
|
+
export type AttackHaltAnswer = 'run-anyway' | 'stop';
|
|
323
|
+
/**
|
|
324
|
+
* §6.1 — callback the {@link GthAgentRunner} invokes when the rater rates a command an `attack`, so
|
|
325
|
+
* an interactive surface can show the red banner and let a human type their way past it.
|
|
326
|
+
*
|
|
327
|
+
* **Absent means halt**, exactly as an absent {@link ToolApprovalCallback} means the §6.2
|
|
328
|
+
* non-interactive exit. A surface that never wires this — a CI run, an AG-UI server, a surface
|
|
329
|
+
* nobody has written yet — keeps the halt, so forgetting fails safe. It may never block a
|
|
330
|
+
* non-interactive run, and no timeout turns waiting into a grant: waiting is something only a wired
|
|
331
|
+
* surface can cause.
|
|
332
|
+
*/
|
|
333
|
+
export type AttackHaltCallback = (halt: PendingAttackHalt) => Promise<AttackHaltAnswer> | AttackHaltAnswer;
|
|
125
334
|
export interface GthAgentInterface {
|
|
126
335
|
init(command: GthCommand | undefined, configIn: GthConfig, checkpointSaver?: BaseCheckpointSaver | undefined): Promise<void>;
|
|
127
336
|
invoke(messages: Message[], runConfig: RunnableConfig): Promise<string>;
|
|
@@ -148,6 +357,38 @@ export interface GthAgentInterface {
|
|
|
148
357
|
* approve/reject confirmation loop.
|
|
149
358
|
*/
|
|
150
359
|
getPendingToolInterrupts?(runConfig: RunnableConfig): Promise<PendingToolInterrupt[]>;
|
|
360
|
+
/**
|
|
361
|
+
* EXT-58 (spec §4.4) — the names of the tools registered with the graph at `init`. The runner
|
|
362
|
+
* intersects them with the built-in summaries table to tell the rater which already-granted
|
|
363
|
+
* built-ins it may offer as an alternative, so a suggestion can never name a tool the model does
|
|
364
|
+
* not have. Optional: an agent that does not track its tools simply omits it, and the rater then
|
|
365
|
+
* receives no granted list (and so suggests nothing).
|
|
366
|
+
*/
|
|
367
|
+
getRegisteredToolNames?(): string[];
|
|
368
|
+
/**
|
|
369
|
+
* EXT-70 (spec §4.7.1) — what the connected MCP servers declared about their own tools in their
|
|
370
|
+
* `tools/list` responses, keyed by the REGISTERED tool name (`mcp__<server>__<tool>`). The runner
|
|
371
|
+
* reads it as the `mcp` half of a declared-annotation lookup when it computes a call's effective
|
|
372
|
+
* annotation set.
|
|
373
|
+
*
|
|
374
|
+
* These are **claims, not credentials**: nothing here has been trusted, and an entry only becomes
|
|
375
|
+
* load-bearing where the user's `approvals.mcp` block believes that hint from that server.
|
|
376
|
+
* Optional — an agent that tracks no tools omits it, and every tool is then fail-closed, which is
|
|
377
|
+
* exactly what a fully distrustful configuration computes anyway.
|
|
378
|
+
*/
|
|
379
|
+
getDeclaredMcpToolAnnotations?(): ReadonlyMap<string, DeclaredToolAnnotations>;
|
|
380
|
+
/**
|
|
381
|
+
* GS2-16 — reset the per-run analytics accumulator so the NEXT turn's token/tool totals start
|
|
382
|
+
* from zero. Called by {@link GthAgentRunner} at each turn boundary (the runner is reused across
|
|
383
|
+
* turns in interactive sessions). Optional: agents that don't collect stats simply omit it.
|
|
384
|
+
*/
|
|
385
|
+
resetRunStats?(): void;
|
|
386
|
+
/**
|
|
387
|
+
* GS2-16 — the analytics harvested from the run(s) since the last {@link resetRunStats}. Used by
|
|
388
|
+
* the runner to thread token/tool data into the opt-in history recorder. Optional; when absent
|
|
389
|
+
* the runner records no analytics for that turn. Reading must never throw.
|
|
390
|
+
*/
|
|
391
|
+
getRunStats?(): GthRunStats;
|
|
151
392
|
cleanup?(): Promise<void>;
|
|
152
393
|
}
|
|
153
394
|
/**
|
|
@@ -161,9 +402,50 @@ export type ToolsResolver = (config: GthConfig, command?: GthCommand) => Promise
|
|
|
161
402
|
export type ToolsCleanup = () => Promise<void>;
|
|
162
403
|
export type MiddlewareResolver = (middleware: any[] | undefined, config: GthConfig) => Promise<any[]>;
|
|
163
404
|
export type MiddlewareCleanup = () => Promise<void>;
|
|
405
|
+
/**
|
|
406
|
+
* EXT-32 — one connected MCP server's discovery `instructions` string (from its MCP `initialize`
|
|
407
|
+
* handshake), paired with the server name it came from. Captured once during tool resolution and
|
|
408
|
+
* reused: injected (fenced + per-server-labelled) into the composed system prompt, and available
|
|
409
|
+
* for [[TUI-C20]]'s MCP debug tab to render the same captured text. Only servers that actually
|
|
410
|
+
* supplied non-empty instructions appear here.
|
|
411
|
+
*/
|
|
412
|
+
export interface McpServerInstruction {
|
|
413
|
+
/** The configured MCP server name (the key under `config.mcpServers`). */
|
|
414
|
+
server: string;
|
|
415
|
+
/** The server-provided instructions text (trimmed, non-empty). */
|
|
416
|
+
instructions: string;
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* A per-server MCP connection failure captured during the most recent {@link ToolsResolver} call.
|
|
420
|
+
* Recorded when a configured MCP server can't be reached (connection/handshake/auth error), so the
|
|
421
|
+
* failure — otherwise a transient `displayWarning` that scrolls away the moment the Ink TUI takes
|
|
422
|
+
* over the screen — can be re-surfaced persistently in the chrome AND named in the /debug MCP tab
|
|
423
|
+
* (which renders per configured server and would otherwise show only a bare "no tools" line, with
|
|
424
|
+
* no hint that the server never connected). Mirrors {@link McpServerInstruction}.
|
|
425
|
+
*/
|
|
426
|
+
export interface McpConnectionFailure {
|
|
427
|
+
/** The configured MCP server name (the key under `config.mcpServers`). */
|
|
428
|
+
server: string;
|
|
429
|
+
/** A concise, human-readable reason (the underlying connection error's message). */
|
|
430
|
+
reason: string;
|
|
431
|
+
}
|
|
164
432
|
export interface AgentResolvers {
|
|
165
433
|
resolveTools?: ToolsResolver;
|
|
166
434
|
cleanupTools?: ToolsCleanup;
|
|
167
435
|
resolveMiddleware?: MiddlewareResolver;
|
|
168
436
|
cleanupMiddleware?: MiddlewareCleanup;
|
|
437
|
+
/**
|
|
438
|
+
* EXT-32 — the per-server MCP discovery instructions captured during the most recent
|
|
439
|
+
* {@link ToolsResolver} call (empty when no MCP servers are configured or none supplied
|
|
440
|
+
* instructions). Optional: resolvers without MCP support simply omit it, and the prompt
|
|
441
|
+
* composition treats an absent accessor as "no instructions" (no MCP section is emitted).
|
|
442
|
+
*/
|
|
443
|
+
getMcpServerInstructions?(): McpServerInstruction[];
|
|
444
|
+
/**
|
|
445
|
+
* The per-server MCP connection failures captured during the most recent {@link ToolsResolver}
|
|
446
|
+
* call (empty when every configured server connected, or none is configured). Optional: resolvers
|
|
447
|
+
* without MCP support omit it, and callers treat an absent accessor as "no failures". Read by the
|
|
448
|
+
* TUI to surface a persistent notice and to annotate the /debug MCP tab.
|
|
449
|
+
*/
|
|
450
|
+
getMcpConnectionFailures?(): McpConnectionFailure[];
|
|
169
451
|
}
|
package/dist/core/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAaA;;;;GAIG;AACH,MAAM,CAAN,IAAY,WAQX;AARD,WAAY,WAAW;IACrB,+CAAS,CAAA;IACT,6CAAQ,CAAA;IACR,mDAAW,CAAA;IACX,mDAAW,CAAA;IACX,mDAAW,CAAA;IACX,+CAAS,CAAA;IACT,iDAAU,CAAA;AACZ,CAAC,EARW,WAAW,KAAX,WAAW,QAQtB"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* GS2-7 (B20) — pure, presentation-only formatters for the history surfaces.
|
|
4
|
+
*
|
|
5
|
+
* Shared by the `gth history` / `gth insights` CLI commands AND the `/history` `/search`
|
|
6
|
+
* `/insights` TUI slash commands so both render identically and both are unit-testable without a
|
|
7
|
+
* DB or a terminal. Every function is a pure `data -> string[]` transform (one display line per
|
|
8
|
+
* element); no I/O, no colour codes.
|
|
9
|
+
*/
|
|
10
|
+
import type { ConversationSummary, HistoryInsights, SessionRecord, SessionSearchResult } from '#src/history/historyStore.js';
|
|
11
|
+
/**
|
|
12
|
+
* Render FTS search hits: a header line per hit plus its snippet (or a prompt preview when the
|
|
13
|
+
* snippet is empty). Returns a friendly single line when there are none.
|
|
14
|
+
*/
|
|
15
|
+
export declare function formatSearchResults(results: SessionSearchResult[]): string[];
|
|
16
|
+
/**
|
|
17
|
+
* GS2-19 — render a conversation-grained listing: one header + last-turn preview per conversation.
|
|
18
|
+
* The header carries the count / timespan / last message that make the conversation the top-level
|
|
19
|
+
* unit (`gth history list`), replacing the old flat per-turn list.
|
|
20
|
+
*/
|
|
21
|
+
export declare function formatConversationList(conversations: ConversationSummary[]): string[];
|
|
22
|
+
/**
|
|
23
|
+
* GS2-19 — render one conversation's full thread (all turns in order) for `gth history show <id>`.
|
|
24
|
+
* Each turn shows its prompt and response preview so a search hit can be expanded into context.
|
|
25
|
+
*/
|
|
26
|
+
export declare function formatConversationThread(turns: SessionRecord[]): string[];
|
|
27
|
+
/** Render the analytics summary: totals, top tools, per-command breakdown. */
|
|
28
|
+
export declare function formatInsightsSummary(insights: HistoryInsights): string[];
|