@gaunt-sloth/core 2.0.0-alpha.2 → 2.0.0-alpha.21
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/.gsloth.code.md +10 -0
- package/README.md +6 -6
- package/dist/config/defaults.d.ts +85 -0
- package/dist/config/defaults.js +103 -0
- package/dist/config/defaults.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 +169 -0
- package/dist/config/loader.js +872 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +673 -0
- package/dist/config/schema.js +524 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/config/shell-policy.d.ts +331 -0
- package/dist/config/shell-policy.js +238 -0
- package/dist/config/shell-policy.js.map +1 -0
- package/dist/config/types.d.ts +596 -0
- package/dist/config/types.js +13 -0
- package/dist/config/types.js.map +1 -0
- package/dist/config.d.ts +18 -647
- package/dist/config.js +15 -516
- package/dist/config.js.map +1 -1
- package/dist/constants.d.ts +42 -0
- package/dist/constants.js +42 -0
- package/dist/constants.js.map +1 -1
- package/dist/core/GthAbstractAgent.d.ts +85 -2
- package/dist/core/GthAbstractAgent.js +398 -28
- package/dist/core/GthAbstractAgent.js.map +1 -1
- package/dist/core/GthAgentRunner.d.ts +158 -1
- package/dist/core/GthAgentRunner.js +367 -4
- package/dist/core/GthAgentRunner.js.map +1 -1
- package/dist/core/GthLangChainAgent.js +193 -16
- package/dist/core/GthLangChainAgent.js.map +1 -1
- package/dist/core/debugCapture.d.ts +59 -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/plainToolIndication.d.ts +15 -0
- package/dist/core/plainToolIndication.js +148 -0
- package/dist/core/plainToolIndication.js.map +1 -0
- package/dist/core/runStats.d.ts +41 -0
- package/dist/core/runStats.js +73 -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/allowlist.d.ts +75 -0
- package/dist/core/shell/allowlist.js +187 -0
- package/dist/core/shell/allowlist.js.map +1 -0
- package/dist/core/shell/arity.d.ts +75 -0
- package/dist/core/shell/arity.js +313 -0
- package/dist/core/shell/arity.js.map +1 -0
- package/dist/core/shell/judge.d.ts +161 -0
- package/dist/core/shell/judge.js +261 -0
- package/dist/core/shell/judge.js.map +1 -0
- package/dist/core/shell/normalize.d.ts +27 -0
- package/dist/core/shell/normalize.js +53 -0
- package/dist/core/shell/normalize.js.map +1 -0
- package/dist/core/toolDisplay.d.ts +101 -0
- package/dist/core/toolDisplay.js +374 -0
- package/dist/core/toolDisplay.js.map +1 -0
- package/dist/core/toolOutputChannel.d.ts +68 -0
- package/dist/core/toolOutputChannel.js +112 -0
- package/dist/core/toolOutputChannel.js.map +1 -0
- package/dist/core/types.d.ts +173 -0
- 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 +52 -0
- package/dist/providers/geminiSchemaSanitizer.js +201 -0
- package/dist/providers/geminiSchemaSanitizer.js.map +1 -0
- package/dist/providers/google-genai.d.ts +1 -1
- package/dist/providers/google-genai.js +9 -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 +111 -3
- package/dist/providers/modelDiscovery.js +183 -27
- 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 +5 -10
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/openrouter.d.ts +1 -1
- package/dist/providers/openrouter.js +12 -12
- package/dist/providers/openrouter.js.map +1 -1
- package/dist/providers/vertexai.d.ts +1 -1
- package/dist/providers/vertexai.js +9 -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 +62 -0
- package/dist/runtime/askStructured.js +76 -0
- package/dist/runtime/askStructured.js.map +1 -0
- package/dist/runtime/conversation.d.ts +59 -0
- package/dist/runtime/conversation.js +137 -0
- package/dist/runtime/conversation.js.map +1 -0
- package/dist/runtime/singleShot.d.ts +24 -5
- package/dist/runtime/singleShot.js +56 -9
- package/dist/runtime/singleShot.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 +22 -0
- package/dist/utils/consoleUtils.js +45 -0
- package/dist/utils/consoleUtils.js.map +1 -1
- package/dist/utils/debugDump.d.ts +57 -0
- package/dist/utils/debugDump.js +236 -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/fileUtils.d.ts +24 -2
- package/dist/utils/fileUtils.js +54 -12
- package/dist/utils/fileUtils.js.map +1 -1
- package/dist/utils/llmUtils.js.map +1 -1
- package/dist/utils/redactSecrets.d.ts +63 -0
- package/dist/utils/redactSecrets.js +238 -0
- package/dist/utils/redactSecrets.js.map +1 -0
- package/dist/utils/systemPromptNotes.d.ts +181 -0
- package/dist/utils/systemPromptNotes.js +298 -0
- package/dist/utils/systemPromptNotes.js.map +1 -0
- package/dist/utils/systemUtils.d.ts +32 -1
- package/dist/utils/systemUtils.js +50 -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/package.json +17 -8
- package/schema/gsloth-config.schema.json +2111 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { displayWarning } from '#src/utils/consoleUtils.js';
|
|
2
2
|
import { env } from '#src/utils/systemUtils.js';
|
|
3
|
-
import {
|
|
3
|
+
import { writeConfigFileWithMessages } from '#src/utils/fileUtils.js';
|
|
4
|
+
import { buildInitConfigContent, getCuratedFallbackModel } from '#src/providers/modelDiscovery.js';
|
|
4
5
|
// Function to process JSON config and create OpenRouter LLM instance
|
|
5
6
|
// noinspection JSUnusedGlobalSymbols
|
|
6
7
|
export async function processJsonConfig(llmConfig) {
|
|
@@ -13,13 +14,18 @@ export async function processJsonConfig(llmConfig) {
|
|
|
13
14
|
const configFields = {
|
|
14
15
|
...llmConfig,
|
|
15
16
|
apiKey: openRouterApiKey,
|
|
16
|
-
model: llmConfig.model || '
|
|
17
|
+
model: llmConfig.model || getCuratedFallbackModel('openrouter'),
|
|
18
|
+
// TUI-C22 — OpenRouter returns a thinking model's reasoning in a top-level `reasoning` field
|
|
19
|
+
// that the ChatOpenAI completions converter drops. `__includeRawResponse` stashes the raw
|
|
20
|
+
// provider response under `additional_kwargs.__raw_response`, which GthAbstractAgent reads
|
|
21
|
+
// (`choices[0].delta.reasoning`) to populate the /reasoning panel. Kept opt-out via config.
|
|
22
|
+
__includeRawResponse: llmConfig.__includeRawResponse ?? true,
|
|
17
23
|
configuration: {
|
|
18
24
|
baseURL: 'https://openrouter.ai/api/v1',
|
|
19
25
|
...(llmConfig.configuration || {}),
|
|
20
26
|
defaultHeaders: {
|
|
21
|
-
'HTTP-Referer': 'https://
|
|
22
|
-
'X-Title': 'Gaunt Sloth
|
|
27
|
+
'HTTP-Referer': 'https://gauntsloth.app/',
|
|
28
|
+
'X-Title': 'Gaunt Sloth',
|
|
23
29
|
},
|
|
24
30
|
},
|
|
25
31
|
};
|
|
@@ -39,18 +45,12 @@ function getApiKey(llmConfig) {
|
|
|
39
45
|
return llmConfig.apiKey || env.OPEN_ROUTER_API_KEY || env.OPENROUTER_API_KEY;
|
|
40
46
|
}
|
|
41
47
|
}
|
|
42
|
-
|
|
43
|
-
"llm": {
|
|
44
|
-
"type": "openrouter",
|
|
45
|
-
"model": "qwen/qwen3-coder"
|
|
46
|
-
}
|
|
47
|
-
}`;
|
|
48
|
-
export function init(configFileName) {
|
|
48
|
+
export function init(configFileName, force = false, model) {
|
|
49
49
|
// Determine which content to use based on file extension
|
|
50
50
|
if (!configFileName.endsWith('.json')) {
|
|
51
51
|
throw new Error('Only JSON config is supported.');
|
|
52
52
|
}
|
|
53
|
-
|
|
53
|
+
writeConfigFileWithMessages(configFileName, buildInitConfigContent('openrouter', model), force);
|
|
54
54
|
displayWarning(`You need to edit your ${configFileName} to configure model, ` +
|
|
55
55
|
'or define OPEN_ROUTER_API_KEY environment variable.');
|
|
56
56
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openrouter.js","sourceRoot":"","sources":["../../src/providers/openrouter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,GAAG,EAAE,MAAM,2BAA2B,CAAC;AAQhD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"openrouter.js","sourceRoot":"","sources":["../../src/providers/openrouter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,GAAG,EAAE,MAAM,2BAA2B,CAAC;AAQhD,OAAO,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAEnG,qEAAqE;AACrE,qCAAqC;AACrC,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,SAAmE;IAEnE,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAC;IACzD,wEAAwE;IACxE,MAAM,gBAAgB,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;IAC9C,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CACb,iGAAiG,CAClG,CAAC;IACJ,CAAC;IACD,MAAM,YAAY,GAAG;QACnB,GAAG,SAAS;QACZ,MAAM,EAAE,gBAAgB;QACxB,KAAK,EAAE,SAAS,CAAC,KAAK,IAAI,uBAAuB,CAAC,YAAY,CAAC;QAC/D,6FAA6F;QAC7F,0FAA0F;QAC1F,2FAA2F;QAC3F,4FAA4F;QAC5F,oBAAoB,EAAE,SAAS,CAAC,oBAAoB,IAAI,IAAI;QAC5D,aAAa,EAAE;YACb,OAAO,EAAE,8BAA8B;YACvC,GAAG,CAAC,SAAS,CAAC,aAAa,IAAI,EAAE,CAAC;YAClC,cAAc,EAAE;gBACd,cAAc,EAAE,yBAAyB;gBACzC,SAAS,EAAE,aAAa;aACzB;SACF;KACF,CAAC;IACF,8DAA8D;IAC9D,OAAQ,YAAoB,CAAC,IAAI,CAAC;IAClC,8DAA8D;IAC9D,OAAQ,YAAoB,CAAC,yBAAyB,CAAC;IACvD,OAAO,IAAI,UAAU,CAAC,YAAY,CAAC,CAAC;AACtC,CAAC;AAED,SAAS,SAAS,CAAC,SAAmE;IACpF,8DAA8D;IAC9D,MAAM,IAAI,GAAG,SAA0C,CAAC;IACxD,IAAI,IAAI,CAAC,yBAAyB,IAAI,GAAG,CAAC,IAAI,CAAC,yBAAyB,CAAC,EAAE,CAAC;QAC1E,OAAO,GAAG,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;SAAM,CAAC;QACN,OAAO,SAAS,CAAC,MAAM,IAAI,GAAG,CAAC,mBAAmB,IAAI,GAAG,CAAC,kBAAkB,CAAC;IAC/E,CAAC;AACH,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,cAAsB,EAAE,KAAK,GAAG,KAAK,EAAE,KAAc;IACxE,yDAAyD;IACzD,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACpD,CAAC;IAED,2BAA2B,CAAC,cAAc,EAAE,sBAAsB,CAAC,YAAY,EAAE,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC;IAChG,cAAc,CACZ,yBAAyB,cAAc,uBAAuB;QAC5D,qDAAqD,CACxD,CAAC;AACJ,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
|
2
2
|
import type { ChatGoogleParams } from '@langchain/google/node';
|
|
3
|
-
export declare function init(configFileName: string): void;
|
|
3
|
+
export declare function init(configFileName: string, force?: boolean, model?: string): void;
|
|
4
4
|
export declare function processJsonConfig(llmConfig: ChatGoogleParams & {
|
|
5
5
|
type?: string;
|
|
6
6
|
apiKeyEnvironmentVariable?: string;
|
|
@@ -11,19 +11,15 @@
|
|
|
11
11
|
* Hopefully this issue will go away when LangChain switches to the new GenAI dependency.
|
|
12
12
|
*/
|
|
13
13
|
import { displayWarning } from '#src/utils/consoleUtils.js';
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"model": "gemini-3.5-flash"
|
|
19
|
-
}
|
|
20
|
-
}`;
|
|
21
|
-
export function init(configFileName) {
|
|
14
|
+
import { writeConfigFileWithMessages } from '#src/utils/fileUtils.js';
|
|
15
|
+
import { buildInitConfigContent, getCuratedFallbackModel } from '#src/providers/modelDiscovery.js';
|
|
16
|
+
import { applyGeminiToolSchemaSanitizer } from '#src/providers/geminiSchemaSanitizer.js';
|
|
17
|
+
export function init(configFileName, force = false, model) {
|
|
22
18
|
// Determine which content to use based on file extension
|
|
23
19
|
if (!configFileName.endsWith('.json')) {
|
|
24
20
|
throw new Error('Only JSON config is supported.');
|
|
25
21
|
}
|
|
26
|
-
|
|
22
|
+
writeConfigFileWithMessages(configFileName, buildInitConfigContent('vertexai', model), force);
|
|
27
23
|
displayWarning('For Google VertexAI you likely to need to do `gcloud auth login` and `gcloud auth application-default login`.');
|
|
28
24
|
}
|
|
29
25
|
// Function to process JSON config and create VertexAI LLM instance
|
|
@@ -31,11 +27,13 @@ export async function processJsonConfig(llmConfig) {
|
|
|
31
27
|
const { ChatGoogle } = await import('@langchain/google/node');
|
|
32
28
|
const configFields = {
|
|
33
29
|
...llmConfig,
|
|
34
|
-
model: llmConfig.model || '
|
|
30
|
+
model: llmConfig.model || getCuratedFallbackModel('vertexai'),
|
|
35
31
|
vertexai: true,
|
|
36
32
|
};
|
|
37
33
|
delete configFields.type;
|
|
38
34
|
delete configFields.apiKeyEnvironmentVariable;
|
|
39
|
-
|
|
35
|
+
// GS2-58: normalise every tool's JSON-Schema at the ChatGoogle boundary so Gemini's OpenAPI-3.0
|
|
36
|
+
// subset accepts built-in, custom, and MCP tools alike (see geminiSchemaSanitizer).
|
|
37
|
+
return applyGeminiToolSchemaSanitizer(new ChatGoogle(configFields));
|
|
40
38
|
}
|
|
41
39
|
//# sourceMappingURL=vertexai.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vertexai.js","sourceRoot":"","sources":["../../src/providers/vertexai.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAI5D,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"vertexai.js","sourceRoot":"","sources":["../../src/providers/vertexai.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAI5D,OAAO,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AACnG,OAAO,EAAE,8BAA8B,EAAE,MAAM,yCAAyC,CAAC;AAEzF,MAAM,UAAU,IAAI,CAAC,cAAsB,EAAE,KAAK,GAAG,KAAK,EAAE,KAAc;IACxE,yDAAyD;IACzD,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACpD,CAAC;IAED,2BAA2B,CAAC,cAAc,EAAE,sBAAsB,CAAC,UAAU,EAAE,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC;IAC9F,cAAc,CACZ,+GAA+G,CAChH,CAAC;AACJ,CAAC;AAED,mEAAmE;AACnE,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,SAAmF;IAEnF,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,wBAAwB,CAAC,CAAC;IAC9D,MAAM,YAAY,GAAG;QACnB,GAAG,SAAS;QACZ,KAAK,EAAE,SAAS,CAAC,KAAK,IAAI,uBAAuB,CAAC,UAAU,CAAC;QAC7D,QAAQ,EAAE,IAAI;KACf,CAAC;IACF,OAAO,YAAY,CAAC,IAAI,CAAC;IACzB,OAAO,YAAY,CAAC,yBAAyB,CAAC;IAC9C,gGAAgG;IAChG,oFAAoF;IACpF,OAAO,8BAA8B,CAAC,IAAI,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC;AACtE,CAAC"}
|
package/dist/providers/xai.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { BaseChatModel, BaseChatModelParams } from '@langchain/core/language_models/chat_models';
|
|
2
2
|
import type { ChatXAIInput } from '@langchain/xai';
|
|
3
3
|
export declare function processJsonConfig(llmConfig: ChatXAIInput & BaseChatModelParams): Promise<BaseChatModel>;
|
|
4
|
-
export declare function init(configFileName: string): void;
|
|
4
|
+
export declare function init(configFileName: string, force?: boolean, model?: string): void;
|
package/dist/providers/xai.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { displayWarning } from '#src/utils/consoleUtils.js';
|
|
2
2
|
import { env } from '#src/utils/systemUtils.js';
|
|
3
|
-
import {
|
|
3
|
+
import { writeConfigFileWithMessages } from '#src/utils/fileUtils.js';
|
|
4
|
+
import { buildInitConfigContent, getCuratedFallbackModel } from '#src/providers/modelDiscovery.js';
|
|
4
5
|
// Function to process JSON config and create XAI LLM instance
|
|
5
6
|
export async function processJsonConfig(llmConfig) {
|
|
6
7
|
const { ChatXAI } = await import('@langchain/xai');
|
|
@@ -9,21 +10,15 @@ export async function processJsonConfig(llmConfig) {
|
|
|
9
10
|
return new ChatXAI({
|
|
10
11
|
...llmConfig,
|
|
11
12
|
apiKey,
|
|
12
|
-
model: llmConfig.model || '
|
|
13
|
+
model: llmConfig.model || getCuratedFallbackModel('xai'),
|
|
13
14
|
});
|
|
14
15
|
}
|
|
15
|
-
|
|
16
|
-
"llm": {
|
|
17
|
-
"type": "xai",
|
|
18
|
-
"model": "grok-4.3"
|
|
19
|
-
}
|
|
20
|
-
}`;
|
|
21
|
-
export function init(configFileName) {
|
|
16
|
+
export function init(configFileName, force = false, model) {
|
|
22
17
|
// Determine which content to use based on file extension
|
|
23
18
|
if (!configFileName.endsWith('.json')) {
|
|
24
19
|
throw new Error('Only JSON config is supported.');
|
|
25
20
|
}
|
|
26
|
-
|
|
21
|
+
writeConfigFileWithMessages(configFileName, buildInitConfigContent('xai', model), force);
|
|
27
22
|
displayWarning(`You need to update your ${configFileName} to add your xAI API key, ` +
|
|
28
23
|
'or define XAI_API_KEY environment variable.');
|
|
29
24
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"xai.js","sourceRoot":"","sources":["../../src/providers/xai.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,GAAG,EAAE,MAAM,2BAA2B,CAAC;AAOhD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"xai.js","sourceRoot":"","sources":["../../src/providers/xai.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,GAAG,EAAE,MAAM,2BAA2B,CAAC;AAOhD,OAAO,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAEnG,8DAA8D;AAC9D,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,SAA6C;IAE7C,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAC;IACnD,wEAAwE;IACxE,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,IAAI,GAAG,CAAC,WAAW,CAAC;IACnD,OAAO,IAAI,OAAO,CAAC;QACjB,GAAG,SAAS;QACZ,MAAM;QACN,KAAK,EAAE,SAAS,CAAC,KAAK,IAAI,uBAAuB,CAAC,KAAK,CAAC;KACzD,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,cAAsB,EAAE,KAAK,GAAG,KAAK,EAAE,KAAc;IACxE,yDAAyD;IACzD,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACpD,CAAC;IAED,2BAA2B,CAAC,cAAc,EAAE,sBAAsB,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC;IACzF,cAAc,CACZ,2BAA2B,cAAc,4BAA4B;QACnE,6CAA6C,CAChD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module runtime/askStructured
|
|
3
|
+
*
|
|
4
|
+
* A reusable, non-agentic "ask the LLM and get a schema-validated object back" primitive — the
|
|
5
|
+
* structured-output half the (later) `gth workflow` host calls. Deliberately mirrors the
|
|
6
|
+
* *mechanism* of the LLM-as-judge calls ({@link judgeEvalCase} in `@gaunt-sloth/batch`'s
|
|
7
|
+
* `judge.ts`, and its in-core ancestor {@link judgeShellCommand} in `core/shell/judge.ts`):
|
|
8
|
+
* `model.withStructuredOutput(schema)` for a single structured call, `.invoke([SystemMessage,
|
|
9
|
+
* HumanMessage])` raced against a wall-clock timeout via `Promise.race`, a defensive `safeParse`
|
|
10
|
+
* re-validation, `clearTimeout` in `finally`, and — crucially — it **never throws**, returning a
|
|
11
|
+
* failure object instead.
|
|
12
|
+
*
|
|
13
|
+
* Differences from the judges: this one is **generic** over the Zod schema and takes the
|
|
14
|
+
* system/user strings from the caller (the judges hard-code a schema and build a rubric/safety
|
|
15
|
+
* prompt), and it reads the model from `config.llm` (like `runSingleShot`/`judgeShellCommand`),
|
|
16
|
+
* so the workflow host can hand it the resolved {@link GthConfig} directly. `judgeEvalCase` could
|
|
17
|
+
* later be refactored to delegate to this primitive — out of scope here.
|
|
18
|
+
*/
|
|
19
|
+
import * as z from 'zod';
|
|
20
|
+
import type { GthConfig } from '#src/config.js';
|
|
21
|
+
/**
|
|
22
|
+
* Default wall-clock budget (ms) for the structured LLM call — same value as the judges'
|
|
23
|
+
* `EVAL_JUDGE_DEFAULT_TIMEOUT_MS` / `JUDGE_DEFAULT_TIMEOUT_MS`, kept as this module's own constant
|
|
24
|
+
* since the primitive is conceptually independent of them.
|
|
25
|
+
*/
|
|
26
|
+
export declare const ASK_STRUCTURED_DEFAULT_TIMEOUT_MS = 30000;
|
|
27
|
+
/** Inputs to {@link askStructured}. The caller supplies the model (via config), the two message
|
|
28
|
+
* texts, and an optional timeout — the Zod schema is a separate positional argument so `<T>` can
|
|
29
|
+
* be inferred from it. */
|
|
30
|
+
export interface AskStructuredOptions {
|
|
31
|
+
config: GthConfig;
|
|
32
|
+
/** System-message text (instructions). May be empty. */
|
|
33
|
+
system: string;
|
|
34
|
+
/** Human-message text (the actual content/question). */
|
|
35
|
+
user: string;
|
|
36
|
+
/** Wall-clock budget in ms. Default {@link ASK_STRUCTURED_DEFAULT_TIMEOUT_MS} (30_000). */
|
|
37
|
+
timeoutMs?: number;
|
|
38
|
+
}
|
|
39
|
+
/** Discriminated result of {@link askStructured}: the parsed value on success, an error string on
|
|
40
|
+
* any failure (unusable model, timeout, unparseable output, or a thrown error). Never throws. */
|
|
41
|
+
export type AskStructuredResult<T> = {
|
|
42
|
+
ok: true;
|
|
43
|
+
value: T;
|
|
44
|
+
} | {
|
|
45
|
+
ok: false;
|
|
46
|
+
error: string;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Ask the configured model for a single schema-validated object — a non-agentic structured-output
|
|
50
|
+
* call that mirrors the judges' mechanism (see the module doc) and never throws.
|
|
51
|
+
*
|
|
52
|
+
* - No usable model (`config.llm` missing or lacking `withStructuredOutput`) →
|
|
53
|
+
* `{ ok: false, error: 'No usable model configured.' }`.
|
|
54
|
+
* - Timeout → `{ ok: false, error: 'Structured call timed out after <ms>ms.' }`.
|
|
55
|
+
* - Output that fails `schema.safeParse` → `{ ok: false, error: 'Model returned unparseable output.' }`.
|
|
56
|
+
* - Any thrown error → `{ ok: false, error: <message> }`.
|
|
57
|
+
* - Success → `{ ok: true, value }` with the parsed data.
|
|
58
|
+
*
|
|
59
|
+
* @param schema The Zod schema the model output must satisfy; `<T>` is inferred from it.
|
|
60
|
+
* @param opts The model (via `config.llm`), the system/user message texts, and an optional timeout.
|
|
61
|
+
*/
|
|
62
|
+
export declare function askStructured<T>(schema: z.ZodType<T>, opts: AskStructuredOptions): Promise<AskStructuredResult<T>>;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module runtime/askStructured
|
|
3
|
+
*
|
|
4
|
+
* A reusable, non-agentic "ask the LLM and get a schema-validated object back" primitive — the
|
|
5
|
+
* structured-output half the (later) `gth workflow` host calls. Deliberately mirrors the
|
|
6
|
+
* *mechanism* of the LLM-as-judge calls ({@link judgeEvalCase} in `@gaunt-sloth/batch`'s
|
|
7
|
+
* `judge.ts`, and its in-core ancestor {@link judgeShellCommand} in `core/shell/judge.ts`):
|
|
8
|
+
* `model.withStructuredOutput(schema)` for a single structured call, `.invoke([SystemMessage,
|
|
9
|
+
* HumanMessage])` raced against a wall-clock timeout via `Promise.race`, a defensive `safeParse`
|
|
10
|
+
* re-validation, `clearTimeout` in `finally`, and — crucially — it **never throws**, returning a
|
|
11
|
+
* failure object instead.
|
|
12
|
+
*
|
|
13
|
+
* Differences from the judges: this one is **generic** over the Zod schema and takes the
|
|
14
|
+
* system/user strings from the caller (the judges hard-code a schema and build a rubric/safety
|
|
15
|
+
* prompt), and it reads the model from `config.llm` (like `runSingleShot`/`judgeShellCommand`),
|
|
16
|
+
* so the workflow host can hand it the resolved {@link GthConfig} directly. `judgeEvalCase` could
|
|
17
|
+
* later be refactored to delegate to this primitive — out of scope here.
|
|
18
|
+
*/
|
|
19
|
+
import { HumanMessage, SystemMessage } from '@langchain/core/messages';
|
|
20
|
+
/**
|
|
21
|
+
* Default wall-clock budget (ms) for the structured LLM call — same value as the judges'
|
|
22
|
+
* `EVAL_JUDGE_DEFAULT_TIMEOUT_MS` / `JUDGE_DEFAULT_TIMEOUT_MS`, kept as this module's own constant
|
|
23
|
+
* since the primitive is conceptually independent of them.
|
|
24
|
+
*/
|
|
25
|
+
export const ASK_STRUCTURED_DEFAULT_TIMEOUT_MS = 30_000;
|
|
26
|
+
/**
|
|
27
|
+
* Ask the configured model for a single schema-validated object — a non-agentic structured-output
|
|
28
|
+
* call that mirrors the judges' mechanism (see the module doc) and never throws.
|
|
29
|
+
*
|
|
30
|
+
* - No usable model (`config.llm` missing or lacking `withStructuredOutput`) →
|
|
31
|
+
* `{ ok: false, error: 'No usable model configured.' }`.
|
|
32
|
+
* - Timeout → `{ ok: false, error: 'Structured call timed out after <ms>ms.' }`.
|
|
33
|
+
* - Output that fails `schema.safeParse` → `{ ok: false, error: 'Model returned unparseable output.' }`.
|
|
34
|
+
* - Any thrown error → `{ ok: false, error: <message> }`.
|
|
35
|
+
* - Success → `{ ok: true, value }` with the parsed data.
|
|
36
|
+
*
|
|
37
|
+
* @param schema The Zod schema the model output must satisfy; `<T>` is inferred from it.
|
|
38
|
+
* @param opts The model (via `config.llm`), the system/user message texts, and an optional timeout.
|
|
39
|
+
*/
|
|
40
|
+
export async function askStructured(schema, opts) {
|
|
41
|
+
const { config, system, user } = opts;
|
|
42
|
+
const timeoutMs = opts.timeoutMs ?? ASK_STRUCTURED_DEFAULT_TIMEOUT_MS;
|
|
43
|
+
const model = config.llm;
|
|
44
|
+
if (!model || typeof model.withStructuredOutput !== 'function') {
|
|
45
|
+
return { ok: false, error: 'No usable model configured.' };
|
|
46
|
+
}
|
|
47
|
+
let timer;
|
|
48
|
+
try {
|
|
49
|
+
// `withStructuredOutput`'s output type is constrained to a record shape, but the schema here is
|
|
50
|
+
// an unconstrained `z.ZodType<T>`; the cast is sound because we re-validate the result with
|
|
51
|
+
// `schema.safeParse` below (a fake or misbehaving model could return a non-conforming object).
|
|
52
|
+
const structured = model.withStructuredOutput(schema);
|
|
53
|
+
const invokePromise = structured.invoke([new SystemMessage(system), new HumanMessage(user)]);
|
|
54
|
+
const TIMEOUT = Symbol('ask-structured-timeout');
|
|
55
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
56
|
+
timer = setTimeout(() => resolve(TIMEOUT), timeoutMs);
|
|
57
|
+
});
|
|
58
|
+
const raced = await Promise.race([invokePromise, timeoutPromise]);
|
|
59
|
+
if (raced === TIMEOUT) {
|
|
60
|
+
return { ok: false, error: `Structured call timed out after ${timeoutMs}ms.` };
|
|
61
|
+
}
|
|
62
|
+
const parsed = schema.safeParse(raced);
|
|
63
|
+
if (!parsed.success) {
|
|
64
|
+
return { ok: false, error: 'Model returned unparseable output.' };
|
|
65
|
+
}
|
|
66
|
+
return { ok: true, value: parsed.data };
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
return { ok: false, error: error instanceof Error ? error.message : String(error) };
|
|
70
|
+
}
|
|
71
|
+
finally {
|
|
72
|
+
if (timer)
|
|
73
|
+
clearTimeout(timer);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=askStructured.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"askStructured.js","sourceRoot":"","sources":["../../src/runtime/askStructured.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAKvE;;;;GAIG;AACH,MAAM,CAAC,MAAM,iCAAiC,GAAG,MAAM,CAAC;AAmBxD;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAAoB,EACpB,IAA0B;IAE1B,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;IACtC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,iCAAiC,CAAC;IAEtE,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC;IACzB,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,CAAC,oBAAoB,KAAK,UAAU,EAAE,CAAC;QAC/D,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,6BAA6B,EAAE,CAAC;IAC7D,CAAC;IAED,IAAI,KAAgD,CAAC;IACrD,IAAI,CAAC;QACH,gGAAgG;QAChG,4FAA4F;QAC5F,+FAA+F;QAC/F,MAAM,UAAU,GAAG,KAAK,CAAC,oBAAoB,CAAC,MAA4C,CAAC,CAAC;QAC5F,MAAM,aAAa,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,aAAa,CAAC,MAAM,CAAC,EAAE,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAE7F,MAAM,OAAO,GAAG,MAAM,CAAC,wBAAwB,CAAC,CAAC;QACjD,MAAM,cAAc,GAAG,IAAI,OAAO,CAAiB,CAAC,OAAO,EAAE,EAAE;YAC7D,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,CAAC;QACxD,CAAC,CAAC,CAAC;QAEH,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,cAAc,CAAC,CAAC,CAAC;QAClE,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;YACtB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,mCAAmC,SAAS,KAAK,EAAE,CAAC;QACjF,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,oCAAoC,EAAE,CAAC;QACpE,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;IAC1C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;IACtF,CAAC;YAAS,CAAC;QACT,IAAI,KAAK;YAAE,YAAY,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { GthConfig } from '#src/config.js';
|
|
2
|
+
import type { AgentResolvers, GthAgentFactory, GthCommand } from '#src/core/types.js';
|
|
3
|
+
import type { GthRunStats } from '#src/core/types.js';
|
|
4
|
+
/**
|
|
5
|
+
* One turn's result inside a {@link runConversation} run: the per-turn `ok`/`answer` plus that
|
|
6
|
+
* turn's run stats (GS2-16 {@link GthRunStats} — token usage + invoked tools), captured PER TURN (a
|
|
7
|
+
* per-invoke delta, not the cumulative conversation total). `ok` is `false` when that turn's agent
|
|
8
|
+
* invocation failed (`error` set, `answer` empty). Extends `GthRunStats` rather than restating its
|
|
9
|
+
* fields — same shape {@link ../runtime/singleShot.js SingleShotResult} uses.
|
|
10
|
+
*/
|
|
11
|
+
export interface ConversationTurnResult extends GthRunStats {
|
|
12
|
+
/** `true` when this turn completed without error, `false` when it failed. */
|
|
13
|
+
ok: boolean;
|
|
14
|
+
/** This turn's full answer text (`runner.processMessages()`'s return value). Empty on failure. */
|
|
15
|
+
answer: string;
|
|
16
|
+
/** Set when `ok` is `false`: why this turn failed. */
|
|
17
|
+
error?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Run a scripted MULTI-TURN conversation and return one {@link ConversationTurnResult} per turn.
|
|
21
|
+
*
|
|
22
|
+
* This is the **conversational** counterpart to {@link ../runtime/singleShot.js runSingleShot}
|
|
23
|
+
* (which is stateless — a fresh agent per call). It builds the agent + resolves tools ONCE, then
|
|
24
|
+
* runs each turn against the ACCUMULATED message history so cross-turn "memory" / identity behaviour
|
|
25
|
+
* is real, and cleans up ONCE at the end (reusing runSingleShot's cleanup discipline — the resolvers
|
|
26
|
+
* are the caller's to tear down, exactly as with runSingleShot).
|
|
27
|
+
*
|
|
28
|
+
* **History mechanism = stateless replay of the growing message array.** Messages accumulate as
|
|
29
|
+
* `[user1, ai1, user2, ai2, …]`: per turn a `HumanMessage(user)` is appended, the agent runs on the
|
|
30
|
+
* WHOLE array, and its answer is appended as an `AIMessage` so the next turn sees it. The system
|
|
31
|
+
* prompt is NOT seeded here — the agent composes it via `createAgent({ systemPrompt })` (BATCH-13;
|
|
32
|
+
* see `runSingleShot`), so the replayed array carries only human/assistant turns. Before each
|
|
33
|
+
* turn the runner's thread is rotated ({@link GthAgentRunner.resetThread}) so the checkpointer starts
|
|
34
|
+
* empty and the replayed array is the sole history (no `add_messages` double-append). This mirrors
|
|
35
|
+
* the AG-UI server's "client is the source of truth for history — it sends the full message list
|
|
36
|
+
* every turn" model and reuses the existing `processMessages` + `resetThread` machinery with no new
|
|
37
|
+
* agent surface. **Known limitation (unverified pending a live pass):** replay carries prior
|
|
38
|
+
* *answers* (as `AIMessage` text) but NOT prior tool-call / tool-result messages — a checkpointer-
|
|
39
|
+
* thread approach (send only the new message, let `add_messages` accumulate) would preserve those.
|
|
40
|
+
*
|
|
41
|
+
* **Per-turn tool capture (GS2-16):** `processMessages` resets the analytics tally at its top, so
|
|
42
|
+
* `getRunStats()` read right after each turn returns THAT turn's tool/token delta (not cumulative).
|
|
43
|
+
*
|
|
44
|
+
* A turn that fails is recorded (`ok:false`, `error`) and the conversation STOPS (later turns depend
|
|
45
|
+
* on the broken context), so the returned array may be shorter than `userMessages` — the caller
|
|
46
|
+
* (`gth eval`'s runner) fails the un-run turns.
|
|
47
|
+
*
|
|
48
|
+
* @param source - The source label (used for output/session-file naming), e.g. `EVAL-<cellId>`.
|
|
49
|
+
* @param _preamble - Deprecated/ignored (BATCH-13): the agent composes the system prompt itself (via
|
|
50
|
+
* `createAgent({ systemPrompt })`); seeding it here too produced a second system message that
|
|
51
|
+
* `@langchain/anthropic` rejects. Retained positionally so existing callers need no change.
|
|
52
|
+
* @param userMessages - The ordered user turns to send (one conversation).
|
|
53
|
+
* @param config - The resolved config.
|
|
54
|
+
* @param resolvers - Optional agent resolvers (tools/middleware); the caller owns their cleanup.
|
|
55
|
+
* @param command - The originating command (defaults to `ask`); selects the agent mode prompt.
|
|
56
|
+
* @param agentFactory - Optional backend factory (B5); omitted = the runner's lean default.
|
|
57
|
+
* @returns One {@link ConversationTurnResult} per turn attempted, in turn order.
|
|
58
|
+
*/
|
|
59
|
+
export declare function runConversation(source: string, _preamble: string, userMessages: string[], config: GthConfig, resolvers?: AgentResolvers, command?: GthCommand, agentFactory?: GthAgentFactory): Promise<ConversationTurnResult[]>;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { defaultStatusCallback, display, displayError, displaySuccess, flushSessionLog, initSessionLogging, stopSessionLogging, } from '#src/utils/consoleUtils.js';
|
|
2
|
+
import { getCommandOutputFilePath } from '#src/utils/fileUtils.js';
|
|
3
|
+
import { GthAgentRunner } from '#src/core/GthAgentRunner.js';
|
|
4
|
+
import { MemorySaver } from '@langchain/langgraph';
|
|
5
|
+
import { AIMessage, HumanMessage } from '@langchain/core/messages';
|
|
6
|
+
import { ProgressIndicator } from '#src/utils/ProgressIndicator.js';
|
|
7
|
+
import { recordSessionSafe } from '#src/history/recordSession.js';
|
|
8
|
+
import { getProjectDir } from '#src/utils/systemUtils.js';
|
|
9
|
+
/**
|
|
10
|
+
* Run a scripted MULTI-TURN conversation and return one {@link ConversationTurnResult} per turn.
|
|
11
|
+
*
|
|
12
|
+
* This is the **conversational** counterpart to {@link ../runtime/singleShot.js runSingleShot}
|
|
13
|
+
* (which is stateless — a fresh agent per call). It builds the agent + resolves tools ONCE, then
|
|
14
|
+
* runs each turn against the ACCUMULATED message history so cross-turn "memory" / identity behaviour
|
|
15
|
+
* is real, and cleans up ONCE at the end (reusing runSingleShot's cleanup discipline — the resolvers
|
|
16
|
+
* are the caller's to tear down, exactly as with runSingleShot).
|
|
17
|
+
*
|
|
18
|
+
* **History mechanism = stateless replay of the growing message array.** Messages accumulate as
|
|
19
|
+
* `[user1, ai1, user2, ai2, …]`: per turn a `HumanMessage(user)` is appended, the agent runs on the
|
|
20
|
+
* WHOLE array, and its answer is appended as an `AIMessage` so the next turn sees it. The system
|
|
21
|
+
* prompt is NOT seeded here — the agent composes it via `createAgent({ systemPrompt })` (BATCH-13;
|
|
22
|
+
* see `runSingleShot`), so the replayed array carries only human/assistant turns. Before each
|
|
23
|
+
* turn the runner's thread is rotated ({@link GthAgentRunner.resetThread}) so the checkpointer starts
|
|
24
|
+
* empty and the replayed array is the sole history (no `add_messages` double-append). This mirrors
|
|
25
|
+
* the AG-UI server's "client is the source of truth for history — it sends the full message list
|
|
26
|
+
* every turn" model and reuses the existing `processMessages` + `resetThread` machinery with no new
|
|
27
|
+
* agent surface. **Known limitation (unverified pending a live pass):** replay carries prior
|
|
28
|
+
* *answers* (as `AIMessage` text) but NOT prior tool-call / tool-result messages — a checkpointer-
|
|
29
|
+
* thread approach (send only the new message, let `add_messages` accumulate) would preserve those.
|
|
30
|
+
*
|
|
31
|
+
* **Per-turn tool capture (GS2-16):** `processMessages` resets the analytics tally at its top, so
|
|
32
|
+
* `getRunStats()` read right after each turn returns THAT turn's tool/token delta (not cumulative).
|
|
33
|
+
*
|
|
34
|
+
* A turn that fails is recorded (`ok:false`, `error`) and the conversation STOPS (later turns depend
|
|
35
|
+
* on the broken context), so the returned array may be shorter than `userMessages` — the caller
|
|
36
|
+
* (`gth eval`'s runner) fails the un-run turns.
|
|
37
|
+
*
|
|
38
|
+
* @param source - The source label (used for output/session-file naming), e.g. `EVAL-<cellId>`.
|
|
39
|
+
* @param _preamble - Deprecated/ignored (BATCH-13): the agent composes the system prompt itself (via
|
|
40
|
+
* `createAgent({ systemPrompt })`); seeding it here too produced a second system message that
|
|
41
|
+
* `@langchain/anthropic` rejects. Retained positionally so existing callers need no change.
|
|
42
|
+
* @param userMessages - The ordered user turns to send (one conversation).
|
|
43
|
+
* @param config - The resolved config.
|
|
44
|
+
* @param resolvers - Optional agent resolvers (tools/middleware); the caller owns their cleanup.
|
|
45
|
+
* @param command - The originating command (defaults to `ask`); selects the agent mode prompt.
|
|
46
|
+
* @param agentFactory - Optional backend factory (B5); omitted = the runner's lean default.
|
|
47
|
+
* @returns One {@link ConversationTurnResult} per turn attempted, in turn order.
|
|
48
|
+
*/
|
|
49
|
+
export async function runConversation(source, _preamble, userMessages, config, resolvers, command = 'ask', agentFactory) {
|
|
50
|
+
const progressIndicator = config.streamOutput ? undefined : new ProgressIndicator('Thinking.');
|
|
51
|
+
// Resolve output path and initialize session logging if enabled (same discipline as runSingleShot;
|
|
52
|
+
// a no-op when `writeOutputToFile` is off, as `gth eval` forces it — getCommandOutputFilePath null).
|
|
53
|
+
const filePath = getCommandOutputFilePath(config, source);
|
|
54
|
+
if (filePath) {
|
|
55
|
+
initSessionLogging(filePath, config.streamSessionInferenceLog);
|
|
56
|
+
}
|
|
57
|
+
// Build the agent + resolve tools ONCE for the whole conversation (the MCP connection / any OAuth /
|
|
58
|
+
// the toolset must persist across turns so cross-turn memory is real). Cleaned up once, in finally.
|
|
59
|
+
const runner = new GthAgentRunner(defaultStatusCallback, resolvers, agentFactory);
|
|
60
|
+
const results = [];
|
|
61
|
+
// The accumulated conversation: [user1, ai1, user2, ai2, …]. Each turn replays the whole array
|
|
62
|
+
// against a freshly-rotated thread (see the doc block). BATCH-13: NO leading SystemMessage — the
|
|
63
|
+
// agent composes the system prompt via `createAgent({ systemPrompt })` (same as runSingleShot);
|
|
64
|
+
// seeding a preamble SystemMessage here too made two system messages, which Anthropic rejects.
|
|
65
|
+
const messages = [];
|
|
66
|
+
try {
|
|
67
|
+
await runner.init(command, config, new MemorySaver());
|
|
68
|
+
for (const userMessage of userMessages) {
|
|
69
|
+
// Rotate to a fresh (empty) checkpointer thread so this turn's replay of the full `messages`
|
|
70
|
+
// array is the sole history the agent sees — no double-append from a prior turn's checkpoint.
|
|
71
|
+
runner.resetThread();
|
|
72
|
+
messages.push(new HumanMessage(userMessage));
|
|
73
|
+
const startedAt = Date.now();
|
|
74
|
+
let answer = '';
|
|
75
|
+
let ok = true;
|
|
76
|
+
let error;
|
|
77
|
+
try {
|
|
78
|
+
answer = await runner.processMessages(messages);
|
|
79
|
+
// Append this turn's answer so the NEXT turn's replay includes it (cross-turn memory).
|
|
80
|
+
messages.push(new AIMessage(answer));
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
ok = false;
|
|
84
|
+
error = err instanceof Error ? err.message : String(err);
|
|
85
|
+
displayError(`Failed to get answer: ${error}`);
|
|
86
|
+
}
|
|
87
|
+
// GS2-16: read this turn's token/tool delta from the live agent (before cleanup). Fail-soft —
|
|
88
|
+
// analytics must never affect the run. `processMessages` reset the tally at its top, so this is
|
|
89
|
+
// THIS turn's usage, not the conversation's cumulative total.
|
|
90
|
+
let runStats = { tools: [] };
|
|
91
|
+
try {
|
|
92
|
+
const s = runner.getRunStats?.();
|
|
93
|
+
if (s)
|
|
94
|
+
runStats = s;
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
/* fail-soft */
|
|
98
|
+
}
|
|
99
|
+
// GS2-7 (B20): opt-in, fail-soft per-turn session history. A no-op unless `history.enabled`.
|
|
100
|
+
recordSessionSafe(config, {
|
|
101
|
+
command,
|
|
102
|
+
project: getProjectDir(),
|
|
103
|
+
model: config.modelDisplayName,
|
|
104
|
+
prompt: userMessage,
|
|
105
|
+
response: answer,
|
|
106
|
+
tokensInput: runStats.tokensInput,
|
|
107
|
+
tokensOutput: runStats.tokensOutput,
|
|
108
|
+
tools: runStats.tools.length > 0 ? runStats.tools : undefined,
|
|
109
|
+
durationMs: Date.now() - startedAt,
|
|
110
|
+
});
|
|
111
|
+
results.push({ ok, answer, error, ...runStats });
|
|
112
|
+
// A failed turn breaks the conversation's context — stop rather than run later turns on it.
|
|
113
|
+
if (!ok)
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
finally {
|
|
118
|
+
await runner.cleanup();
|
|
119
|
+
}
|
|
120
|
+
progressIndicator?.stop();
|
|
121
|
+
if (config.writeOutputToFile === false) {
|
|
122
|
+
display('\n'); // something going on in some terminals, they swallow last line of output
|
|
123
|
+
}
|
|
124
|
+
if (filePath) {
|
|
125
|
+
try {
|
|
126
|
+
flushSessionLog();
|
|
127
|
+
stopSessionLogging();
|
|
128
|
+
displaySuccess(`\n\nThis report can be found in ${filePath}`);
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
displayError(`Failed to write answer to file: ${filePath}`);
|
|
132
|
+
displayError(err instanceof Error ? err.message : String(err));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return results;
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=conversation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversation.js","sourceRoot":"","sources":["../../src/runtime/conversation.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
import type { GthConfig } from '#src/config.js';
|
|
2
|
-
import type { AgentResolvers, GthCommand } from '#src/core/types.js';
|
|
2
|
+
import type { AgentResolvers, GthAgentFactory, GthCommand } from '#src/core/types.js';
|
|
3
|
+
import type { GthRunStats } from '#src/core/types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Result of a {@link runSingleShot} run: the pass/fail contract callers such as `ask`/`exec` have
|
|
6
|
+
* always used (`ok`), plus the SUT's answer text and run stats (GS2-16's {@link GthRunStats}) that
|
|
7
|
+
* were already computed internally but previously discarded. Extends `GthRunStats` rather than
|
|
8
|
+
* restating `tokensInput`/`tokensOutput`/`tools` as parallel fields.
|
|
9
|
+
*/
|
|
10
|
+
export interface SingleShotResult extends GthRunStats {
|
|
11
|
+
/** `true` when the run completed without error, `false` when it failed. */
|
|
12
|
+
ok: boolean;
|
|
13
|
+
/** The SUT's full answer text (`runner.processMessages()`'s return value). Empty on failure. */
|
|
14
|
+
answer: string;
|
|
15
|
+
}
|
|
3
16
|
/**
|
|
4
17
|
* Ask a question and get an answer from the LLM.
|
|
5
18
|
*
|
|
@@ -8,12 +21,18 @@ import type { AgentResolvers, GthCommand } from '#src/core/types.js';
|
|
|
8
21
|
* is forwarded to the agent so it can pick the right mode prompt (e.g. exec-mode for `exec`).
|
|
9
22
|
*
|
|
10
23
|
* @param source - The source of the question (used for file naming)
|
|
11
|
-
* @param
|
|
24
|
+
* @param _preamble - Deprecated/ignored (BATCH-13): the agent composes the system prompt itself;
|
|
25
|
+
* see the body comment. Retained positionally so existing callers need no change.
|
|
12
26
|
* @param content - The content of the question
|
|
13
27
|
* @param config - The resolved config
|
|
14
28
|
* @param resolvers - Optional agent resolvers (tools/middleware)
|
|
15
29
|
* @param command - The originating command (defaults to `ask`); selects the agent mode prompt
|
|
16
|
-
* @
|
|
17
|
-
*
|
|
30
|
+
* @param agentFactory - Optional backend factory (B5). When omitted the runner uses its built-in
|
|
31
|
+
* lean {@link GthLangChainAgent} default (unchanged behavior for existing callers). The app
|
|
32
|
+
* layer passes `resolveAgentFactory(config, 'lean')` so an explicit `agent.backend` is honored.
|
|
33
|
+
* @returns A {@link SingleShotResult}: `ok` is `true` when the run completed without error, `false`
|
|
34
|
+
* when it failed (so callers such as `exec` can set a non-zero exit code); `answer`/`tokensInput`/
|
|
35
|
+
* `tokensOutput`/`tools` carry the SUT's answer text and run stats for callers that need them
|
|
36
|
+
* (e.g. `gth batch`/`gth eval`).
|
|
18
37
|
*/
|
|
19
|
-
export declare function runSingleShot(source: string,
|
|
38
|
+
export declare function runSingleShot(source: string, _preamble: string, content: string, config: GthConfig, resolvers?: AgentResolvers, command?: GthCommand, agentFactory?: GthAgentFactory): Promise<SingleShotResult>;
|