@carlonicora/nestjs-neo4jsonapi 1.110.3 → 1.112.0

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 (156) hide show
  1. package/dist/agents/graph/tools/describe-entity.tool.d.ts +1 -1
  2. package/dist/agents/graph/tools/describe-entity.tool.d.ts.map +1 -1
  3. package/dist/agents/graph/tools/describe-entity.tool.js +2 -1
  4. package/dist/agents/graph/tools/describe-entity.tool.js.map +1 -1
  5. package/dist/agents/graph/tools/read-entity.tool.d.ts +1 -1
  6. package/dist/agents/graph/tools/read-entity.tool.d.ts.map +1 -1
  7. package/dist/agents/graph/tools/read-entity.tool.js +2 -1
  8. package/dist/agents/graph/tools/read-entity.tool.js.map +1 -1
  9. package/dist/agents/graph/tools/resolve-entity.tool.d.ts +1 -1
  10. package/dist/agents/graph/tools/resolve-entity.tool.d.ts.map +1 -1
  11. package/dist/agents/graph/tools/resolve-entity.tool.js +2 -1
  12. package/dist/agents/graph/tools/resolve-entity.tool.js.map +1 -1
  13. package/dist/agents/graph/tools/search-entities.tool.d.ts +1 -1
  14. package/dist/agents/graph/tools/search-entities.tool.d.ts.map +1 -1
  15. package/dist/agents/graph/tools/search-entities.tool.js +2 -1
  16. package/dist/agents/graph/tools/search-entities.tool.js.map +1 -1
  17. package/dist/agents/graph/tools/traverse.tool.d.ts +1 -1
  18. package/dist/agents/graph/tools/traverse.tool.d.ts.map +1 -1
  19. package/dist/agents/graph/tools/traverse.tool.js +2 -1
  20. package/dist/agents/graph/tools/traverse.tool.js.map +1 -1
  21. package/dist/agents/operator/tools/search-documents.tool.d.ts +1 -1
  22. package/dist/agents/operator/tools/search-documents.tool.d.ts.map +1 -1
  23. package/dist/agents/operator/tools/search-documents.tool.js +2 -1
  24. package/dist/agents/operator/tools/search-documents.tool.js.map +1 -1
  25. package/dist/bootstrap/app.module.factory.d.ts.map +1 -1
  26. package/dist/bootstrap/app.module.factory.js +3 -0
  27. package/dist/bootstrap/app.module.factory.js.map +1 -1
  28. package/dist/bootstrap/bootstrap.options.d.ts +2 -0
  29. package/dist/bootstrap/bootstrap.options.d.ts.map +1 -1
  30. package/dist/config/base.config.d.ts.map +1 -1
  31. package/dist/config/base.config.js +15 -0
  32. package/dist/config/base.config.js.map +1 -1
  33. package/dist/config/interfaces/base.config.interface.d.ts +2 -0
  34. package/dist/config/interfaces/base.config.interface.d.ts.map +1 -1
  35. package/dist/config/interfaces/config.ai.interface.d.ts +29 -0
  36. package/dist/config/interfaces/config.ai.interface.d.ts.map +1 -1
  37. package/dist/config/interfaces/config.mcp.interface.d.ts +34 -0
  38. package/dist/config/interfaces/config.mcp.interface.d.ts.map +1 -0
  39. package/dist/config/interfaces/config.mcp.interface.js +3 -0
  40. package/dist/config/interfaces/config.mcp.interface.js.map +1 -0
  41. package/dist/config/interfaces/index.d.ts +1 -0
  42. package/dist/config/interfaces/index.d.ts.map +1 -1
  43. package/dist/config/interfaces/index.js +1 -0
  44. package/dist/config/interfaces/index.js.map +1 -1
  45. package/dist/core/llm/services/llm.service.d.ts +52 -0
  46. package/dist/core/llm/services/llm.service.d.ts.map +1 -1
  47. package/dist/core/llm/services/llm.service.js +163 -10
  48. package/dist/core/llm/services/llm.service.js.map +1 -1
  49. package/dist/core/llm/services/model.service.d.ts +2 -0
  50. package/dist/core/llm/services/model.service.d.ts.map +1 -1
  51. package/dist/core/llm/services/model.service.js +7 -0
  52. package/dist/core/llm/services/model.service.js.map +1 -1
  53. package/dist/foundations/oauth/constants/oauth.scopes.d.ts +2 -0
  54. package/dist/foundations/oauth/constants/oauth.scopes.d.ts.map +1 -1
  55. package/dist/foundations/oauth/constants/oauth.scopes.js +4 -0
  56. package/dist/foundations/oauth/constants/oauth.scopes.js.map +1 -1
  57. package/dist/foundations/oauth/controllers/index.d.ts +2 -0
  58. package/dist/foundations/oauth/controllers/index.d.ts.map +1 -1
  59. package/dist/foundations/oauth/controllers/index.js +2 -0
  60. package/dist/foundations/oauth/controllers/index.js.map +1 -1
  61. package/dist/foundations/oauth/controllers/oauth.discovery.controller.d.ts +46 -0
  62. package/dist/foundations/oauth/controllers/oauth.discovery.controller.d.ts.map +1 -0
  63. package/dist/foundations/oauth/controllers/oauth.discovery.controller.js +102 -0
  64. package/dist/foundations/oauth/controllers/oauth.discovery.controller.js.map +1 -0
  65. package/dist/foundations/oauth/controllers/oauth.registration.controller.d.ts +36 -0
  66. package/dist/foundations/oauth/controllers/oauth.registration.controller.d.ts.map +1 -0
  67. package/dist/foundations/oauth/controllers/oauth.registration.controller.js +81 -0
  68. package/dist/foundations/oauth/controllers/oauth.registration.controller.js.map +1 -0
  69. package/dist/foundations/oauth/dtos/index.d.ts +1 -0
  70. package/dist/foundations/oauth/dtos/index.d.ts.map +1 -1
  71. package/dist/foundations/oauth/dtos/index.js +1 -0
  72. package/dist/foundations/oauth/dtos/index.js.map +1 -1
  73. package/dist/foundations/oauth/dtos/oauth.register.dto.d.ts +14 -0
  74. package/dist/foundations/oauth/dtos/oauth.register.dto.d.ts.map +1 -0
  75. package/dist/foundations/oauth/dtos/oauth.register.dto.js +49 -0
  76. package/dist/foundations/oauth/dtos/oauth.register.dto.js.map +1 -0
  77. package/dist/foundations/oauth/index.d.ts +1 -0
  78. package/dist/foundations/oauth/index.d.ts.map +1 -1
  79. package/dist/foundations/oauth/index.js +3 -1
  80. package/dist/foundations/oauth/index.js.map +1 -1
  81. package/dist/foundations/oauth/oauth.module.d.ts +3 -1
  82. package/dist/foundations/oauth/oauth.module.d.ts.map +1 -1
  83. package/dist/foundations/oauth/oauth.module.js +12 -2
  84. package/dist/foundations/oauth/oauth.module.js.map +1 -1
  85. package/dist/foundations/oauth/repositories/oauth.repository.d.ts +2 -1
  86. package/dist/foundations/oauth/repositories/oauth.repository.d.ts.map +1 -1
  87. package/dist/foundations/oauth/repositories/oauth.repository.js +16 -34
  88. package/dist/foundations/oauth/repositories/oauth.repository.js.map +1 -1
  89. package/dist/foundations/oauth/services/oauth.client.service.d.ts +2 -1
  90. package/dist/foundations/oauth/services/oauth.client.service.d.ts.map +1 -1
  91. package/dist/foundations/oauth/services/oauth.client.service.js.map +1 -1
  92. package/dist/foundations/rbac/index.d.ts +4 -0
  93. package/dist/foundations/rbac/index.d.ts.map +1 -1
  94. package/dist/foundations/rbac/index.js +7 -1
  95. package/dist/foundations/rbac/index.js.map +1 -1
  96. package/dist/foundations/rbac/rbac-permission.module.d.ts +14 -0
  97. package/dist/foundations/rbac/rbac-permission.module.d.ts.map +1 -0
  98. package/dist/foundations/rbac/rbac-permission.module.js +33 -0
  99. package/dist/foundations/rbac/rbac-permission.module.js.map +1 -0
  100. package/dist/foundations/rbac/repositories/rbac-permission.repository.d.ts +31 -0
  101. package/dist/foundations/rbac/repositories/rbac-permission.repository.d.ts.map +1 -0
  102. package/dist/foundations/rbac/repositories/rbac-permission.repository.js +80 -0
  103. package/dist/foundations/rbac/repositories/rbac-permission.repository.js.map +1 -0
  104. package/dist/foundations/rbac/services/rbac-permission.service.d.ts +31 -0
  105. package/dist/foundations/rbac/services/rbac-permission.service.d.ts.map +1 -0
  106. package/dist/foundations/rbac/services/rbac-permission.service.js +41 -0
  107. package/dist/foundations/rbac/services/rbac-permission.service.js.map +1 -0
  108. package/dist/index.d.ts +1 -0
  109. package/dist/index.d.ts.map +1 -1
  110. package/dist/index.js +2 -0
  111. package/dist/index.js.map +1 -1
  112. package/dist/mcp/controllers/mcp.controller.d.ts +34 -0
  113. package/dist/mcp/controllers/mcp.controller.d.ts.map +1 -0
  114. package/dist/mcp/controllers/mcp.controller.js +108 -0
  115. package/dist/mcp/controllers/mcp.controller.js.map +1 -0
  116. package/dist/mcp/filters/mcp.auth.filter.d.ts +21 -0
  117. package/dist/mcp/filters/mcp.auth.filter.d.ts.map +1 -0
  118. package/dist/mcp/filters/mcp.auth.filter.js +52 -0
  119. package/dist/mcp/filters/mcp.auth.filter.js.map +1 -0
  120. package/dist/mcp/index.d.ts +4 -0
  121. package/dist/mcp/index.d.ts.map +1 -0
  122. package/dist/mcp/index.js +11 -0
  123. package/dist/mcp/index.js.map +1 -0
  124. package/dist/mcp/interfaces/mcp.tool.interface.d.ts +37 -0
  125. package/dist/mcp/interfaces/mcp.tool.interface.d.ts.map +1 -0
  126. package/dist/mcp/interfaces/mcp.tool.interface.js +6 -0
  127. package/dist/mcp/interfaces/mcp.tool.interface.js.map +1 -0
  128. package/dist/mcp/mcp.module.d.ts +23 -0
  129. package/dist/mcp/mcp.module.d.ts.map +1 -0
  130. package/dist/mcp/mcp.module.js +59 -0
  131. package/dist/mcp/mcp.module.js.map +1 -0
  132. package/dist/mcp/services/mcp.entity.write.service.d.ts +79 -0
  133. package/dist/mcp/services/mcp.entity.write.service.d.ts.map +1 -0
  134. package/dist/mcp/services/mcp.entity.write.service.js +270 -0
  135. package/dist/mcp/services/mcp.entity.write.service.js.map +1 -0
  136. package/dist/mcp/services/mcp.errors.d.ts +24 -0
  137. package/dist/mcp/services/mcp.errors.d.ts.map +1 -0
  138. package/dist/mcp/services/mcp.errors.js +50 -0
  139. package/dist/mcp/services/mcp.errors.js.map +1 -0
  140. package/dist/mcp/services/mcp.generic.tools.service.d.ts +26 -0
  141. package/dist/mcp/services/mcp.generic.tools.service.d.ts.map +1 -0
  142. package/dist/mcp/services/mcp.generic.tools.service.js +108 -0
  143. package/dist/mcp/services/mcp.generic.tools.service.js.map +1 -0
  144. package/dist/mcp/services/mcp.promoted.tools.factory.d.ts +58 -0
  145. package/dist/mcp/services/mcp.promoted.tools.factory.d.ts.map +1 -0
  146. package/dist/mcp/services/mcp.promoted.tools.factory.js +260 -0
  147. package/dist/mcp/services/mcp.promoted.tools.factory.js.map +1 -0
  148. package/dist/mcp/services/mcp.server.factory.d.ts +24 -0
  149. package/dist/mcp/services/mcp.server.factory.d.ts.map +1 -0
  150. package/dist/mcp/services/mcp.server.factory.js +60 -0
  151. package/dist/mcp/services/mcp.server.factory.js.map +1 -0
  152. package/dist/mcp/services/mcp.tool.registry.d.ts +21 -0
  153. package/dist/mcp/services/mcp.tool.registry.d.ts.map +1 -0
  154. package/dist/mcp/services/mcp.tool.registry.js +72 -0
  155. package/dist/mcp/services/mcp.tool.registry.js.map +1 -0
  156. package/package.json +17 -12
@@ -81,6 +81,35 @@ export interface ConfigAiInterface {
81
81
  * `ENV === "production"` to enforce this. Driven by MOCK_AI=true.
82
82
  */
83
83
  mock: boolean;
84
+ /**
85
+ * Per-ATTEMPT wall-clock budget for one provider request, in milliseconds.
86
+ * Driven by AI_REQUEST_TIMEOUT_MS (default 120000).
87
+ *
88
+ * Without it the only bound is the OpenAI SDK's own 600s default, so a
89
+ * provider that accepts a request and never answers freezes the caller for
90
+ * ten minutes with no error, no log and no dump (the dump file is written on
91
+ * close). Callers that need a different bound pass `timeout` per call.
92
+ *
93
+ * This is the budget for ONE attempt: the LangChain retry layer may re-issue
94
+ * (on OpenRouter each retry escalates `allow_fallbacks`, so a stalled provider
95
+ * is rerouted rather than waited on again). {@link requestDeadlineAttempts}
96
+ * bounds the total.
97
+ */
98
+ requestTimeoutMs: number;
99
+ /**
100
+ * How many attempts the absolute deadline budgets for before it force-fails a
101
+ * call, so an adapter that ignores its own timeout still settles. Driven by
102
+ * AI_REQUEST_DEADLINE_ATTEMPTS (default 3 — matches LangChain's maxRetries: 2
103
+ * plus the first attempt).
104
+ */
105
+ requestDeadlineAttempts: number;
106
+ /**
107
+ * How often, in milliseconds, a still-pending provider request logs a warning.
108
+ * Driven by AI_REQUEST_WATCHDOG_MS (default 30000). A stall used to be
109
+ * completely silent until it resolved; this makes it visible while it happens.
110
+ * Set to 0 to disable.
111
+ */
112
+ requestWatchdogMs: number;
84
113
  /**
85
114
  * Mistral Document AI (OCR) on Azure AI Foundry — see DocumentAiService.
86
115
  * Driven by DOCUMENT_AI_{ENABLED,PROVIDER,API_KEY,MODEL,URL,API_VERSION}.
@@ -1 +1 @@
1
- {"version":3,"file":"config.ai.interface.d.ts","sourceRoot":"","sources":["../../../src/config/interfaces/config.ai.interface.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.ai.interface.d.ts","sourceRoot":"","sources":["../../../src/config/interfaces/config.ai.interface.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * MCP (Model Context Protocol) Server Configuration Interface
3
+ *
4
+ * Controls the MCP server exposed at POST /mcp, which lets external AI agents
5
+ * (claude.ai connectors, Claude Desktop, ChatGPT) interact with the application
6
+ * through OAuth-authenticated, RBAC-gated tools.
7
+ *
8
+ * @see https://modelcontextprotocol.io - Model Context Protocol specification
9
+ */
10
+ export interface ConfigMcpInterface {
11
+ /**
12
+ * Master switch to enable/disable the MCP server.
13
+ * When false, the MCP endpoint is not served.
14
+ * @default false
15
+ */
16
+ enabled: boolean;
17
+ /**
18
+ * Server name advertised to MCP clients during initialization.
19
+ * @default "neural-erp"
20
+ */
21
+ serverName: string;
22
+ /**
23
+ * Optional instructions string advertised to MCP clients,
24
+ * describing how to best use this server's tools.
25
+ */
26
+ instructions?: string;
27
+ /**
28
+ * JSON:API types promoted to dedicated per-entity MCP tools,
29
+ * parsed from a comma-separated environment variable.
30
+ * @default []
31
+ */
32
+ promotedEntities: string[];
33
+ }
34
+ //# sourceMappingURL=config.mcp.interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.mcp.interface.d.ts","sourceRoot":"","sources":["../../../src/config/interfaces/config.mcp.interface.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,OAAO,EAAE,OAAO,CAAC;IAEjB;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;;OAIG;IACH,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=config.mcp.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.mcp.interface.js","sourceRoot":"","sources":["../../../src/config/interfaces/config.mcp.interface.ts"],"names":[],"mappings":""}
@@ -21,6 +21,7 @@ export * from "./config.interface";
21
21
  export * from "./config.job.names.interface";
22
22
  export * from "./config.jwt.interface";
23
23
  export * from "./config.logging.interface";
24
+ export * from "./config.mcp.interface";
24
25
  export * from "./config.neo4j.interface";
25
26
  export * from "./config.oauth.interface";
26
27
  export * from "./config.operator.interface";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/config/interfaces/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,iCAAiC,CAAC;AAChD,cAAc,kCAAkC,CAAC;AACjD,cAAc,yBAAyB,CAAC;AACxC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sCAAsC,CAAC;AACrD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,0BAA0B,CAAC;AACzC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,oBAAoB,CAAC;AACnC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,wBAAwB,CAAC;AACvC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,0BAA0B,CAAC;AACzC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/config/interfaces/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,iCAAiC,CAAC;AAChD,cAAc,kCAAkC,CAAC;AACjD,cAAc,yBAAyB,CAAC;AACxC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sCAAsC,CAAC;AACrD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,0BAA0B,CAAC;AACzC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,oBAAoB,CAAC;AACnC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,wBAAwB,CAAC;AACvC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,0BAA0B,CAAC;AACzC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,0BAA0B,CAAC"}
@@ -37,6 +37,7 @@ __exportStar(require("./config.interface"), exports);
37
37
  __exportStar(require("./config.job.names.interface"), exports);
38
38
  __exportStar(require("./config.jwt.interface"), exports);
39
39
  __exportStar(require("./config.logging.interface"), exports);
40
+ __exportStar(require("./config.mcp.interface"), exports);
40
41
  __exportStar(require("./config.neo4j.interface"), exports);
41
42
  __exportStar(require("./config.oauth.interface"), exports);
42
43
  __exportStar(require("./config.operator.interface"), exports);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/config/interfaces/index.ts"],"names":[],"mappings":";AAAA;;GAEG;;;;;;;;;;;;;;;;AAEH,0DAAwC;AACxC,wDAAsC;AACtC,yDAAuC;AACvC,yDAAuC;AACvC,0DAAwC;AACxC,2DAAyC;AACzC,6DAA2C;AAC3C,kEAAgD;AAChD,mEAAiD;AACjD,0DAAwC;AACxC,6DAA2C;AAC3C,uEAAqD;AACrD,4DAA0C;AAC1C,2DAAyC;AACzC,gEAA8C;AAC9C,iEAA+C;AAC/C,qDAAmC;AACnC,+DAA6C;AAC7C,yDAAuC;AACvC,6DAA2C;AAC3C,2DAAyC;AACzC,2DAAyC;AACzC,8DAA4C;AAC5C,6DAA2C;AAC3C,+DAA6C;AAC7C,2DAAyC;AACzC,wDAAsC;AACtC,4DAA0C;AAC1C,2DAAyC;AACzC,gEAA8C;AAC9C,2DAAyC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/config/interfaces/index.ts"],"names":[],"mappings":";AAAA;;GAEG;;;;;;;;;;;;;;;;AAEH,0DAAwC;AACxC,wDAAsC;AACtC,yDAAuC;AACvC,yDAAuC;AACvC,0DAAwC;AACxC,2DAAyC;AACzC,6DAA2C;AAC3C,kEAAgD;AAChD,mEAAiD;AACjD,0DAAwC;AACxC,6DAA2C;AAC3C,uEAAqD;AACrD,4DAA0C;AAC1C,2DAAyC;AACzC,gEAA8C;AAC9C,iEAA+C;AAC/C,qDAAmC;AACnC,+DAA6C;AAC7C,yDAAuC;AACvC,6DAA2C;AAC3C,yDAAuC;AACvC,2DAAyC;AACzC,2DAAyC;AACzC,8DAA4C;AAC5C,6DAA2C;AAC3C,+DAA6C;AAC7C,2DAAyC;AACzC,wDAAsC;AACtC,4DAA0C;AAC1C,2DAAyC;AACzC,gEAA8C;AAC9C,2DAAyC"}
@@ -10,6 +10,23 @@ import { LLMCacheService } from "./llm-cache.service";
10
10
  import { ModelService } from "../../llm/services/model.service";
11
11
  import { LLMCallDumper } from "./llm-call-dumper.service";
12
12
  export { injectOpenRouterProvider } from "./openrouter-fetch";
13
+ /**
14
+ * True for the abort a request timeout raises, whichever layer raised it — the
15
+ * OpenAI SDK's `APIConnectionTimeoutError`, undici's `TimeoutError`/
16
+ * `AbortError` DOMException, or a LangChain wrapper around either. Matched on
17
+ * name and message because the concrete class differs per transport.
18
+ */
19
+ export declare function isTimeoutError(error: unknown): boolean;
20
+ /**
21
+ * Thrown when a provider call burns its whole deadline without settling.
22
+ * Distinguishable from a provider error so callers can treat a stall
23
+ * differently from a refusal if they choose — both are retryable.
24
+ */
25
+ export declare class LLMTimeoutError extends Error {
26
+ readonly label: string;
27
+ readonly deadlineMs: number;
28
+ constructor(label: string, deadlineMs: number);
29
+ }
13
30
  /**
14
31
  * Parameters for LLM service calls
15
32
  */
@@ -47,6 +64,39 @@ export declare class LLMService {
47
64
  private readonly cache?;
48
65
  private readonly logger;
49
66
  constructor(modelService: ModelService, config: ConfigService<BaseConfigInterface>, dumper: LLMCallDumper, tokenUsageService: TokenUsageService, cache?: LLMCacheService);
67
+ /**
68
+ * The per-ATTEMPT budget for one provider request. `params.timeout` wins;
69
+ * otherwise the configured default (`AI_REQUEST_TIMEOUT_MS`).
70
+ */
71
+ private attemptTimeoutMs;
72
+ /**
73
+ * Runs one provider call under a WATCHDOG and an ABSOLUTE DEADLINE.
74
+ *
75
+ * Why this exists (game e51493e4 r002, 2026-07-26): a plotter request was
76
+ * accepted by the provider and never answered. Nothing in the stack could
77
+ * interrupt it — no timeout was configured anywhere, the dump file is only
78
+ * written when the call closes, and the callers' retry/fallback wrappers catch
79
+ * ERRORS, not promises that never settle. The round froze for 639 seconds with
80
+ * no log, no dump and no error, and only unfroze because the OpenAI SDK's own
81
+ * 600s default finally fired. Three such stalls are on record (547s, 514s,
82
+ * 639s) across two tiers and two models, so this is a property of talking to a
83
+ * provider, not of one model.
84
+ *
85
+ * Two independent guarantees, because the first one can be ignored by an
86
+ * adapter that owns its own transport:
87
+ * - the WATCHDOG logs every `requestWatchdogMs` while the call is pending, so
88
+ * a stall is visible AS IT HAPPENS instead of after it resolves;
89
+ * - the DEADLINE aborts the signal and rejects with {@link LLMTimeoutError}
90
+ * once the call has burned its whole attempt budget, so the promise ALWAYS
91
+ * settles and the caller's existing retry/fallback path gets to run.
92
+ *
93
+ * The deadline is deliberately the LAST line of defence: it budgets
94
+ * `requestDeadlineAttempts` attempts, so in normal operation the per-attempt
95
+ * timeout fires first and the retry escalates the OpenRouter pin onto a
96
+ * healthy provider — which is the outcome we actually want. Reaching the
97
+ * deadline means the adapter never honoured its own timeout.
98
+ */
99
+ private runBounded;
50
100
  /**
51
101
  * Records token usage for cost/observability attribution. Never throws —
52
102
  * a persistence failure logs a warning and the LLM call continues, so
@@ -331,6 +381,8 @@ export declare class LLMService {
331
381
  * systemPrompts/prompt). A hit returns early WITHOUT invoking the provider,
332
382
  * so it costs no tokens. Default: false. */
333
383
  cacheable?: boolean;
384
+ /** Per-attempt request budget in ms. Defaults to `ai.requestTimeoutMs`. */
385
+ timeout?: number;
334
386
  }): Promise<T>;
335
387
  /**
336
388
  * Single-step model invocation with tools bound — the durable-checkpointing
@@ -1 +1 @@
1
- {"version":3,"file":"llm.service.d.ts","sourceRoot":"","sources":["../../../../src/core/llm/services/llm.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"llm.service.d.ts","sourceRoot":"","sources":["../../../../src/core/llm/services/llm.service.ts"],"names":[],"mappings":"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"}
@@ -46,7 +46,8 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
46
46
  };
47
47
  var LLMService_1;
48
48
  Object.defineProperty(exports, "__esModule", { value: true });
49
- exports.LLMService = exports.injectOpenRouterProvider = void 0;
49
+ exports.LLMService = exports.LLMTimeoutError = exports.injectOpenRouterProvider = void 0;
50
+ exports.isTimeoutError = isTimeoutError;
50
51
  const openai_compatible_1 = require("@ai-sdk/openai-compatible");
51
52
  const messages_1 = require("@langchain/core/messages");
52
53
  const prompts_1 = require("@langchain/core/prompts");
@@ -77,6 +78,40 @@ const { streamText, streamObject } = (0, vercel_1.wrapAISDK)(ai);
77
78
  // Re-export for the existing test import path.
78
79
  var openrouter_fetch_2 = require("./openrouter-fetch");
79
80
  Object.defineProperty(exports, "injectOpenRouterProvider", { enumerable: true, get: function () { return openrouter_fetch_2.injectOpenRouterProvider; } });
81
+ /** Fallbacks used only when no `ai` config block is registered (test harnesses). */
82
+ const DEFAULT_REQUEST_TIMEOUT_MS = 120_000;
83
+ const DEFAULT_REQUEST_WATCHDOG_MS = 30_000;
84
+ const DEFAULT_REQUEST_DEADLINE_ATTEMPTS = 3;
85
+ /** Grace on top of the budgeted attempts, covering backoff between retries. */
86
+ const DEADLINE_SLACK_MS = 15_000;
87
+ /**
88
+ * True for the abort a request timeout raises, whichever layer raised it — the
89
+ * OpenAI SDK's `APIConnectionTimeoutError`, undici's `TimeoutError`/
90
+ * `AbortError` DOMException, or a LangChain wrapper around either. Matched on
91
+ * name and message because the concrete class differs per transport.
92
+ */
93
+ function isTimeoutError(error) {
94
+ const name = error?.name ?? "";
95
+ const message = error instanceof Error ? error.message : String(error ?? "");
96
+ return (name === "TimeoutError" ||
97
+ name === "AbortError" ||
98
+ name === "APIConnectionTimeoutError" ||
99
+ /aborted due to timeout|timed? ?out|Request was aborted/i.test(message));
100
+ }
101
+ /**
102
+ * Thrown when a provider call burns its whole deadline without settling.
103
+ * Distinguishable from a provider error so callers can treat a stall
104
+ * differently from a refusal if they choose — both are retryable.
105
+ */
106
+ class LLMTimeoutError extends Error {
107
+ constructor(label, deadlineMs) {
108
+ super(`LLM call "${label}" exceeded its ${Math.round(deadlineMs / 1000)}s deadline`);
109
+ this.label = label;
110
+ this.deadlineMs = deadlineMs;
111
+ this.name = "LLMTimeoutError";
112
+ }
113
+ }
114
+ exports.LLMTimeoutError = LLMTimeoutError;
80
115
  /**
81
116
  * Best-effort extraction of a JSON object from free-form model text. Local
82
117
  * models (notably Gemma over Ollama) routinely ignore a forced `tool_choice`
@@ -187,6 +222,73 @@ let LLMService = LLMService_1 = class LLMService {
187
222
  this.cache = cache;
188
223
  this.logger = new common_1.Logger(LLMService_1.name);
189
224
  }
225
+ /**
226
+ * The per-ATTEMPT budget for one provider request. `params.timeout` wins;
227
+ * otherwise the configured default (`AI_REQUEST_TIMEOUT_MS`).
228
+ */
229
+ attemptTimeoutMs(explicit) {
230
+ return explicit ?? this.config.get("ai")?.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
231
+ }
232
+ /**
233
+ * Runs one provider call under a WATCHDOG and an ABSOLUTE DEADLINE.
234
+ *
235
+ * Why this exists (game e51493e4 r002, 2026-07-26): a plotter request was
236
+ * accepted by the provider and never answered. Nothing in the stack could
237
+ * interrupt it — no timeout was configured anywhere, the dump file is only
238
+ * written when the call closes, and the callers' retry/fallback wrappers catch
239
+ * ERRORS, not promises that never settle. The round froze for 639 seconds with
240
+ * no log, no dump and no error, and only unfroze because the OpenAI SDK's own
241
+ * 600s default finally fired. Three such stalls are on record (547s, 514s,
242
+ * 639s) across two tiers and two models, so this is a property of talking to a
243
+ * provider, not of one model.
244
+ *
245
+ * Two independent guarantees, because the first one can be ignored by an
246
+ * adapter that owns its own transport:
247
+ * - the WATCHDOG logs every `requestWatchdogMs` while the call is pending, so
248
+ * a stall is visible AS IT HAPPENS instead of after it resolves;
249
+ * - the DEADLINE aborts the signal and rejects with {@link LLMTimeoutError}
250
+ * once the call has burned its whole attempt budget, so the promise ALWAYS
251
+ * settles and the caller's existing retry/fallback path gets to run.
252
+ *
253
+ * The deadline is deliberately the LAST line of defence: it budgets
254
+ * `requestDeadlineAttempts` attempts, so in normal operation the per-attempt
255
+ * timeout fires first and the retry escalates the OpenRouter pin onto a
256
+ * healthy provider — which is the outcome we actually want. Reaching the
257
+ * deadline means the adapter never honoured its own timeout.
258
+ */
259
+ async runBounded(label, attemptTimeoutMs, controller, work) {
260
+ const aiConfig = this.config.get("ai");
261
+ const watchdogMs = aiConfig?.requestWatchdogMs ?? DEFAULT_REQUEST_WATCHDOG_MS;
262
+ const attempts = aiConfig?.requestDeadlineAttempts ?? DEFAULT_REQUEST_DEADLINE_ATTEMPTS;
263
+ const deadlineMs = attemptTimeoutMs * Math.max(1, attempts) + DEADLINE_SLACK_MS;
264
+ const startedAt = Date.now();
265
+ const watchdog = watchdogMs > 0
266
+ ? setInterval(() => {
267
+ this.logger.warn(`[${label}] still pending after ${Math.round((Date.now() - startedAt) / 1000)}s ` +
268
+ `(attempt budget ${Math.round(attemptTimeoutMs / 1000)}s, hard deadline ${Math.round(deadlineMs / 1000)}s)`);
269
+ }, watchdogMs)
270
+ : undefined;
271
+ watchdog?.unref?.();
272
+ let deadline;
273
+ try {
274
+ return await new Promise((resolve, reject) => {
275
+ deadline = setTimeout(() => {
276
+ // Abort first so the in-flight socket is released, then reject — the
277
+ // caller must not be left waiting on a request nobody is reading.
278
+ controller.abort();
279
+ reject(new LLMTimeoutError(label, deadlineMs));
280
+ }, deadlineMs);
281
+ deadline.unref?.();
282
+ work().then(resolve, reject);
283
+ });
284
+ }
285
+ finally {
286
+ if (watchdog)
287
+ clearInterval(watchdog);
288
+ if (deadline)
289
+ clearTimeout(deadline);
290
+ }
291
+ }
190
292
  /**
191
293
  * Records token usage for cost/observability attribution. Never throws —
192
294
  * a persistence failure logs a warning and the LLM call continues, so
@@ -478,12 +580,18 @@ let LLMService = LLMService_1 = class LLMService {
478
580
  let totalCached = 0;
479
581
  const parseFallbacks = [];
480
582
  const warnings = [];
583
+ // Bounded from here on: the request carries an abort signal, a watchdog
584
+ // reports it while it is still open, and the deadline guarantees this
585
+ // promise settles even if the provider never answers.
586
+ const attemptTimeoutMs = this.attemptTimeoutMs(params.timeout);
587
+ const controller = new AbortController();
588
+ const label = `${params.metadata?.nodeName ?? "llm.call"}:${aiConfig.model}`;
481
589
  try {
482
- const result = await this._invokeOriginal(params, session, (i, o, c) => {
590
+ const result = await this.runBounded(label, attemptTimeoutMs, controller, () => this._invokeOriginal(params, session, (i, o, c) => {
483
591
  totalInput += i;
484
592
  totalOutput += o;
485
593
  totalCached += c;
486
- }, (kind) => parseFallbacks.push(kind), (w) => warnings.push(w));
594
+ }, (kind) => parseFallbacks.push(kind), (w) => warnings.push(w), { attemptTimeoutMs, signal: controller.signal }));
487
595
  session.close({
488
596
  finalStatus: "success",
489
597
  totalTokens: { input: totalInput, output: totalOutput, cached: totalCached },
@@ -517,7 +625,10 @@ let LLMService = LLMService_1 = class LLMService {
517
625
  throw new Error(`LLM service error: ${message}`);
518
626
  }
519
627
  }
520
- async _invokeOriginal(params, session, addTokens, addParseFallback, addWarning) {
628
+ async _invokeOriginal(params, session, addTokens, addParseFallback, addWarning,
629
+ // The per-attempt budget and the deadline's abort signal, supplied by
630
+ // `call()`. Optional so direct callers (tests) keep working unbounded.
631
+ bounds) {
521
632
  // Optional: Validate input parameters against schema
522
633
  if (params.inputSchema && params.validateInput) {
523
634
  try {
@@ -538,11 +649,15 @@ let LLMService = LLMService_1 = class LLMService {
538
649
  maxHistoryMessages: params.maxHistoryMessages,
539
650
  });
540
651
  const prompt = prompts_1.ChatPromptTemplate.fromMessages(template);
541
- // Get base model
652
+ // Get base model. The per-attempt budget rides on the model itself: the
653
+ // OpenAI client is built with it, so each attempt aborts on schedule and the
654
+ // LangChain retry re-issues (escalating the OpenRouter pin) instead of the
655
+ // whole call sitting on one dead socket.
542
656
  const baseModel = this.modelService.getLLM({
543
657
  temperature: params.temperature,
544
658
  modelWeight: params.modelWeight,
545
659
  disableThinking: params.disableThinking,
660
+ timeoutMs: bounds?.attemptTimeoutMs ?? params.timeout,
546
661
  });
547
662
  // Build config options for the invocation
548
663
  const configOptions = {};
@@ -554,6 +669,10 @@ let LLMService = LLMService_1 = class LLMService {
554
669
  configOptions.metadata = params.metadata;
555
670
  if (params.timeout)
556
671
  configOptions.timeout = params.timeout;
672
+ // The deadline's signal — aborting it releases the in-flight request rather
673
+ // than leaving an orphaned socket behind a rejected promise.
674
+ if (bounds?.signal)
675
+ configOptions.signal = bounds.signal;
557
676
  // Track token usage across tool iterations
558
677
  let totalInputTokens = 0;
559
678
  let totalOutputTokens = 0;
@@ -684,7 +803,33 @@ let LLMService = LLMService_1 = class LLMService {
684
803
  });
685
804
  }
686
805
  session.startIteration("final-structured", conversationMessages);
687
- const response = (await structuredLlm.invoke(conversationMessages, Object.keys(configOptions).length > 0 ? configOptions : undefined));
806
+ // A timed-out attempt is RE-ISSUED ONCE on the same model instance, because
807
+ // that is what actually recovers a stall: the instance's
808
+ // `openRouterEscalatingFetch` closure escalates on its second request, so
809
+ // the retry allows fallbacks and OpenRouter reroutes off the provider that
810
+ // went quiet. (This is precisely how the 639s stall eventually resolved —
811
+ // the SDK's 600s abort, then a rerouted retry that answered in 39s. Here it
812
+ // happens after the attempt budget instead of after ten minutes.)
813
+ //
814
+ // A fresh call would NOT get this: `getLLM` builds a new instance per call,
815
+ // resetting the escalation, so a hard-pinned tier would retry straight back
816
+ // onto the stalled provider. An abort is the ONLY thing retried here —
817
+ // provider errors and parse failures stay the caller's business.
818
+ const invokeStructured = async () => (await structuredLlm.invoke(conversationMessages, Object.keys(configOptions).length > 0 ? configOptions : undefined));
819
+ let response;
820
+ try {
821
+ response = await invokeStructured();
822
+ }
823
+ catch (error) {
824
+ // The deadline's own abort is NOT a stall to reroute around — it means the
825
+ // whole call is over, so let it through.
826
+ if (!isTimeoutError(error) || bounds?.signal?.aborted)
827
+ throw error;
828
+ const msg = `[LLMService] attempt timed out after ${Math.round((bounds?.attemptTimeoutMs ?? 0) / 1000)}s — re-issuing with provider fallbacks escalated`;
829
+ console.warn(msg);
830
+ addWarning(msg);
831
+ response = await invokeStructured();
832
+ }
688
833
  // Extract token usage with type guard (includes tool iteration tokens)
689
834
  const raw = (0, llm_raw_response_1.isValidRaw)(response.raw) ? response.raw : undefined;
690
835
  session.recordResponse({
@@ -910,7 +1055,7 @@ let LLMService = LLMService_1 = class LLMService {
910
1055
  // the session open indefinitely. The AbortError surfaces as a rejection on
911
1056
  // the awaited promises below (caught + logged).
912
1057
  const controller = new AbortController();
913
- const timeoutId = setTimeout(() => controller.abort(), params.timeout ?? 60_000);
1058
+ const timeoutId = setTimeout(() => controller.abort(), this.attemptTimeoutMs(params.timeout));
914
1059
  // Schema cast: `streamObject`'s typing is a conditional union over the
915
1060
  // output mode (`object` / `enum` / `array` / `no-schema`). Our T is always
916
1061
  // a Zod object schema; the runtime call is correct.
@@ -1055,7 +1200,7 @@ let LLMService = LLMService_1 = class LLMService {
1055
1200
  // Abort the stream if the provider stalls (see streamCall). The AbortError
1056
1201
  // surfaces as a rejection on the awaited promises below (caught + logged).
1057
1202
  const controller = new AbortController();
1058
- const timeoutId = setTimeout(() => controller.abort(), params.timeout ?? 60_000);
1203
+ const timeoutId = setTimeout(() => controller.abort(), this.attemptTimeoutMs(params.timeout));
1059
1204
  const streamResult = streamText({
1060
1205
  model,
1061
1206
  system,
@@ -1175,6 +1320,7 @@ let LLMService = LLMService_1 = class LLMService {
1175
1320
  tools: [{ name: params.tool.name, description: params.tool.description, schema: params.tool.schema }],
1176
1321
  outputSchemaName: params.tool.name,
1177
1322
  });
1323
+ const attemptTimeoutMs = this.attemptTimeoutMs(params.timeout);
1178
1324
  try {
1179
1325
  const model = this.modelService.getLLM({
1180
1326
  modelWeight,
@@ -1182,6 +1328,7 @@ let LLMService = LLMService_1 = class LLMService {
1182
1328
  maxOutputTokens: params.maxOutputTokens,
1183
1329
  frequencyPenalty: params.frequencyPenalty,
1184
1330
  temperature: params.temperature,
1331
+ timeoutMs: attemptTimeoutMs,
1185
1332
  });
1186
1333
  const tool = new tools_1.DynamicStructuredTool({
1187
1334
  name: params.tool.name,
@@ -1251,14 +1398,20 @@ let LLMService = LLMService_1 = class LLMService {
1251
1398
  }
1252
1399
  return null;
1253
1400
  };
1254
- let response = (await bound.invoke(baseMessages));
1401
+ // Each provider invocation is bounded independently — the nudge retry is a
1402
+ // second request and gets its own budget, not the leftovers of the first.
1403
+ const invokeBounded = async (messages, attempt) => {
1404
+ const controller = new AbortController();
1405
+ return (await this.runBounded(`extractViaTool:${params.tool.name}:${attempt}`, attemptTimeoutMs, controller, () => bound.invoke(messages, { signal: controller.signal })));
1406
+ };
1407
+ let response = await invokeBounded(baseMessages, "attempt-1");
1255
1408
  let parsed = tryExtract(response);
1256
1409
  // One retry with an explicit nudge — local models frequently comply on a
1257
1410
  // second pass once told plainly that prose is not acceptable.
1258
1411
  if (parsed === null) {
1259
1412
  describe(response, "attempt-1");
1260
1413
  const nudge = new messages_1.HumanMessage(`You did NOT call the \`${params.tool.name}\` tool. Do not write prose, refusals, or explanations. Respond ONLY by calling \`${params.tool.name}\` with valid arguments now.`);
1261
- response = (await bound.invoke([...baseMessages, nudge]));
1414
+ response = await invokeBounded([...baseMessages, nudge], "attempt-2");
1262
1415
  parsed = tryExtract(response);
1263
1416
  if (parsed === null)
1264
1417
  describe(response, "attempt-2");