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,21 @@
1
+ import type { ChatCompletionMessage } from '../chat-completion-stream.js';
2
+ import type { PermissionAskRequest } from '@langflower/tools/permission';
3
+ import { type Observable } from 'rxjs';
4
+ export type LlmSessionPreparation<Session> = {
5
+ readonly history: readonly ChatCompletionMessage[];
6
+ readonly trackAssistantHistory: boolean;
7
+ readonly appendUserFeedbackToHistory: boolean;
8
+ readonly session: Session;
9
+ };
10
+ type LlmSessionContext = {
11
+ readonly maxFeedbackTurns: number;
12
+ readonly requestPermission?: (request: PermissionAskRequest) => Promise<'allow' | 'deny'>;
13
+ };
14
+ /**
15
+ * Sequential session fold. Each turn is an inner Observable reduced into the
16
+ * accumulator; concurrency 1 queues feedback while a turn is streaming.
17
+ */
18
+ export declare const runLlmSessionMachine: <Context extends LlmSessionContext, Session, Chunk extends {
19
+ readonly kind: string;
20
+ }>(context: Context, turn$: Observable<unknown>, preparation: LlmSessionPreparation<Session>, runTurn: (context: Context, turnPayload: unknown, history: readonly ChatCompletionMessage[], session: Session) => Observable<Chunk>, primeTurn0: boolean) => Observable<Chunk>;
21
+ export {};
@@ -0,0 +1,118 @@
1
+ import { EMPTY, concat, filter, from, map, mergeScan, of, scan, startWith, switchMap, throwError, } from 'rxjs';
2
+ const isBlankTurn = (raw) => raw === null ||
3
+ raw === undefined ||
4
+ (typeof raw === 'string' && raw.trim().length === 0);
5
+ const readHistorySync = (chunk) => {
6
+ if (chunk.kind !== 'historySync' ||
7
+ !('messages' in chunk) ||
8
+ !Array.isArray(chunk.messages)) {
9
+ return undefined;
10
+ }
11
+ return chunk.messages;
12
+ };
13
+ const readAssistantResponse = (chunk) => chunk.kind === 'response' &&
14
+ 'text' in chunk &&
15
+ typeof chunk.text === 'string'
16
+ ? chunk.text
17
+ : undefined;
18
+ const reduceChunk = (state, chunk) => {
19
+ const syncedHistory = readHistorySync(chunk);
20
+ if (syncedHistory !== undefined) {
21
+ return {
22
+ ...state,
23
+ history: [...syncedHistory],
24
+ emitted: chunk,
25
+ };
26
+ }
27
+ const assistantResponse = readAssistantResponse(chunk);
28
+ if (assistantResponse !== undefined &&
29
+ state.preparation.trackAssistantHistory) {
30
+ return {
31
+ ...state,
32
+ history: [
33
+ ...state.history,
34
+ { role: 'assistant', content: assistantResponse },
35
+ ],
36
+ emitted: chunk,
37
+ };
38
+ }
39
+ return { ...state, emitted: chunk };
40
+ };
41
+ const acceptFeedbackTurn = (context, state, raw, runTurn, feedbackTurns) => {
42
+ const history = state.preparation.appendUserFeedbackToHistory
43
+ ? [
44
+ ...state.history,
45
+ { role: 'user', content: String(raw ?? '') },
46
+ ]
47
+ : state.history;
48
+ const next = {
49
+ ...state,
50
+ history,
51
+ feedbackTurns,
52
+ emitted: undefined,
53
+ };
54
+ return runTurn(context, raw, next.history, next.preparation.session).pipe(scan((accumulator, chunk) => reduceChunk(accumulator, chunk), next));
55
+ };
56
+ const denyMaxFeedbackTurns = (state, maxFeedbackTurns) => {
57
+ const message = `Stopped: maxFeedbackTurns ` + `(${maxFeedbackTurns}) reached`;
58
+ return concat(of({
59
+ ...state,
60
+ emitted: {
61
+ kind: 'toolLog',
62
+ text: `⚠ ${message}`,
63
+ },
64
+ }), throwError(() => message));
65
+ };
66
+ const runTurnFromState = (context, state, raw, primeTurn0, runTurn) => {
67
+ if (!state.turn0Done) {
68
+ if (!primeTurn0 && isBlankTurn(raw)) {
69
+ return EMPTY;
70
+ }
71
+ const next = { ...state, turn0Done: true };
72
+ return runTurn(context, primeTurn0 ? undefined : raw, next.history, next.preparation.session).pipe(scan((accumulator, chunk) => reduceChunk(accumulator, chunk), next));
73
+ }
74
+ if (isBlankTurn(raw)) {
75
+ return EMPTY;
76
+ }
77
+ if (context.maxFeedbackTurns > 0 &&
78
+ state.feedbackTurns >= context.maxFeedbackTurns) {
79
+ const ask = context.requestPermission;
80
+ if (ask === undefined) {
81
+ return denyMaxFeedbackTurns(state, context.maxFeedbackTurns);
82
+ }
83
+ const waitingText = `⚠ Max feedback turns (${context.maxFeedbackTurns}) reached. ` +
84
+ 'Allow to continue for another budget, or Deny to stop.';
85
+ return concat(of({
86
+ ...state,
87
+ emitted: {
88
+ kind: 'toolLog',
89
+ text: waitingText,
90
+ },
91
+ }), from(ask({
92
+ toolId: 'agent.maxFeedbackTurns',
93
+ detail: String(context.maxFeedbackTurns),
94
+ summary: `Max feedback turns (${context.maxFeedbackTurns}) ` +
95
+ 'reached. Allow to continue?',
96
+ })).pipe(switchMap((decision) => {
97
+ if (decision !== 'allow') {
98
+ return denyMaxFeedbackTurns(state, context.maxFeedbackTurns);
99
+ }
100
+ return acceptFeedbackTurn(context, state, raw, runTurn, 1);
101
+ })));
102
+ }
103
+ return acceptFeedbackTurn(context, state, raw, runTurn, state.feedbackTurns + 1);
104
+ };
105
+ /**
106
+ * Sequential session fold. Each turn is an inner Observable reduced into the
107
+ * accumulator; concurrency 1 queues feedback while a turn is streaming.
108
+ */
109
+ export const runLlmSessionMachine = (context, turn$, preparation, runTurn, primeTurn0) => {
110
+ const initial = {
111
+ history: [...preparation.history],
112
+ turn0Done: false,
113
+ feedbackTurns: 0,
114
+ preparation,
115
+ };
116
+ const turns$ = primeTurn0 ? turn$.pipe(startWith('')) : turn$;
117
+ return turns$.pipe(mergeScan((state, raw) => runTurnFromState(context, state, raw, primeTurn0, runTurn), initial, 1), filter((state) => state.emitted !== undefined), map((state) => state.emitted));
118
+ };
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Typed context-window overflow from OpenAI-compatible chat.create.
3
+ * Detected before the stream yields reasoning/draft chunks.
4
+ */
5
+ export declare class ContextLengthExceededError extends Error {
6
+ readonly code: "context_length_exceeded";
7
+ constructor(message?: string);
8
+ }
9
+ export declare const isContextLengthExceededError: (error: unknown) => error is ContextLengthExceededError;
10
+ /**
11
+ * Classify provider/SDK errors thrown while creating a chat completion stream.
12
+ * Structured fields win; narrow message fallback covers LM Studio / vLLM.
13
+ */
14
+ export declare const classifyContextLengthError: (error: unknown) => ContextLengthExceededError | undefined;
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Typed context-window overflow from OpenAI-compatible chat.create.
3
+ * Detected before the stream yields reasoning/draft chunks.
4
+ */
5
+ export class ContextLengthExceededError extends Error {
6
+ code = 'context_length_exceeded';
7
+ constructor(message = 'Context length exceeded') {
8
+ super(message);
9
+ this.name = 'ContextLengthExceededError';
10
+ }
11
+ }
12
+ export const isContextLengthExceededError = (error) => error instanceof ContextLengthExceededError;
13
+ const CONTEXT_MESSAGE_RE = /context[_ ]length|maximum context|context window|too many tokens|n_ctx|max_model_len|prompt is too long|exceeds? (?:the )?(?:maximum|model) (?:context|token)/i;
14
+ const readString = (value) => typeof value === 'string' && value.length > 0 ? value : undefined;
15
+ const readNested = (record, key) => {
16
+ const nested = record[key];
17
+ return nested !== null && typeof nested === 'object'
18
+ ? nested
19
+ : undefined;
20
+ };
21
+ /**
22
+ * Classify provider/SDK errors thrown while creating a chat completion stream.
23
+ * Structured fields win; narrow message fallback covers LM Studio / vLLM.
24
+ */
25
+ export const classifyContextLengthError = (error) => {
26
+ if (error instanceof ContextLengthExceededError) {
27
+ return error;
28
+ }
29
+ if (error === null || typeof error !== 'object') {
30
+ return undefined;
31
+ }
32
+ const record = error;
33
+ const status = typeof record['status'] === 'number'
34
+ ? record['status']
35
+ : typeof record['statusCode'] === 'number'
36
+ ? record['statusCode']
37
+ : undefined;
38
+ const code = readString(record['code']) ??
39
+ readString(readNested(record, 'error')?.['code']);
40
+ const type = readString(record['type']) ??
41
+ readString(readNested(record, 'error')?.['type']);
42
+ const message = readString(record['message']) ??
43
+ readString(readNested(record, 'error')?.['message']) ??
44
+ (error instanceof Error ? error.message : undefined);
45
+ if (code === 'context_length_exceeded') {
46
+ return new ContextLengthExceededError(message ?? 'Context length exceeded');
47
+ }
48
+ if (type === 'invalid_request_error' &&
49
+ message !== undefined &&
50
+ CONTEXT_MESSAGE_RE.test(message)) {
51
+ return new ContextLengthExceededError(message);
52
+ }
53
+ if ((status === 400 || status === undefined) &&
54
+ message !== undefined &&
55
+ CONTEXT_MESSAGE_RE.test(message)) {
56
+ // Avoid false positives on rate-limit / auth wording.
57
+ if (/rate[_ ]?limit|unauthorized|authentication|invalid[_ ]api[_ ]key|timeout/i.test(message)) {
58
+ return undefined;
59
+ }
60
+ return new ContextLengthExceededError(message);
61
+ }
62
+ return undefined;
63
+ };
@@ -0,0 +1,19 @@
1
+ import type { ChatCompletionFinishReason, CreateChatCompletionStream } from '../chat-completion-stream.js';
2
+ import { classifyContextLengthError, ContextLengthExceededError } from './context-length-error.js';
3
+ export type { ChatCompletionAbortSignal, ChatCompletionFinishReason, ChatCompletionMessage, ChatCompletionStreamChunk, ChatCompletionToolCall, ChatCompletionToolDefinition, CreateChatCompletionStream, CreateChatCompletionStreamArgs, } from '../chat-completion-stream.js';
4
+ export { ContextLengthExceededError, classifyContextLengthError };
5
+ export { isContextLengthExceededError } from './context-length-error.js';
6
+ export type OpenAiProviderCredentials = {
7
+ readonly apiKey?: string;
8
+ readonly baseURL?: string;
9
+ };
10
+ export declare const mapFinishReason: (value: string | null | undefined) => ChatCompletionFinishReason;
11
+ /** LM Studio / DeepSeek-style CoT fields on OpenAI-compatible deltas. */
12
+ export declare const reasoningTextFromDelta: (delta: unknown) => string;
13
+ /**
14
+ * Unbound OpenAI-compatible chat stream factory.
15
+ * Caller supplies credential resolve (server injects secrets).
16
+ */
17
+ export declare const createChatCompletionStream: (deps: {
18
+ readonly resolveProvider: (providerId: string) => Promise<OpenAiProviderCredentials>;
19
+ }) => CreateChatCompletionStream;
@@ -0,0 +1,182 @@
1
+ import OpenAI from 'openai';
2
+ import { classifyContextLengthError, ContextLengthExceededError, } from './context-length-error.js';
3
+ export { ContextLengthExceededError, classifyContextLengthError };
4
+ export { isContextLengthExceededError } from './context-length-error.js';
5
+ const requireNonEmpty = (value, label) => {
6
+ const trimmed = value.trim();
7
+ if (trimmed.length === 0) {
8
+ throw new Error(`${label} is required for OpenAI-compatible chat`);
9
+ }
10
+ return trimmed;
11
+ };
12
+ export const mapFinishReason = (value) => {
13
+ switch (value) {
14
+ case 'stop':
15
+ case 'length':
16
+ case 'tool_calls':
17
+ case 'content_filter':
18
+ return value;
19
+ default:
20
+ return 'unknown';
21
+ }
22
+ };
23
+ const toOpenAiMessages = (messages) => messages.map((message) => {
24
+ if (message.role === 'tool') {
25
+ return {
26
+ role: 'tool',
27
+ content: message.content,
28
+ tool_call_id: message.tool_call_id,
29
+ };
30
+ }
31
+ if (message.role === 'assistant' && message.tool_calls !== undefined) {
32
+ return {
33
+ role: 'assistant',
34
+ content: message.content.length > 0 ? message.content : null,
35
+ tool_calls: message.tool_calls.map((call) => ({
36
+ id: call.id,
37
+ type: 'function',
38
+ function: {
39
+ name: call.name,
40
+ arguments: call.arguments,
41
+ },
42
+ })),
43
+ };
44
+ }
45
+ return {
46
+ role: message.role,
47
+ content: message.content,
48
+ };
49
+ });
50
+ const mergeToolCallDelta = (acc, index, delta) => {
51
+ const current = acc.get(index) ?? { id: '', name: '', arguments: '' };
52
+ acc.set(index, {
53
+ id: delta.id !== undefined && delta.id.length > 0
54
+ ? delta.id
55
+ : current.id,
56
+ name: delta.function?.name !== undefined && delta.function.name.length > 0
57
+ ? `${current.name}${delta.function.name}`
58
+ : current.name,
59
+ arguments: delta.function?.arguments !== undefined
60
+ ? `${current.arguments}${delta.function.arguments}`
61
+ : current.arguments,
62
+ });
63
+ };
64
+ const finalizeToolCalls = (acc) => [...acc.entries()]
65
+ .sort(([a], [b]) => a - b)
66
+ .map(([, call]) => ({
67
+ id: call.id.length > 0 ? call.id : `call_${call.name}`,
68
+ name: call.name,
69
+ arguments: call.arguments,
70
+ }))
71
+ .filter((call) => call.name.length > 0);
72
+ /** LM Studio / DeepSeek-style CoT fields on OpenAI-compatible deltas. */
73
+ export const reasoningTextFromDelta = (delta) => {
74
+ if (delta === null || typeof delta !== 'object') {
75
+ return '';
76
+ }
77
+ const record = delta;
78
+ const reasoning = record['reasoning'];
79
+ const reasoningContent = record['reasoning_content'];
80
+ if (typeof reasoning === 'string' && reasoning.length > 0) {
81
+ return reasoning;
82
+ }
83
+ if (typeof reasoningContent === 'string' && reasoningContent.length > 0) {
84
+ return reasoningContent;
85
+ }
86
+ return '';
87
+ };
88
+ /**
89
+ * Unbound OpenAI-compatible chat stream factory.
90
+ * Caller supplies credential resolve (server injects secrets).
91
+ */
92
+ export const createChatCompletionStream = (deps) => {
93
+ return async (args) => {
94
+ const providerId = requireNonEmpty(args.providerId, 'Provider');
95
+ const model = requireNonEmpty(args.model, 'Model');
96
+ const credentials = await deps.resolveProvider(providerId);
97
+ const client = new OpenAI({
98
+ apiKey: credentials.apiKey ?? 'local-no-key',
99
+ ...(credentials.baseURL !== undefined
100
+ ? { baseURL: credentials.baseURL }
101
+ : {}),
102
+ });
103
+ const tools = args.tools !== undefined && args.tools.length > 0
104
+ ? args.tools.map((tool) => ({
105
+ type: 'function',
106
+ function: {
107
+ name: tool.function.name,
108
+ ...(tool.function.description !== undefined
109
+ ? { description: tool.function.description }
110
+ : {}),
111
+ ...(tool.function.parameters !== undefined
112
+ ? {
113
+ parameters: tool.function
114
+ .parameters,
115
+ }
116
+ : {}),
117
+ },
118
+ }))
119
+ : undefined;
120
+ let stream;
121
+ try {
122
+ stream = (await client.chat.completions.create({
123
+ model,
124
+ messages: toOpenAiMessages(args.messages),
125
+ stream: true,
126
+ ...(tools !== undefined ? { tools } : {}),
127
+ ...(args.frequency_penalty !== undefined
128
+ ? { frequency_penalty: args.frequency_penalty }
129
+ : {}),
130
+ ...(args.presence_penalty !== undefined
131
+ ? { presence_penalty: args.presence_penalty }
132
+ : {}),
133
+ }, {
134
+ signal: args.signal,
135
+ }));
136
+ }
137
+ catch (error) {
138
+ const contextError = classifyContextLengthError(error);
139
+ if (contextError !== undefined) {
140
+ throw contextError;
141
+ }
142
+ throw error;
143
+ }
144
+ async function* iterate() {
145
+ let fullText = '';
146
+ let lastFinishReason;
147
+ const toolAcc = new Map();
148
+ for await (const chunk of stream) {
149
+ const choice = chunk.choices[0];
150
+ if (choice?.finish_reason !== undefined) {
151
+ lastFinishReason = mapFinishReason(choice.finish_reason);
152
+ }
153
+ const delta = choice?.delta;
154
+ const reasoningText = reasoningTextFromDelta(delta);
155
+ if (reasoningText.length > 0) {
156
+ yield { kind: 'reasoning', text: reasoningText };
157
+ }
158
+ const content = delta?.content;
159
+ if (content !== undefined &&
160
+ content !== null &&
161
+ content.length > 0) {
162
+ fullText += content;
163
+ yield { kind: 'draft', text: content };
164
+ }
165
+ const toolDeltas = delta?.tool_calls;
166
+ if (toolDeltas !== undefined) {
167
+ for (const toolDelta of toolDeltas) {
168
+ mergeToolCallDelta(toolAcc, toolDelta.index ?? 0, toolDelta);
169
+ }
170
+ }
171
+ }
172
+ const tool_calls = finalizeToolCalls(toolAcc);
173
+ yield {
174
+ kind: 'done',
175
+ text: fullText,
176
+ finishReason: lastFinishReason ?? 'unknown',
177
+ ...(tool_calls.length > 0 ? { tool_calls } : {}),
178
+ };
179
+ }
180
+ return iterate();
181
+ };
182
+ };
@@ -0,0 +1,28 @@
1
+ import type { OpenAiProviderCredentials } from './create-chat-completion-stream.js';
2
+ export type ProviderModelEntry = {
3
+ readonly id: string;
4
+ readonly name?: string;
5
+ };
6
+ export type ListProviderModelsResult = {
7
+ readonly models: readonly ProviderModelEntry[];
8
+ readonly error?: string;
9
+ };
10
+ type OpenAiModelsClient = {
11
+ readonly models: {
12
+ readonly list: () => Promise<{
13
+ readonly data: readonly {
14
+ readonly id: string;
15
+ readonly name?: string;
16
+ }[];
17
+ }>;
18
+ };
19
+ };
20
+ type ListProviderModelsDeps = {
21
+ readonly createClient?: (credentials: OpenAiProviderCredentials) => OpenAiModelsClient;
22
+ };
23
+ /**
24
+ * Lists models for resolved credentials. Never throws — failures return
25
+ * `{ models: [], error }`.
26
+ */
27
+ export declare const listProviderModels: (credentials: OpenAiProviderCredentials, deps?: ListProviderModelsDeps) => Promise<ListProviderModelsResult>;
28
+ export {};
@@ -0,0 +1,52 @@
1
+ import OpenAI from 'openai';
2
+ const SECRET_SUBSTRINGS = ['sk-', 'apiKey', 'api_key', 'authorization'];
3
+ const toSafeErrorMessage = (message) => {
4
+ const lower = message.toLowerCase();
5
+ for (const needle of SECRET_SUBSTRINGS) {
6
+ if (lower.includes(needle.toLowerCase())) {
7
+ return 'Failed to list models for provider';
8
+ }
9
+ }
10
+ return message;
11
+ };
12
+ const mapModelEntry = (entry) => {
13
+ const name = 'name' in entry && typeof entry.name === 'string'
14
+ ? entry.name
15
+ : undefined;
16
+ return {
17
+ id: entry.id,
18
+ ...(name !== undefined ? { name } : {}),
19
+ };
20
+ };
21
+ const defaultCreateClient = (credentials) => new OpenAI({
22
+ apiKey: credentials.apiKey ?? 'local-no-key',
23
+ ...(credentials.baseURL !== undefined
24
+ ? { baseURL: credentials.baseURL }
25
+ : {}),
26
+ });
27
+ /**
28
+ * Lists models for resolved credentials. Never throws — failures return
29
+ * `{ models: [], error }`.
30
+ */
31
+ export const listProviderModels = async (credentials, deps) => {
32
+ try {
33
+ const createClient = deps?.createClient ?? defaultCreateClient;
34
+ const client = createClient(credentials);
35
+ const page = await client.models.list();
36
+ const models = (page.data ?? []).map(mapModelEntry);
37
+ if (models.length === 0) {
38
+ return {
39
+ models: [],
40
+ error: 'Provider returned no models. For LM Studio / local OpenAI-compatible servers, baseURL usually ends with /v1 (e.g. http://127.0.0.1:1234/v1).',
41
+ };
42
+ }
43
+ return { models };
44
+ }
45
+ catch (error) {
46
+ const raw = error instanceof Error ? error.message : String(error);
47
+ return {
48
+ models: [],
49
+ error: toSafeErrorMessage(raw),
50
+ };
51
+ }
52
+ };
@@ -0,0 +1,31 @@
1
+ import type { ChatCompletionMessage, ChatCompletionToolDefinition, CreateChatCompletionStream } from '../chat-completion-stream.js';
2
+ import type { LlmCompactionConfig } from './normalize-compaction-params.js';
3
+ export type CompactMessagesResult = {
4
+ readonly ok: true;
5
+ readonly messages: readonly ChatCompletionMessage[];
6
+ readonly beforeTokens: number;
7
+ readonly afterTokens: number;
8
+ } | {
9
+ readonly ok: false;
10
+ readonly message: string;
11
+ };
12
+ export declare const SUMMARY_SYSTEM_PROMPT: string;
13
+ export declare const estimateMessagesTokens: (messages: readonly ChatCompletionMessage[]) => number;
14
+ export declare const estimateToolsTokens: (tools: readonly ChatCompletionToolDefinition[]) => number;
15
+ export declare const estimateRequestTokens: (messages: readonly ChatCompletionMessage[], tools: readonly ChatCompletionToolDefinition[]) => number;
16
+ /**
17
+ * LLM-summary compaction: replace contiguous unprotected message blocks with
18
+ * a summary user message while preserving leading system + last user + newest
19
+ * block and full assistant/tool groups.
20
+ */
21
+ export declare const compactMessagesWithSummary: (args: {
22
+ readonly factory: CreateChatCompletionStream;
23
+ readonly providerId: string;
24
+ readonly model: string;
25
+ readonly messages: readonly ChatCompletionMessage[];
26
+ readonly tools: readonly ChatCompletionToolDefinition[];
27
+ readonly targetTokens: number;
28
+ readonly signal?: AbortSignal;
29
+ }) => Promise<CompactMessagesResult>;
30
+ export declare const resolveProactiveTargetTokens: (config: LlmCompactionConfig) => number | undefined;
31
+ export declare const resolveForceTargetTokens: (config: LlmCompactionConfig, currentInputEstimate: number) => number;