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.
- package/package.json +1 -1
- package/ui-dist/{chunk-Y6VMBLSJ.js → chunk-7UMVYN3A.js} +1 -1
- package/ui-dist/{chunk-6DQ2XSRW.js → chunk-MDGXX73Z.js} +3 -3
- package/ui-dist/index.html +1 -1
- package/ui-dist/main-2JJGCNTD.js +313 -0
- package/vendor/common-nodes/dist/ai/chat-completion-stream.d.ts +2 -0
- package/vendor/common-nodes/dist/ai/critique/node.d.ts +246 -0
- package/vendor/common-nodes/dist/ai/critique/node.js +2 -2
- package/vendor/common-nodes/dist/ai/fake-llm/node.d.ts +246 -0
- package/vendor/common-nodes/dist/ai/features/chat-completion-stream.d.ts +53 -0
- package/vendor/common-nodes/dist/ai/features/chat-completion-stream.js +1 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/autokick-recovery.d.ts +13 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/autokick-recovery.js +17 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/classify-llm-failure.d.ts +2 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/classify-llm-failure.js +113 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/dead-loop-detector.d.ts +28 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/dead-loop-detector.js +194 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/live-get-tools.d.ts +9 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/live-get-tools.js +21 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/llm-loop-reducer.d.ts +2 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/llm-loop-reducer.js +216 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/llm-loop-types.d.ts +125 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/llm-loop-types.js +39 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/normalize-llm-recovery-policy.d.ts +2 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/normalize-llm-recovery-policy.js +59 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/operators/normalize-tool-result.d.ts +1 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/operators/normalize-tool-result.js +7 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/operators/observe-provider-stream.d.ts +43 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/operators/observe-provider-stream.js +96 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/run-agent-loop.d.ts +32 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/run-agent-loop.js +58 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/run-llm-loop.d.ts +80 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/run-llm-loop.js +681 -0
- package/vendor/common-nodes/dist/ai/features/llm-role-preset.d.ts +69 -0
- package/vendor/common-nodes/dist/ai/features/llm-role-preset.js +265 -0
- package/vendor/common-nodes/dist/ai/features/llm-session/llm-session-shell.d.ts +148 -0
- package/vendor/common-nodes/dist/ai/features/llm-session/llm-session-shell.js +198 -0
- package/vendor/common-nodes/dist/ai/features/llm-session/run-session-machine.d.ts +21 -0
- package/vendor/common-nodes/dist/ai/features/llm-session/run-session-machine.js +118 -0
- package/vendor/common-nodes/dist/ai/features/openai/context-length-error.d.ts +14 -0
- package/vendor/common-nodes/dist/ai/features/openai/context-length-error.js +63 -0
- package/vendor/common-nodes/dist/ai/features/openai/create-chat-completion-stream.d.ts +19 -0
- package/vendor/common-nodes/dist/ai/features/openai/create-chat-completion-stream.js +182 -0
- package/vendor/common-nodes/dist/ai/features/openai/list-provider-models.d.ts +28 -0
- package/vendor/common-nodes/dist/ai/features/openai/list-provider-models.js +52 -0
- package/vendor/common-nodes/dist/ai/features/openai/llm-context-compaction.d.ts +31 -0
- package/vendor/common-nodes/dist/ai/features/openai/llm-context-compaction.js +326 -0
- package/vendor/common-nodes/dist/ai/features/openai/normalize-compaction-params.d.ts +14 -0
- package/vendor/common-nodes/dist/ai/features/openai/normalize-compaction-params.js +21 -0
- package/vendor/common-nodes/dist/ai/features/openai/prepare-chat-completion.d.ts +30 -0
- package/vendor/common-nodes/dist/ai/features/openai/prepare-chat-completion.js +132 -0
- package/vendor/common-nodes/dist/ai/features/path-choice/control-tools.d.ts +20 -0
- package/vendor/common-nodes/dist/ai/features/path-choice/control-tools.js +70 -0
- package/vendor/common-nodes/dist/ai/features/path-choice/run-reactive-path-choice-loop.d.ts +35 -0
- package/vendor/common-nodes/dist/ai/features/path-choice/run-reactive-path-choice-loop.js +106 -0
- package/vendor/common-nodes/dist/ai/features/prompt/build-effective-system-prompt.d.ts +9 -0
- package/vendor/common-nodes/dist/ai/features/prompt/build-effective-system-prompt.js +21 -0
- package/vendor/common-nodes/dist/ai/features/prompt/normalize-max-iterations.d.ts +13 -0
- package/vendor/common-nodes/dist/ai/features/prompt/normalize-max-iterations.js +23 -0
- package/vendor/common-nodes/dist/ai/features/prompt/resolve-chat-provider-model.d.ts +10 -0
- package/vendor/common-nodes/dist/ai/features/prompt/resolve-chat-provider-model.js +8 -0
- package/vendor/common-nodes/dist/ai/features/run-host-services.d.ts +54 -0
- package/vendor/common-nodes/dist/ai/features/run-host-services.js +29 -0
- package/vendor/common-nodes/dist/ai/features/scripted-chat-completion-stream.d.ts +17 -0
- package/vendor/common-nodes/dist/ai/features/scripted-chat-completion-stream.js +61 -0
- package/vendor/common-nodes/dist/ai/features/sub-agent-protocol.d.ts +39 -0
- package/vendor/common-nodes/dist/ai/features/sub-agent-protocol.js +43 -0
- package/vendor/common-nodes/dist/ai/features/ui-schema/llm-compaction-ui-schema.d.ts +14 -0
- package/vendor/common-nodes/dist/ai/features/ui-schema/llm-compaction-ui-schema.js +18 -0
- package/vendor/common-nodes/dist/ai/features/ui-schema/llm-panel-ui-schema.d.ts +80 -0
- package/vendor/common-nodes/dist/ai/features/ui-schema/llm-panel-ui-schema.js +76 -0
- package/vendor/common-nodes/dist/ai/features/ui-schema/llm-recovery-ui-schema.d.ts +113 -0
- package/vendor/common-nodes/dist/ai/features/ui-schema/llm-recovery-ui-schema.js +131 -0
- package/vendor/common-nodes/dist/ai/features/wait-for-subagent-result.d.ts +6 -0
- package/vendor/common-nodes/dist/ai/features/wait-for-subagent-result.js +30 -0
- package/vendor/common-nodes/dist/ai/llm-loop/autokick-recovery.d.ts +13 -0
- package/vendor/common-nodes/dist/ai/llm-loop/autokick-recovery.js +17 -0
- package/vendor/common-nodes/dist/ai/llm-loop/dead-loop-detector.d.ts +28 -0
- package/vendor/common-nodes/dist/ai/llm-loop/dead-loop-detector.js +194 -0
- package/vendor/common-nodes/dist/ai/llm-loop/llm-loop-reducer.js +36 -0
- package/vendor/common-nodes/dist/ai/llm-loop/llm-loop-types.d.ts +35 -0
- package/vendor/common-nodes/dist/ai/llm-loop/llm-loop-types.js +19 -0
- package/vendor/common-nodes/dist/ai/llm-loop/normalize-llm-recovery-policy.js +52 -9
- package/vendor/common-nodes/dist/ai/llm-loop/operators/observe-provider-stream.d.ts +8 -2
- package/vendor/common-nodes/dist/ai/llm-loop/operators/observe-provider-stream.js +43 -13
- package/vendor/common-nodes/dist/ai/llm-loop/run-llm-loop.d.ts +3 -5
- package/vendor/common-nodes/dist/ai/llm-loop/run-llm-loop.js +116 -1
- package/vendor/common-nodes/dist/ai/llm-recovery-ui-schema.d.ts +82 -0
- package/vendor/common-nodes/dist/ai/llm-recovery-ui-schema.js +95 -0
- package/vendor/common-nodes/dist/ai/llm-session-shell.d.ts +4 -9
- package/vendor/common-nodes/dist/ai/llm-session-shell.js +2 -4
- package/vendor/common-nodes/dist/ai/nodes/critique/node.d.ts +588 -0
- package/vendor/common-nodes/dist/ai/nodes/critique/node.js +240 -0
- package/vendor/common-nodes/dist/ai/nodes/fake-llm/node.d.ts +571 -0
- package/vendor/common-nodes/dist/ai/nodes/fake-llm/node.js +208 -0
- package/vendor/common-nodes/dist/ai/nodes/openai-llm/node.d.ts +587 -0
- package/vendor/common-nodes/dist/ai/nodes/openai-llm/node.js +91 -0
- package/vendor/common-nodes/dist/ai/nodes/review/node.d.ts +593 -0
- package/vendor/common-nodes/dist/ai/nodes/review/node.js +240 -0
- package/vendor/common-nodes/dist/ai/nodes/sub-agent/node.d.ts +630 -0
- package/vendor/common-nodes/dist/ai/nodes/sub-agent/node.js +302 -0
- package/vendor/common-nodes/dist/ai/openai/create-chat-completion-stream.js +6 -0
- package/vendor/common-nodes/dist/ai/openai/prepare-chat-completion.d.ts +2 -0
- package/vendor/common-nodes/dist/ai/openai/prepare-chat-completion.js +18 -0
- package/vendor/common-nodes/dist/ai/openai-llm/node.d.ts +246 -0
- package/vendor/common-nodes/dist/ai/review/node.d.ts +246 -0
- package/vendor/common-nodes/dist/ai/review/node.js +2 -2
- package/vendor/common-nodes/dist/ai/sub-agent/node.d.ts +246 -0
- package/vendor/common-nodes/dist/ai/sub-agent/node.js +2 -2
- package/vendor/common-nodes/dist/catalog.js +7 -5
- package/vendor/common-nodes/dist/compile-custom-nodes/node.d.ts +21 -0
- package/vendor/common-nodes/dist/compile-custom-nodes/node.js +45 -0
- package/vendor/common-nodes/dist/crawl/crawl/node.js +1 -1
- package/vendor/common-nodes/dist/crawl/fetch-url/node.js +1 -1
- package/vendor/common-nodes/dist/flow/repeat/node.js +6 -1
- package/vendor/common-nodes/dist/langflower-tools/emit-registration-tools.d.ts +18 -0
- package/vendor/common-nodes/dist/langflower-tools/emit-registration-tools.js +29 -0
- package/vendor/common-nodes/dist/langflower-tools/node.d.ts +20 -0
- package/vendor/common-nodes/dist/langflower-tools/node.js +77 -0
- package/vendor/common-nodes/dist/text/append-file/node.js +1 -1
- package/vendor/common-nodes/dist/text/read-file/node.js +1 -1
- package/vendor/common-nodes/dist/text/write-file/node.js +1 -1
- package/vendor/common-nodes/dist/tools/inventory-tool-round.d.ts +2 -2
- package/vendor/common-nodes/package.json +10 -10
- package/vendor/compiler/dist/compile-project-nodes.d.ts +2 -1
- package/vendor/compiler/dist/compile-project-nodes.js +35 -6
- package/vendor/compiler/dist/resolve-host-types.d.ts +0 -5
- package/vendor/compiler/dist/resolve-host-types.js +0 -8
- package/vendor/node-sdk/dist/node-factory/define-llm-node/define-llm-node.d.ts +1 -1
- package/vendor/node-sdk/dist/node-factory/define-llm-node/define-llm-node.js +1 -1
- package/vendor/node-sdk/dist/node-factory/define-llm-node/recovery-notice.d.ts +8 -0
- package/vendor/node-sdk/dist/node-factory/define-llm-node/recovery-notice.js +14 -0
- package/vendor/runtime/dist/runtime-editor.d.ts +5 -1
- package/vendor/runtime/dist/runtime-editor.js +19 -0
- package/vendor/runtime/dist/runtime-runner.js +17 -17
- package/vendor/runtime/dist/runtime.d.ts +2 -1
- package/vendor/runtime/dist/runtime.js +1 -0
- package/vendor/runtime/dist/testing/workflows/workflow-events.d.ts +8 -6
- package/vendor/runtime/dist/testing/workflows/workflow-events.js +19 -31
- package/vendor/runtime/dist/types.d.ts +33 -38
- package/vendor/runtime/dist/types.js +2 -1
- package/vendor/server/dist/bridge/attach-langflower-bridge.js +3 -2
- package/vendor/server/dist/bridge/bridge-event-log.js +17 -102
- package/vendor/server/dist/bridge/build-execution-context.d.ts +5 -2
- package/vendor/server/dist/bridge/build-execution-context.js +45 -5
- package/vendor/server/dist/bridge/forward-runner-event.d.ts +1 -1
- package/vendor/server/dist/bridge/forward-runner-event.js +7 -12
- package/vendor/server/dist/bridge/get-live-wired-tools.d.ts +12 -0
- package/vendor/server/dist/bridge/get-live-wired-tools.js +80 -0
- package/vendor/server/dist/bridge/langflower-tools-rpc.d.ts +7 -0
- package/vendor/server/dist/bridge/langflower-tools-rpc.js +29 -0
- package/vendor/server/dist/bridge/settings-draft-controller.js +26 -3
- package/vendor/server/dist/bridge/wire-custom-palette-handlers.d.ts +2 -1
- package/vendor/server/dist/bridge/wire-custom-palette-handlers.js +3 -5
- package/vendor/server/dist/bridge/wire-runner-handlers.js +15 -8
- package/vendor/server/dist/checkpoint/run-checkpoint-session.d.ts +1 -1
- package/vendor/server/dist/checkpoint/run-checkpoint-session.js +10 -9
- package/vendor/server/dist/palette/compile-and-hot-swap-custom-nodes.d.ts +10 -0
- package/vendor/server/dist/palette/compile-and-hot-swap-custom-nodes.js +23 -0
- package/vendor/server/dist/workflow/apply-editor-mutation.d.ts +5 -0
- package/vendor/server/dist/workflow/apply-editor-mutation.js +32 -0
- package/vendor/server/skeleton/instructions.md +9 -5
- package/vendor/server/skeleton/nodes/my-nodes/README.md +4 -3
- package/vendor/server/skeleton/schemas/langflower-config.schema.json +11 -1
- package/vendor/server/skeleton/skills/langflower-helper/SKILL.md +49 -19
- package/vendor/server/skeleton/skills/langflower-helper/architecture.md +22 -9
- package/vendor/server/skeleton/skills/langflower-helper/layout.md +15 -15
- package/vendor/server/skeleton/skills/langflower-node-writer/SKILL.md +19 -9
- package/vendor/server/skeleton/skills/langflower-workflow-writer/SKILL.md +14 -10
- package/vendor/server/skeleton/workflows/starter.json +30 -3
- package/vendor/shared/dist/execution/derive-run-settle-outcome.d.ts +1 -1
- package/vendor/shared/dist/execution/derive-run-settle-outcome.js +4 -3
- package/vendor/shared/dist/execution/derive-run-settle-outcome.test.js +9 -9
- package/vendor/shared/dist/langflower-bus-config.d.ts +6 -14
- package/vendor/shared/dist/langflower-bus-config.js +4 -12
- package/vendor/shared/dist/langflower-config/resolve-wired-tool-options.js +6 -0
- package/vendor/shared/dist/langflower-config/resolve-wired-tool-options.test.js +30 -0
- package/vendor/shared/dist/langflower-ws-waits.d.ts +7 -14
- package/vendor/shared/dist/langflower-ws-waits.js +14 -14
- package/vendor/websocket-bridge/dist/bridge-codec.d.ts +1 -0
- package/vendor/websocket-bridge/dist/bridge-codec.js +11 -11
- package/vendor/websocket-bridge/dist/bridge-frame.js +1 -1
- package/vendor/websocket-bridge/dist/bridge-subjects.d.ts +1 -1
- package/vendor/websocket-bridge/dist/bridge-subjects.js +2 -2
- package/vendor/websocket-bridge/dist/bridge-types.d.ts +13 -1
- package/vendor/websocket-bridge/dist/create-client.js +3 -3
- package/vendor/websocket-bridge/dist/create-server.js +12 -6
- package/vendor/websocket-bridge/package.json +8 -0
- package/ui-dist/main-SMO3L7U5.js +0 -311
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { isContextLengthExceededError } from '../openai/context-length-error.js';
|
|
2
|
+
const readRecord = (value) => value !== null && typeof value === 'object'
|
|
3
|
+
? value
|
|
4
|
+
: undefined;
|
|
5
|
+
const readString = (value) => typeof value === 'string' && value.trim().length > 0
|
|
6
|
+
? value.trim()
|
|
7
|
+
: undefined;
|
|
8
|
+
const readStatus = (record) => {
|
|
9
|
+
const value = record['status'] ?? record['statusCode'];
|
|
10
|
+
return typeof value === 'number' && Number.isFinite(value)
|
|
11
|
+
? value
|
|
12
|
+
: undefined;
|
|
13
|
+
};
|
|
14
|
+
const readHeader = (record, name) => {
|
|
15
|
+
const headers = readRecord(record['headers']);
|
|
16
|
+
if (headers === undefined) {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
return readString(headers[name]) ?? readString(headers[name.toLowerCase()]);
|
|
20
|
+
};
|
|
21
|
+
const sanitizeMessage = (message, status) => {
|
|
22
|
+
if (/<(?:!doctype|html|head|body|pre)\b/i.test(message)) {
|
|
23
|
+
return status === undefined
|
|
24
|
+
? 'Provider returned an HTML error response.'
|
|
25
|
+
: `Provider returned HTTP ${status} with an HTML error response.`;
|
|
26
|
+
}
|
|
27
|
+
return message.length <= 500 ? message : `${message.slice(0, 499)}…`;
|
|
28
|
+
};
|
|
29
|
+
export const classifyLlmFailure = (error) => {
|
|
30
|
+
if (isContextLengthExceededError(error)) {
|
|
31
|
+
return {
|
|
32
|
+
kind: 'context-overflow',
|
|
33
|
+
message: sanitizeMessage(error.message),
|
|
34
|
+
recoverable: true,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const record = readRecord(error);
|
|
38
|
+
const nestedError = readRecord(record?.['error']);
|
|
39
|
+
const status = record === undefined ? undefined : readStatus(record);
|
|
40
|
+
const rawMessage = readString(record?.['message']) ??
|
|
41
|
+
readString(nestedError?.['message']) ??
|
|
42
|
+
(error instanceof Error ? error.message : String(error));
|
|
43
|
+
const message = sanitizeMessage(rawMessage, status);
|
|
44
|
+
const rawContentType = record === undefined ? undefined : readHeader(record, 'content-type');
|
|
45
|
+
const retryAfterRaw = record === undefined ? undefined : readHeader(record, 'retry-after');
|
|
46
|
+
const retryAfterSeconds = retryAfterRaw === undefined ? Number.NaN : Number(retryAfterRaw);
|
|
47
|
+
const retryAfterMs = Number.isFinite(retryAfterSeconds)
|
|
48
|
+
? Math.max(0, retryAfterSeconds * 1_000)
|
|
49
|
+
: undefined;
|
|
50
|
+
const code = readString(record?.['code']) ?? readString(nestedError?.['code']);
|
|
51
|
+
const messageLower = message.toLowerCase();
|
|
52
|
+
if (status === 401 ||
|
|
53
|
+
status === 403 ||
|
|
54
|
+
/authentication|unauthorized|invalid api key|invalid_api_key/.test(messageLower)) {
|
|
55
|
+
return {
|
|
56
|
+
kind: 'authentication',
|
|
57
|
+
message,
|
|
58
|
+
recoverable: false,
|
|
59
|
+
...(status !== undefined ? { status } : {}),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
if (status === 404 ||
|
|
63
|
+
/model .* not found|unknown model|provider is required|model is required/.test(messageLower)) {
|
|
64
|
+
return {
|
|
65
|
+
kind: 'configuration',
|
|
66
|
+
message,
|
|
67
|
+
recoverable: false,
|
|
68
|
+
...(status !== undefined ? { status } : {}),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
if (status === 429 || /rate.?limit/.test(messageLower)) {
|
|
72
|
+
return {
|
|
73
|
+
kind: 'rate-limit',
|
|
74
|
+
message,
|
|
75
|
+
recoverable: true,
|
|
76
|
+
...(status !== undefined ? { status } : {}),
|
|
77
|
+
...(retryAfterMs !== undefined ? { retryAfterMs } : {}),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
if (status !== undefined && (status === 408 || status >= 500)) {
|
|
81
|
+
return {
|
|
82
|
+
kind: 'provider-unavailable',
|
|
83
|
+
message,
|
|
84
|
+
recoverable: true,
|
|
85
|
+
status,
|
|
86
|
+
...(rawContentType !== undefined ? { rawContentType } : {}),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
if (code === 'ECONNRESET' ||
|
|
90
|
+
code === 'ECONNREFUSED' ||
|
|
91
|
+
code === 'ETIMEDOUT' ||
|
|
92
|
+
/network|socket|connection reset|fetch failed|timeout/.test(messageLower)) {
|
|
93
|
+
return {
|
|
94
|
+
kind: 'network',
|
|
95
|
+
message,
|
|
96
|
+
recoverable: true,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
if (message.startsWith('Cannot compact history:')) {
|
|
100
|
+
return {
|
|
101
|
+
kind: 'protocol',
|
|
102
|
+
message,
|
|
103
|
+
recoverable: true,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
kind: 'unknown',
|
|
108
|
+
message,
|
|
109
|
+
recoverable: true,
|
|
110
|
+
...(status !== undefined ? { status } : {}),
|
|
111
|
+
...(rawContentType !== undefined ? { rawContentType } : {}),
|
|
112
|
+
};
|
|
113
|
+
};
|
|
@@ -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
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ToolHandle } from '@langflower/node-sdk';
|
|
2
|
+
/**
|
|
3
|
+
* Stash a live inventory reader on the snapshot array so agent loops can
|
|
4
|
+
* re-read after custom-node hot-swap without each catalog node forwarding
|
|
5
|
+
* `getTools` through `runAgentLoop` args.
|
|
6
|
+
*/
|
|
7
|
+
export declare const tagLiveGetTools: (list: readonly ToolHandle[], getTools: () => readonly ToolHandle[]) => readonly ToolHandle[];
|
|
8
|
+
export declare const readTaggedGetTools: (list: readonly ToolHandle[]) => (() => readonly ToolHandle[]) | undefined;
|
|
9
|
+
//# sourceMappingURL=live-get-tools.d.ts.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const liveGetToolsSymbol = Symbol('langflower.liveGetTools');
|
|
2
|
+
/**
|
|
3
|
+
* Stash a live inventory reader on the snapshot array so agent loops can
|
|
4
|
+
* re-read after custom-node hot-swap without each catalog node forwarding
|
|
5
|
+
* `getTools` through `runAgentLoop` args.
|
|
6
|
+
*/
|
|
7
|
+
export const tagLiveGetTools = (list, getTools) => {
|
|
8
|
+
Object.defineProperty(list, liveGetToolsSymbol, {
|
|
9
|
+
value: getTools,
|
|
10
|
+
enumerable: false,
|
|
11
|
+
writable: false,
|
|
12
|
+
});
|
|
13
|
+
return list;
|
|
14
|
+
};
|
|
15
|
+
export const readTaggedGetTools = (list) => {
|
|
16
|
+
const tagged = list[liveGetToolsSymbol];
|
|
17
|
+
return typeof tagged === 'function'
|
|
18
|
+
? tagged
|
|
19
|
+
: undefined;
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=live-get-tools.js.map
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { autokickKickUserTurn } from './autokick-recovery.js';
|
|
2
|
+
const assertNever = (value) => {
|
|
3
|
+
throw new Error(`Unhandled LLM loop action: ${JSON.stringify(value)}`);
|
|
4
|
+
};
|
|
5
|
+
export const reduceLlmLoop = (state, action) => {
|
|
6
|
+
switch (action.type) {
|
|
7
|
+
case 'round.prepared':
|
|
8
|
+
return {
|
|
9
|
+
...state,
|
|
10
|
+
phase: 'streaming',
|
|
11
|
+
committedMessages: [...action.messages],
|
|
12
|
+
roundCheckpoint: [...action.messages],
|
|
13
|
+
partial: { reasoning: '', draft: '' },
|
|
14
|
+
suspendedBy: undefined,
|
|
15
|
+
failure: undefined,
|
|
16
|
+
};
|
|
17
|
+
case 'stream.reasoning':
|
|
18
|
+
return {
|
|
19
|
+
...state,
|
|
20
|
+
partial: {
|
|
21
|
+
...state.partial,
|
|
22
|
+
reasoning: `${state.partial.reasoning}${action.text}`,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
case 'stream.draft':
|
|
26
|
+
return {
|
|
27
|
+
...state,
|
|
28
|
+
partial: {
|
|
29
|
+
...state.partial,
|
|
30
|
+
draft: `${state.partial.draft}${action.text}`,
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
case 'stream.done':
|
|
34
|
+
if (action.toolCalls !== undefined && action.toolCalls.length > 0) {
|
|
35
|
+
return {
|
|
36
|
+
...state,
|
|
37
|
+
phase: 'tools',
|
|
38
|
+
committedMessages: [
|
|
39
|
+
...state.committedMessages,
|
|
40
|
+
{
|
|
41
|
+
role: 'assistant',
|
|
42
|
+
content: action.text.length > 0
|
|
43
|
+
? action.text
|
|
44
|
+
: state.partial.draft,
|
|
45
|
+
tool_calls: action.toolCalls,
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
partial: {
|
|
49
|
+
...state.partial,
|
|
50
|
+
draft: action.text.length > 0
|
|
51
|
+
? action.text
|
|
52
|
+
: state.partial.draft,
|
|
53
|
+
toolCalls: action.toolCalls,
|
|
54
|
+
},
|
|
55
|
+
pendingToolCalls: action.toolCalls,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
...state,
|
|
60
|
+
phase: 'complete',
|
|
61
|
+
partial: {
|
|
62
|
+
...state.partial,
|
|
63
|
+
draft: action.text.length > 0
|
|
64
|
+
? action.text
|
|
65
|
+
: state.partial.draft,
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
case 'stream.paused':
|
|
69
|
+
return {
|
|
70
|
+
...state,
|
|
71
|
+
phase: 'suspended',
|
|
72
|
+
committedMessages: [...state.roundCheckpoint],
|
|
73
|
+
suspendedBy: { kind: 'user-pause' },
|
|
74
|
+
};
|
|
75
|
+
case 'stream.idle':
|
|
76
|
+
return {
|
|
77
|
+
...state,
|
|
78
|
+
phase: 'suspended',
|
|
79
|
+
committedMessages: [...state.roundCheckpoint],
|
|
80
|
+
suspendedBy: {
|
|
81
|
+
kind: 'stream-idle',
|
|
82
|
+
idleMs: action.idleMs,
|
|
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
|
+
};
|
|
96
|
+
case 'provider.failed':
|
|
97
|
+
return {
|
|
98
|
+
...state,
|
|
99
|
+
phase: action.failure.recoverable ? 'suspended' : 'failed',
|
|
100
|
+
committedMessages: [...state.roundCheckpoint],
|
|
101
|
+
suspendedBy: action.failure.recoverable
|
|
102
|
+
? {
|
|
103
|
+
kind: 'provider-failure',
|
|
104
|
+
failure: action.failure,
|
|
105
|
+
}
|
|
106
|
+
: undefined,
|
|
107
|
+
failure: action.failure,
|
|
108
|
+
};
|
|
109
|
+
case 'tool.completed': {
|
|
110
|
+
const pendingToolCalls = state.pendingToolCalls.slice(1);
|
|
111
|
+
const messages = [
|
|
112
|
+
...state.committedMessages,
|
|
113
|
+
{
|
|
114
|
+
role: 'tool',
|
|
115
|
+
content: action.result,
|
|
116
|
+
tool_call_id: action.call.id,
|
|
117
|
+
},
|
|
118
|
+
];
|
|
119
|
+
return {
|
|
120
|
+
...state,
|
|
121
|
+
phase: pendingToolCalls.length === 0 ? 'prepare' : 'tools',
|
|
122
|
+
committedMessages: messages,
|
|
123
|
+
roundCheckpoint: pendingToolCalls.length === 0
|
|
124
|
+
? messages
|
|
125
|
+
: state.roundCheckpoint,
|
|
126
|
+
iteration: pendingToolCalls.length === 0
|
|
127
|
+
? state.iteration + 1
|
|
128
|
+
: state.iteration,
|
|
129
|
+
transientAttempts: pendingToolCalls.length === 0 ? 0 : state.transientAttempts,
|
|
130
|
+
partial: pendingToolCalls.length === 0
|
|
131
|
+
? { reasoning: '', draft: '' }
|
|
132
|
+
: state.partial,
|
|
133
|
+
pendingToolCalls,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
case 'subagent.waiting':
|
|
137
|
+
return {
|
|
138
|
+
...state,
|
|
139
|
+
phase: 'waiting-subagent',
|
|
140
|
+
openSpawnCallId: action.callId,
|
|
141
|
+
};
|
|
142
|
+
case 'subagent.completed':
|
|
143
|
+
return {
|
|
144
|
+
...state,
|
|
145
|
+
phase: 'tools',
|
|
146
|
+
openSpawnCallId: undefined,
|
|
147
|
+
};
|
|
148
|
+
case 'retry.scheduled':
|
|
149
|
+
return {
|
|
150
|
+
...state,
|
|
151
|
+
phase: 'prepare',
|
|
152
|
+
committedMessages: [...state.roundCheckpoint],
|
|
153
|
+
transientAttempts: state.transientAttempts + 1,
|
|
154
|
+
partial: { reasoning: '', draft: '' },
|
|
155
|
+
pendingToolCalls: [],
|
|
156
|
+
suspendedBy: undefined,
|
|
157
|
+
failure: undefined,
|
|
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
|
+
};
|
|
180
|
+
case 'steer.received': {
|
|
181
|
+
const text = action.text?.trim() ?? '';
|
|
182
|
+
const messages = text.length === 0
|
|
183
|
+
? [...state.roundCheckpoint]
|
|
184
|
+
: [
|
|
185
|
+
...state.roundCheckpoint,
|
|
186
|
+
{ role: 'user', content: text },
|
|
187
|
+
];
|
|
188
|
+
return {
|
|
189
|
+
...state,
|
|
190
|
+
phase: 'prepare',
|
|
191
|
+
committedMessages: messages,
|
|
192
|
+
roundCheckpoint: messages,
|
|
193
|
+
transientAttempts: 0,
|
|
194
|
+
autokickAttempts: 0,
|
|
195
|
+
autokickKickAttempts: 0,
|
|
196
|
+
lastAutokickAt: undefined,
|
|
197
|
+
partial: { reasoning: '', draft: '' },
|
|
198
|
+
pendingToolCalls: [],
|
|
199
|
+
suspendedBy: undefined,
|
|
200
|
+
failure: undefined,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
case 'round.completed':
|
|
204
|
+
return { ...state, phase: 'complete' };
|
|
205
|
+
case 'failure.fatal':
|
|
206
|
+
return {
|
|
207
|
+
...state,
|
|
208
|
+
phase: 'failed',
|
|
209
|
+
failure: action.failure,
|
|
210
|
+
};
|
|
211
|
+
case 'cancel.requested':
|
|
212
|
+
return { ...state, phase: 'cancelled' };
|
|
213
|
+
default:
|
|
214
|
+
return assertNever(action);
|
|
215
|
+
}
|
|
216
|
+
};
|