@gaunt-sloth/core 2.0.0-alpha.19 → 2.0.0-alpha.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/README.md +5 -4
  2. package/dist/config/defaults.js +6 -4
  3. package/dist/config/defaults.js.map +1 -1
  4. package/dist/config/loader.d.ts +29 -0
  5. package/dist/config/loader.js +158 -8
  6. package/dist/config/loader.js.map +1 -1
  7. package/dist/config/schema.d.ts +45 -0
  8. package/dist/config/schema.js +45 -1
  9. package/dist/config/schema.js.map +1 -1
  10. package/dist/config/shell-policy.d.ts +17 -0
  11. package/dist/config/shell-policy.js.map +1 -1
  12. package/dist/config/types.d.ts +60 -0
  13. package/dist/config/types.js.map +1 -1
  14. package/dist/constants.d.ts +11 -1
  15. package/dist/constants.js +11 -1
  16. package/dist/constants.js.map +1 -1
  17. package/dist/core/GthAbstractAgent.d.ts +28 -1
  18. package/dist/core/GthAbstractAgent.js +227 -33
  19. package/dist/core/GthAbstractAgent.js.map +1 -1
  20. package/dist/core/GthLangChainAgent.js +31 -14
  21. package/dist/core/GthLangChainAgent.js.map +1 -1
  22. package/dist/providers/geminiSchemaSanitizer.d.ts +52 -0
  23. package/dist/providers/geminiSchemaSanitizer.js +201 -0
  24. package/dist/providers/geminiSchemaSanitizer.js.map +1 -0
  25. package/dist/providers/google-genai.js +4 -1
  26. package/dist/providers/google-genai.js.map +1 -1
  27. package/dist/providers/ollama.d.ts +18 -4
  28. package/dist/providers/ollama.js +55 -37
  29. package/dist/providers/ollama.js.map +1 -1
  30. package/dist/providers/openrouter.js +5 -0
  31. package/dist/providers/openrouter.js.map +1 -1
  32. package/dist/providers/vertexai.js +4 -1
  33. package/dist/providers/vertexai.js.map +1 -1
  34. package/dist/runtime/conversation.d.ts +59 -0
  35. package/dist/runtime/conversation.js +137 -0
  36. package/dist/runtime/conversation.js.map +1 -0
  37. package/dist/runtime/singleShot.d.ts +3 -2
  38. package/dist/runtime/singleShot.js +16 -4
  39. package/dist/runtime/singleShot.js.map +1 -1
  40. package/dist/utils/debugDump.d.ts +30 -8
  41. package/dist/utils/debugDump.js +133 -10
  42. package/dist/utils/debugDump.js.map +1 -1
  43. package/dist/utils/redactSecrets.d.ts +63 -0
  44. package/dist/utils/redactSecrets.js +238 -0
  45. package/dist/utils/redactSecrets.js.map +1 -0
  46. package/dist/utils/systemPromptNotes.d.ts +92 -0
  47. package/dist/utils/systemPromptNotes.js +114 -0
  48. package/dist/utils/systemPromptNotes.js.map +1 -1
  49. package/dist/utils/systemUtils.d.ts +1 -1
  50. package/dist/utils/systemUtils.js +7 -2
  51. package/dist/utils/systemUtils.js.map +1 -1
  52. package/dist/utils/toolMatching.d.ts +30 -0
  53. package/dist/utils/toolMatching.js +44 -0
  54. package/dist/utils/toolMatching.js.map +1 -0
  55. package/package.json +5 -1
  56. package/schema/gsloth-config.schema.json +91 -0
@@ -3,58 +3,76 @@ import { env } from '#src/utils/systemUtils.js';
3
3
  import { writeConfigFileWithMessages } from '#src/utils/fileUtils.js';
4
4
  import { buildInitConfigContent, getCuratedFallbackModel } from '#src/providers/modelDiscovery.js';
5
5
  /**
6
- * Default Ollama daemon host, matching the Ollama CLI/library default. The
7
- * OpenAI-compatible surface lives under `/v1` on this host. Kept in sync with
8
- * `DEFAULT_OLLAMA_HOST` in `modelDiscovery.ts`.
6
+ * Default Ollama daemon host, matching the Ollama CLI/library default. GS2-59 — `ChatOllama` talks
7
+ * to the daemon's NATIVE endpoint (`/api/chat`), NOT the OpenAI-compatible `/v1` shim this provider
8
+ * used before. The same root host is reused by `modelDiscovery.ts`'s model picker, which still
9
+ * queries the `/v1/models` surface (discovery only); both derive from this root — they stay in sync
10
+ * at the host level even though the two use different endpoints under it.
9
11
  */
10
12
  const DEFAULT_OLLAMA_HOST = 'http://127.0.0.1:11434';
11
13
  /**
12
- * Ollama serves an unauthenticated local daemon, but `ChatOpenAI` requires a
13
- * non-empty `apiKey` string. Send a harmless placeholder so the client builds;
14
- * the local daemon ignores it.
14
+ * GS2-59 — default context window (`num_ctx`) for Ollama models. Ollama's OWN default is 4096, but
15
+ * gaunt-sloth's agentic prompt (system + full lean toolset + a tool result) already lands ~4000
16
+ * tokens; at 4096 a thinking model (e.g. gemma4:31b) spends its entire remaining budget on the
17
+ * reasoning field and emits EMPTY `content` on the turn after a tool executes — the GS2-59
18
+ * blank-answer regression. The previous `ChatOpenAI`→`/v1` path could not fix this because the
19
+ * OpenAI-compat shim IGNORES `num_ctx`; the native `/api/chat` path honors it.
20
+ *
21
+ * 16384 is chosen as the largest window that is BOTH safely above the ~4000-token starvation point
22
+ * (4× headroom for reasoning + a few tool results) AND fits constrained consumer VRAM: Ollama
23
+ * preallocates the KV cache at `num_ctx`, so on a box where a large model already spills partly to
24
+ * CPU (e.g. a 19GB model on ~18GB of GPU), a 32768 cache tips the GPU allocation into an
25
+ * out-of-memory error. 16384 was verified live to run the agentic tool→synthesis turn on such a
26
+ * box; 32768 OOM'd it. Overridable per config via `llm.numCtx` — raise it if you have the VRAM and
27
+ * run long sessions, lower it on very tight hardware. NOTE: a per-request `num_ctx` overrides the
28
+ * daemon's `OLLAMA_CONTEXT_LENGTH`, so a user who tuned their server window higher should set
29
+ * `llm.numCtx` to match rather than rely on the server default.
15
30
  */
16
- const OLLAMA_PLACEHOLDER_API_KEY = 'ollama';
31
+ const DEFAULT_OLLAMA_NUM_CTX = 16384;
17
32
  /**
18
- * Resolve the OpenAI-compatible base URL for the local Ollama daemon.
19
- *
20
- * Honors the `OLLAMA_HOST` env override (the same variable the Ollama CLI uses).
21
- * `OLLAMA_HOST` is typically a full URL (`http://127.0.0.1:11434`) or a bare
22
- * `host:port`; either form is normalized to a `http(s)://host[:port]/v1` base.
33
+ * Resolve the base URL for the local Ollama daemon — the NATIVE root (no `/v1` suffix; `ChatOllama`
34
+ * appends its own `/api/chat` path). Honors the `OLLAMA_HOST` env override (the same variable the
35
+ * Ollama CLI uses): a full URL (`http://127.0.0.1:11434`) or a bare `host:port` is normalized to
36
+ * `http(s)://host[:port]` with any trailing slash stripped.
23
37
  */
24
38
  function resolveBaseUrl() {
25
39
  const host = env.OLLAMA_HOST;
26
- let base;
27
- if (!host) {
28
- base = DEFAULT_OLLAMA_HOST;
29
- }
30
- else if (/^https?:\/\//.test(host)) {
31
- base = host.replace(/\/+$/, '');
32
- }
33
- else {
34
- base = `http://${host}`.replace(/\/+$/, '');
35
- }
36
- return `${base}/v1`;
40
+ if (!host)
41
+ return DEFAULT_OLLAMA_HOST;
42
+ const base = /^https?:\/\//.test(host) ? host : `http://${host}`;
43
+ return base.replace(/\/+$/, '');
37
44
  }
38
- // Function to process JSON config and create an Ollama (OpenAI-compatible) LLM instance
45
+ /**
46
+ * GS2-59 — build a native `ChatOllama` client (`@langchain/ollama`, talking to Ollama's
47
+ * `/api/chat`). This replaces the previous `ChatOpenAI`→`/v1` client, which had two fatal
48
+ * properties for local thinking models: it DROPPED the model's separate reasoning field (the
49
+ * completions converter discards it — `__includeRawResponse` is openrouter-only), and it IGNORED
50
+ * `num_ctx` so a large agentic prompt starved the answer to empty content. `ChatOllama` fixes both:
51
+ * it honors `numCtx`, and it surfaces the model's thinking in `additional_kwargs.reasoning_content`
52
+ * — the exact field the reasoning pipeline (`pickReasoningDelta`) already reads — so the `/reasoning`
53
+ * panel populates with no downstream change.
54
+ *
55
+ * Ollama is a local, unauthenticated daemon, so the old OpenAI-client knobs are gone (2.0 migration
56
+ * note): point elsewhere with `OLLAMA_HOST`; the previous `configuration.baseURL` / placeholder
57
+ * `apiKey` fields no longer apply. If a reverse proxy in front of Ollama needs auth, set `headers`
58
+ * in the config (passed straight through to `ChatOllama`).
59
+ */
39
60
  // noinspection JSUnusedGlobalSymbols
40
61
  export async function processJsonConfig(llmConfig) {
41
- const { ChatOpenAI } = await import('@langchain/openai');
42
- // Ollama is local and unauthenticated; ChatOpenAI still needs a non-empty key.
43
- const apiKey = llmConfig.apiKey || OLLAMA_PLACEHOLDER_API_KEY;
62
+ const { ChatOllama } = await import('@langchain/ollama');
44
63
  const configFields = {
45
64
  ...llmConfig,
46
- apiKey,
47
65
  model: llmConfig.model || getCuratedFallbackModel('ollama'),
48
- configuration: {
49
- baseURL: resolveBaseUrl(),
50
- ...(llmConfig.configuration || {}),
51
- },
66
+ // Precedence: an explicit config `baseUrl` (the native ChatOllama field) wins, else the
67
+ // `OLLAMA_HOST` env, else the local default. Config is the more specific/intentional signal.
68
+ baseUrl: llmConfig.baseUrl ?? resolveBaseUrl(),
69
+ numCtx: llmConfig.numCtx ?? DEFAULT_OLLAMA_NUM_CTX,
52
70
  };
53
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
54
- delete configFields.type;
55
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
56
- delete configFields.apiKeyEnvironmentVariable;
57
- return new ChatOpenAI(configFields);
71
+ // Strip OpenAI-client / gaunt-sloth-internal keys ChatOllama neither needs nor understands.
72
+ for (const key of ['type', 'apiKeyEnvironmentVariable', 'apiKey', 'configuration']) {
73
+ delete configFields[key];
74
+ }
75
+ return new ChatOllama(configFields);
58
76
  }
59
77
  export function init(configFileName, force = false, model) {
60
78
  // Determine which content to use based on file extension
@@ -1 +1 @@
1
- {"version":3,"file":"ollama.js","sourceRoot":"","sources":["../../src/providers/ollama.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;;;;GAIG;AACH,MAAM,mBAAmB,GAAG,wBAAwB,CAAC;AAErD;;;;GAIG;AACH,MAAM,0BAA0B,GAAG,QAAQ,CAAC;AAE5C;;;;;;GAMG;AACH,SAAS,cAAc;IACrB,MAAM,IAAI,GAAG,GAAG,CAAC,WAAW,CAAC;IAC7B,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,IAAI,GAAG,mBAAmB,CAAC;IAC7B,CAAC;SAAM,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACrC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAClC,CAAC;SAAM,CAAC;QACN,IAAI,GAAG,UAAU,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC9C,CAAC;IACD,OAAO,GAAG,IAAI,KAAK,CAAC;AACtB,CAAC;AAED,wFAAwF;AACxF,qCAAqC;AACrC,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,SAAmE;IAEnE,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAC;IACzD,+EAA+E;IAC/E,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,IAAI,0BAA0B,CAAC;IAC9D,MAAM,YAAY,GAAG;QACnB,GAAG,SAAS;QACZ,MAAM;QACN,KAAK,EAAE,SAAS,CAAC,KAAK,IAAI,uBAAuB,CAAC,QAAQ,CAAC;QAC3D,aAAa,EAAE;YACb,OAAO,EAAE,cAAc,EAAE;YACzB,GAAG,CAAC,SAAS,CAAC,aAAa,IAAI,EAAE,CAAC;SACnC;KACF,CAAC;IACF,8DAA8D;IAC9D,OAAQ,YAAoB,CAAC,IAAI,CAAC;IAClC,8DAA8D;IAC9D,OAAQ,YAAoB,CAAC,yBAAyB,CAAC;IAEvD,OAAO,IAAI,UAAU,CAAC,YAAY,CAAC,CAAC;AACtC,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,QAAQ,EAAE,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC;IAC5F,cAAc,CACZ,yBAAyB,cAAc,2BAA2B;QAChE,2EAA2E;QAC3E,+CAA+C,CAClD,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"ollama.js","sourceRoot":"","sources":["../../src/providers/ollama.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;;;;;;GAMG;AACH,MAAM,mBAAmB,GAAG,wBAAwB,CAAC;AAErD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,sBAAsB,GAAG,KAAK,CAAC;AAErC;;;;;GAKG;AACH,SAAS,cAAc;IACrB,MAAM,IAAI,GAAG,GAAG,CAAC,WAAW,CAAC;IAC7B,IAAI,CAAC,IAAI;QAAE,OAAO,mBAAmB,CAAC;IACtC,MAAM,IAAI,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,IAAI,EAAE,CAAC;IACjE,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAClC,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,qCAAqC;AACrC,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,SAAgD;IAEhD,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAC;IACzD,MAAM,YAAY,GAA4B;QAC5C,GAAG,SAAS;QACZ,KAAK,EAAE,SAAS,CAAC,KAAK,IAAI,uBAAuB,CAAC,QAAQ,CAAC;QAC3D,wFAAwF;QACxF,6FAA6F;QAC7F,OAAO,EAAE,SAAS,CAAC,OAAO,IAAI,cAAc,EAAE;QAC9C,MAAM,EAAE,SAAS,CAAC,MAAM,IAAI,sBAAsB;KACnD,CAAC;IACF,4FAA4F;IAC5F,KAAK,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,2BAA2B,EAAE,QAAQ,EAAE,eAAe,CAAC,EAAE,CAAC;QACnF,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IACD,OAAO,IAAI,UAAU,CAAC,YAA+B,CAAC,CAAC;AACzD,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,QAAQ,EAAE,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC;IAC5F,cAAc,CACZ,yBAAyB,cAAc,2BAA2B;QAChE,2EAA2E;QAC3E,+CAA+C,CAClD,CAAC;AACJ,CAAC"}
@@ -15,6 +15,11 @@ export async function processJsonConfig(llmConfig) {
15
15
  ...llmConfig,
16
16
  apiKey: openRouterApiKey,
17
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,
18
23
  configuration: {
19
24
  baseURL: 'https://openrouter.ai/api/v1',
20
25
  ...(llmConfig.configuration || {}),
@@ -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,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,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
+ {"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"}
@@ -13,6 +13,7 @@
13
13
  import { displayWarning } from '#src/utils/consoleUtils.js';
14
14
  import { writeConfigFileWithMessages } from '#src/utils/fileUtils.js';
15
15
  import { buildInitConfigContent, getCuratedFallbackModel } from '#src/providers/modelDiscovery.js';
16
+ import { applyGeminiToolSchemaSanitizer } from '#src/providers/geminiSchemaSanitizer.js';
16
17
  export function init(configFileName, force = false, model) {
17
18
  // Determine which content to use based on file extension
18
19
  if (!configFileName.endsWith('.json')) {
@@ -31,6 +32,8 @@ export async function processJsonConfig(llmConfig) {
31
32
  };
32
33
  delete configFields.type;
33
34
  delete configFields.apiKeyEnvironmentVariable;
34
- return new ChatGoogle(configFields);
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));
35
38
  }
36
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,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAEnG,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,OAAO,IAAI,UAAU,CAAC,YAAY,CAAC,CAAC;AACtC,CAAC"}
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"}
@@ -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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"}
@@ -21,7 +21,8 @@ export interface SingleShotResult extends GthRunStats {
21
21
  * is forwarded to the agent so it can pick the right mode prompt (e.g. exec-mode for `exec`).
22
22
  *
23
23
  * @param source - The source of the question (used for file naming)
24
- * @param preamble - The preamble to send to the LLM
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.
25
26
  * @param content - The content of the question
26
27
  * @param config - The resolved config
27
28
  * @param resolvers - Optional agent resolvers (tools/middleware)
@@ -34,4 +35,4 @@ export interface SingleShotResult extends GthRunStats {
34
35
  * `tokensOutput`/`tools` carry the SUT's answer text and run stats for callers that need them
35
36
  * (e.g. `gth batch`/`gth eval`).
36
37
  */
37
- export declare function runSingleShot(source: string, preamble: string, content: string, config: GthConfig, resolvers?: AgentResolvers, command?: GthCommand, agentFactory?: GthAgentFactory): Promise<SingleShotResult>;
38
+ export declare function runSingleShot(source: string, _preamble: string, content: string, config: GthConfig, resolvers?: AgentResolvers, command?: GthCommand, agentFactory?: GthAgentFactory): Promise<SingleShotResult>;
@@ -2,7 +2,7 @@ import { defaultStatusCallback, display, displayError, displaySuccess, flushSess
2
2
  import { getCommandOutputFilePath } from '#src/utils/fileUtils.js';
3
3
  import { GthAgentRunner } from '#src/core/GthAgentRunner.js';
4
4
  import { MemorySaver } from '@langchain/langgraph';
5
- import { HumanMessage, SystemMessage } from '@langchain/core/messages';
5
+ import { HumanMessage } from '@langchain/core/messages';
6
6
  import { ProgressIndicator } from '#src/utils/ProgressIndicator.js';
7
7
  import { recordSessionSafe } from '#src/history/recordSession.js';
8
8
  import { getProjectDir } from '#src/utils/systemUtils.js';
@@ -14,7 +14,8 @@ import { getProjectDir } from '#src/utils/systemUtils.js';
14
14
  * is forwarded to the agent so it can pick the right mode prompt (e.g. exec-mode for `exec`).
15
15
  *
16
16
  * @param source - The source of the question (used for file naming)
17
- * @param preamble - The preamble to send to the LLM
17
+ * @param _preamble - Deprecated/ignored (BATCH-13): the agent composes the system prompt itself;
18
+ * see the body comment. Retained positionally so existing callers need no change.
18
19
  * @param content - The content of the question
19
20
  * @param config - The resolved config
20
21
  * @param resolvers - Optional agent resolvers (tools/middleware)
@@ -27,9 +28,20 @@ import { getProjectDir } from '#src/utils/systemUtils.js';
27
28
  * `tokensOutput`/`tools` carry the SUT's answer text and run stats for callers that need them
28
29
  * (e.g. `gth batch`/`gth eval`).
29
30
  */
30
- export async function runSingleShot(source, preamble, content, config, resolvers, command = 'ask', agentFactory) {
31
+ export async function runSingleShot(source,
32
+ // BATCH-13: `_preamble` is retained for signature stability but is NO LONGER injected as a
33
+ // SystemMessage. The agent backends (lean `GthLangChainAgent` since GS2-21, and `GthDeepAgent`)
34
+ // each COMPOSE the full system prompt themselves from the same config — backstory + guidelines +
35
+ // per-command mode prompt + system prompt, PLUS the model-identity (GS2-34) and MCP-instructions
36
+ // (EXT-32) notes — and hand it to `createAgent` as `systemPrompt`. Also passing this preamble as a
37
+ // leading SystemMessage produced TWO system messages, which `@langchain/anthropic` rejects
38
+ // ("System messages are only permitted as the first passed message"), breaking EVERY single-shot
39
+ // run (ask/exec/batch/eval) on Anthropic on BOTH backends (Google/OpenAI silently merged them).
40
+ // The agent's composed prompt is a superset of this preamble, so dropping it is content-preserving.
41
+ _preamble, content, config, resolvers, command = 'ask', agentFactory) {
31
42
  const progressIndicator = config.streamOutput ? undefined : new ProgressIndicator('Thinking.');
32
- const messages = [new SystemMessage(preamble), new HumanMessage(content)];
43
+ // Only the human turn: the agent supplies the system prompt via `createAgent({ systemPrompt })`.
44
+ const messages = [new HumanMessage(content)];
33
45
  // Resolve output path and initialize session logging if enabled
34
46
  const filePath = getCommandOutputFilePath(config, source);
35
47
  if (filePath) {
@@ -1 +1 @@
1
- {"version":3,"file":"singleShot.js","sourceRoot":"","sources":["../../src/runtime/singleShot.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"singleShot.js","sourceRoot":"","sources":["../../src/runtime/singleShot.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,11 @@
1
1
  /**
2
- * GS2-46 — `/debug-dump`: a live-session diagnostic archive, written UNSANITIZED (that's GS2-47's
3
- * job on top of this). The user typed the command themselves, mid-session, knowingly, so the
4
- * caller (the slash command) is responsible for the loud "may contain secrets" warning this
5
- * module only writes the files.
2
+ * GS2-46/GS2-47 — `/debug-dump`: a live-session diagnostic archive. GS2-46 shipped it raw; GS2-47
3
+ * adds a shared secret-redaction pass ({@link file://./redactSecrets.ts}) that is ON BY DEFAULT and
4
+ * applied to EVERY artifact before it hits disk. The caller opts out via `redact: false`, in which
5
+ * case the archive is raw and the caller surfaces the loud "may contain secrets" warning; when
6
+ * redaction is on the caller shows a softened "secrets redacted; review before sharing" note.
6
7
  */
7
- /** Input to {@link writeDebugDump}. `transcript`/`config` are dumped as-is (raw, unsanitized). */
8
+ /** Input to {@link writeDebugDump}. */
8
9
  export interface WriteDebugDumpInput {
9
10
  /** The full transcript (all turns, tool calls + results). Opaque — serialized as JSON. */
10
11
  transcript: unknown;
@@ -12,6 +13,13 @@ export interface WriteDebugDumpInput {
12
13
  config: unknown;
13
14
  /** Model display name, already resolved by the caller. */
14
15
  modelDisplayName?: string;
16
+ /**
17
+ * GS2-47 — apply the shared secret-redaction pass to every artifact before writing. Defaults to
18
+ * ON: omitted or any value other than the literal `false` redacts (read-site `!== false`, matching
19
+ * the config default so an opt-out has to be explicit). `false` writes a RAW archive (the caller
20
+ * is then responsible for the loud "may contain secrets" warning).
21
+ */
22
+ redact?: boolean;
15
23
  /**
16
24
  * Working directory for git-state collection. Defaults to `process.cwd()`; overridable for
17
25
  * tests so the "not a git repo" / "inside a git repo" paths are both exercisable without
@@ -23,13 +31,27 @@ export interface WriteDebugDumpResult {
23
31
  /** The absolute path to the archive directory just written. */
24
32
  archiveDir: string;
25
33
  }
34
+ /**
35
+ * The filesystem-safe directory-name segment for one dump: the ISO timestamp with `:` and `.`
36
+ * (illegal on Windows, noisy everywhere) replaced by `-`. This is the ONLY path component
37
+ * debugDump generates — and the only one it is responsible for sanitizing. The parent it is joined
38
+ * under (the global `~/.gsloth` dir) is supplied by the environment and may legitimately carry a
39
+ * drive-letter colon on Windows (`C:\…`), which is not ours to strip. Exported so the invariant
40
+ * "the generated segment is colon-free" is testable on any platform without asserting anything
41
+ * about the (platform-dependent) parent path (GS2-50).
42
+ */
43
+ export declare function debugDumpDirName(date?: Date): string;
26
44
  /**
27
45
  * Write one timestamped `/debug-dump` archive under the GLOBAL `~/.gsloth/debug-dumps/<timestamp>/`
28
46
  * (via `ensureGlobalGslothDir()` — mirrors how `resolveHistoryDbPath()` builds its path under the
29
47
  * same dir — NOT the per-project cwd-relative helper of the same name elsewhere in this codebase).
30
48
  * Contains: the full transcript, the resolved config, env/version info, the in-memory debugLog
31
- * ring buffer, and (best-effort) git repo state. Everything is dumped raw/unsanitized — this node
32
- * ships deliberately unsanitized (GS2-47 adds redaction on top later); the caller is responsible
33
- * for surfacing the "may contain secrets" warning to the user.
49
+ * ring buffer, and (best-effort) git repo state.
50
+ *
51
+ * GS2-47 unless `input.redact === false`, the shared secret-redaction pass
52
+ * ({@link file://./redactSecrets.ts}) is applied to EVERY artifact before it is written: the literal
53
+ * values of secret-named env vars + inline config secrets are substituted everywhere, a tight set of
54
+ * provider-key/auth-header patterns is masked, and the config's sensitive fields are masked in place.
55
+ * On opt-out the archive is raw and the caller surfaces the loud "may contain secrets" warning.
34
56
  */
35
57
  export declare function writeDebugDump(input: WriteDebugDumpInput): WriteDebugDumpResult;