langflower 0.0.7 → 0.0.9

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 (189) hide show
  1. package/package.json +1 -1
  2. package/ui-dist/{chunk-Y6VMBLSJ.js → chunk-7UMVYN3A.js} +1 -1
  3. package/ui-dist/{chunk-6DQ2XSRW.js → chunk-MDGXX73Z.js} +3 -3
  4. package/ui-dist/index.html +1 -1
  5. package/ui-dist/main-2JJGCNTD.js +313 -0
  6. package/vendor/common-nodes/dist/ai/chat-completion-stream.d.ts +2 -0
  7. package/vendor/common-nodes/dist/ai/critique/node.d.ts +246 -0
  8. package/vendor/common-nodes/dist/ai/critique/node.js +2 -2
  9. package/vendor/common-nodes/dist/ai/fake-llm/node.d.ts +246 -0
  10. package/vendor/common-nodes/dist/ai/features/chat-completion-stream.d.ts +53 -0
  11. package/vendor/common-nodes/dist/ai/features/chat-completion-stream.js +1 -0
  12. package/vendor/common-nodes/dist/ai/features/llm-loop/autokick-recovery.d.ts +13 -0
  13. package/vendor/common-nodes/dist/ai/features/llm-loop/autokick-recovery.js +17 -0
  14. package/vendor/common-nodes/dist/ai/features/llm-loop/classify-llm-failure.d.ts +2 -0
  15. package/vendor/common-nodes/dist/ai/features/llm-loop/classify-llm-failure.js +113 -0
  16. package/vendor/common-nodes/dist/ai/features/llm-loop/dead-loop-detector.d.ts +28 -0
  17. package/vendor/common-nodes/dist/ai/features/llm-loop/dead-loop-detector.js +194 -0
  18. package/vendor/common-nodes/dist/ai/features/llm-loop/live-get-tools.d.ts +9 -0
  19. package/vendor/common-nodes/dist/ai/features/llm-loop/live-get-tools.js +21 -0
  20. package/vendor/common-nodes/dist/ai/features/llm-loop/llm-loop-reducer.d.ts +2 -0
  21. package/vendor/common-nodes/dist/ai/features/llm-loop/llm-loop-reducer.js +216 -0
  22. package/vendor/common-nodes/dist/ai/features/llm-loop/llm-loop-types.d.ts +125 -0
  23. package/vendor/common-nodes/dist/ai/features/llm-loop/llm-loop-types.js +39 -0
  24. package/vendor/common-nodes/dist/ai/features/llm-loop/normalize-llm-recovery-policy.d.ts +2 -0
  25. package/vendor/common-nodes/dist/ai/features/llm-loop/normalize-llm-recovery-policy.js +59 -0
  26. package/vendor/common-nodes/dist/ai/features/llm-loop/operators/normalize-tool-result.d.ts +1 -0
  27. package/vendor/common-nodes/dist/ai/features/llm-loop/operators/normalize-tool-result.js +7 -0
  28. package/vendor/common-nodes/dist/ai/features/llm-loop/operators/observe-provider-stream.d.ts +43 -0
  29. package/vendor/common-nodes/dist/ai/features/llm-loop/operators/observe-provider-stream.js +96 -0
  30. package/vendor/common-nodes/dist/ai/features/llm-loop/run-agent-loop.d.ts +32 -0
  31. package/vendor/common-nodes/dist/ai/features/llm-loop/run-agent-loop.js +58 -0
  32. package/vendor/common-nodes/dist/ai/features/llm-loop/run-llm-loop.d.ts +80 -0
  33. package/vendor/common-nodes/dist/ai/features/llm-loop/run-llm-loop.js +681 -0
  34. package/vendor/common-nodes/dist/ai/features/llm-role-preset.d.ts +69 -0
  35. package/vendor/common-nodes/dist/ai/features/llm-role-preset.js +265 -0
  36. package/vendor/common-nodes/dist/ai/features/llm-session/llm-session-shell.d.ts +148 -0
  37. package/vendor/common-nodes/dist/ai/features/llm-session/llm-session-shell.js +198 -0
  38. package/vendor/common-nodes/dist/ai/features/llm-session/run-session-machine.d.ts +21 -0
  39. package/vendor/common-nodes/dist/ai/features/llm-session/run-session-machine.js +118 -0
  40. package/vendor/common-nodes/dist/ai/features/openai/context-length-error.d.ts +14 -0
  41. package/vendor/common-nodes/dist/ai/features/openai/context-length-error.js +63 -0
  42. package/vendor/common-nodes/dist/ai/features/openai/create-chat-completion-stream.d.ts +19 -0
  43. package/vendor/common-nodes/dist/ai/features/openai/create-chat-completion-stream.js +182 -0
  44. package/vendor/common-nodes/dist/ai/features/openai/list-provider-models.d.ts +28 -0
  45. package/vendor/common-nodes/dist/ai/features/openai/list-provider-models.js +52 -0
  46. package/vendor/common-nodes/dist/ai/features/openai/llm-context-compaction.d.ts +31 -0
  47. package/vendor/common-nodes/dist/ai/features/openai/llm-context-compaction.js +326 -0
  48. package/vendor/common-nodes/dist/ai/features/openai/normalize-compaction-params.d.ts +14 -0
  49. package/vendor/common-nodes/dist/ai/features/openai/normalize-compaction-params.js +21 -0
  50. package/vendor/common-nodes/dist/ai/features/openai/prepare-chat-completion.d.ts +30 -0
  51. package/vendor/common-nodes/dist/ai/features/openai/prepare-chat-completion.js +132 -0
  52. package/vendor/common-nodes/dist/ai/features/path-choice/control-tools.d.ts +20 -0
  53. package/vendor/common-nodes/dist/ai/features/path-choice/control-tools.js +70 -0
  54. package/vendor/common-nodes/dist/ai/features/path-choice/run-reactive-path-choice-loop.d.ts +35 -0
  55. package/vendor/common-nodes/dist/ai/features/path-choice/run-reactive-path-choice-loop.js +106 -0
  56. package/vendor/common-nodes/dist/ai/features/prompt/build-effective-system-prompt.d.ts +9 -0
  57. package/vendor/common-nodes/dist/ai/features/prompt/build-effective-system-prompt.js +21 -0
  58. package/vendor/common-nodes/dist/ai/features/prompt/normalize-max-iterations.d.ts +13 -0
  59. package/vendor/common-nodes/dist/ai/features/prompt/normalize-max-iterations.js +23 -0
  60. package/vendor/common-nodes/dist/ai/features/prompt/resolve-chat-provider-model.d.ts +10 -0
  61. package/vendor/common-nodes/dist/ai/features/prompt/resolve-chat-provider-model.js +8 -0
  62. package/vendor/common-nodes/dist/ai/features/run-host-services.d.ts +54 -0
  63. package/vendor/common-nodes/dist/ai/features/run-host-services.js +29 -0
  64. package/vendor/common-nodes/dist/ai/features/scripted-chat-completion-stream.d.ts +17 -0
  65. package/vendor/common-nodes/dist/ai/features/scripted-chat-completion-stream.js +61 -0
  66. package/vendor/common-nodes/dist/ai/features/sub-agent-protocol.d.ts +39 -0
  67. package/vendor/common-nodes/dist/ai/features/sub-agent-protocol.js +43 -0
  68. package/vendor/common-nodes/dist/ai/features/ui-schema/llm-compaction-ui-schema.d.ts +14 -0
  69. package/vendor/common-nodes/dist/ai/features/ui-schema/llm-compaction-ui-schema.js +18 -0
  70. package/vendor/common-nodes/dist/ai/features/ui-schema/llm-panel-ui-schema.d.ts +80 -0
  71. package/vendor/common-nodes/dist/ai/features/ui-schema/llm-panel-ui-schema.js +76 -0
  72. package/vendor/common-nodes/dist/ai/features/ui-schema/llm-recovery-ui-schema.d.ts +113 -0
  73. package/vendor/common-nodes/dist/ai/features/ui-schema/llm-recovery-ui-schema.js +131 -0
  74. package/vendor/common-nodes/dist/ai/features/wait-for-subagent-result.d.ts +6 -0
  75. package/vendor/common-nodes/dist/ai/features/wait-for-subagent-result.js +30 -0
  76. package/vendor/common-nodes/dist/ai/llm-loop/autokick-recovery.d.ts +13 -0
  77. package/vendor/common-nodes/dist/ai/llm-loop/autokick-recovery.js +17 -0
  78. package/vendor/common-nodes/dist/ai/llm-loop/dead-loop-detector.d.ts +28 -0
  79. package/vendor/common-nodes/dist/ai/llm-loop/dead-loop-detector.js +194 -0
  80. package/vendor/common-nodes/dist/ai/llm-loop/llm-loop-reducer.js +36 -0
  81. package/vendor/common-nodes/dist/ai/llm-loop/llm-loop-types.d.ts +35 -0
  82. package/vendor/common-nodes/dist/ai/llm-loop/llm-loop-types.js +19 -0
  83. package/vendor/common-nodes/dist/ai/llm-loop/normalize-llm-recovery-policy.js +52 -9
  84. package/vendor/common-nodes/dist/ai/llm-loop/operators/observe-provider-stream.d.ts +8 -2
  85. package/vendor/common-nodes/dist/ai/llm-loop/operators/observe-provider-stream.js +43 -13
  86. package/vendor/common-nodes/dist/ai/llm-loop/run-llm-loop.d.ts +3 -5
  87. package/vendor/common-nodes/dist/ai/llm-loop/run-llm-loop.js +116 -1
  88. package/vendor/common-nodes/dist/ai/llm-recovery-ui-schema.d.ts +82 -0
  89. package/vendor/common-nodes/dist/ai/llm-recovery-ui-schema.js +95 -0
  90. package/vendor/common-nodes/dist/ai/llm-session-shell.d.ts +4 -9
  91. package/vendor/common-nodes/dist/ai/llm-session-shell.js +2 -4
  92. package/vendor/common-nodes/dist/ai/nodes/critique/node.d.ts +588 -0
  93. package/vendor/common-nodes/dist/ai/nodes/critique/node.js +240 -0
  94. package/vendor/common-nodes/dist/ai/nodes/fake-llm/node.d.ts +571 -0
  95. package/vendor/common-nodes/dist/ai/nodes/fake-llm/node.js +208 -0
  96. package/vendor/common-nodes/dist/ai/nodes/openai-llm/node.d.ts +587 -0
  97. package/vendor/common-nodes/dist/ai/nodes/openai-llm/node.js +91 -0
  98. package/vendor/common-nodes/dist/ai/nodes/review/node.d.ts +593 -0
  99. package/vendor/common-nodes/dist/ai/nodes/review/node.js +240 -0
  100. package/vendor/common-nodes/dist/ai/nodes/sub-agent/node.d.ts +630 -0
  101. package/vendor/common-nodes/dist/ai/nodes/sub-agent/node.js +302 -0
  102. package/vendor/common-nodes/dist/ai/openai/create-chat-completion-stream.js +6 -0
  103. package/vendor/common-nodes/dist/ai/openai/prepare-chat-completion.d.ts +2 -0
  104. package/vendor/common-nodes/dist/ai/openai/prepare-chat-completion.js +18 -0
  105. package/vendor/common-nodes/dist/ai/openai-llm/node.d.ts +246 -0
  106. package/vendor/common-nodes/dist/ai/review/node.d.ts +246 -0
  107. package/vendor/common-nodes/dist/ai/review/node.js +2 -2
  108. package/vendor/common-nodes/dist/ai/sub-agent/node.d.ts +246 -0
  109. package/vendor/common-nodes/dist/ai/sub-agent/node.js +2 -2
  110. package/vendor/common-nodes/dist/catalog.js +7 -5
  111. package/vendor/common-nodes/dist/compile-custom-nodes/node.d.ts +21 -0
  112. package/vendor/common-nodes/dist/compile-custom-nodes/node.js +45 -0
  113. package/vendor/common-nodes/dist/crawl/crawl/node.js +1 -1
  114. package/vendor/common-nodes/dist/crawl/fetch-url/node.js +1 -1
  115. package/vendor/common-nodes/dist/flow/repeat/node.js +6 -1
  116. package/vendor/common-nodes/dist/langflower-tools/emit-registration-tools.d.ts +18 -0
  117. package/vendor/common-nodes/dist/langflower-tools/emit-registration-tools.js +29 -0
  118. package/vendor/common-nodes/dist/langflower-tools/node.d.ts +20 -0
  119. package/vendor/common-nodes/dist/langflower-tools/node.js +77 -0
  120. package/vendor/common-nodes/dist/text/append-file/node.js +1 -1
  121. package/vendor/common-nodes/dist/text/read-file/node.js +1 -1
  122. package/vendor/common-nodes/dist/text/write-file/node.js +1 -1
  123. package/vendor/common-nodes/dist/tools/inventory-tool-round.d.ts +2 -2
  124. package/vendor/common-nodes/package.json +10 -10
  125. package/vendor/compiler/dist/compile-project-nodes.d.ts +2 -1
  126. package/vendor/compiler/dist/compile-project-nodes.js +35 -6
  127. package/vendor/compiler/dist/resolve-host-types.d.ts +0 -5
  128. package/vendor/compiler/dist/resolve-host-types.js +0 -8
  129. package/vendor/node-sdk/dist/node-factory/define-llm-node/define-llm-node.d.ts +1 -1
  130. package/vendor/node-sdk/dist/node-factory/define-llm-node/define-llm-node.js +1 -1
  131. package/vendor/node-sdk/dist/node-factory/define-llm-node/recovery-notice.d.ts +8 -0
  132. package/vendor/node-sdk/dist/node-factory/define-llm-node/recovery-notice.js +14 -0
  133. package/vendor/runtime/dist/runtime-editor.d.ts +5 -1
  134. package/vendor/runtime/dist/runtime-editor.js +19 -0
  135. package/vendor/runtime/dist/runtime-runner.js +17 -17
  136. package/vendor/runtime/dist/runtime.d.ts +2 -1
  137. package/vendor/runtime/dist/runtime.js +1 -0
  138. package/vendor/runtime/dist/testing/workflows/workflow-events.d.ts +8 -6
  139. package/vendor/runtime/dist/testing/workflows/workflow-events.js +19 -31
  140. package/vendor/runtime/dist/types.d.ts +33 -38
  141. package/vendor/runtime/dist/types.js +2 -1
  142. package/vendor/server/dist/bridge/attach-langflower-bridge.js +3 -2
  143. package/vendor/server/dist/bridge/bridge-event-log.js +17 -102
  144. package/vendor/server/dist/bridge/build-execution-context.d.ts +5 -2
  145. package/vendor/server/dist/bridge/build-execution-context.js +45 -5
  146. package/vendor/server/dist/bridge/forward-runner-event.d.ts +1 -1
  147. package/vendor/server/dist/bridge/forward-runner-event.js +7 -12
  148. package/vendor/server/dist/bridge/get-live-wired-tools.d.ts +12 -0
  149. package/vendor/server/dist/bridge/get-live-wired-tools.js +80 -0
  150. package/vendor/server/dist/bridge/langflower-tools-rpc.d.ts +7 -0
  151. package/vendor/server/dist/bridge/langflower-tools-rpc.js +29 -0
  152. package/vendor/server/dist/bridge/settings-draft-controller.js +26 -3
  153. package/vendor/server/dist/bridge/wire-custom-palette-handlers.d.ts +2 -1
  154. package/vendor/server/dist/bridge/wire-custom-palette-handlers.js +3 -5
  155. package/vendor/server/dist/bridge/wire-runner-handlers.js +15 -8
  156. package/vendor/server/dist/checkpoint/run-checkpoint-session.d.ts +1 -1
  157. package/vendor/server/dist/checkpoint/run-checkpoint-session.js +10 -9
  158. package/vendor/server/dist/palette/compile-and-hot-swap-custom-nodes.d.ts +10 -0
  159. package/vendor/server/dist/palette/compile-and-hot-swap-custom-nodes.js +23 -0
  160. package/vendor/server/dist/workflow/apply-editor-mutation.d.ts +5 -0
  161. package/vendor/server/dist/workflow/apply-editor-mutation.js +32 -0
  162. package/vendor/server/skeleton/instructions.md +9 -5
  163. package/vendor/server/skeleton/nodes/my-nodes/README.md +4 -3
  164. package/vendor/server/skeleton/schemas/langflower-config.schema.json +11 -1
  165. package/vendor/server/skeleton/skills/langflower-helper/SKILL.md +49 -19
  166. package/vendor/server/skeleton/skills/langflower-helper/architecture.md +22 -9
  167. package/vendor/server/skeleton/skills/langflower-helper/layout.md +15 -15
  168. package/vendor/server/skeleton/skills/langflower-node-writer/SKILL.md +19 -9
  169. package/vendor/server/skeleton/skills/langflower-workflow-writer/SKILL.md +14 -10
  170. package/vendor/server/skeleton/workflows/starter.json +30 -3
  171. package/vendor/shared/dist/execution/derive-run-settle-outcome.d.ts +1 -1
  172. package/vendor/shared/dist/execution/derive-run-settle-outcome.js +4 -3
  173. package/vendor/shared/dist/execution/derive-run-settle-outcome.test.js +9 -9
  174. package/vendor/shared/dist/langflower-bus-config.d.ts +6 -14
  175. package/vendor/shared/dist/langflower-bus-config.js +4 -12
  176. package/vendor/shared/dist/langflower-config/resolve-wired-tool-options.js +6 -0
  177. package/vendor/shared/dist/langflower-config/resolve-wired-tool-options.test.js +30 -0
  178. package/vendor/shared/dist/langflower-ws-waits.d.ts +7 -14
  179. package/vendor/shared/dist/langflower-ws-waits.js +14 -14
  180. package/vendor/websocket-bridge/dist/bridge-codec.d.ts +1 -0
  181. package/vendor/websocket-bridge/dist/bridge-codec.js +11 -11
  182. package/vendor/websocket-bridge/dist/bridge-frame.js +1 -1
  183. package/vendor/websocket-bridge/dist/bridge-subjects.d.ts +1 -1
  184. package/vendor/websocket-bridge/dist/bridge-subjects.js +2 -2
  185. package/vendor/websocket-bridge/dist/bridge-types.d.ts +13 -1
  186. package/vendor/websocket-bridge/dist/create-client.js +3 -3
  187. package/vendor/websocket-bridge/dist/create-server.js +12 -6
  188. package/vendor/websocket-bridge/package.json +8 -0
  189. package/ui-dist/main-SMO3L7U5.js +0 -311
@@ -0,0 +1,113 @@
1
+ /** Shared Inspector fields for provider/tool recovery policy. */
2
+ export declare const llmRecoveryUiSchema: readonly [{
3
+ readonly field: "streamIdleTimeoutMs";
4
+ readonly type: "number";
5
+ readonly label: "Stream idle timeout (ms, 0 disables)";
6
+ readonly default: 90000;
7
+ readonly min: 0;
8
+ readonly step: 1;
9
+ }, {
10
+ readonly field: "toolTimeoutMs";
11
+ readonly type: "number";
12
+ readonly label: "Tool timeout (ms, 0 disables)";
13
+ readonly default: 60000;
14
+ readonly min: 0;
15
+ readonly step: 1;
16
+ }, {
17
+ readonly field: "subagentTimeoutMs";
18
+ readonly type: "number";
19
+ readonly label: "Sub-Agent timeout (ms, 0 disables)";
20
+ readonly default: 300000;
21
+ readonly min: 0;
22
+ readonly step: 1;
23
+ }, {
24
+ readonly field: "maxTransientRetries";
25
+ readonly type: "number";
26
+ readonly label: "Transient provider retries";
27
+ readonly default: 2;
28
+ readonly min: 0;
29
+ readonly max: 32;
30
+ readonly step: 1;
31
+ }, {
32
+ readonly field: "autokickOnIdle";
33
+ readonly type: "boolean";
34
+ readonly label: "Autokick on idle and dead-loop";
35
+ readonly default: boolean;
36
+ }, {
37
+ readonly field: "deadLoopEnabled";
38
+ readonly type: "boolean";
39
+ readonly label: "Detect repetition dead loops";
40
+ readonly default: boolean;
41
+ }, {
42
+ readonly field: "maxAutokickAttempts";
43
+ readonly type: "number";
44
+ readonly label: "Max autokick reconnects (0 = unlimited)";
45
+ readonly default: number;
46
+ readonly min: 0;
47
+ readonly max: 1000;
48
+ readonly step: 1;
49
+ }, {
50
+ readonly field: "autokickBackoffMs";
51
+ readonly type: "number";
52
+ readonly label: "Autokick backoff base (ms)";
53
+ readonly default: number;
54
+ readonly min: 1000;
55
+ readonly step: 1000;
56
+ }, {
57
+ readonly field: "autokickMaxBackoffMs";
58
+ readonly type: "number";
59
+ readonly label: "Autokick backoff clamp (ms)";
60
+ readonly default: number;
61
+ readonly min: 1000;
62
+ readonly step: 1000;
63
+ }, {
64
+ readonly field: "autokickUserMessage";
65
+ readonly type: "string";
66
+ readonly label: "Autokick kick message";
67
+ readonly default: string;
68
+ }, {
69
+ readonly field: "autokickPenaltyFrequency";
70
+ readonly type: "number";
71
+ readonly label: "Autokick frequency_penalty delta";
72
+ readonly default: number;
73
+ readonly min: -2;
74
+ readonly max: 2;
75
+ readonly step: 0.1;
76
+ }, {
77
+ readonly field: "autokickPenaltyPresence";
78
+ readonly type: "number";
79
+ readonly label: "Autokick presence_penalty delta";
80
+ readonly default: number;
81
+ readonly min: -2;
82
+ readonly max: 2;
83
+ readonly step: 0.1;
84
+ }, {
85
+ readonly field: "deadLoopMaxWindowTokens";
86
+ readonly type: "number";
87
+ readonly label: "Dead-loop window (tokens)";
88
+ readonly default: number;
89
+ readonly min: 10;
90
+ readonly max: 8000;
91
+ readonly step: 1;
92
+ }, {
93
+ readonly field: "deadLoopConsecutiveThreshold";
94
+ readonly type: "number";
95
+ readonly label: "Dead-loop consecutive identical deltas";
96
+ readonly default: number;
97
+ readonly min: 1;
98
+ readonly step: 1;
99
+ }, {
100
+ readonly field: "deadLoopMinRepetitions";
101
+ readonly type: "number";
102
+ readonly label: "Dead-loop cyclic repetitions";
103
+ readonly default: number;
104
+ readonly min: 1;
105
+ readonly step: 1;
106
+ }, {
107
+ readonly field: "deadLoopMinPatternTokens";
108
+ readonly type: "number";
109
+ readonly label: "Dead-loop min pattern tokens";
110
+ readonly default: number;
111
+ readonly min: 1;
112
+ readonly step: 1;
113
+ }];
@@ -0,0 +1,131 @@
1
+ import { DEFAULT_LLM_RECOVERY_POLICY } from '../llm-loop/llm-loop-types.js';
2
+ /** Shared Inspector fields for provider/tool recovery policy. */
3
+ export const llmRecoveryUiSchema = [
4
+ {
5
+ field: 'streamIdleTimeoutMs',
6
+ type: 'number',
7
+ label: 'Stream idle timeout (ms, 0 disables)',
8
+ default: 90000,
9
+ min: 0,
10
+ step: 1,
11
+ },
12
+ {
13
+ field: 'toolTimeoutMs',
14
+ type: 'number',
15
+ label: 'Tool timeout (ms, 0 disables)',
16
+ default: 60000,
17
+ min: 0,
18
+ step: 1,
19
+ },
20
+ {
21
+ field: 'subagentTimeoutMs',
22
+ type: 'number',
23
+ label: 'Sub-Agent timeout (ms, 0 disables)',
24
+ default: 300000,
25
+ min: 0,
26
+ step: 1,
27
+ },
28
+ {
29
+ field: 'maxTransientRetries',
30
+ type: 'number',
31
+ label: 'Transient provider retries',
32
+ default: 2,
33
+ min: 0,
34
+ max: 32,
35
+ step: 1,
36
+ },
37
+ {
38
+ field: 'autokickOnIdle',
39
+ type: 'boolean',
40
+ label: 'Autokick on idle and dead-loop',
41
+ default: DEFAULT_LLM_RECOVERY_POLICY.autokickOnIdle,
42
+ },
43
+ {
44
+ field: 'deadLoopEnabled',
45
+ type: 'boolean',
46
+ label: 'Detect repetition dead loops',
47
+ default: DEFAULT_LLM_RECOVERY_POLICY.deadLoopEnabled,
48
+ },
49
+ {
50
+ field: 'maxAutokickAttempts',
51
+ type: 'number',
52
+ label: 'Max autokick reconnects (0 = unlimited)',
53
+ default: DEFAULT_LLM_RECOVERY_POLICY.maxAutokickAttempts,
54
+ min: 0,
55
+ max: 1000,
56
+ step: 1,
57
+ },
58
+ {
59
+ field: 'autokickBackoffMs',
60
+ type: 'number',
61
+ label: 'Autokick backoff base (ms)',
62
+ default: DEFAULT_LLM_RECOVERY_POLICY.autokickBackoffMs,
63
+ min: 1000,
64
+ step: 1000,
65
+ },
66
+ {
67
+ field: 'autokickMaxBackoffMs',
68
+ type: 'number',
69
+ label: 'Autokick backoff clamp (ms)',
70
+ default: DEFAULT_LLM_RECOVERY_POLICY.autokickMaxBackoffMs,
71
+ min: 1000,
72
+ step: 1000,
73
+ },
74
+ {
75
+ field: 'autokickUserMessage',
76
+ type: 'string',
77
+ label: 'Autokick kick message',
78
+ default: DEFAULT_LLM_RECOVERY_POLICY.autokickUserMessage,
79
+ },
80
+ {
81
+ field: 'autokickPenaltyFrequency',
82
+ type: 'number',
83
+ label: 'Autokick frequency_penalty delta',
84
+ default: DEFAULT_LLM_RECOVERY_POLICY.autokickPenaltyDelta.frequency,
85
+ min: -2,
86
+ max: 2,
87
+ step: 0.1,
88
+ },
89
+ {
90
+ field: 'autokickPenaltyPresence',
91
+ type: 'number',
92
+ label: 'Autokick presence_penalty delta',
93
+ default: DEFAULT_LLM_RECOVERY_POLICY.autokickPenaltyDelta.presence,
94
+ min: -2,
95
+ max: 2,
96
+ step: 0.1,
97
+ },
98
+ {
99
+ field: 'deadLoopMaxWindowTokens',
100
+ type: 'number',
101
+ label: 'Dead-loop window (tokens)',
102
+ default: DEFAULT_LLM_RECOVERY_POLICY.deadLoop.maxWindowTokens,
103
+ min: 10,
104
+ max: 8000,
105
+ step: 1,
106
+ },
107
+ {
108
+ field: 'deadLoopConsecutiveThreshold',
109
+ type: 'number',
110
+ label: 'Dead-loop consecutive identical deltas',
111
+ default: DEFAULT_LLM_RECOVERY_POLICY.deadLoop.consecutiveThreshold,
112
+ min: 1,
113
+ step: 1,
114
+ },
115
+ {
116
+ field: 'deadLoopMinRepetitions',
117
+ type: 'number',
118
+ label: 'Dead-loop cyclic repetitions',
119
+ default: DEFAULT_LLM_RECOVERY_POLICY.deadLoop.minRepetitions,
120
+ min: 1,
121
+ step: 1,
122
+ },
123
+ {
124
+ field: 'deadLoopMinPatternTokens',
125
+ type: 'number',
126
+ label: 'Dead-loop min pattern tokens',
127
+ default: DEFAULT_LLM_RECOVERY_POLICY.deadLoop.minPatternTokens,
128
+ min: 1,
129
+ step: 1,
130
+ },
131
+ ];
@@ -0,0 +1,6 @@
1
+ import { type Observable } from 'rxjs';
2
+ /**
3
+ * Agent-node internal router: first matching `subagentResult` for `callId`,
4
+ * aborted when the tool-loop AbortSignal fires (turn Observable teardown).
5
+ */
6
+ export declare const waitForSubagentResult: (result$: Observable<unknown>, callId: string, signal: AbortSignal, timeoutMs?: number) => Promise<string>;
@@ -0,0 +1,30 @@
1
+ import { filter, firstValueFrom, fromEvent, map, take, takeUntil, timeout, } from 'rxjs';
2
+ import { isSubAgentResultPayload, } from './sub-agent-protocol.js';
3
+ const normalizeResult = (value) => {
4
+ if (isSubAgentResultPayload(value)) {
5
+ return value;
6
+ }
7
+ if (typeof value === 'string') {
8
+ try {
9
+ const parsed = JSON.parse(value);
10
+ return isSubAgentResultPayload(parsed) ? parsed : null;
11
+ }
12
+ catch {
13
+ return null;
14
+ }
15
+ }
16
+ return null;
17
+ };
18
+ const observeSubagentResult = (result$, callId, signal, timeoutMs = 0) => {
19
+ const matching$ = result$.pipe(map(normalizeResult), filter((payload) => payload !== null && payload.callId === callId), map((payload) => payload.result), take(1), takeUntil(fromEvent(signal, 'abort')));
20
+ return timeoutMs > 0
21
+ ? matching$.pipe(timeout({ first: timeoutMs }))
22
+ : matching$;
23
+ };
24
+ /**
25
+ * Agent-node internal router: first matching `subagentResult` for `callId`,
26
+ * aborted when the tool-loop AbortSignal fires (turn Observable teardown).
27
+ */
28
+ export const waitForSubagentResult = (result$, callId, signal, timeoutMs = 0) => signal.aborted
29
+ ? Promise.reject(new Error('Sub-Agent wait aborted'))
30
+ : firstValueFrom(observeSubagentResult(result$, callId, signal, timeoutMs));
@@ -0,0 +1,13 @@
1
+ export declare const autokickBackoffMs: (attempt: number, baseMs: number, maxMs: number) => number;
2
+ export declare const clampChatPenalty: (value: number) => number;
3
+ export declare const autokickPenalties: (attempt: number, delta: {
4
+ readonly frequency: number;
5
+ readonly presence: number;
6
+ }) => {
7
+ readonly frequency: number;
8
+ readonly presence: number;
9
+ };
10
+ export declare const autokickKickUserTurn: (content: string) => {
11
+ readonly role: "user";
12
+ readonly content: string;
13
+ };
@@ -0,0 +1,17 @@
1
+ export const autokickBackoffMs = (attempt, baseMs, maxMs) => {
2
+ const safeAttempt = Math.max(1, attempt);
3
+ const delay = baseMs * 2 ** (safeAttempt - 1);
4
+ return Math.min(delay, maxMs);
5
+ };
6
+ export const clampChatPenalty = (value) => Math.min(2, Math.max(-2, value));
7
+ export const autokickPenalties = (attempt, delta) => {
8
+ const safeAttempt = Math.max(1, attempt);
9
+ return {
10
+ frequency: clampChatPenalty(delta.frequency * safeAttempt),
11
+ presence: clampChatPenalty(delta.presence * safeAttempt),
12
+ };
13
+ };
14
+ export const autokickKickUserTurn = (content) => ({
15
+ role: 'user',
16
+ content,
17
+ });
@@ -0,0 +1,28 @@
1
+ export type DeadLoopChannel = 'reasoning' | 'draft';
2
+ export type DeadLoopDetectorOptions = {
3
+ readonly maxWindowTokens?: number;
4
+ readonly consecutiveThreshold?: number;
5
+ readonly minRepetitions?: number;
6
+ readonly minPatternTokens?: number;
7
+ };
8
+ type DeadLoopError = {
9
+ readonly name: 'DeadLoopError';
10
+ readonly message: string;
11
+ readonly partialText: string;
12
+ readonly lastTokens: readonly string[];
13
+ readonly reason: 'consecutive' | 'cyclic';
14
+ readonly channel: DeadLoopChannel;
15
+ };
16
+ type DeadLoopPushResult = {
17
+ readonly ok: true;
18
+ } | {
19
+ readonly ok: false;
20
+ readonly error: DeadLoopError;
21
+ };
22
+ export type DeadLoopDetector = {
23
+ readonly hashLookups: number;
24
+ readonly exactCompareTokenVisits: number;
25
+ readonly push: (text: string) => DeadLoopPushResult;
26
+ };
27
+ export declare const createDeadLoopDetector: (channel: DeadLoopChannel, options?: DeadLoopDetectorOptions) => DeadLoopDetector;
28
+ export {};
@@ -0,0 +1,194 @@
1
+ const DEFAULT_DEAD_LOOP_OPTIONS = {
2
+ maxWindowTokens: 1_000,
3
+ consecutiveThreshold: 5,
4
+ minRepetitions: 3,
5
+ minPatternTokens: 2,
6
+ };
7
+ const BASE1 = 911_382_323;
8
+ const BASE2 = 972_663_749;
9
+ const FNV_OFFSET1 = 2_166_136_261;
10
+ const FNV_OFFSET2 = 84_696_351;
11
+ const FNV_PRIME = 16_777_619;
12
+ const hashString = (text, offset) => {
13
+ let hash = offset >>> 0;
14
+ for (let index = 0; index < text.length; index += 1) {
15
+ hash ^= text.charCodeAt(index);
16
+ hash = Math.imul(hash, FNV_PRIME);
17
+ }
18
+ return hash >>> 0;
19
+ };
20
+ const createPowTable = (base, maxExponent) => {
21
+ const table = new Uint32Array(maxExponent + 1);
22
+ table[0] = 1;
23
+ for (let exponent = 1; exponent <= maxExponent; exponent += 1) {
24
+ table[exponent] = Math.imul(table[exponent - 1] ?? 1, base) >>> 0;
25
+ }
26
+ return table;
27
+ };
28
+ export const createDeadLoopDetector = (channel, options = {}) => {
29
+ const maxWindowTokens = options.maxWindowTokens ?? DEFAULT_DEAD_LOOP_OPTIONS.maxWindowTokens;
30
+ const consecutiveThreshold = options.consecutiveThreshold ??
31
+ DEFAULT_DEAD_LOOP_OPTIONS.consecutiveThreshold;
32
+ const minRepetitions = options.minRepetitions ?? DEFAULT_DEAD_LOOP_OPTIONS.minRepetitions;
33
+ const minPatternTokens = options.minPatternTokens ?? DEFAULT_DEAD_LOOP_OPTIONS.minPatternTokens;
34
+ const capacity = Math.max(1, maxWindowTokens);
35
+ const tokens = new Array(capacity);
36
+ const hashes1 = new Uint32Array(capacity);
37
+ const hashes2 = new Uint32Array(capacity);
38
+ const prefix1 = new Uint32Array(capacity + 1);
39
+ const prefix2 = new Uint32Array(capacity + 1);
40
+ const pow1 = createPowTable(BASE1, capacity);
41
+ const pow2 = createPowTable(BASE2, capacity);
42
+ const stats = {
43
+ hashLookups: 0,
44
+ exactCompareTokenVisits: 0,
45
+ };
46
+ let head = 0;
47
+ let size = 0;
48
+ let consecutiveCount = 0;
49
+ const physicalIndex = (logical) => (head + logical) % capacity;
50
+ const tokenAt = (logical) => tokens[physicalIndex(logical)] ?? '';
51
+ const dropOldest = () => {
52
+ const removedPhysical = head;
53
+ const removed1 = hashes1[removedPhysical] ?? 0;
54
+ const removed2 = hashes2[removedPhysical] ?? 0;
55
+ for (let logical = 1; logical < size; logical += 1) {
56
+ prefix1[logical] =
57
+ ((prefix1[logical + 1] ?? 0) -
58
+ Math.imul(removed1, pow1[logical] ?? 1)) >>>
59
+ 0;
60
+ prefix2[logical] =
61
+ ((prefix2[logical + 1] ?? 0) -
62
+ Math.imul(removed2, pow2[logical] ?? 1)) >>>
63
+ 0;
64
+ }
65
+ prefix1[0] = 0;
66
+ prefix2[0] = 0;
67
+ head = (head + 1) % capacity;
68
+ size -= 1;
69
+ };
70
+ const appendPrefix = (physical) => {
71
+ prefix1[size] =
72
+ (Math.imul(prefix1[size - 1] ?? 0, BASE1) +
73
+ (hashes1[physical] ?? 0)) >>>
74
+ 0;
75
+ prefix2[size] =
76
+ (Math.imul(prefix2[size - 1] ?? 0, BASE2) +
77
+ (hashes2[physical] ?? 0)) >>>
78
+ 0;
79
+ };
80
+ const rangeHashesEqual = (leftStart, rightStart, length) => {
81
+ stats.hashLookups += 1;
82
+ const leftEnd = leftStart + length;
83
+ const rightEnd = rightStart + length;
84
+ const powA = pow1[length] ?? 1;
85
+ const powB = pow2[length] ?? 1;
86
+ const left1 = ((prefix1[leftEnd] ?? 0) -
87
+ Math.imul(prefix1[leftStart] ?? 0, powA)) >>>
88
+ 0;
89
+ const right1 = ((prefix1[rightEnd] ?? 0) -
90
+ Math.imul(prefix1[rightStart] ?? 0, powA)) >>>
91
+ 0;
92
+ if (left1 !== right1) {
93
+ return false;
94
+ }
95
+ const left2 = ((prefix2[leftEnd] ?? 0) -
96
+ Math.imul(prefix2[leftStart] ?? 0, powB)) >>>
97
+ 0;
98
+ const right2 = ((prefix2[rightEnd] ?? 0) -
99
+ Math.imul(prefix2[rightStart] ?? 0, powB)) >>>
100
+ 0;
101
+ return left2 === right2;
102
+ };
103
+ const sliceTokens = (start, end) => {
104
+ const sliced = [];
105
+ for (let logical = start; logical < end; logical += 1) {
106
+ sliced.push(tokenAt(logical));
107
+ }
108
+ return sliced;
109
+ };
110
+ const joinTokens = () => {
111
+ let text = '';
112
+ for (let logical = 0; logical < size; logical += 1) {
113
+ text += tokenAt(logical);
114
+ }
115
+ return text;
116
+ };
117
+ const exactBlocksMatch = (patternLength) => {
118
+ const baseStart = size - patternLength;
119
+ for (let repeat = 1; repeat < minRepetitions; repeat += 1) {
120
+ const otherStart = size - (repeat + 1) * patternLength;
121
+ for (let offset = 0; offset < patternLength; offset += 1) {
122
+ stats.exactCompareTokenVisits += 1;
123
+ if (tokenAt(baseStart + offset) !== tokenAt(otherStart + offset)) {
124
+ return false;
125
+ }
126
+ }
127
+ }
128
+ return true;
129
+ };
130
+ const fail = (reason, lastTokens) => ({
131
+ ok: false,
132
+ error: {
133
+ name: 'DeadLoopError',
134
+ message: reason === 'consecutive'
135
+ ? `Consecutive token repetition on ${channel}`
136
+ : `Cyclic repetition on ${channel}`,
137
+ partialText: joinTokens(),
138
+ lastTokens,
139
+ reason,
140
+ channel,
141
+ },
142
+ });
143
+ const detectCyclic = () => {
144
+ const maxPatternLength = Math.floor(size / minRepetitions);
145
+ for (let patternLength = minPatternTokens; patternLength <= maxPatternLength; patternLength += 1) {
146
+ const blockStart = size - patternLength;
147
+ let repeats = true;
148
+ for (let repeat = 1; repeat < minRepetitions; repeat += 1) {
149
+ const start = size - (repeat + 1) * patternLength;
150
+ if (!rangeHashesEqual(start, blockStart, patternLength)) {
151
+ repeats = false;
152
+ break;
153
+ }
154
+ }
155
+ if (!repeats) {
156
+ continue;
157
+ }
158
+ if (exactBlocksMatch(patternLength)) {
159
+ return fail('cyclic', sliceTokens(blockStart, size));
160
+ }
161
+ }
162
+ return undefined;
163
+ };
164
+ const push = (text) => {
165
+ if (text.length === 0) {
166
+ return { ok: true };
167
+ }
168
+ const previous = size === 0 ? undefined : tokenAt(size - 1);
169
+ consecutiveCount = previous === text ? consecutiveCount + 1 : 1;
170
+ if (size === capacity) {
171
+ dropOldest();
172
+ }
173
+ const physical = physicalIndex(size);
174
+ tokens[physical] = text;
175
+ hashes1[physical] = hashString(text, FNV_OFFSET1);
176
+ hashes2[physical] = hashString(text, FNV_OFFSET2);
177
+ size += 1;
178
+ appendPrefix(physical);
179
+ if (consecutiveCount >= consecutiveThreshold) {
180
+ const start = Math.max(0, size - consecutiveCount);
181
+ return fail('consecutive', sliceTokens(start, size));
182
+ }
183
+ return detectCyclic() ?? { ok: true };
184
+ };
185
+ return {
186
+ get hashLookups() {
187
+ return stats.hashLookups;
188
+ },
189
+ get exactCompareTokenVisits() {
190
+ return stats.exactCompareTokenVisits;
191
+ },
192
+ push,
193
+ };
194
+ };
@@ -1,3 +1,4 @@
1
+ import { autokickKickUserTurn } from './autokick-recovery.js';
1
2
  const assertNever = (value) => {
2
3
  throw new Error(`Unhandled LLM loop action: ${JSON.stringify(value)}`);
3
4
  };
@@ -81,6 +82,17 @@ export const reduceLlmLoop = (state, action) => {
81
82
  idleMs: action.idleMs,
82
83
  },
83
84
  };
85
+ case 'stream.dead-loop':
86
+ return {
87
+ ...state,
88
+ phase: 'suspended',
89
+ committedMessages: [...state.roundCheckpoint],
90
+ suspendedBy: {
91
+ kind: 'dead-loop',
92
+ channel: action.channel,
93
+ reason: action.reason,
94
+ },
95
+ };
84
96
  case 'provider.failed':
85
97
  return {
86
98
  ...state,
@@ -144,6 +156,27 @@ export const reduceLlmLoop = (state, action) => {
144
156
  suspendedBy: undefined,
145
157
  failure: undefined,
146
158
  };
159
+ case 'autokick.scheduled':
160
+ return {
161
+ ...state,
162
+ phase: 'prepare',
163
+ committedMessages: action.kickUserMessage === undefined
164
+ ? [...state.roundCheckpoint]
165
+ : [
166
+ ...state.roundCheckpoint,
167
+ autokickKickUserTurn(action.kickUserMessage),
168
+ ],
169
+ autokickAttempts: state.autokickAttempts + 1,
170
+ autokickKickAttempts: action.kickUserMessage === undefined
171
+ ? state.autokickKickAttempts
172
+ : state.autokickKickAttempts + 1,
173
+ lastAutokickAt: action.atMs,
174
+ transientAttempts: 0,
175
+ partial: { reasoning: '', draft: '' },
176
+ pendingToolCalls: [],
177
+ suspendedBy: undefined,
178
+ failure: undefined,
179
+ };
147
180
  case 'steer.received': {
148
181
  const text = action.text?.trim() ?? '';
149
182
  const messages = text.length === 0
@@ -158,6 +191,9 @@ export const reduceLlmLoop = (state, action) => {
158
191
  committedMessages: messages,
159
192
  roundCheckpoint: messages,
160
193
  transientAttempts: 0,
194
+ autokickAttempts: 0,
195
+ autokickKickAttempts: 0,
196
+ lastAutokickAt: undefined,
161
197
  partial: { reasoning: '', draft: '' },
162
198
  pendingToolCalls: [],
163
199
  suspendedBy: undefined,
@@ -13,6 +13,10 @@ type LlmSuspendReason = {
13
13
  } | {
14
14
  readonly kind: 'stream-idle';
15
15
  readonly idleMs: number;
16
+ } | {
17
+ readonly kind: 'dead-loop';
18
+ readonly channel: 'reasoning' | 'draft';
19
+ readonly reason: 'consecutive' | 'cyclic';
16
20
  } | {
17
21
  readonly kind: 'provider-failure';
18
22
  readonly failure: LlmFailure;
@@ -30,6 +34,10 @@ export type LlmLoopState = {
30
34
  readonly toolCalls?: readonly ChatCompletionToolCall[];
31
35
  };
32
36
  readonly pendingToolCalls: readonly ChatCompletionToolCall[];
37
+ readonly autokickAttempts: number;
38
+ /** Kick-mode autokicks only; HTTP join does not bump penalties. */
39
+ readonly autokickKickAttempts: number;
40
+ readonly lastAutokickAt?: number | undefined;
33
41
  readonly openSpawnCallId?: string | undefined;
34
42
  readonly suspendedBy?: LlmSuspendReason | undefined;
35
43
  readonly failure?: LlmFailure | undefined;
@@ -52,6 +60,10 @@ export type LlmLoopAction = {
52
60
  } | {
53
61
  readonly type: 'stream.idle';
54
62
  readonly idleMs: number;
63
+ } | {
64
+ readonly type: 'stream.dead-loop';
65
+ readonly channel: 'reasoning' | 'draft';
66
+ readonly reason: 'consecutive' | 'cyclic';
55
67
  } | {
56
68
  readonly type: 'provider.failed';
57
69
  readonly failure: LlmFailure;
@@ -66,6 +78,11 @@ export type LlmLoopAction = {
66
78
  readonly type: 'subagent.completed';
67
79
  } | {
68
80
  readonly type: 'retry.scheduled';
81
+ } | {
82
+ readonly type: 'autokick.scheduled';
83
+ /** Omit for HTTP replay-only (no kick user turn). */
84
+ readonly kickUserMessage?: string;
85
+ readonly atMs: number;
69
86
  } | {
70
87
  readonly type: 'steer.received';
71
88
  readonly text?: string;
@@ -77,6 +94,12 @@ export type LlmLoopAction = {
77
94
  } | {
78
95
  readonly type: 'cancel.requested';
79
96
  };
97
+ type LlmDeadLoopPolicy = {
98
+ readonly maxWindowTokens: number;
99
+ readonly consecutiveThreshold: number;
100
+ readonly minRepetitions: number;
101
+ readonly minPatternTokens: number;
102
+ };
80
103
  export type LlmRecoveryPolicy = {
81
104
  readonly streamIdleTimeoutMs: number;
82
105
  readonly toolTimeoutMs: number;
@@ -84,7 +107,19 @@ export type LlmRecoveryPolicy = {
84
107
  readonly maxTransientRetries: number;
85
108
  readonly retryBaseDelayMs: number;
86
109
  readonly maxToolResultChars: number;
110
+ readonly autokickOnIdle: boolean;
111
+ readonly deadLoopEnabled: boolean;
112
+ readonly maxAutokickAttempts: number;
113
+ readonly autokickBackoffMs: number;
114
+ readonly autokickMaxBackoffMs: number;
115
+ readonly autokickUserMessage: string;
116
+ readonly autokickPenaltyDelta: {
117
+ readonly frequency: number;
118
+ readonly presence: number;
119
+ };
120
+ readonly deadLoop: LlmDeadLoopPolicy;
87
121
  };
122
+ export declare const DEFAULT_AUTOKICK_USER_MESSAGE = "I notice you are repeating yourself. Please stop and provide a concise answer.";
88
123
  export declare const DEFAULT_LLM_RECOVERY_POLICY: LlmRecoveryPolicy;
89
124
  export declare const initialLlmLoopState: (messages: readonly ChatCompletionMessage[]) => LlmLoopState;
90
125
  export {};