@gaunt-sloth/agent 2.0.0-alpha.9 → 2.0.0-beta.1

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 (124) hide show
  1. package/README.md +73 -23
  2. package/cli-acp.js +21 -24
  3. package/dist/builtInToolsConfig.d.ts +17 -3
  4. package/dist/builtInToolsConfig.js +43 -41
  5. package/dist/builtInToolsConfig.js.map +1 -1
  6. package/dist/core/debugCapture.d.ts +7 -49
  7. package/dist/core/debugCapture.js +1 -1
  8. package/dist/core/debugCapture.js.map +1 -1
  9. package/dist/core/resolveAgentFactory.d.ts +10 -9
  10. package/dist/core/resolveAgentFactory.js +11 -12
  11. package/dist/core/resolveAgentFactory.js.map +1 -1
  12. package/dist/index.d.ts +4 -4
  13. package/dist/index.js +7 -5
  14. package/dist/index.js.map +1 -1
  15. package/dist/mcp/OAuthClientProviderImpl.js.map +1 -1
  16. package/dist/mcp/tlsTrust.d.ts +61 -0
  17. package/dist/mcp/tlsTrust.js +109 -0
  18. package/dist/mcp/tlsTrust.js.map +1 -0
  19. package/dist/middleware/binaryContentInjectionMiddleware.d.ts +8 -1
  20. package/dist/middleware/binaryContentInjectionMiddleware.js +11 -2
  21. package/dist/middleware/binaryContentInjectionMiddleware.js.map +1 -1
  22. package/dist/middleware/frontendImageInjectionMiddleware.d.ts +107 -0
  23. package/dist/middleware/frontendImageInjectionMiddleware.js +167 -0
  24. package/dist/middleware/frontendImageInjectionMiddleware.js.map +1 -0
  25. package/dist/middleware/registry.js +49 -1
  26. package/dist/middleware/registry.js.map +1 -1
  27. package/dist/middleware/types.d.ts +16 -2
  28. package/dist/modules/a2a/A2AClientWrapper.d.ts +56 -1
  29. package/dist/modules/a2a/A2AClientWrapper.js +131 -31
  30. package/dist/modules/a2a/A2AClientWrapper.js.map +1 -1
  31. package/dist/modules/acp/acpAgentApp.d.ts +57 -0
  32. package/dist/modules/acp/acpAgentApp.js +378 -0
  33. package/dist/modules/acp/acpAgentApp.js.map +1 -0
  34. package/dist/modules/acp/acpAgentAppV1.d.ts +52 -0
  35. package/dist/modules/acp/acpAgentAppV1.js +307 -0
  36. package/dist/modules/acp/acpAgentAppV1.js.map +1 -0
  37. package/dist/modules/acp/acpCommon.d.ts +167 -0
  38. package/dist/modules/acp/acpCommon.js +282 -0
  39. package/dist/modules/acp/acpCommon.js.map +1 -0
  40. package/dist/modules/acp/acpPermissions.d.ts +65 -0
  41. package/dist/modules/acp/acpPermissions.js +162 -0
  42. package/dist/modules/acp/acpPermissions.js.map +1 -0
  43. package/dist/modules/acp/acpPermissionsV1.d.ts +45 -0
  44. package/dist/modules/acp/acpPermissionsV1.js +110 -0
  45. package/dist/modules/acp/acpPermissionsV1.js.map +1 -0
  46. package/dist/modules/acp/acpRouter.d.ts +41 -0
  47. package/dist/modules/acp/acpRouter.js +48 -0
  48. package/dist/modules/acp/acpRouter.js.map +1 -0
  49. package/dist/modules/acp/acpStdio.d.ts +47 -0
  50. package/dist/modules/acp/acpStdio.js +71 -0
  51. package/dist/modules/acp/acpStdio.js.map +1 -0
  52. package/dist/modules/acp/acpToolCalls.d.ts +93 -0
  53. package/dist/modules/acp/acpToolCalls.js +193 -0
  54. package/dist/modules/acp/acpToolCalls.js.map +1 -0
  55. package/dist/modules/acp/acpUpdates.d.ts +48 -0
  56. package/dist/modules/acp/acpUpdates.js +142 -0
  57. package/dist/modules/acp/acpUpdates.js.map +1 -0
  58. package/dist/modules/acp/acpUpdatesV1.d.ts +61 -0
  59. package/dist/modules/acp/acpUpdatesV1.js +162 -0
  60. package/dist/modules/acp/acpUpdatesV1.js.map +1 -0
  61. package/dist/modules/apiAgUiModule.d.ts +87 -0
  62. package/dist/modules/apiAgUiModule.js +193 -28
  63. package/dist/modules/apiAgUiModule.js.map +1 -1
  64. package/dist/modules/interactiveSessionModule.js +497 -51
  65. package/dist/modules/interactiveSessionModule.js.map +1 -1
  66. package/dist/modules/slashCommands.d.ts +582 -0
  67. package/dist/modules/slashCommands.js +1001 -0
  68. package/dist/modules/slashCommands.js.map +1 -0
  69. package/dist/resolvers.js +119 -9
  70. package/dist/resolvers.js.map +1 -1
  71. package/dist/tools/GthCustomToolkit.js +95 -11
  72. package/dist/tools/GthCustomToolkit.js.map +1 -1
  73. package/dist/tools/GthDevToolkit.d.ts +8 -5
  74. package/dist/tools/GthDevToolkit.js +89 -43
  75. package/dist/tools/GthDevToolkit.js.map +1 -1
  76. package/dist/tools/GthFileSystemToolkit.d.ts +63 -0
  77. package/dist/tools/GthFileSystemToolkit.js +506 -105
  78. package/dist/tools/GthFileSystemToolkit.js.map +1 -1
  79. package/dist/tools/McpResourceTool.d.ts +31 -0
  80. package/dist/tools/McpResourceTool.js +106 -0
  81. package/dist/tools/McpResourceTool.js.map +1 -0
  82. package/dist/tools/gthChecklistTool.d.ts +30 -0
  83. package/dist/tools/gthChecklistTool.js +80 -0
  84. package/dist/tools/gthChecklistTool.js.map +1 -0
  85. package/dist/tools/gthGrepTool.d.ts +54 -0
  86. package/dist/tools/gthGrepTool.js +482 -0
  87. package/dist/tools/gthGrepTool.js.map +1 -0
  88. package/dist/tools/shell/env.js +1 -1
  89. package/dist/tools/shell/env.js.map +1 -1
  90. package/dist/tools/shell/outputBuffer.js.map +1 -1
  91. package/dist/tools/shell/workDir.d.ts +1 -10
  92. package/dist/tools/shell/workDir.js +10 -36
  93. package/dist/tools/shell/workDir.js.map +1 -1
  94. package/dist/utils/mcpAuthError.d.ts +36 -0
  95. package/dist/utils/mcpAuthError.js +89 -0
  96. package/dist/utils/mcpAuthError.js.map +1 -0
  97. package/package.json +13 -13
  98. package/dist/core/GthDeepAgent.d.ts +0 -181
  99. package/dist/core/GthDeepAgent.js +0 -682
  100. package/dist/core/GthDeepAgent.js.map +0 -1
  101. package/dist/core/deepAgentPermissions.d.ts +0 -115
  102. package/dist/core/deepAgentPermissions.js +0 -282
  103. package/dist/core/deepAgentPermissions.js.map +0 -1
  104. package/dist/core/gthAcpServer.d.ts +0 -27
  105. package/dist/core/gthAcpServer.js +0 -82
  106. package/dist/core/gthAcpServer.js.map +0 -1
  107. package/dist/core/gthDeepAgentFactory.d.ts +0 -8
  108. package/dist/core/gthDeepAgentFactory.js +0 -9
  109. package/dist/core/gthDeepAgentFactory.js.map +0 -1
  110. package/dist/modules/acpModule.d.ts +0 -40
  111. package/dist/modules/acpModule.js +0 -78
  112. package/dist/modules/acpModule.js.map +0 -1
  113. package/dist/tools/shell/allowlist.d.ts +0 -11
  114. package/dist/tools/shell/allowlist.js +0 -12
  115. package/dist/tools/shell/allowlist.js.map +0 -1
  116. package/dist/tools/shell/arity.d.ts +0 -11
  117. package/dist/tools/shell/arity.js +0 -12
  118. package/dist/tools/shell/arity.js.map +0 -1
  119. package/dist/tools/shell/hardline.d.ts +0 -15
  120. package/dist/tools/shell/hardline.js +0 -88
  121. package/dist/tools/shell/hardline.js.map +0 -1
  122. package/dist/tools/shell/normalize.d.ts +0 -10
  123. package/dist/tools/shell/normalize.js +0 -11
  124. package/dist/tools/shell/normalize.js.map +0 -1
@@ -0,0 +1,36 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * EXT-31 — classify and format MCP integration connect/tool-load failures so an expired or invalid
4
+ * credential is SURFACED (named + actionable) instead of silently dropping the integration's tools.
5
+ *
6
+ * The `@langchain/mcp-adapters` client only tags a bare HTTP 401 as an authentication error; a 403
7
+ * (forbidden / expired scope) otherwise falls through as a generic "Failed to connect". This module
8
+ * classifies auth failures independently (401/403 + credential keywords) so a stale token is not
9
+ * mistaken for "this integration was never configured" or an unrelated transient error.
10
+ *
11
+ * Pure + side-effect free: callers do the surfacing (`displayWarning`) with the returned message.
12
+ */
13
+ /** Coarse classification of an MCP connect/tool-load failure. */
14
+ export type McpConnectErrorKind = 'auth' | 'other';
15
+ /** Options that tune the suggested fix path in the surfaced message. */
16
+ export interface McpConnectFailureOptions {
17
+ /** The server uses OAuth (`authProvider: 'OAuth'`) — suggest re-running the OAuth login. */
18
+ oauth?: boolean;
19
+ }
20
+ /**
21
+ * Classify an MCP connect/tool-load failure as a credential problem (`auth`) or anything else
22
+ * (`other`). Detection is independent of the adapter (which only tags 401), so a 403 or an
23
+ * "expired token" surfaced by the upstream server is still recognised as auth.
24
+ */
25
+ export declare function classifyMcpConnectError(error: unknown): McpConnectErrorKind;
26
+ /**
27
+ * Build the user-facing message for a failed MCP integration. For `auth` failures it names the
28
+ * integration, states the credential is expired/invalid, and points at the concrete fix path
29
+ * (OAuth login or the API token / authorization header, plus the `mcpServers` entry in gth config).
30
+ * For `other` failures it surfaces the failure plainly and explicitly says it is NOT an auth error,
31
+ * so an unrelated transient never triggers a spurious "re-authenticate" nudge.
32
+ *
33
+ * Either way the caller degrades gracefully AFTER surfacing this — the integration's tools are
34
+ * dropped for the session, but the user (and the log) now knows why.
35
+ */
36
+ export declare function formatMcpConnectFailureMessage(serverName: string | undefined, error: unknown, options?: McpConnectFailureOptions): string;
@@ -0,0 +1,89 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * EXT-31 — classify and format MCP integration connect/tool-load failures so an expired or invalid
4
+ * credential is SURFACED (named + actionable) instead of silently dropping the integration's tools.
5
+ *
6
+ * The `@langchain/mcp-adapters` client only tags a bare HTTP 401 as an authentication error; a 403
7
+ * (forbidden / expired scope) otherwise falls through as a generic "Failed to connect". This module
8
+ * classifies auth failures independently (401/403 + credential keywords) so a stale token is not
9
+ * mistaken for "this integration was never configured" or an unrelated transient error.
10
+ *
11
+ * Pure + side-effect free: callers do the surfacing (`displayWarning`) with the returned message.
12
+ */
13
+ /** Extract a readable message from an unknown thrown value. */
14
+ function errorMessage(error) {
15
+ if (error instanceof Error)
16
+ return error.message;
17
+ if (typeof error === 'string')
18
+ return error;
19
+ try {
20
+ return String(error?.message ?? error);
21
+ }
22
+ catch {
23
+ return String(error);
24
+ }
25
+ }
26
+ /** Read a numeric HTTP status from an error object or a `(HTTP NNN)` / `HTTP NNN` / `status NNN` message. */
27
+ function httpStatusOf(error, message) {
28
+ const code = error?.code;
29
+ if (typeof code === 'number')
30
+ return code;
31
+ if (typeof code === 'string' && /^\d{3}$/.test(code))
32
+ return parseInt(code, 10);
33
+ // Only treat 4xx/5xx numbers as a status when they carry HTTP/status context — never a bare "401"
34
+ // substring (which could be a port, a byte count, an id, …) to avoid misclassifying transient errors.
35
+ const m = message.match(/\b(?:HTTP|status(?:\s*code)?)[\s:]*\(?(\d{3})\)?/i);
36
+ return m ? parseInt(m[1], 10) : undefined;
37
+ }
38
+ // Credential-failure phrasing across MCP adapter wrapping, transports, and common upstream servers.
39
+ // Includes the canonical OAuth error codes (`invalid_grant` = expired/revoked refresh token,
40
+ // `invalid_token`, `unauthorized_client`) and generic `oauth …` credential phrasing, so a keyword-
41
+ // bearing OAuth failure is classified as auth even when it does NOT arrive via the OAuth catch site.
42
+ const AUTH_KEYWORDS = /\b(unauthorized|forbidden|authentication failed|authenti[sc]ation (?:error|required)|authorization (?:error|failed|required)|invalid (?:token|credentials?|api[\s-]?key|authorization)|invalid_grant|invalid_token|unauthorized_client|oauth[\s_-]?(?:error|failed|failure|denied|token|authorization|handshake|login)|(?:token|credentials?|session|api[\s-]?key)s? (?:has |have )?(?:expired|is expired|are expired)|expired (?:token|credentials?|session)|access denied|401 unauthorized|403 forbidden)\b/i;
43
+ /**
44
+ * Classify an MCP connect/tool-load failure as a credential problem (`auth`) or anything else
45
+ * (`other`). Detection is independent of the adapter (which only tags 401), so a 403 or an
46
+ * "expired token" surfaced by the upstream server is still recognised as auth.
47
+ */
48
+ export function classifyMcpConnectError(error) {
49
+ const message = errorMessage(error);
50
+ const status = httpStatusOf(error, message);
51
+ if (status === 401 || status === 403)
52
+ return 'auth';
53
+ if (AUTH_KEYWORDS.test(message))
54
+ return 'auth';
55
+ return 'other';
56
+ }
57
+ /**
58
+ * Build the user-facing message for a failed MCP integration. For `auth` failures it names the
59
+ * integration, states the credential is expired/invalid, and points at the concrete fix path
60
+ * (OAuth login or the API token / authorization header, plus the `mcpServers` entry in gth config).
61
+ * For `other` failures it surfaces the failure plainly and explicitly says it is NOT an auth error,
62
+ * so an unrelated transient never triggers a spurious "re-authenticate" nudge.
63
+ *
64
+ * Either way the caller degrades gracefully AFTER surfacing this — the integration's tools are
65
+ * dropped for the session, but the user (and the log) now knows why.
66
+ */
67
+ export function formatMcpConnectFailureMessage(serverName, error, options = {}) {
68
+ // Reaching the OAuth surfacing site means createAuthProviderAndAuthenticate() threw, i.e. the
69
+ // OAuth handshake/refresh itself failed — that is inherently an auth failure regardless of the
70
+ // message text (e.g. a keyword-less `invalid_grant`). Force `auth` here rather than inferring it
71
+ // from keywords, so an OAuth credential failure never mis-surfaces as "not an authentication error".
72
+ const kind = options.oauth ? 'auth' : classifyMcpConnectError(error);
73
+ const name = serverName ? `"${serverName}"` : 'an MCP server';
74
+ const configHint = serverName
75
+ ? `check the ${name} entry under mcpServers in your gth config`
76
+ : 'check the mcpServers entries in your gth config';
77
+ if (kind === 'auth') {
78
+ const reAuth = options.oauth
79
+ ? 'complete the OAuth login flow again (clear the stored token first if needed)'
80
+ : 'refresh its API token or key (the apiKeyEnvironmentVariable or authorization header it uses)';
81
+ return (`Integration ${name} authentication failed: its credentials appear expired or invalid ` +
82
+ `(the MCP server rejected the connection with an authorization error). Its tools are ` +
83
+ `unavailable for this session. To restore them, re-authenticate this integration: ` +
84
+ `${reAuth} and ${configHint}, then restart.`);
85
+ }
86
+ return (`Integration ${name} could not connect to its MCP server (this is not an authentication ` +
87
+ `error). Its tools are unavailable for this session. Underlying error: ${errorMessage(error)}`);
88
+ }
89
+ //# sourceMappingURL=mcpAuthError.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcpAuthError.js","sourceRoot":"","sources":["../../src/utils/mcpAuthError.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAaH,+DAA+D;AAC/D,SAAS,YAAY,CAAC,KAAc;IAClC,IAAI,KAAK,YAAY,KAAK;QAAE,OAAO,KAAK,CAAC,OAAO,CAAC;IACjD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,CAAC;QACH,OAAO,MAAM,CAAE,KAA+B,EAAE,OAAO,IAAI,KAAK,CAAC,CAAC;IACpE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;AACH,CAAC;AAED,6GAA6G;AAC7G,SAAS,YAAY,CAAC,KAAc,EAAE,OAAe;IACnD,MAAM,IAAI,GAAI,KAA4B,EAAE,IAAI,CAAC;IACjD,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC1C,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAChF,kGAAkG;IAClG,sGAAsG;IACtG,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,mDAAmD,CAAC,CAAC;IAC7E,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC5C,CAAC;AAED,oGAAoG;AACpG,6FAA6F;AAC7F,mGAAmG;AACnG,qGAAqG;AACrG,MAAM,aAAa,GACjB,gfAAgf,CAAC;AAEnf;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAAc;IACpD,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IACpC,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAC5C,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,MAAM,CAAC;IACpD,IAAI,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,MAAM,CAAC;IAC/C,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,8BAA8B,CAC5C,UAA8B,EAC9B,KAAc,EACd,OAAO,GAA6B,EAAE;IAEtC,8FAA8F;IAC9F,+FAA+F;IAC/F,iGAAiG;IACjG,qGAAqG;IACrG,MAAM,IAAI,GAAwB,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,uBAAuB,CAAC,KAAK,CAAC,CAAC;IAC1F,MAAM,IAAI,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,UAAU,GAAG,CAAC,CAAC,CAAC,eAAe,CAAC;IAC9D,MAAM,UAAU,GAAG,UAAU;QAC3B,CAAC,CAAC,aAAa,IAAI,4CAA4C;QAC/D,CAAC,CAAC,iDAAiD,CAAC;IAEtD,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACpB,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK;YAC1B,CAAC,CAAC,8EAA8E;YAChF,CAAC,CAAC,8FAA8F,CAAC;QACnG,OAAO,CACL,eAAe,IAAI,oEAAoE;YACvF,sFAAsF;YACtF,mFAAmF;YACnF,GAAG,MAAM,QAAQ,UAAU,iBAAiB,CAC7C,CAAC;IACJ,CAAC;IAED,OAAO,CACL,eAAe,IAAI,sEAAsE;QACzF,yEAAyE,YAAY,CAAC,KAAK,CAAC,EAAE,CAC/F,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gaunt-sloth/agent",
3
- "version": "2.0.0-alpha.9",
4
- "description": "Deep agent runtime for Gaunt Sloth: tools, middleware, MCP/A2A clients and the AG-UI server",
3
+ "version": "2.0.0-beta.1",
4
+ "description": "Agent runtime for Gaunt Sloth: tools, middleware, MCP/A2A clients and the AG-UI server",
5
5
  "license": "MIT",
6
6
  "author": "Andrew Kondratev",
7
7
  "repository": {
@@ -38,21 +38,21 @@
38
38
  "#src/*.js": "./dist/*.js"
39
39
  },
40
40
  "dependencies": {
41
- "@a2a-js/sdk": "^0.3.13",
41
+ "@a2a-js/sdk": "^1.0.1",
42
42
  "@ag-ui/core": "^0.0.57",
43
43
  "@ag-ui/encoder": "^0.0.57",
44
- "@langchain/core": "^1.2.1",
45
- "@langchain/langgraph": "^1.4.7",
44
+ "@agentclientprotocol/sdk": "1.3.0",
45
+ "@langchain/core": "^1.2.5",
46
+ "@langchain/langgraph": "^1.4.9",
46
47
  "@langchain/mcp-adapters": "^1.1.3",
47
- "@modelcontextprotocol/sdk": "^1.29.0",
48
- "deepagents": "^1.10.5",
49
- "deepagents-acp": "^0.1.15",
48
+ "@modelcontextprotocol/sdk": "^1.30.0",
50
49
  "diff": "^9.0.0",
51
50
  "express": "^5.2.1",
52
- "langchain": "^1.5.2",
53
- "uuid": ">=11.1.1",
54
- "zod": "^4.0.0",
55
- "@gaunt-sloth/core": "2.0.0-alpha.9"
51
+ "langchain": "^1.5.5",
52
+ "undici": "^8.10.0",
53
+ "uuid": "^14.0.1",
54
+ "zod": "^4.4.3",
55
+ "@gaunt-sloth/core": "2.0.0-beta.1"
56
56
  },
57
57
  "files": [
58
58
  "./dist/*",
@@ -60,7 +60,7 @@
60
60
  "cli-acp.js"
61
61
  ],
62
62
  "publishConfig": {
63
- "tag": "alpha"
63
+ "tag": "beta"
64
64
  },
65
65
  "scripts": {
66
66
  "build": "tsc"
@@ -1,181 +0,0 @@
1
- import type { GthConfig } from '@gaunt-sloth/core/config.js';
2
- import { GthAbstractAgent } from '@gaunt-sloth/core/core/GthAbstractAgent.js';
3
- import { type GthCommand } from '@gaunt-sloth/core/core/types.js';
4
- import type { StructuredToolInterface } from '@langchain/core/tools';
5
- import type { BaseCheckpointSaver } from '@langchain/langgraph';
6
- import { type InterruptOnConfig } from 'langchain';
7
- import { type FilesystemPermission } from '#src/core/deepAgentPermissions.js';
8
- import type { DebugCapture, DebugRequestExtras } from '#src/core/debugCapture.js';
9
- /**
10
- * The subset of `createDeepAgent` params that are independent of the transport
11
- * (the local runner vs. the ACP server). Both {@link GthDeepAgent.init} (which adds the
12
- * console-bound tool-call-status middleware + a virtual {@link FilesystemBackend} +
13
- * checkpointer and calls `createDeepAgent`) and the ACP entry (deepagents-acp
14
- * `startServer`, which supplies its own ACP-proxying backend, checkpointer and tool-call
15
- * reporting) consume these.
16
- *
17
- * `middleware` here deliberately EXCLUDES the tool-call-status middleware: that one writes
18
- * to stdout, which on the ACP path is the JSON-RPC channel and must stay clean. The runner
19
- * path appends it in {@link GthDeepAgent.init}.
20
- */
21
- export interface GthDeepAgentParams {
22
- model: any;
23
- tools: StructuredToolInterface[];
24
- permissions: FilesystemPermission[];
25
- middleware: any[];
26
- /**
27
- * gsloth's composed system prompt (backstory + guidelines + per-command mode prompt +
28
- * system prompt). Passed to `createDeepAgent({ systemPrompt })`, where deepagents combines
29
- * it ADDITIVELY with its own base + filesystem prompts into ONE system message. This replaces
30
- * the previous per-turn `SystemMessage` injection by the runner/AG-UI callers — two system
31
- * messages (deepagents' own + gsloth's, not first) are rejected by Anthropic. `undefined` when
32
- * no prompt content is composed (lets deepagents use only its base prompt).
33
- */
34
- systemPrompt: string | undefined;
35
- /**
36
- * Per-tool human-in-the-loop configuration passed straight to
37
- * `createDeepAgent({ interruptOn })` (deepagents installs LangChain's
38
- * `humanInTheLoopMiddleware` for it). A matching tool call suspends the graph with a
39
- * `__interrupt__` (a `HITLRequest`) so a consumer can approve/reject before the tool runs;
40
- * resume with `new Command({ resume: { decisions: [...] } })` on the same `thread_id`.
41
- *
42
- * gsloth currently sets this only for the opt-in `run_shell_command` tool (when its
43
- * `devTools.shell` is enabled and `devTools.shellYolo` is NOT). Left `undefined` otherwise —
44
- * including under yolo — so no tool is gated and runs never suspend for approval.
45
- */
46
- interruptOn?: Record<string, boolean | InterruptOnConfig>;
47
- }
48
- /**
49
- * Deep agent: builds a `createDeepAgent` graph (deepagents). All run/stream/event
50
- * plumbing lives in {@link GthAbstractAgent}; this class only knows how to construct
51
- * the graph in {@link init}.
52
- *
53
- * Differences from the lean {@link GthLangChainAgent}:
54
- * - deepagents provides the filesystem tools (`read_file`/`write_file`/`edit_file`/
55
- * `ls`/`glob`/`grep`/`execute`) via its own middleware, backed by a
56
- * {@link FilesystemBackend}. gsloth's `.aiignore` + `filesystem` config are mapped
57
- * onto deepagents `permissions` (see {@link buildPermissions}). Any resolved tool
58
- * that reuses a deepagents filesystem-tool name is therefore superseded and dropped
59
- * (`createDeepAgent` would otherwise throw on the collision). EXT-14: the
60
- * `FilesystemBackend` itself is wrapped with {@link guardFilesystemBackend} before it
61
- * reaches `createDeepAgent`, adding a realpath (symlink-resolved) containment check the
62
- * permission globs alone can't provide.
63
- * - todos / subagents / summarization come from deepagents' standard middleware.
64
- *
65
- * The transport-agnostic param assembly lives in {@link buildDeepAgentParams} so the ACP
66
- * entry (`deepagents-acp`) can reuse the exact same tool resolution, permission mapping and
67
- * middleware hardening without re-running `createDeepAgent` locally.
68
- */
69
- export declare class GthDeepAgent extends GthAbstractAgent {
70
- /**
71
- * Opt-in debug sink for the TUI `/debug` panel. Set AFTER {@link init} via
72
- * `runner.getAgent()`; read lazily inside the `wrapModelCall` middleware so that when it
73
- * is `undefined` (the normal path) the middleware is a transparent pass-through. Never
74
- * touched by the lean agent or the AG-UI server, so those contracts are unchanged.
75
- */
76
- debugCapture: DebugCapture | undefined;
77
- init(command: GthCommand | undefined, configIn: GthConfig, checkpointer?: BaseCheckpointSaver | undefined): Promise<void>;
78
- /**
79
- * Assemble the transport-agnostic {@link GthDeepAgentParams}: resolve tools (with the
80
- * filesystem disabled so deepagents owns fs access), apply the allowedTools allow-list and
81
- * the deepagents fs-name supersession safety-net, map `.aiignore` + filesystem mode onto
82
- * deepagents permissions, and build the fs-denial-softening middleware. Shared by the local
83
- * runner ({@link init}) and the `deepagents-acp` ACP entry.
84
- */
85
- buildDeepAgentParams(command: GthCommand | undefined, configIn: GthConfig): Promise<GthDeepAgentParams>;
86
- /**
87
- * Resolve the {@link GthDevToolsConfig} that applies to the active command, mirroring the
88
- * per-command selection in `builtInToolsConfig.getDefaultTools` (which is what actually emits
89
- * the dev tools): `exec` → `commands.exec.devTools`, `ask --write` → `commands.ask.devTools`,
90
- * otherwise (`code`) → `commands.code.devTools`. Returns `undefined` for any other command,
91
- * matching the toolkit being inert there. Kept private and side-effect-free so the interrupt
92
- * wiring above and the tool emission stay in lockstep.
93
- */
94
- private getEffectiveDevToolsConfig;
95
- }
96
- /**
97
- * EXT-22: shared virtualMode path-namespace guidance — ONE source of truth used by BOTH the S2
98
- * early-framing note ({@link appendVirtualCwdNote}, injected into gsloth's composed systemPrompt =
99
- * block 0) and the S1 last-word correction middleware
100
- * ({@link createPathNamespaceCorrectionMiddleware}, appended after deepagents' `/`-rooted line).
101
- *
102
- * In a virtualMode `code` session (EXT-16, e.g. Windows) the deepagents filesystem tools use a
103
- * VIRTUAL `/` root (= the working dir) while `run_shell_command` uses REAL native OS paths; the
104
- * model conflates the two forms. This text draws the distinction and steers toward cwd-relative
105
- * paths (the one form both tool families read alike).
106
- *
107
- * It deliberately does NOT equate the virtual root with a specific real path (no "`/` = D:\\work"):
108
- * virtualMode withholds the real cwd on purpose (see the systemPrompt gate in {@link
109
- * GthDeepAgent.init}), so the guidance is about the DISTINCTION between the two namespaces and the
110
- * safety of relative paths, not a mapping between them.
111
- */
112
- export declare const PATH_NAMESPACE_GUIDANCE: string;
113
- /**
114
- * EXT-22 (S2): virtualMode variant of {@link appendCwdNote}. On the `code` path when the fs
115
- * backend runs in virtualMode (EXT-16), inject the shared path-namespace guidance EARLY in
116
- * gsloth's composed systemPrompt (block 0) so the model is framed before deepagents' own prompt.
117
- *
118
- * This is early framing only: deepagents' hardcoded `/`-rooted line lands in a LATER block and can
119
- * partially override block 0, so the authoritative last word is delivered by the S1 middleware
120
- * ({@link createPathNamespaceCorrectionMiddleware}); see handoff/spike-systemmessage-ordering.md.
121
- * Returns the note alone when there is no base prompt.
122
- */
123
- export declare function appendVirtualCwdNote(systemPrompt: string | undefined): string;
124
- /**
125
- * EXT-22 (S1): the load-bearing path-namespace correction. A gsloth `wrapModelCall` middleware
126
- * runs INNERMOST (inside deepagents' filesystem middleware), so appending a trailing block to
127
- * `request.systemMessage` lands AFTER deepagents' hardcoded "All file paths must start with a /."
128
- * line — giving gsloth the last word on path semantics (empirically verified; see
129
- * handoff/spike-systemmessage-ordering.md). It APPENDS via `request.systemMessage.concat(...)`
130
- * (mirroring how deepagents appends its own fs prompt), never string-splices, and returns a NEW
131
- * request so it never mutates persisted state (no compounding across turns).
132
- *
133
- * `appendCorrection` gates it to `code` + virtualMode: only there do the fs virtual `/` root and
134
- * the shell's real-OS paths diverge. On POSIX real-path mode deepagents' "start with /" is
135
- * literally true, so the middleware is a transparent pass-through (like the debug-capture
136
- * middleware when no sink is attached).
137
- */
138
- export declare function createPathNamespaceCorrectionMiddleware(appendCorrection: boolean): import("langchain").AgentMiddleware<undefined, undefined, unknown, readonly (import("@langchain/core/tools").ClientTool | import("@langchain/core/tools").ServerTool)[], readonly []>;
139
- /**
140
- * EXT-13 (part b): append a real-cwd / path-model note to the composed code-mode system prompt.
141
- *
142
- * The default code-mode backend runs in REAL-path mode (no virtualMode), so the deepagents fs
143
- * tools and `run_shell_command` share one real-absolute-path namespace rooted at `cwd`. Neither
144
- * deepagents' base prompt nor `.gsloth.code.md` states the actual cwd, so without this the model
145
- * assumes `/` is cwd and hands `/`-rooted paths to the real-fs shell. The cwd is injected
146
- * dynamically (never baked into the .md). Returns the note alone when there is no base prompt.
147
- */
148
- export declare function appendCwdNote(systemPrompt: string | undefined, cwd: string): string;
149
- /**
150
- * EXT-26: the platform-agnostic tail shared by both {@link appendOsShellNote} branches.
151
- *
152
- * The recurring failure mode on non-POSIX hosts is not just wrong command NAMES but shell
153
- * REDIRECTION quoting: a grouped/multi-line `echo` redirect on cmd.exe reported success yet wrote
154
- * a 0-byte file. So on every platform we steer file creation/mutation to the deepagents built-in
155
- * `write_file`/`edit_file` tools (which never touch the shell's quoting) and keep each shell
156
- * command a single line. Kept short — this is prompt text an LLM reads, not documentation.
157
- */
158
- export declare const OS_SHELL_GUIDANCE: string;
159
- /**
160
- * EXT-26: append an OS + shell-dialect note to the composed code-mode system prompt.
161
- *
162
- * The deep-agent model was never told its host OS or which shell `run_shell_command` uses, so on
163
- * non-POSIX hosts it defaulted to POSIX idioms that fail (ran `ls` where cmd.exe has `dir`, a
164
- * multi-line echo-redirect that wrote 0 bytes, a PowerShell here-string, `python -c` multi-line).
165
- * This is ORTHOGONAL to the EXT-13/16/22 path-namespace notes: those say WHERE the model is (path
166
- * form); this says WHAT shell it speaks (dialect).
167
- *
168
- * The shell is derived from the SAME rule Node's `spawn(command, { shell: true })` uses — exactly
169
- * how `run_shell_command` spawns (GthDevToolkit spawn) — so on `win32` it is cmd.exe (via
170
- * `%ComSpec%`) and on POSIX it is `/bin/sh` (POSIX sh, NOT guaranteed bash). Computed from
171
- * `process.platform` at call time so the text is correct per host. Returns the note alone when
172
- * there is no base prompt. A single injection is authoritative (nothing in deepagents' base prompt
173
- * contradicts shell dialect), so unlike EXT-22 no correction middleware is needed.
174
- */
175
- export declare function appendOsShellNote(systemPrompt: string | undefined): string;
176
- /**
177
- * Assemble the non-message request parts ({@link DebugRequestExtras}) for the `/debug`
178
- * panel from a `wrapModelCall` request, defensively and key-free. Never throws (the caller
179
- * already guards, but a debug sink must never break a run) and never dumps the raw model.
180
- */
181
- export declare function extractDebugRequestExtras(request: unknown): DebugRequestExtras | undefined;