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,125 @@
1
+ import type { ChatCompletionMessage, ChatCompletionToolCall } from '../chat-completion-stream.js';
2
+ type LlmFailureKind = 'authentication' | 'configuration' | 'context-overflow' | 'output-truncated' | 'rate-limit' | 'provider-unavailable' | 'stream-idle' | 'network' | 'tool-timeout' | 'subagent-timeout' | 'protocol' | 'unknown';
3
+ export type LlmFailure = {
4
+ readonly kind: LlmFailureKind;
5
+ readonly message: string;
6
+ readonly recoverable: boolean;
7
+ readonly status?: number;
8
+ readonly retryAfterMs?: number;
9
+ readonly rawContentType?: string;
10
+ };
11
+ type LlmSuspendReason = {
12
+ readonly kind: 'user-pause';
13
+ } | {
14
+ readonly kind: 'stream-idle';
15
+ readonly idleMs: number;
16
+ } | {
17
+ readonly kind: 'dead-loop';
18
+ readonly channel: 'reasoning' | 'draft';
19
+ readonly reason: 'consecutive' | 'cyclic';
20
+ } | {
21
+ readonly kind: 'provider-failure';
22
+ readonly failure: LlmFailure;
23
+ };
24
+ type LlmLoopPhase = 'prepare' | 'streaming' | 'tools' | 'waiting-subagent' | 'suspended' | 'complete' | 'failed' | 'cancelled';
25
+ export type LlmLoopState = {
26
+ readonly phase: LlmLoopPhase;
27
+ readonly committedMessages: readonly ChatCompletionMessage[];
28
+ readonly roundCheckpoint: readonly ChatCompletionMessage[];
29
+ readonly iteration: number;
30
+ readonly transientAttempts: number;
31
+ readonly partial: {
32
+ readonly reasoning: string;
33
+ readonly draft: string;
34
+ readonly toolCalls?: readonly ChatCompletionToolCall[];
35
+ };
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;
41
+ readonly openSpawnCallId?: string | undefined;
42
+ readonly suspendedBy?: LlmSuspendReason | undefined;
43
+ readonly failure?: LlmFailure | undefined;
44
+ };
45
+ export type LlmLoopAction = {
46
+ readonly type: 'round.prepared';
47
+ readonly messages: readonly ChatCompletionMessage[];
48
+ } | {
49
+ readonly type: 'stream.reasoning';
50
+ readonly text: string;
51
+ } | {
52
+ readonly type: 'stream.draft';
53
+ readonly text: string;
54
+ } | {
55
+ readonly type: 'stream.done';
56
+ readonly text: string;
57
+ readonly toolCalls?: readonly ChatCompletionToolCall[];
58
+ } | {
59
+ readonly type: 'stream.paused';
60
+ } | {
61
+ readonly type: 'stream.idle';
62
+ readonly idleMs: number;
63
+ } | {
64
+ readonly type: 'stream.dead-loop';
65
+ readonly channel: 'reasoning' | 'draft';
66
+ readonly reason: 'consecutive' | 'cyclic';
67
+ } | {
68
+ readonly type: 'provider.failed';
69
+ readonly failure: LlmFailure;
70
+ } | {
71
+ readonly type: 'tool.completed';
72
+ readonly call: ChatCompletionToolCall;
73
+ readonly result: string;
74
+ } | {
75
+ readonly type: 'subagent.waiting';
76
+ readonly callId: string;
77
+ } | {
78
+ readonly type: 'subagent.completed';
79
+ } | {
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;
86
+ } | {
87
+ readonly type: 'steer.received';
88
+ readonly text?: string;
89
+ } | {
90
+ readonly type: 'round.completed';
91
+ } | {
92
+ readonly type: 'failure.fatal';
93
+ readonly failure: LlmFailure;
94
+ } | {
95
+ readonly type: 'cancel.requested';
96
+ };
97
+ type LlmDeadLoopPolicy = {
98
+ readonly maxWindowTokens: number;
99
+ readonly consecutiveThreshold: number;
100
+ readonly minRepetitions: number;
101
+ readonly minPatternTokens: number;
102
+ };
103
+ export type LlmRecoveryPolicy = {
104
+ readonly streamIdleTimeoutMs: number;
105
+ readonly toolTimeoutMs: number;
106
+ readonly subagentTimeoutMs: number;
107
+ readonly maxTransientRetries: number;
108
+ readonly retryBaseDelayMs: number;
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;
121
+ };
122
+ export declare const DEFAULT_AUTOKICK_USER_MESSAGE = "I notice you are repeating yourself. Please stop and provide a concise answer.";
123
+ export declare const DEFAULT_LLM_RECOVERY_POLICY: LlmRecoveryPolicy;
124
+ export declare const initialLlmLoopState: (messages: readonly ChatCompletionMessage[]) => LlmLoopState;
125
+ export {};
@@ -0,0 +1,39 @@
1
+ export const DEFAULT_AUTOKICK_USER_MESSAGE = 'I notice you are repeating yourself. Please stop and provide a concise answer.';
2
+ export const DEFAULT_LLM_RECOVERY_POLICY = {
3
+ streamIdleTimeoutMs: 90_000,
4
+ toolTimeoutMs: 60_000,
5
+ subagentTimeoutMs: 300_000,
6
+ maxTransientRetries: 2,
7
+ retryBaseDelayMs: 1_000,
8
+ maxToolResultChars: 40_000,
9
+ autokickOnIdle: true,
10
+ deadLoopEnabled: true,
11
+ maxAutokickAttempts: 0,
12
+ autokickBackoffMs: 60_000,
13
+ autokickMaxBackoffMs: 960_000,
14
+ autokickUserMessage: DEFAULT_AUTOKICK_USER_MESSAGE,
15
+ autokickPenaltyDelta: {
16
+ frequency: 0.3,
17
+ presence: 0.3,
18
+ },
19
+ deadLoop: {
20
+ maxWindowTokens: 1_000,
21
+ consecutiveThreshold: 5,
22
+ minRepetitions: 3,
23
+ minPatternTokens: 2,
24
+ },
25
+ };
26
+ export const initialLlmLoopState = (messages) => ({
27
+ phase: 'prepare',
28
+ committedMessages: [...messages],
29
+ roundCheckpoint: [...messages],
30
+ iteration: 0,
31
+ transientAttempts: 0,
32
+ partial: {
33
+ reasoning: '',
34
+ draft: '',
35
+ },
36
+ pendingToolCalls: [],
37
+ autokickAttempts: 0,
38
+ autokickKickAttempts: 0,
39
+ });
@@ -0,0 +1,2 @@
1
+ import { type LlmRecoveryPolicy } from './llm-loop-types.js';
2
+ export declare const normalizeLlmRecoveryPolicy: (params: Readonly<Record<string, unknown>>) => LlmRecoveryPolicy;
@@ -0,0 +1,59 @@
1
+ import { DEFAULT_AUTOKICK_USER_MESSAGE, DEFAULT_LLM_RECOVERY_POLICY, } from './llm-loop-types.js';
2
+ const normalizePositiveInteger = (value, fallback, max) => {
3
+ const number = typeof value === 'number' ? value : Number(value);
4
+ if (!Number.isFinite(number) || number < 0) {
5
+ return fallback;
6
+ }
7
+ return Math.min(max, Math.floor(number));
8
+ };
9
+ const normalizeBoolean = (value, fallback) => typeof value === 'boolean' ? value : fallback;
10
+ const normalizePenalty = (value, fallback) => {
11
+ const number = typeof value === 'number' ? value : Number(value);
12
+ if (!Number.isFinite(number)) {
13
+ return fallback;
14
+ }
15
+ return Math.min(2, Math.max(-2, number));
16
+ };
17
+ const readRecord = (value) => value !== null && typeof value === 'object' && !Array.isArray(value)
18
+ ? value
19
+ : undefined;
20
+ const nestedDeadLoop = (params) => readRecord(params['deadLoop']) ?? {};
21
+ const nestedPenalty = (params) => readRecord(params['autokickPenaltyDelta']) ?? {};
22
+ export const normalizeLlmRecoveryPolicy = (params) => {
23
+ const deadLoop = nestedDeadLoop(params);
24
+ const penalty = nestedPenalty(params);
25
+ const autokickBackoffMs = Math.max(1_000, normalizePositiveInteger(params['autokickBackoffMs'], DEFAULT_LLM_RECOVERY_POLICY.autokickBackoffMs, 3_600_000));
26
+ const autokickMaxBackoffMs = Math.max(autokickBackoffMs, normalizePositiveInteger(params['autokickMaxBackoffMs'], DEFAULT_LLM_RECOVERY_POLICY.autokickMaxBackoffMs, 3_600_000));
27
+ const kick = typeof params['autokickUserMessage'] === 'string' &&
28
+ params['autokickUserMessage'].trim().length > 0
29
+ ? params['autokickUserMessage'].trim()
30
+ : DEFAULT_AUTOKICK_USER_MESSAGE;
31
+ return {
32
+ streamIdleTimeoutMs: normalizePositiveInteger(params['streamIdleTimeoutMs'], DEFAULT_LLM_RECOVERY_POLICY.streamIdleTimeoutMs, 3_600_000),
33
+ toolTimeoutMs: normalizePositiveInteger(params['toolTimeoutMs'], DEFAULT_LLM_RECOVERY_POLICY.toolTimeoutMs, 3_600_000),
34
+ subagentTimeoutMs: normalizePositiveInteger(params['subagentTimeoutMs'], DEFAULT_LLM_RECOVERY_POLICY.subagentTimeoutMs, 86_400_000),
35
+ maxTransientRetries: normalizePositiveInteger(params['maxTransientRetries'], DEFAULT_LLM_RECOVERY_POLICY.maxTransientRetries, 10),
36
+ retryBaseDelayMs: normalizePositiveInteger(params['retryBaseDelayMs'], DEFAULT_LLM_RECOVERY_POLICY.retryBaseDelayMs, 60_000),
37
+ maxToolResultChars: normalizePositiveInteger(params['maxToolResultChars'], DEFAULT_LLM_RECOVERY_POLICY.maxToolResultChars, 1_000_000),
38
+ autokickOnIdle: normalizeBoolean(params['autokickOnIdle'], DEFAULT_LLM_RECOVERY_POLICY.autokickOnIdle),
39
+ deadLoopEnabled: normalizeBoolean(params['deadLoopEnabled'], DEFAULT_LLM_RECOVERY_POLICY.deadLoopEnabled),
40
+ maxAutokickAttempts: normalizePositiveInteger(params['maxAutokickAttempts'], DEFAULT_LLM_RECOVERY_POLICY.maxAutokickAttempts, 1_000),
41
+ autokickBackoffMs,
42
+ autokickMaxBackoffMs,
43
+ autokickUserMessage: kick,
44
+ autokickPenaltyDelta: {
45
+ frequency: normalizePenalty(penalty['frequency'] ?? params['autokickPenaltyFrequency'], DEFAULT_LLM_RECOVERY_POLICY.autokickPenaltyDelta.frequency),
46
+ presence: normalizePenalty(penalty['presence'] ?? params['autokickPenaltyPresence'], DEFAULT_LLM_RECOVERY_POLICY.autokickPenaltyDelta.presence),
47
+ },
48
+ deadLoop: {
49
+ maxWindowTokens: Math.min(8_000, Math.max(10, normalizePositiveInteger(deadLoop['maxWindowTokens'] ??
50
+ params['deadLoopMaxWindowTokens'], DEFAULT_LLM_RECOVERY_POLICY.deadLoop.maxWindowTokens, 8_000))),
51
+ consecutiveThreshold: Math.max(1, normalizePositiveInteger(deadLoop['consecutiveThreshold'] ??
52
+ params['deadLoopConsecutiveThreshold'], DEFAULT_LLM_RECOVERY_POLICY.deadLoop.consecutiveThreshold, 100)),
53
+ minRepetitions: Math.max(1, normalizePositiveInteger(deadLoop['minRepetitions'] ??
54
+ params['deadLoopMinRepetitions'], DEFAULT_LLM_RECOVERY_POLICY.deadLoop.minRepetitions, 20)),
55
+ minPatternTokens: Math.max(1, normalizePositiveInteger(deadLoop['minPatternTokens'] ??
56
+ params['deadLoopMinPatternTokens'], DEFAULT_LLM_RECOVERY_POLICY.deadLoop.minPatternTokens, 100)),
57
+ },
58
+ };
59
+ };
@@ -0,0 +1 @@
1
+ export declare const normalizeToolResult: (text: string, maxChars: number) => string;
@@ -0,0 +1,7 @@
1
+ export const normalizeToolResult = (text, maxChars) => {
2
+ if (maxChars <= 0 || text.length <= maxChars) {
3
+ return text;
4
+ }
5
+ const omitted = text.length - maxChars;
6
+ return `${text.slice(0, maxChars)}\n\n[tool result truncated: ${omitted} characters omitted]`;
7
+ };
@@ -0,0 +1,43 @@
1
+ import type { SteerControlPayload } from '@langflower/node-sdk/llm';
2
+ import { type Observable } from 'rxjs';
3
+ import type { ChatCompletionFinishReason, ChatCompletionStreamChunk, ChatCompletionToolCall } from '../../chat-completion-stream.js';
4
+ import { type DeadLoopChannel, type DeadLoopDetectorOptions } from '../dead-loop-detector.js';
5
+ import type { LlmFailure } from '../llm-loop-types.js';
6
+ export type ProviderStreamFact = {
7
+ readonly kind: 'provider.reasoning';
8
+ readonly text: string;
9
+ } | {
10
+ readonly kind: 'provider.draft';
11
+ readonly text: string;
12
+ } | {
13
+ readonly kind: 'provider.done';
14
+ readonly text: string;
15
+ readonly toolCalls?: readonly ChatCompletionToolCall[];
16
+ readonly finishReason?: ChatCompletionFinishReason;
17
+ } | {
18
+ readonly kind: 'provider.paused';
19
+ } | {
20
+ readonly kind: 'provider.idle';
21
+ readonly idleMs: number;
22
+ } | {
23
+ readonly kind: 'provider.dead-loop';
24
+ readonly channel: DeadLoopChannel;
25
+ readonly reason: 'consecutive' | 'cyclic';
26
+ } | {
27
+ readonly kind: 'provider.failed';
28
+ readonly failure: LlmFailure;
29
+ };
30
+ export type ObserveProviderStreamOptions = {
31
+ readonly createStream: (signal: AbortSignal) => Promise<AsyncIterable<ChatCompletionStreamChunk>>;
32
+ readonly pause$: Observable<SteerControlPayload>;
33
+ readonly cancel$: Observable<void>;
34
+ readonly idleTimeoutMs: number;
35
+ readonly onAbort?: () => void;
36
+ readonly deadLoop?: DeadLoopDetectorOptions | false;
37
+ };
38
+ /**
39
+ * Convert the provider AsyncIterable into typed, cancellable RxJS facts.
40
+ * Pause, idle, and dead-loop are terminal for one provider attempt, not
41
+ * terminal for the surrounding LLM loop.
42
+ */
43
+ export declare const observeProviderStream: (options: ObserveProviderStreamOptions) => Observable<ProviderStreamFact>;
@@ -0,0 +1,96 @@
1
+ import { isSteerControlPause } from '@langflower/node-sdk/llm';
2
+ import { catchError, concatMap, defer, endWith, filter, finalize, from, map, merge, of, switchMap, take, takeUntil, takeWhile, tap, timeout, } from 'rxjs';
3
+ import { classifyLlmFailure } from '../classify-llm-failure.js';
4
+ import { createDeadLoopDetector, } from '../dead-loop-detector.js';
5
+ const toProviderStreamFact = (chunk) => {
6
+ switch (chunk.kind) {
7
+ case 'reasoning':
8
+ return { kind: 'provider.reasoning', text: chunk.text };
9
+ case 'draft':
10
+ return { kind: 'provider.draft', text: chunk.text };
11
+ case 'done':
12
+ return {
13
+ kind: 'provider.done',
14
+ text: chunk.text,
15
+ ...(chunk.tool_calls !== undefined
16
+ ? { toolCalls: chunk.tool_calls }
17
+ : {}),
18
+ ...(chunk.finishReason !== undefined
19
+ ? { finishReason: chunk.finishReason }
20
+ : {}),
21
+ };
22
+ }
23
+ };
24
+ const isTerminalProviderFact = (fact) => fact.kind === 'provider.done' ||
25
+ fact.kind === 'provider.paused' ||
26
+ fact.kind === 'provider.idle' ||
27
+ fact.kind === 'provider.dead-loop' ||
28
+ fact.kind === 'provider.failed';
29
+ const withIdleTimeout = (source$, idleTimeoutMs, onIdle) => {
30
+ if (idleTimeoutMs <= 0) {
31
+ return source$;
32
+ }
33
+ return source$.pipe(timeout({
34
+ first: idleTimeoutMs,
35
+ each: idleTimeoutMs,
36
+ with: () => {
37
+ onIdle();
38
+ return of({
39
+ kind: 'provider.idle',
40
+ idleMs: idleTimeoutMs,
41
+ });
42
+ },
43
+ }));
44
+ };
45
+ const guardDeadLoop = (fact, detectors, abort) => {
46
+ if (detectors === undefined ||
47
+ (fact.kind !== 'provider.reasoning' && fact.kind !== 'provider.draft')) {
48
+ return of(fact);
49
+ }
50
+ const channel = fact.kind === 'provider.reasoning' ? 'reasoning' : 'draft';
51
+ const detected = detectors[channel].push(fact.text);
52
+ if (detected.ok) {
53
+ return of(fact);
54
+ }
55
+ abort();
56
+ return of(fact, {
57
+ kind: 'provider.dead-loop',
58
+ channel: detected.error.channel,
59
+ reason: detected.error.reason,
60
+ });
61
+ };
62
+ /**
63
+ * Convert the provider AsyncIterable into typed, cancellable RxJS facts.
64
+ * Pause, idle, and dead-loop are terminal for one provider attempt, not
65
+ * terminal for the surrounding LLM loop.
66
+ */
67
+ export const observeProviderStream = (options) => defer(() => {
68
+ const abort = new AbortController();
69
+ const stopProvider = () => {
70
+ abort.abort();
71
+ options.onAbort?.();
72
+ };
73
+ const detectors = options.deadLoop === false
74
+ ? undefined
75
+ : {
76
+ reasoning: createDeadLoopDetector('reasoning', options.deadLoop ?? {}),
77
+ draft: createDeadLoopDetector('draft', options.deadLoop ?? {}),
78
+ };
79
+ const pause$ = options.pause$.pipe(filter(isSteerControlPause), take(1), tap(() => {
80
+ stopProvider();
81
+ }), map(() => ({ kind: 'provider.paused' })));
82
+ const chunks$ = withIdleTimeout(from(options.createStream(abort.signal)).pipe(switchMap((stream) => from(stream)), concatMap((chunk) => guardDeadLoop(toProviderStreamFact(chunk), detectors, stopProvider)), catchError((error) => of({
83
+ kind: 'provider.failed',
84
+ failure: classifyLlmFailure(error),
85
+ })), endWith({
86
+ kind: 'provider.failed',
87
+ failure: {
88
+ kind: 'protocol',
89
+ message: 'Provider stream completed without a done chunk.',
90
+ recoverable: true,
91
+ },
92
+ })), options.idleTimeoutMs, stopProvider);
93
+ return merge(chunks$, pause$).pipe(takeWhile((fact) => !isTerminalProviderFact(fact), true), takeUntil(options.cancel$), finalize(() => {
94
+ stopProvider();
95
+ }));
96
+ });
@@ -0,0 +1,32 @@
1
+ import type { ToolHandle } from '@langflower/node-sdk';
2
+ import type { SteerControlPayload } from '@langflower/node-sdk/llm';
3
+ import type { Harness } from '@langflower/tools/create-project-harness';
4
+ import type { ToolHandlerContext } from '@langflower/tools/domain-tool-configs';
5
+ import type { PermissionAskRequest } from '@langflower/tools/permission';
6
+ import type { Observable } from 'rxjs';
7
+ import type { ChatCompletionMessage, CreateChatCompletionStream } from '../chat-completion-stream.js';
8
+ import type { SubAgentRegistration } from '../sub-agent-protocol.js';
9
+ import type { LlmCompactionConfig } from '../openai/normalize-compaction-params.js';
10
+ import { type LlmRecoveryPolicy } from './llm-loop-types.js';
11
+ import { type SharedLlmLoopChunk } from './run-llm-loop.js';
12
+ export type ToolLoopChunk = SharedLlmLoopChunk | {
13
+ readonly kind: 'response';
14
+ readonly text: string;
15
+ };
16
+ export declare const runAgentLoop: (args: {
17
+ readonly factory: CreateChatCompletionStream;
18
+ readonly providerId: string;
19
+ readonly model: string;
20
+ readonly messages: readonly ChatCompletionMessage[];
21
+ readonly tools: readonly ToolHandle[];
22
+ readonly getTools?: () => readonly ToolHandle[];
23
+ readonly harness?: Harness;
24
+ readonly toolCtx?: ToolHandlerContext;
25
+ readonly maxIterations: number;
26
+ readonly subagentRegistrations?: readonly SubAgentRegistration[];
27
+ readonly compaction?: LlmCompactionConfig;
28
+ readonly recovery?: LlmRecoveryPolicy;
29
+ readonly requestPermission?: (request: PermissionAskRequest) => Promise<"allow" | "deny">;
30
+ readonly waitForSubagentResult?: (callId: string, signal: AbortSignal) => Promise<string>;
31
+ readonly steerControl$?: Observable<SteerControlPayload>;
32
+ }) => Observable<ToolLoopChunk>;
@@ -0,0 +1,58 @@
1
+ import { buildSpawnSubagentChatTool, toChatToolDefinitions, } from '../../../tools/inventory-tool-round.js';
2
+ import { DISABLED_COMPACTION_CONFIG } from '../openai/normalize-compaction-params.js';
3
+ import { DEFAULT_LLM_RECOVERY_POLICY, } from './llm-loop-types.js';
4
+ import { runLlmLoop, } from './run-llm-loop.js';
5
+ const AGENT_LOOP_POLICY = {
6
+ decideCompletion: ({ text, toolCalls }) => toolCalls.length > 0
7
+ ? { kind: 'run-tools', calls: toolCalls }
8
+ : {
9
+ kind: 'complete',
10
+ chunks: [{ kind: 'response', text }],
11
+ },
12
+ maxIterationsFailure: (maxIterations) => {
13
+ const text = `Stopped after ${maxIterations} tool-loop iterations ` +
14
+ '(maxIterations).';
15
+ return {
16
+ kind: 'complete',
17
+ chunks: [
18
+ { kind: 'toolLog', text },
19
+ { kind: 'response', text },
20
+ ],
21
+ };
22
+ },
23
+ };
24
+ export const runAgentLoop = (args) => {
25
+ const subagentRegistrations = args.subagentRegistrations ?? [];
26
+ return runLlmLoop({
27
+ factory: args.factory,
28
+ providerId: args.providerId,
29
+ model: args.model,
30
+ messages: args.messages,
31
+ chatTools: [
32
+ ...toChatToolDefinitions(args.tools),
33
+ ...(subagentRegistrations.length > 0
34
+ ? [buildSpawnSubagentChatTool(subagentRegistrations)]
35
+ : []),
36
+ ],
37
+ inventoryTools: args.tools,
38
+ ...(args.getTools !== undefined ? { getTools: args.getTools } : {}),
39
+ maxIterations: args.maxIterations,
40
+ compaction: args.compaction ?? DISABLED_COMPACTION_CONFIG,
41
+ recovery: args.recovery ?? DEFAULT_LLM_RECOVERY_POLICY,
42
+ policy: AGENT_LOOP_POLICY,
43
+ subagentRegistrations,
44
+ ...(args.harness !== undefined ? { harness: args.harness } : {}),
45
+ ...(args.toolCtx !== undefined ? { toolCtx: args.toolCtx } : {}),
46
+ ...(args.requestPermission !== undefined
47
+ ? { requestPermission: args.requestPermission }
48
+ : {}),
49
+ ...(args.waitForSubagentResult !== undefined
50
+ ? {
51
+ waitForSubagentResult: args.waitForSubagentResult,
52
+ }
53
+ : {}),
54
+ ...(args.steerControl$ !== undefined
55
+ ? { steerControl$: args.steerControl$ }
56
+ : {}),
57
+ });
58
+ };
@@ -0,0 +1,80 @@
1
+ import type { ToolHandle } from '@langflower/node-sdk';
2
+ import { type LlmRecoveryNotice, type SteerControlPayload } from '@langflower/node-sdk/llm';
3
+ import type { Harness } from '@langflower/tools/create-project-harness';
4
+ import type { ToolHandlerContext } from '@langflower/tools/domain-tool-configs';
5
+ import type { PermissionAskRequest } from '@langflower/tools/permission';
6
+ import { type Observable } from 'rxjs';
7
+ import type { ChatCompletionMessage, ChatCompletionToolCall, ChatCompletionToolDefinition, CreateChatCompletionStream } from '../chat-completion-stream.js';
8
+ import type { SubAgentRegistration, SubAgentSpawnPayload } from '../sub-agent-protocol.js';
9
+ import type { LlmCompactionConfig } from '../openai/normalize-compaction-params.js';
10
+ import { type LlmFailure, type LlmLoopState, type LlmRecoveryPolicy } from './llm-loop-types.js';
11
+ export type SharedLlmLoopChunk = {
12
+ readonly kind: 'reasoning';
13
+ readonly text: string;
14
+ } | {
15
+ readonly kind: 'draftResponse';
16
+ readonly text: string;
17
+ } | {
18
+ readonly kind: 'toolLog';
19
+ readonly text: string;
20
+ } | ({
21
+ readonly kind: 'recoveryNotice';
22
+ } & LlmRecoveryNotice) | {
23
+ readonly kind: 'historySync';
24
+ readonly messages: readonly ChatCompletionMessage[];
25
+ } | {
26
+ readonly kind: 'subagentSpawn';
27
+ readonly payload: SubAgentSpawnPayload;
28
+ };
29
+ type LlmCompletionDecision<Chunk> = {
30
+ readonly kind: 'complete';
31
+ readonly chunks: readonly Chunk[];
32
+ } | {
33
+ readonly kind: 'run-tools';
34
+ readonly calls: readonly ChatCompletionToolCall[];
35
+ } | {
36
+ readonly kind: 'continue';
37
+ readonly messages: readonly ChatCompletionMessage[];
38
+ readonly chunks: readonly Chunk[];
39
+ } | {
40
+ readonly kind: 'fail';
41
+ readonly failure: LlmFailure;
42
+ };
43
+ export type LlmLoopPolicy<Chunk> = {
44
+ readonly decideCompletion: (input: {
45
+ readonly state: LlmLoopState;
46
+ readonly text: string;
47
+ readonly toolCalls: readonly ChatCompletionToolCall[];
48
+ }) => LlmCompletionDecision<Chunk>;
49
+ readonly toolNotAllowedText?: (toolName: string) => string;
50
+ readonly maxIterationsFailure: (maxIterations: number) => LlmCompletionDecision<Chunk>;
51
+ };
52
+ export type RunLlmLoopOptions<Chunk> = {
53
+ readonly factory: CreateChatCompletionStream;
54
+ readonly providerId: string;
55
+ readonly model: string;
56
+ readonly messages: readonly ChatCompletionMessage[];
57
+ readonly chatTools: readonly ChatCompletionToolDefinition[];
58
+ readonly inventoryTools: readonly ToolHandle[];
59
+ readonly getTools?: () => readonly ToolHandle[];
60
+ readonly harness?: Harness;
61
+ readonly toolCtx?: ToolHandlerContext;
62
+ readonly maxIterations: number;
63
+ readonly compaction: LlmCompactionConfig;
64
+ readonly recovery: LlmRecoveryPolicy;
65
+ readonly policy: LlmLoopPolicy<Chunk>;
66
+ /**
67
+ * When set, maxIterations exhaustion asks HITL continue instead of
68
+ * immediately applying {@link LlmLoopPolicy.maxIterationsFailure}.
69
+ */
70
+ readonly requestPermission?: (request: PermissionAskRequest) => Promise<'allow' | 'deny'>;
71
+ readonly steerControl$?: Observable<SteerControlPayload>;
72
+ readonly subagentRegistrations?: readonly SubAgentRegistration[];
73
+ readonly waitForSubagentResult?: (callId: string, signal: AbortSignal) => Promise<string>;
74
+ };
75
+ /**
76
+ * One reactive state machine for provider, tool, Sub-Agent, retry, and Steer
77
+ * phases. Policy owns only the semantic completion decision.
78
+ */
79
+ export declare const runLlmLoop: <Chunk>(options: RunLlmLoopOptions<Chunk>) => Observable<Chunk | SharedLlmLoopChunk>;
80
+ export {};