@gaunt-sloth/core 2.0.0-alpha.10 → 2.0.0-alpha.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/types.d.ts +1 -1
- package/dist/config/types.js +1 -0
- package/dist/config/types.js.map +1 -1
- package/dist/constants.d.ts +8 -0
- package/dist/constants.js +8 -0
- package/dist/constants.js.map +1 -1
- package/dist/core/GthLangChainAgent.js +25 -1
- package/dist/core/GthLangChainAgent.js.map +1 -1
- package/dist/core/types.d.ts +20 -0
- package/dist/history/historyFormat.d.ts +12 -3
- package/dist/history/historyFormat.js +50 -8
- package/dist/history/historyFormat.js.map +1 -1
- package/dist/history/historyStore.d.ts +77 -0
- package/dist/history/historyStore.js +159 -5
- package/dist/history/historyStore.js.map +1 -1
- package/dist/history/recordSession.d.ts +10 -1
- package/dist/history/recordSession.js +27 -0
- package/dist/history/recordSession.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.js +13 -0
- package/dist/providers/modelDiscovery.js.map +1 -1
- package/dist/utils/consoleUtils.d.ts +13 -0
- package/dist/utils/consoleUtils.js +31 -0
- package/dist/utils/consoleUtils.js.map +1 -1
- package/dist/utils/systemPromptNotes.d.ts +89 -0
- package/dist/utils/systemPromptNotes.js +184 -0
- package/dist/utils/systemPromptNotes.js.map +1 -0
- package/package.json +1 -1
package/dist/config/types.d.ts
CHANGED
|
@@ -442,7 +442,7 @@ export interface LLMConfig extends Record<string, unknown> {
|
|
|
442
442
|
configuration: Record<string, unknown>;
|
|
443
443
|
apiKeyEnvironmentVariable?: string;
|
|
444
444
|
}
|
|
445
|
-
export declare const availableDefaultConfigs: readonly ["vertexai", "anthropic", "groq", "deepseek", "openai", "google-genai", "xai", "openrouter", "ollama"];
|
|
445
|
+
export declare const availableDefaultConfigs: readonly ["vertexai", "anthropic", "groq", "deepseek", "openai", "google-genai", "xai", "openrouter", "huggingface", "ollama"];
|
|
446
446
|
export type ConfigType = (typeof availableDefaultConfigs)[number];
|
|
447
447
|
export interface CommandLineConfigOverrides {
|
|
448
448
|
/**
|
package/dist/config/types.js
CHANGED
package/dist/config/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"AA2cA,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,UAAU;IACV,WAAW;IACX,MAAM;IACN,UAAU;IACV,QAAQ;IACR,cAAc;IACd,KAAK;IACL,YAAY;IACZ,QAAQ;CACA,CAAC"}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"AA2cA,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/constants.d.ts
CHANGED
|
@@ -36,3 +36,11 @@ export declare const CONFIG_SCHEMA_POINTER = "https://gauntsloth.app/schema/v2/g
|
|
|
36
36
|
* Lives under `.gsloth/.gsloth-settings/` like other project settings.
|
|
37
37
|
*/
|
|
38
38
|
export declare const SHELL_ALLOWLIST_FILE = "shell-allowlist.json";
|
|
39
|
+
/**
|
|
40
|
+
* The `additionalToolNamePrefix` handed to `MultiServerMCPClient` so every MCP tool name is
|
|
41
|
+
* namespaced. Combined with `prefixToolNameWithServerName`, the adapter emits tool names shaped
|
|
42
|
+
* `${MCP_TOOL_NAME_PREFIX}__<serverName>__<toolName>` (the `__` separator is the mcp-adapters
|
|
43
|
+
* convention). Single-sourced here so the resolver that sets the prefix (EXT-32) and any consumer
|
|
44
|
+
* that groups tools back by server (the [[TUI-C20]] MCP debug tab) can never silently drift apart.
|
|
45
|
+
*/
|
|
46
|
+
export declare const MCP_TOOL_NAME_PREFIX = "mcp";
|
package/dist/constants.js
CHANGED
|
@@ -36,4 +36,12 @@ export const CONFIG_SCHEMA_POINTER = 'https://gauntsloth.app/schema/v2/gsloth-co
|
|
|
36
36
|
* Lives under `.gsloth/.gsloth-settings/` like other project settings.
|
|
37
37
|
*/
|
|
38
38
|
export const SHELL_ALLOWLIST_FILE = 'shell-allowlist.json';
|
|
39
|
+
/**
|
|
40
|
+
* The `additionalToolNamePrefix` handed to `MultiServerMCPClient` so every MCP tool name is
|
|
41
|
+
* namespaced. Combined with `prefixToolNameWithServerName`, the adapter emits tool names shaped
|
|
42
|
+
* `${MCP_TOOL_NAME_PREFIX}__<serverName>__<toolName>` (the `__` separator is the mcp-adapters
|
|
43
|
+
* convention). Single-sourced here so the resolver that sets the prefix (EXT-32) and any consumer
|
|
44
|
+
* that groups tools back by server (the [[TUI-C20]] MCP debug tab) can never silently drift apart.
|
|
45
|
+
*/
|
|
46
|
+
export const MCP_TOOL_NAME_PREFIX = 'mcp';
|
|
39
47
|
//# sourceMappingURL=constants.js.map
|
package/dist/constants.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,UAAU,GAAG,SAAS,CAAC;AACpC,MAAM,CAAC,MAAM,mBAAmB,GAAG,kBAAkB,CAAC;AACtD,MAAM,CAAC,MAAM,WAAW,GAAG,cAAc,CAAC;AAC1C,MAAM,CAAC,MAAM,sBAAsB,GAAG,mBAAmB,CAAC;AAC1D,MAAM,CAAC,MAAM,wBAAwB,GAAG,qBAAqB,CAAC;AAC9D,MAAM,CAAC,MAAM,uBAAuB,GAAG,oBAAoB,CAAC;AAC5D,MAAM,CAAC,MAAM,sBAAsB,GAAG,mBAAmB,CAAC;AAC1D,MAAM,CAAC,MAAM,gBAAgB,GAAG,sBAAsB,CAAC;AACvD,MAAM,CAAC,MAAM,kBAAkB,GAAG,uBAAuB,CAAC;AAC1D,MAAM,CAAC,MAAM,2BAA2B,GAAG,mBAAmB,CAAC;AAC/D,MAAM,CAAC,MAAM,oBAAoB,GAAG,mBAAmB,CAAC;AACxD,MAAM,CAAC,MAAM,kBAAkB,GAAG,iBAAiB,CAAC;AACpD,MAAM,CAAC,MAAM,kBAAkB,GAAG,iBAAiB,CAAC;AACpD,MAAM,CAAC,MAAM,kBAAkB,GAAG,iBAAiB,CAAC;AACpD,MAAM,CAAC,MAAM,aAAa,GAAG,WAAW,CAAC;AACzC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,4DAA4D,CAAC;AAClG;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,sBAAsB,CAAC"}
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,UAAU,GAAG,SAAS,CAAC;AACpC,MAAM,CAAC,MAAM,mBAAmB,GAAG,kBAAkB,CAAC;AACtD,MAAM,CAAC,MAAM,WAAW,GAAG,cAAc,CAAC;AAC1C,MAAM,CAAC,MAAM,sBAAsB,GAAG,mBAAmB,CAAC;AAC1D,MAAM,CAAC,MAAM,wBAAwB,GAAG,qBAAqB,CAAC;AAC9D,MAAM,CAAC,MAAM,uBAAuB,GAAG,oBAAoB,CAAC;AAC5D,MAAM,CAAC,MAAM,sBAAsB,GAAG,mBAAmB,CAAC;AAC1D,MAAM,CAAC,MAAM,gBAAgB,GAAG,sBAAsB,CAAC;AACvD,MAAM,CAAC,MAAM,kBAAkB,GAAG,uBAAuB,CAAC;AAC1D,MAAM,CAAC,MAAM,2BAA2B,GAAG,mBAAmB,CAAC;AAC/D,MAAM,CAAC,MAAM,oBAAoB,GAAG,mBAAmB,CAAC;AACxD,MAAM,CAAC,MAAM,kBAAkB,GAAG,iBAAiB,CAAC;AACpD,MAAM,CAAC,MAAM,kBAAkB,GAAG,iBAAiB,CAAC;AACpD,MAAM,CAAC,MAAM,kBAAkB,GAAG,iBAAiB,CAAC;AACpD,MAAM,CAAC,MAAM,aAAa,GAAG,WAAW,CAAC;AACzC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,4DAA4D,CAAC;AAClG;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,sBAAsB,CAAC;AAE3D;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,KAAK,CAAC"}
|
|
@@ -3,6 +3,7 @@ import { GthAbstractAgent } from '#src/core/GthAbstractAgent.js';
|
|
|
3
3
|
import { debugLog, debugLogObject } from '#src/utils/debugUtils.js';
|
|
4
4
|
import { buildSystemMessages, formatToolCalls, readChatPrompt, readCodePrompt, readExecPrompt, } from '#src/utils/llmUtils.js';
|
|
5
5
|
import { getCurrentWorkDir } from '#src/utils/systemUtils.js';
|
|
6
|
+
import { appendOsShellNote, appendCwdNote, appendMcpServerInstructionsNote, } from '#src/utils/systemPromptNotes.js';
|
|
6
7
|
import { isShellCommandFailedError } from '#src/core/shell/ShellCommandFailedError.js';
|
|
7
8
|
import { extractDebugRequestExtras } from '#src/core/debugCapture.js';
|
|
8
9
|
import { AIMessage, ToolMessage } from '@langchain/core/messages';
|
|
@@ -176,7 +177,30 @@ export class GthLangChainAgent extends GthAbstractAgent {
|
|
|
176
177
|
? readExecPrompt(this.config)
|
|
177
178
|
: readChatPrompt(this.config);
|
|
178
179
|
const systemMessages = buildSystemMessages(this.config, modePrompt);
|
|
179
|
-
const
|
|
180
|
+
const baseSystemPrompt = typeof systemMessages[0]?.content === 'string' ? systemMessages[0].content : undefined;
|
|
181
|
+
// GS2-27: in `code` mode append the SHARED code-mode notes the deep backend has always carried
|
|
182
|
+
// — the real-cwd / path-model note (EXT-13) and the OS + shell-dialect note (EXT-26). Both are
|
|
183
|
+
// backend-agnostic (the lean backend also exposes `run_shell_command` and runs on the real-fs
|
|
184
|
+
// cwd), so composing them here closes the deep-only drift that left a lean code session with no
|
|
185
|
+
// cwd value and no shell-dialect guidance (e.g. on Windows). The deepagents virtual-fs-namespace
|
|
186
|
+
// notes stay deep-only (lean never runs virtualMode). Same order the deep backend's real-path
|
|
187
|
+
// branch uses: cwd note first, OS/shell note last. `getCurrentWorkDir()` is already read above
|
|
188
|
+
// for the status line, so the value is free.
|
|
189
|
+
const codeNotesPrompt = this.command === 'code'
|
|
190
|
+
? appendOsShellNote(appendCwdNote(baseSystemPrompt, getCurrentWorkDir()))
|
|
191
|
+
: baseSystemPrompt;
|
|
192
|
+
// EXT-32: inject each connected MCP server's discovery `instructions` (captured during tool
|
|
193
|
+
// resolution) into the prompt — fenced + per-server-labelled as untrusted server-provided
|
|
194
|
+
// context. Mode-independent: MCP tools load in every mode, so their usage guidance applies in
|
|
195
|
+
// every mode (not just `code`). Empty/absent capture (or a resolver without the accessor) adds
|
|
196
|
+
// nothing. Composed through this shared path so it reaches the lean AND deep backends alike.
|
|
197
|
+
// When tools are disabled, resolveTools is skipped entirely (no MCP contact), so a REUSED
|
|
198
|
+
// resolver could still hold a prior run's capture — gate on toolsDisabled so no stale
|
|
199
|
+
// instructions leak into a tools-disabled session.
|
|
200
|
+
const mcpInstructions = toolsDisabled
|
|
201
|
+
? []
|
|
202
|
+
: (this.resolvers?.getMcpServerInstructions?.() ?? []);
|
|
203
|
+
const systemPrompt = appendMcpServerInstructionsNote(codeNotesPrompt, mcpInstructions);
|
|
180
204
|
// Create agent with configured middleware. Only pass systemPrompt when non-empty so we never
|
|
181
205
|
// hand createAgent an empty system message.
|
|
182
206
|
this.agent = createAgent({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GthLangChainAgent.js","sourceRoot":"","sources":["../../src/core/GthLangChainAgent.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"GthLangChainAgent.js","sourceRoot":"","sources":["../../src/core/GthLangChainAgent.ts"],"names":[],"mappings":"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"}
|
package/dist/core/types.d.ts
CHANGED
|
@@ -197,9 +197,29 @@ export type ToolsResolver = (config: GthConfig, command?: GthCommand) => Promise
|
|
|
197
197
|
export type ToolsCleanup = () => Promise<void>;
|
|
198
198
|
export type MiddlewareResolver = (middleware: any[] | undefined, config: GthConfig) => Promise<any[]>;
|
|
199
199
|
export type MiddlewareCleanup = () => Promise<void>;
|
|
200
|
+
/**
|
|
201
|
+
* EXT-32 — one connected MCP server's discovery `instructions` string (from its MCP `initialize`
|
|
202
|
+
* handshake), paired with the server name it came from. Captured once during tool resolution and
|
|
203
|
+
* reused: injected (fenced + per-server-labelled) into the composed system prompt, and available
|
|
204
|
+
* for [[TUI-C20]]'s MCP debug tab to render the same captured text. Only servers that actually
|
|
205
|
+
* supplied non-empty instructions appear here.
|
|
206
|
+
*/
|
|
207
|
+
export interface McpServerInstruction {
|
|
208
|
+
/** The configured MCP server name (the key under `config.mcpServers`). */
|
|
209
|
+
server: string;
|
|
210
|
+
/** The server-provided instructions text (trimmed, non-empty). */
|
|
211
|
+
instructions: string;
|
|
212
|
+
}
|
|
200
213
|
export interface AgentResolvers {
|
|
201
214
|
resolveTools?: ToolsResolver;
|
|
202
215
|
cleanupTools?: ToolsCleanup;
|
|
203
216
|
resolveMiddleware?: MiddlewareResolver;
|
|
204
217
|
cleanupMiddleware?: MiddlewareCleanup;
|
|
218
|
+
/**
|
|
219
|
+
* EXT-32 — the per-server MCP discovery instructions captured during the most recent
|
|
220
|
+
* {@link ToolsResolver} call (empty when no MCP servers are configured or none supplied
|
|
221
|
+
* instructions). Optional: resolvers without MCP support simply omit it, and the prompt
|
|
222
|
+
* composition treats an absent accessor as "no instructions" (no MCP section is emitted).
|
|
223
|
+
*/
|
|
224
|
+
getMcpServerInstructions?(): McpServerInstruction[];
|
|
205
225
|
}
|
|
@@ -7,13 +7,22 @@
|
|
|
7
7
|
* DB or a terminal. Every function is a pure `data -> string[]` transform (one display line per
|
|
8
8
|
* element); no I/O, no colour codes.
|
|
9
9
|
*/
|
|
10
|
-
import type { HistoryInsights, SessionSearchResult } from '#src/history/historyStore.js';
|
|
10
|
+
import type { ConversationSummary, HistoryInsights, SessionRecord, SessionSearchResult } from '#src/history/historyStore.js';
|
|
11
11
|
/**
|
|
12
12
|
* Render FTS search hits: a header line per hit plus its snippet (or a prompt preview when the
|
|
13
13
|
* snippet is empty). Returns a friendly single line when there are none.
|
|
14
14
|
*/
|
|
15
15
|
export declare function formatSearchResults(results: SessionSearchResult[]): string[];
|
|
16
|
-
/**
|
|
17
|
-
|
|
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[];
|
|
18
27
|
/** Render the analytics summary: totals, top tools, per-command breakdown. */
|
|
19
28
|
export declare function formatInsightsSummary(insights: HistoryInsights): string[];
|
|
@@ -3,13 +3,17 @@ function oneLine(text, max = 80) {
|
|
|
3
3
|
const s = (text ?? '').replace(/\s+/g, ' ').trim();
|
|
4
4
|
return s.length > max ? s.slice(0, max - 1) + '…' : s;
|
|
5
5
|
}
|
|
6
|
-
/** A compact `#id <ts> [command] model` header line for one
|
|
6
|
+
/** A compact `#id <ts> [command] model (conversation #cid)` header line for one turn. */
|
|
7
7
|
function headerLine(r) {
|
|
8
8
|
const parts = [`#${r.id}`, r.ts];
|
|
9
9
|
if (r.command)
|
|
10
10
|
parts.push(`[${r.command}]`);
|
|
11
11
|
if (r.model)
|
|
12
12
|
parts.push(r.model);
|
|
13
|
+
// GS2-19: a search hit resolves to the conversation it belongs to, so the reader can pull up the
|
|
14
|
+
// whole thread (`gth history show <cid>`). Older rows migrated from GS2-7 always have one now.
|
|
15
|
+
if (r.conversationId != null)
|
|
16
|
+
parts.push(`(conversation #${r.conversationId})`);
|
|
13
17
|
return parts.join(' ');
|
|
14
18
|
}
|
|
15
19
|
/**
|
|
@@ -29,22 +33,60 @@ export function formatSearchResults(results) {
|
|
|
29
33
|
}
|
|
30
34
|
return lines;
|
|
31
35
|
}
|
|
32
|
-
/**
|
|
33
|
-
|
|
34
|
-
|
|
36
|
+
/**
|
|
37
|
+
* GS2-19 — render a conversation-grained listing: one header + last-turn preview per conversation.
|
|
38
|
+
* The header carries the count / timespan / last message that make the conversation the top-level
|
|
39
|
+
* unit (`gth history list`), replacing the old flat per-turn list.
|
|
40
|
+
*/
|
|
41
|
+
export function formatConversationList(conversations) {
|
|
42
|
+
if (conversations.length === 0) {
|
|
35
43
|
return [
|
|
36
|
-
'No
|
|
44
|
+
'No conversations recorded yet. Enable history with `history.enabled: true` in your config.',
|
|
37
45
|
];
|
|
38
46
|
}
|
|
39
47
|
const lines = [];
|
|
40
|
-
for (const
|
|
41
|
-
|
|
42
|
-
|
|
48
|
+
for (const c of conversations) {
|
|
49
|
+
const parts = [`#${c.id}`];
|
|
50
|
+
// Timespan across the conversation's turns; a 1-turn (or not-yet-started) conversation collapses
|
|
51
|
+
// to a single instant, so show one timestamp rather than an `a → a` range.
|
|
52
|
+
if (c.firstTs && c.lastTs && c.firstTs !== c.lastTs) {
|
|
53
|
+
parts.push(`${c.firstTs} → ${c.lastTs}`);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
parts.push(c.lastTs ?? c.firstTs ?? c.startedTs);
|
|
57
|
+
}
|
|
58
|
+
if (c.command)
|
|
59
|
+
parts.push(`[${c.command}]`);
|
|
60
|
+
if (c.model)
|
|
61
|
+
parts.push(c.model);
|
|
62
|
+
parts.push(`(${c.turnCount} ${c.turnCount === 1 ? 'turn' : 'turns'})`);
|
|
63
|
+
lines.push(parts.join(' '));
|
|
64
|
+
const preview = oneLine(c.lastPrompt, 100);
|
|
43
65
|
if (preview)
|
|
44
66
|
lines.push(` ${preview}`);
|
|
45
67
|
}
|
|
46
68
|
return lines;
|
|
47
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* GS2-19 — render one conversation's full thread (all turns in order) for `gth history show <id>`.
|
|
72
|
+
* Each turn shows its prompt and response preview so a search hit can be expanded into context.
|
|
73
|
+
*/
|
|
74
|
+
export function formatConversationThread(turns) {
|
|
75
|
+
if (turns.length === 0)
|
|
76
|
+
return ['No turns found for that conversation.'];
|
|
77
|
+
const lines = [];
|
|
78
|
+
turns.forEach((t, i) => {
|
|
79
|
+
const header = t.ts ? `Turn ${i + 1} ${t.ts}` : `Turn ${i + 1}`;
|
|
80
|
+
lines.push(header);
|
|
81
|
+
const prompt = oneLine(t.prompt, 200);
|
|
82
|
+
if (prompt)
|
|
83
|
+
lines.push(` > ${prompt}`);
|
|
84
|
+
const response = oneLine(t.response, 200);
|
|
85
|
+
if (response)
|
|
86
|
+
lines.push(` ${response}`);
|
|
87
|
+
});
|
|
88
|
+
return lines;
|
|
89
|
+
}
|
|
48
90
|
/** Render the analytics summary: totals, top tools, per-command breakdown. */
|
|
49
91
|
export function formatInsightsSummary(insights) {
|
|
50
92
|
if (insights.sessionCount === 0) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"historyFormat.js","sourceRoot":"","sources":["../../src/history/historyFormat.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"historyFormat.js","sourceRoot":"","sources":["../../src/history/historyFormat.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
export declare const HISTORY_DB_FILENAME = "history.db";
|
|
3
3
|
/** A single persisted session record (all analytics fields optional; populated when available). */
|
|
4
4
|
export interface SessionRecord {
|
|
5
|
+
/**
|
|
6
|
+
* GS2-19 — the parent conversation this turn belongs to. When omitted, {@link HistoryStore.record}
|
|
7
|
+
* opens a fresh single-turn conversation for the row (so a bare single-shot run = a 1-turn
|
|
8
|
+
* conversation). Interactive sessions {@link HistoryStore.openConversation | open} one conversation
|
|
9
|
+
* up-front and pass its id here on every turn, grouping the whole chat under one conversation.
|
|
10
|
+
*/
|
|
11
|
+
conversationId?: number;
|
|
5
12
|
/** ISO-8601 timestamp; defaults to now when omitted. */
|
|
6
13
|
ts?: string;
|
|
7
14
|
/** Project / working directory the run happened in. */
|
|
@@ -32,6 +39,41 @@ export interface SessionSearchResult extends SessionRecord {
|
|
|
32
39
|
/** FTS5 snippet around the match (may be empty). */
|
|
33
40
|
snippet: string;
|
|
34
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* GS2-19 — metadata for a conversation (a group of turns). Passed to
|
|
44
|
+
* {@link HistoryStore.openConversation} at interactive-session start.
|
|
45
|
+
*/
|
|
46
|
+
export interface ConversationMeta {
|
|
47
|
+
/** ISO-8601 start timestamp; defaults to now when omitted. */
|
|
48
|
+
ts?: string;
|
|
49
|
+
/** Project / working directory the conversation happened in. */
|
|
50
|
+
project?: string;
|
|
51
|
+
/** Originating command (chat/code/ask/exec/…). */
|
|
52
|
+
command?: string;
|
|
53
|
+
/** Human-readable model/provider label. */
|
|
54
|
+
model?: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* GS2-19 — a conversation-grained listing row: the conversation's metadata plus the aggregate of
|
|
58
|
+
* its turns (how many, the timespan they cover, and a preview of the last one). This is the
|
|
59
|
+
* top-level unit `gth history list` shows, in place of isolated per-turn rows.
|
|
60
|
+
*/
|
|
61
|
+
export interface ConversationSummary {
|
|
62
|
+
id: number;
|
|
63
|
+
/** When the conversation was opened. */
|
|
64
|
+
startedTs: string;
|
|
65
|
+
project?: string;
|
|
66
|
+
command?: string;
|
|
67
|
+
model?: string;
|
|
68
|
+
/** Number of turns recorded under this conversation (0 for a conversation with no turns). */
|
|
69
|
+
turnCount: number;
|
|
70
|
+
/** Timestamp of the first / last turn, when any turns exist. */
|
|
71
|
+
firstTs?: string;
|
|
72
|
+
lastTs?: string;
|
|
73
|
+
/** Prompt / response of the most recent turn (a one-line preview source). */
|
|
74
|
+
lastPrompt?: string;
|
|
75
|
+
lastResponse?: string;
|
|
76
|
+
}
|
|
35
77
|
/** Aggregate analytics over the whole store (local only). */
|
|
36
78
|
export interface HistoryInsights {
|
|
37
79
|
sessionCount: number;
|
|
@@ -85,6 +127,25 @@ export declare class HistoryStore {
|
|
|
85
127
|
*/
|
|
86
128
|
static open(dbPath: string, options?: OpenHistoryStoreOptions): HistoryStore | null;
|
|
87
129
|
private initSchema;
|
|
130
|
+
/**
|
|
131
|
+
* GS2-19 — in-place, idempotent upgrade of a pre-existing GS2-7 DB (flat `sessions` rows, no
|
|
132
|
+
* grouping) to the conversation-grained model. Runs on every open (including read-only `list` /
|
|
133
|
+
* `search` opens, which open the file read-write): it adds the `conversation_id` column if an
|
|
134
|
+
* older `sessions` table lacks it, then back-fills each ungrouped turn into its own 1-turn
|
|
135
|
+
* conversation. After the first pass there are no ungrouped rows, so it is a cheap no-op.
|
|
136
|
+
*
|
|
137
|
+
* Fully fail-soft: a migration hiccup is swallowed here rather than nulling the store, so reads
|
|
138
|
+
* still work against whatever is already there and new turns just fall back to fresh 1-turn
|
|
139
|
+
* conversations. Never throws.
|
|
140
|
+
*/
|
|
141
|
+
private migrate;
|
|
142
|
+
/**
|
|
143
|
+
* GS2-19 — open a new conversation and return its id (or `null` on any error). Interactive
|
|
144
|
+
* sessions call this once at start, then pass the id on every {@link record} so all the session's
|
|
145
|
+
* turns group under it. A single-shot run does not need this: {@link record} opens a 1-turn
|
|
146
|
+
* conversation itself when no `conversationId` is supplied.
|
|
147
|
+
*/
|
|
148
|
+
openConversation(meta?: ConversationMeta): number | null;
|
|
88
149
|
/**
|
|
89
150
|
* Persist one session and its full-text index entry. Returns the new row id, or `null` on any
|
|
90
151
|
* error (the run continues regardless). The two inserts run in a transaction so a failure can't
|
|
@@ -99,6 +160,22 @@ export declare class HistoryStore {
|
|
|
99
160
|
search(query: string, limit?: number): SessionSearchResult[];
|
|
100
161
|
/** Most recent sessions, newest first. Fail-soft ([] on error). */
|
|
101
162
|
listRecent(limit?: number): SessionSearchResult[];
|
|
163
|
+
/**
|
|
164
|
+
* GS2-19 — conversations newest-first, each with its turn count, timespan, and a preview of the
|
|
165
|
+
* last turn. This is the top-level unit for `gth history list` (the turn-grained {@link listRecent}
|
|
166
|
+
* remains for callers that want raw turns). Fail-soft ([] on error).
|
|
167
|
+
*
|
|
168
|
+
* Empty conversations are **excluded** (`HAVING COUNT(s.id) > 0`): a session opens its conversation
|
|
169
|
+
* at start (before any turn), so one that exits with zero turns would otherwise show as a
|
|
170
|
+
* contentless `turnCount: 0` row. The LEFT JOIN still keeps every conversation that has ≥1 turn —
|
|
171
|
+
* including back-filled 1-turn conversations, whose single turn satisfies the HAVING.
|
|
172
|
+
*/
|
|
173
|
+
listConversations(limit?: number): ConversationSummary[];
|
|
174
|
+
/**
|
|
175
|
+
* GS2-19 — all turns of one conversation in chronological (insert) order, so a search hit can be
|
|
176
|
+
* expanded into the whole thread it belonged to. Fail-soft ([] on error / unknown id).
|
|
177
|
+
*/
|
|
178
|
+
getConversationThread(conversationId: number): SessionRecord[];
|
|
102
179
|
/**
|
|
103
180
|
* Aggregate token/cost totals, a top-tool tally, and a per-command breakdown over the whole
|
|
104
181
|
* store. Tool tallying reads each row's JSON `tools` array in JS (robust to nulls). Fail-soft:
|
|
@@ -73,7 +73,20 @@ export class HistoryStore {
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
initSchema() {
|
|
76
|
+
// GS2-19: the `sessions` table is turn-grained (its rows are prompt→response turns, despite the
|
|
77
|
+
// name). A `conversations` table groups the turns of one interactive session; each turn carries
|
|
78
|
+
// a `conversation_id`. `conversation_id` is a plain INTEGER join key, not an enforced FK — SQLite
|
|
79
|
+
// leaves `foreign_keys` off by default and `ALTER TABLE ADD COLUMN` can't add a REFERENCES clause,
|
|
80
|
+
// so declaring one here would only make the fresh schema drift from the migrated one. The column
|
|
81
|
+
// definition is kept byte-identical between this fresh path and {@link migrate}'s ALTER.
|
|
76
82
|
this.db.exec(`
|
|
83
|
+
CREATE TABLE IF NOT EXISTS conversations (
|
|
84
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
85
|
+
started_ts TEXT NOT NULL,
|
|
86
|
+
project TEXT,
|
|
87
|
+
command TEXT,
|
|
88
|
+
model TEXT
|
|
89
|
+
);
|
|
77
90
|
CREATE TABLE IF NOT EXISTS sessions (
|
|
78
91
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
79
92
|
ts TEXT NOT NULL,
|
|
@@ -86,12 +99,77 @@ export class HistoryStore {
|
|
|
86
99
|
tokens_output INTEGER,
|
|
87
100
|
cost_usd REAL,
|
|
88
101
|
tools TEXT,
|
|
89
|
-
duration_ms INTEGER
|
|
102
|
+
duration_ms INTEGER,
|
|
103
|
+
conversation_id INTEGER
|
|
90
104
|
);
|
|
91
105
|
CREATE VIRTUAL TABLE IF NOT EXISTS sessions_fts USING fts5(
|
|
92
106
|
prompt, response, command, project
|
|
93
107
|
);
|
|
94
108
|
`);
|
|
109
|
+
this.migrate();
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* GS2-19 — in-place, idempotent upgrade of a pre-existing GS2-7 DB (flat `sessions` rows, no
|
|
113
|
+
* grouping) to the conversation-grained model. Runs on every open (including read-only `list` /
|
|
114
|
+
* `search` opens, which open the file read-write): it adds the `conversation_id` column if an
|
|
115
|
+
* older `sessions` table lacks it, then back-fills each ungrouped turn into its own 1-turn
|
|
116
|
+
* conversation. After the first pass there are no ungrouped rows, so it is a cheap no-op.
|
|
117
|
+
*
|
|
118
|
+
* Fully fail-soft: a migration hiccup is swallowed here rather than nulling the store, so reads
|
|
119
|
+
* still work against whatever is already there and new turns just fall back to fresh 1-turn
|
|
120
|
+
* conversations. Never throws.
|
|
121
|
+
*/
|
|
122
|
+
migrate() {
|
|
123
|
+
try {
|
|
124
|
+
const cols = this.db.prepare(`PRAGMA table_info(sessions)`).all();
|
|
125
|
+
const hasConversationId = cols.some((c) => c.name === 'conversation_id');
|
|
126
|
+
if (!hasConversationId) {
|
|
127
|
+
this.db.exec(`ALTER TABLE sessions ADD COLUMN conversation_id INTEGER`);
|
|
128
|
+
}
|
|
129
|
+
const orphans = this.db
|
|
130
|
+
.prepare(`SELECT id, ts, project, command, model
|
|
131
|
+
FROM sessions
|
|
132
|
+
WHERE conversation_id IS NULL
|
|
133
|
+
ORDER BY id`)
|
|
134
|
+
.all();
|
|
135
|
+
if (orphans.length === 0)
|
|
136
|
+
return;
|
|
137
|
+
this.db.exec('BEGIN');
|
|
138
|
+
try {
|
|
139
|
+
const insertConversation = this.db.prepare(`INSERT INTO conversations (started_ts, project, command, model) VALUES (?, ?, ?, ?)`);
|
|
140
|
+
const stampTurn = this.db.prepare(`UPDATE sessions SET conversation_id = ? WHERE id = ?`);
|
|
141
|
+
for (const row of orphans) {
|
|
142
|
+
const info = insertConversation.run(row.ts != null ? String(row.ts) : new Date().toISOString(), row.project != null ? String(row.project) : null, row.command != null ? String(row.command) : null, row.model != null ? String(row.model) : null);
|
|
143
|
+
stampTurn.run(Number(info.lastInsertRowid), Number(row.id));
|
|
144
|
+
}
|
|
145
|
+
this.db.exec('COMMIT');
|
|
146
|
+
}
|
|
147
|
+
catch (e) {
|
|
148
|
+
this.db.exec('ROLLBACK');
|
|
149
|
+
throw e;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
/* fail-soft: a migration failure must not break opening the store or a run */
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* GS2-19 — open a new conversation and return its id (or `null` on any error). Interactive
|
|
158
|
+
* sessions call this once at start, then pass the id on every {@link record} so all the session's
|
|
159
|
+
* turns group under it. A single-shot run does not need this: {@link record} opens a 1-turn
|
|
160
|
+
* conversation itself when no `conversationId` is supplied.
|
|
161
|
+
*/
|
|
162
|
+
openConversation(meta = {}) {
|
|
163
|
+
try {
|
|
164
|
+
const ts = meta.ts ?? new Date().toISOString();
|
|
165
|
+
const info = this.db
|
|
166
|
+
.prepare(`INSERT INTO conversations (started_ts, project, command, model) VALUES (?, ?, ?, ?)`)
|
|
167
|
+
.run(ts, meta.project ?? null, meta.command ?? null, meta.model ?? null);
|
|
168
|
+
return Number(info.lastInsertRowid);
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
95
173
|
}
|
|
96
174
|
/**
|
|
97
175
|
* Persist one session and its full-text index entry. Returns the new row id, or `null` on any
|
|
@@ -104,11 +182,21 @@ export class HistoryStore {
|
|
|
104
182
|
const tools = rec.tools && rec.tools.length > 0 ? JSON.stringify(rec.tools) : null;
|
|
105
183
|
this.db.exec('BEGIN');
|
|
106
184
|
try {
|
|
185
|
+
// GS2-19: every turn belongs to a conversation. When the caller opened one up-front
|
|
186
|
+
// (interactive sessions), stamp it; otherwise open a fresh 1-turn conversation for this row
|
|
187
|
+
// (single-shot runs / bare record() calls) so the turn is never left ungrouped.
|
|
188
|
+
let conversationId = rec.conversationId ?? null;
|
|
189
|
+
if (conversationId == null) {
|
|
190
|
+
const cinfo = this.db
|
|
191
|
+
.prepare(`INSERT INTO conversations (started_ts, project, command, model) VALUES (?, ?, ?, ?)`)
|
|
192
|
+
.run(ts, rec.project ?? null, rec.command ?? null, rec.model ?? null);
|
|
193
|
+
conversationId = Number(cinfo.lastInsertRowid);
|
|
194
|
+
}
|
|
107
195
|
const insert = this.db.prepare(`INSERT INTO sessions
|
|
108
196
|
(ts, project, command, model, prompt, response,
|
|
109
|
-
tokens_input, tokens_output, cost_usd, tools, duration_ms)
|
|
110
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
111
|
-
const info = insert.run(ts, rec.project ?? null, rec.command ?? null, rec.model ?? null, rec.prompt ?? null, rec.response ?? null, rec.tokensInput ?? null, rec.tokensOutput ?? null, rec.costUsd ?? null, tools, rec.durationMs ?? null);
|
|
197
|
+
tokens_input, tokens_output, cost_usd, tools, duration_ms, conversation_id)
|
|
198
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
199
|
+
const info = insert.run(ts, rec.project ?? null, rec.command ?? null, rec.model ?? null, rec.prompt ?? null, rec.response ?? null, rec.tokensInput ?? null, rec.tokensOutput ?? null, rec.costUsd ?? null, tools, rec.durationMs ?? null, conversationId);
|
|
112
200
|
const id = Number(info.lastInsertRowid);
|
|
113
201
|
this.db
|
|
114
202
|
.prepare(`INSERT INTO sessions_fts (rowid, prompt, response, command, project)
|
|
@@ -141,6 +229,7 @@ export class HistoryStore {
|
|
|
141
229
|
s.model AS model, s.prompt AS prompt, s.response AS response,
|
|
142
230
|
s.tokens_input AS tokens_input, s.tokens_output AS tokens_output,
|
|
143
231
|
s.cost_usd AS cost_usd, s.tools AS tools, s.duration_ms AS duration_ms,
|
|
232
|
+
s.conversation_id AS conversation_id,
|
|
144
233
|
snippet(sessions_fts, 0, '[', ']', '…', 12) AS snippet
|
|
145
234
|
FROM sessions_fts f
|
|
146
235
|
JOIN sessions s ON s.id = f.rowid
|
|
@@ -164,7 +253,7 @@ export class HistoryStore {
|
|
|
164
253
|
try {
|
|
165
254
|
const rows = this.db
|
|
166
255
|
.prepare(`SELECT id, ts, project, command, model, prompt, response,
|
|
167
|
-
tokens_input, tokens_output, cost_usd, tools, duration_ms
|
|
256
|
+
tokens_input, tokens_output, cost_usd, tools, duration_ms, conversation_id
|
|
168
257
|
FROM sessions
|
|
169
258
|
ORDER BY id DESC
|
|
170
259
|
LIMIT ?`)
|
|
@@ -180,6 +269,70 @@ export class HistoryStore {
|
|
|
180
269
|
return [];
|
|
181
270
|
}
|
|
182
271
|
}
|
|
272
|
+
/**
|
|
273
|
+
* GS2-19 — conversations newest-first, each with its turn count, timespan, and a preview of the
|
|
274
|
+
* last turn. This is the top-level unit for `gth history list` (the turn-grained {@link listRecent}
|
|
275
|
+
* remains for callers that want raw turns). Fail-soft ([] on error).
|
|
276
|
+
*
|
|
277
|
+
* Empty conversations are **excluded** (`HAVING COUNT(s.id) > 0`): a session opens its conversation
|
|
278
|
+
* at start (before any turn), so one that exits with zero turns would otherwise show as a
|
|
279
|
+
* contentless `turnCount: 0` row. The LEFT JOIN still keeps every conversation that has ≥1 turn —
|
|
280
|
+
* including back-filled 1-turn conversations, whose single turn satisfies the HAVING.
|
|
281
|
+
*/
|
|
282
|
+
listConversations(limit = 20) {
|
|
283
|
+
try {
|
|
284
|
+
const rows = this.db
|
|
285
|
+
.prepare(`SELECT c.id AS id, c.started_ts AS started_ts, c.project AS project,
|
|
286
|
+
c.command AS command, c.model AS model,
|
|
287
|
+
COUNT(s.id) AS turn_count, MIN(s.ts) AS first_ts, MAX(s.ts) AS last_ts
|
|
288
|
+
FROM conversations c
|
|
289
|
+
LEFT JOIN sessions s ON s.conversation_id = c.id
|
|
290
|
+
GROUP BY c.id
|
|
291
|
+
HAVING COUNT(s.id) > 0
|
|
292
|
+
ORDER BY c.id DESC
|
|
293
|
+
LIMIT ?`)
|
|
294
|
+
.all(limit);
|
|
295
|
+
const lastTurn = this.db.prepare(`SELECT prompt, response FROM sessions
|
|
296
|
+
WHERE conversation_id = ? ORDER BY id DESC LIMIT 1`);
|
|
297
|
+
return rows.map((r) => {
|
|
298
|
+
const last = lastTurn.get(Number(r.id));
|
|
299
|
+
return {
|
|
300
|
+
id: Number(r.id),
|
|
301
|
+
startedTs: String(r.started_ts),
|
|
302
|
+
project: r.project != null ? String(r.project) : undefined,
|
|
303
|
+
command: r.command != null ? String(r.command) : undefined,
|
|
304
|
+
model: r.model != null ? String(r.model) : undefined,
|
|
305
|
+
turnCount: Number(r.turn_count ?? 0),
|
|
306
|
+
firstTs: r.first_ts != null ? String(r.first_ts) : undefined,
|
|
307
|
+
lastTs: r.last_ts != null ? String(r.last_ts) : undefined,
|
|
308
|
+
lastPrompt: last?.prompt != null ? String(last.prompt) : undefined,
|
|
309
|
+
lastResponse: last?.response != null ? String(last.response) : undefined,
|
|
310
|
+
};
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
catch {
|
|
314
|
+
return [];
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* GS2-19 — all turns of one conversation in chronological (insert) order, so a search hit can be
|
|
319
|
+
* expanded into the whole thread it belonged to. Fail-soft ([] on error / unknown id).
|
|
320
|
+
*/
|
|
321
|
+
getConversationThread(conversationId) {
|
|
322
|
+
try {
|
|
323
|
+
const rows = this.db
|
|
324
|
+
.prepare(`SELECT id, ts, project, command, model, prompt, response,
|
|
325
|
+
tokens_input, tokens_output, cost_usd, tools, duration_ms, conversation_id
|
|
326
|
+
FROM sessions
|
|
327
|
+
WHERE conversation_id = ?
|
|
328
|
+
ORDER BY id ASC`)
|
|
329
|
+
.all(conversationId);
|
|
330
|
+
return rows.map((r) => rowToRecord(r));
|
|
331
|
+
}
|
|
332
|
+
catch {
|
|
333
|
+
return [];
|
|
334
|
+
}
|
|
335
|
+
}
|
|
183
336
|
/**
|
|
184
337
|
* Aggregate token/cost totals, a top-tool tally, and a per-command breakdown over the whole
|
|
185
338
|
* store. Tool tallying reads each row's JSON `tools` array in JS (robust to nulls). Fail-soft:
|
|
@@ -281,6 +434,7 @@ function rowToRecord(r) {
|
|
|
281
434
|
}
|
|
282
435
|
}
|
|
283
436
|
return {
|
|
437
|
+
conversationId: r.conversation_id != null ? Number(r.conversation_id) : undefined,
|
|
284
438
|
ts: r.ts != null ? String(r.ts) : undefined,
|
|
285
439
|
project: r.project != null ? String(r.project) : undefined,
|
|
286
440
|
command: r.command != null ? String(r.command) : undefined,
|