@openclaw/lobster 2026.9.4 → 2026.9.6
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/assets/activity.svg +4 -0
- package/assets/icon.png +0 -0
- package/dist/index.js +39 -10
- package/node_modules/@clawdbot/lobster/README.md +129 -131
- package/node_modules/@clawdbot/lobster/VISION.md +15 -238
- package/node_modules/@clawdbot/lobster/bin/clawd.invoke.js +2 -15
- package/node_modules/@clawdbot/lobster/bin/invoke.js +19 -0
- package/node_modules/@clawdbot/lobster/bin/lobster.js +2 -21
- package/node_modules/@clawdbot/lobster/bin/openclaw.invoke.js +2 -18
- package/node_modules/@clawdbot/lobster/dist/src/abortable_process.js +297 -0
- package/node_modules/@clawdbot/lobster/dist/src/abortable_process.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/src/cli.js +128 -296
- package/node_modules/@clawdbot/lobster/dist/src/cli.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/command_tokens.js +81 -0
- package/node_modules/@clawdbot/lobster/dist/src/command_tokens.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/src/commands/commands_list.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/registry.js +2 -0
- package/node_modules/@clawdbot/lobster/dist/src/commands/registry.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/approve.js +2 -0
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/approve.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/ask.js +3 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/ask.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/dedupe.js +1 -12
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/dedupe.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/diff_last.js +6 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/diff_last.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/email_triage.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/exec.js +30 -34
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/exec.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/gog_gmail_search.js +12 -25
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/gog_gmail_search.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/gog_gmail_send.js +19 -25
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/gog_gmail_send.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/group_by.js +2 -14
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/group_by.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/head.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/json.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/llm_invoke.js +260 -42
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/llm_invoke.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/map.js +2 -13
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/map.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/openclaw_agent.js +139 -0
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/openclaw_agent.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/openclaw_invoke.js +20 -2
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/openclaw_invoke.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/pick.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/sort.js +4 -21
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/sort.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/state.js +48 -20
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/state.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/table.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/template.js +2 -13
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/template.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/stdlib/where.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/workflows/workflows_list.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/commands/workflows/workflows_run.js +0 -18
- package/node_modules/@clawdbot/lobster/dist/src/commands/workflows/workflows_run.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/core/cost_tracker.js +45 -3
- package/node_modules/@clawdbot/lobster/dist/src/core/cost_tracker.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/core/filters.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/core/llm_accounting.js +304 -0
- package/node_modules/@clawdbot/lobster/dist/src/core/llm_accounting.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/src/core/retry.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/core/tool_runtime.js +147 -21
- package/node_modules/@clawdbot/lobster/dist/src/core/tool_runtime.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/core/value_path.js +11 -0
- package/node_modules/@clawdbot/lobster/dist/src/core/value_path.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/src/input_request.js +4 -2
- package/node_modules/@clawdbot/lobster/dist/src/input_request.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/parser.js +5 -69
- package/node_modules/@clawdbot/lobster/dist/src/parser.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/pipeline_resume_state.js +241 -74
- package/node_modules/@clawdbot/lobster/dist/src/pipeline_resume_state.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/read_line.js +52 -7
- package/node_modules/@clawdbot/lobster/dist/src/read_line.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/read_response_text.js +86 -0
- package/node_modules/@clawdbot/lobster/dist/src/read_response_text.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/src/recipes/github/index.js +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/recipes/github/pr-monitor.js +9 -66
- package/node_modules/@clawdbot/lobster/dist/src/recipes/github/pr-monitor.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/recipes/github/read_pr.js +45 -0
- package/node_modules/@clawdbot/lobster/dist/src/recipes/github/read_pr.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/src/recipes/github/snapshot.js +45 -0
- package/node_modules/@clawdbot/lobster/dist/src/recipes/github/snapshot.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/src/recipes/github/stages/pr-view.js +13 -65
- package/node_modules/@clawdbot/lobster/dist/src/recipes/github/stages/pr-view.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/recipes/registry.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/renderers/json.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/resume.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/runtime.js +187 -17
- package/node_modules/@clawdbot/lobster/dist/src/runtime.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/sdk/Lobster.js +25 -134
- package/node_modules/@clawdbot/lobster/dist/src/sdk/Lobster.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/sdk/index.js +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/sdk/primitives/approve.js +1 -2
- package/node_modules/@clawdbot/lobster/dist/src/sdk/primitives/approve.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/sdk/primitives/diff.js +11 -86
- package/node_modules/@clawdbot/lobster/dist/src/sdk/primitives/diff.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/sdk/primitives/exec.js +20 -96
- package/node_modules/@clawdbot/lobster/dist/src/sdk/primitives/exec.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/sdk/primitives/state.js +8 -106
- package/node_modules/@clawdbot/lobster/dist/src/sdk/primitives/state.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/sdk/runtime.js +2 -13
- package/node_modules/@clawdbot/lobster/dist/src/sdk/runtime.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/sdk/state_env.js +6 -0
- package/node_modules/@clawdbot/lobster/dist/src/sdk/state_env.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/src/shell.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/state/atomic_file.js +192 -0
- package/node_modules/@clawdbot/lobster/dist/src/state/atomic_file.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/src/state/store.js +550 -136
- package/node_modules/@clawdbot/lobster/dist/src/state/store.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/token.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/validation.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/workflows/dry_run.js +262 -0
- package/node_modules/@clawdbot/lobster/dist/src/workflows/dry_run.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/src/workflows/expressions.js +345 -0
- package/node_modules/@clawdbot/lobster/dist/src/workflows/expressions.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/src/workflows/file.js +950 -1285
- package/node_modules/@clawdbot/lobster/dist/src/workflows/file.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/workflows/github_pr_monitor.js +20 -90
- package/node_modules/@clawdbot/lobster/dist/src/workflows/github_pr_monitor.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/workflows/graph.js +9 -8
- package/node_modules/@clawdbot/lobster/dist/src/workflows/graph.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/workflows/load.js +347 -0
- package/node_modules/@clawdbot/lobster/dist/src/workflows/load.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/src/workflows/registry.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/src/workflows/types.js +2 -0
- package/node_modules/@clawdbot/lobster/dist/src/workflows/types.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/src/workflows/values.js +93 -0
- package/node_modules/@clawdbot/lobster/dist/src/workflows/values.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/test/approval_id.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/approve_preview.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/bin_smoke.test.js +25 -0
- package/node_modules/@clawdbot/lobster/dist/test/bin_smoke.test.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/test/cancellation.test.js +5171 -0
- package/node_modules/@clawdbot/lobster/dist/test/cancellation.test.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/test/clawd_invoke.test.js +22 -0
- package/node_modules/@clawdbot/lobster/dist/test/clawd_invoke.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/clawd_invoke_legacy.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/cli_run_errors.test.js +53 -0
- package/node_modules/@clawdbot/lobster/dist/test/cli_run_errors.test.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/test/cli_run_file_args_json.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/command_arguments.test.js +82 -0
- package/node_modules/@clawdbot/lobster/dist/test/command_arguments.test.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/test/commands_list.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/condition_comparison.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/core_tool_runtime.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/cost_tracker.test.js +1774 -12
- package/node_modules/@clawdbot/lobster/dist/test/cost_tracker.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/dedupe.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/diff_last.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/doctor.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/dry_run.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/email_triage.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/exec_stdin.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/for_each.test.js +254 -0
- package/node_modules/@clawdbot/lobster/dist/test/for_each.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/github_pr_notify_format.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/github_pr_summary.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/github_pr_view.test.js +176 -0
- package/node_modules/@clawdbot/lobster/dist/test/github_pr_view.test.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/test/gog_gmail_send.test.js +100 -0
- package/node_modules/@clawdbot/lobster/dist/test/gog_gmail_send.test.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/test/group_by.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/helpers/node_shell_fixture.js +17 -0
- package/node_modules/@clawdbot/lobster/dist/test/helpers/node_shell_fixture.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/test/helpers/wait_for_pid.js +19 -0
- package/node_modules/@clawdbot/lobster/dist/test/helpers/wait_for_pid.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/test/http_response_body_cap.test.js +318 -0
- package/node_modules/@clawdbot/lobster/dist/test/http_response_body_cap.test.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/test/llm_invoke.test.js +948 -1
- package/node_modules/@clawdbot/lobster/dist/test/llm_invoke.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/llm_task_invoke.test.js +103 -0
- package/node_modules/@clawdbot/lobster/dist/test/llm_task_invoke.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/map.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/multi_approval_resume.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/on_error.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/openclaw_agent.test.js +169 -0
- package/node_modules/@clawdbot/lobster/dist/test/openclaw_agent.test.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/test/openclaw_dispatch_retry.test.js +96 -0
- package/node_modules/@clawdbot/lobster/dist/test/openclaw_dispatch_retry.test.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/test/openclaw_invoke_alias.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/parallel.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/parser.test.js +57 -0
- package/node_modules/@clawdbot/lobster/dist/test/parser.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/pipeline_resume_state.test.js +65 -0
- package/node_modules/@clawdbot/lobster/dist/test/pipeline_resume_state.test.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/test/process_output_limit.test.js +175 -0
- package/node_modules/@clawdbot/lobster/dist/test/process_output_limit.test.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/test/read_line.test.js +54 -0
- package/node_modules/@clawdbot/lobster/dist/test/read_line.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/release_changelog.test.js +39 -0
- package/node_modules/@clawdbot/lobster/dist/test/release_changelog.test.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/test/request_input.test.js +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/request_input.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/resume.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/sdk_exec.test.js +248 -0
- package/node_modules/@clawdbot/lobster/dist/test/sdk_exec.test.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/test/sdk_lobster.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/shell.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/sort.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/state.test.js +584 -1
- package/node_modules/@clawdbot/lobster/dist/test/state.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/step_retry.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/step_stdin_epipe.test.js +44 -0
- package/node_modules/@clawdbot/lobster/dist/test/step_stdin_epipe.test.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/test/step_timeout.test.js +67 -1
- package/node_modules/@clawdbot/lobster/dist/test/step_timeout.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/template.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/template_filters.test.js +37 -0
- package/node_modules/@clawdbot/lobster/dist/test/template_filters.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/tool_envelope_version.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/tool_mode.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/validation.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/where.test.js +94 -0
- package/node_modules/@clawdbot/lobster/dist/test/where.test.js.map +1 -0
- package/node_modules/@clawdbot/lobster/dist/test/workflow_args_env.test.js +5 -3
- package/node_modules/@clawdbot/lobster/dist/test/workflow_args_env.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/workflow_composition.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/workflow_file.test.js +647 -1
- package/node_modules/@clawdbot/lobster/dist/test/workflow_file.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/workflow_graph.test.js +13 -3
- package/node_modules/@clawdbot/lobster/dist/test/workflow_graph.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/dist/test/workflows.test.js.map +1 -1
- package/node_modules/@clawdbot/lobster/package.json +72 -73
- package/node_modules/typebox/build/compile/validator.d.mts +1 -1
- package/node_modules/typebox/build/compile/validator.mjs +1 -1
- package/node_modules/typebox/build/format/idna/idn-hostname.mjs +7 -5
- package/node_modules/typebox/build/format/iri.mjs +5 -1
- package/node_modules/typebox/build/guard/emit.mjs +2 -4
- package/node_modules/typebox/build/guard/guard.mjs +6 -18
- package/node_modules/typebox/build/guard/string.mjs +16 -24
- package/node_modules/typebox/build/schema/build.mjs +2 -2
- package/node_modules/typebox/build/schema/check.mjs +1 -1
- package/node_modules/typebox/build/schema/compile.d.mts +3 -2
- package/node_modules/typebox/build/schema/compile.mjs +8 -8
- package/node_modules/typebox/build/schema/engine/_context.d.mts +6 -7
- package/node_modules/typebox/build/schema/engine/_context.mjs +23 -15
- package/node_modules/typebox/build/schema/engine/_functions.d.mts +2 -2
- package/node_modules/typebox/build/schema/engine/_functions.mjs +1 -1
- package/node_modules/typebox/build/schema/engine/_reducer.d.mts +3 -3
- package/node_modules/typebox/build/schema/engine/_refine.d.mts +5 -5
- package/node_modules/typebox/build/schema/engine/_refine.mjs +4 -7
- package/node_modules/typebox/build/schema/engine/_stack.d.mts +34 -16
- package/node_modules/typebox/build/schema/engine/_stack.mjs +148 -104
- package/node_modules/typebox/build/schema/engine/additionalItems.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/additionalProperties.d.mts +8 -8
- package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +26 -18
- package/node_modules/typebox/build/schema/engine/allOf.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/allOf.mjs +3 -3
- package/node_modules/typebox/build/schema/engine/anyOf.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/anyOf.mjs +5 -10
- package/node_modules/typebox/build/schema/engine/boolean.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/boolean.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/const.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/const.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/contains.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/contains.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/dependencies.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/dependencies.mjs +3 -6
- package/node_modules/typebox/build/schema/engine/dependentRequired.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/dependentRequired.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/dependentSchemas.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/dynamicRef.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/dynamicRef.mjs +11 -7
- package/node_modules/typebox/build/schema/engine/enum.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/enum.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/exclusiveMaximum.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/exclusiveMaximum.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/exclusiveMinimum.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/exclusiveMinimum.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/format.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/format.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/if.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/if.mjs +7 -15
- package/node_modules/typebox/build/schema/engine/items.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/items.mjs +1 -1
- package/node_modules/typebox/build/schema/engine/maxContains.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/maxContains.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/maxItems.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/maxItems.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/maxLength.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/maxLength.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/maxProperties.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/maxProperties.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/maximum.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/maximum.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/minContains.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/minContains.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/minItems.d.mts +5 -5
- package/node_modules/typebox/build/schema/engine/minItems.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/minLength.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/minLength.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/minProperties.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/minProperties.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/minimum.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/minimum.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/multipleOf.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/multipleOf.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/not.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/not.mjs +4 -8
- package/node_modules/typebox/build/schema/engine/oneOf.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/oneOf.mjs +6 -11
- package/node_modules/typebox/build/schema/engine/pattern.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/pattern.mjs +3 -7
- package/node_modules/typebox/build/schema/engine/patternProperties.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/patternProperties.mjs +1 -1
- package/node_modules/typebox/build/schema/engine/prefixItems.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/prefixItems.mjs +1 -1
- package/node_modules/typebox/build/schema/engine/properties.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/properties.mjs +1 -1
- package/node_modules/typebox/build/schema/engine/propertyNames.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/propertyNames.mjs +4 -10
- package/node_modules/typebox/build/schema/engine/recursiveRef.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/recursiveRef.mjs +11 -7
- package/node_modules/typebox/build/schema/engine/ref.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/ref.mjs +19 -15
- package/node_modules/typebox/build/schema/engine/required.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/required.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/schema.d.mts +7 -7
- package/node_modules/typebox/build/schema/engine/schema.mjs +137 -133
- package/node_modules/typebox/build/schema/engine/type.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/type.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/unevaluatedItems.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/unevaluatedItems.mjs +5 -9
- package/node_modules/typebox/build/schema/engine/unevaluatedProperties.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/unevaluatedProperties.mjs +5 -9
- package/node_modules/typebox/build/schema/engine/uniqueItems.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/uniqueItems.mjs +2 -6
- package/node_modules/typebox/build/schema/errors.d.mts +2 -2
- package/node_modules/typebox/build/schema/errors.mjs +8 -14
- package/node_modules/typebox/build/schema/intern/index.d.mts +1 -0
- package/node_modules/typebox/build/schema/intern/index.mjs +1 -0
- package/node_modules/typebox/build/schema/intern/intern.d.mts +11 -0
- package/node_modules/typebox/build/schema/intern/intern.mjs +293 -0
- package/node_modules/typebox/build/schema/meta/draft_2019_09.d.mts +2 -0
- package/node_modules/typebox/build/schema/meta/draft_2019_09.mjs +288 -0
- package/node_modules/typebox/build/schema/meta/draft_2020_12.d.mts +2 -0
- package/node_modules/typebox/build/schema/meta/draft_2020_12.mjs +300 -0
- package/node_modules/typebox/build/schema/meta/draft_3.d.mts +2 -0
- package/node_modules/typebox/build/schema/meta/draft_3.mjs +143 -0
- package/node_modules/typebox/build/schema/meta/draft_4.d.mts +2 -0
- package/node_modules/typebox/build/schema/meta/draft_4.mjs +149 -0
- package/node_modules/typebox/build/schema/meta/draft_6.d.mts +2 -0
- package/node_modules/typebox/build/schema/meta/draft_6.mjs +155 -0
- package/node_modules/typebox/build/schema/meta/draft_7.d.mts +2 -0
- package/node_modules/typebox/build/schema/meta/draft_7.mjs +172 -0
- package/node_modules/typebox/build/schema/meta/index.d.mts +2 -0
- package/node_modules/typebox/build/schema/meta/index.mjs +2 -0
- package/node_modules/typebox/build/schema/meta/meta.d.mts +9 -0
- package/node_modules/typebox/build/schema/meta/meta.mjs +15 -0
- package/node_modules/typebox/build/schema/meta/schema.d.mts +6 -0
- package/node_modules/typebox/build/schema/meta/schema.mjs +1 -0
- package/node_modules/typebox/build/schema/parse.d.mts +1 -0
- package/node_modules/typebox/build/schema/parse.mjs +10 -5
- package/node_modules/typebox/build/schema/resolve/resolve.d.mts +8 -3
- package/node_modules/typebox/build/schema/resolve/resolve.mjs +268 -139
- package/node_modules/typebox/build/schema/schema.d.mts +2 -0
- package/node_modules/typebox/build/schema/schema.mjs +2 -0
- package/node_modules/typebox/build/value/errors/errors.d.mts +2 -12
- package/node_modules/typebox/build/value/errors/errors.mjs +2 -7
- package/node_modules/typebox/package.json +1 -1
- package/node_modules/typebox/readme.md +59 -89
- package/openclaw.plugin.json +1 -1
- package/package.json +10 -7
- package/node_modules/@clawdbot/lobster/dist/src/sdk/token.js +0 -9
- package/node_modules/@clawdbot/lobster/dist/src/sdk/token.js.map +0 -1
|
@@ -1,13 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
const parts = path.split(".").filter(Boolean);
|
|
3
|
-
let cur = obj;
|
|
4
|
-
for (const p of parts) {
|
|
5
|
-
if (cur == null)
|
|
6
|
-
return undefined;
|
|
7
|
-
cur = cur[p];
|
|
8
|
-
}
|
|
9
|
-
return cur;
|
|
10
|
-
}
|
|
1
|
+
import { getByPath } from "../../core/value_path.js";
|
|
11
2
|
export const groupByCommand = {
|
|
12
3
|
name: "groupBy",
|
|
13
4
|
meta: {
|
|
@@ -36,20 +27,17 @@ export const groupByCommand = {
|
|
|
36
27
|
if (!keyPath)
|
|
37
28
|
throw new Error("groupBy requires --key");
|
|
38
29
|
const groups = new Map();
|
|
39
|
-
const order = [];
|
|
40
30
|
for await (const item of input) {
|
|
41
31
|
const keyVal = getByPath(item, keyPath);
|
|
42
32
|
const k = JSON.stringify(keyVal);
|
|
43
33
|
if (!groups.has(k)) {
|
|
44
34
|
groups.set(k, { key: keyVal, items: [] });
|
|
45
|
-
order.push(k);
|
|
46
35
|
}
|
|
47
36
|
groups.get(k).items.push(item);
|
|
48
37
|
}
|
|
49
38
|
return {
|
|
50
39
|
output: (async function* () {
|
|
51
|
-
for (const
|
|
52
|
-
const g = groups.get(k);
|
|
40
|
+
for (const g of groups.values()) {
|
|
53
41
|
yield { key: g.key, items: g.items, count: g.items.length };
|
|
54
42
|
}
|
|
55
43
|
})(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"group_by.js","sourceRoot":"","sources":["../../../../src/commands/stdlib/group_by.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"group_by.js","sourceRoot":"","sources":["../../../../src/commands/stdlib/group_by.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAErD,MAAM,CAAC,MAAM,cAAc,GAAG;IAC7B,IAAI,EAAE,SAAS;IACf,IAAI,EAAE;QACL,WAAW,EAAE,2CAA2C;QACxD,UAAU,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACX,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,qCAAqC,EAAE;gBAC3E,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;aAC/C;YACD,QAAQ,EAAE,CAAC,KAAK,CAAC;SACjB;QACD,WAAW,EAAE,EAAE;KACf;IACD,IAAI;QACH,OAAO,CACN,oCAAoC;YACpC,UAAU;YACV,gCAAgC;YAChC,WAAW;YACX,+CAA+C;YAC/C,UAAU;YACV,0DAA0D,CAC1D,CAAC;IACH,CAAC;IACD,KAAK,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,IAAI,EAAO;QAC7B,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAC9C,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;QAExD,MAAM,MAAM,GAAG,IAAI,GAAG,EAA8C,CAAC;QAErE,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YAChC,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YACxC,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YACjC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpB,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;YAC3C,CAAC;YACD,MAAM,CAAC,GAAG,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjC,CAAC;QAED,OAAO;YACN,MAAM,EAAE,CAAC,KAAK,SAAS,CAAC;gBACvB,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;oBACjC,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;gBAC7D,CAAC;YACF,CAAC,CAAC,EAAE;SACJ,CAAC;IACH,CAAC;CACD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"head.js","sourceRoot":"","sources":["../../../../src/commands/stdlib/head.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG;
|
|
1
|
+
{"version":3,"file":"head.js","sourceRoot":"","sources":["../../../../src/commands/stdlib/head.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG;IAC1B,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE;QACL,WAAW,EAAE,oBAAoB;QACjC,UAAU,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACX,CAAC,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,yBAAyB,EAAE,OAAO,EAAE,EAAE,EAAE;gBAC1E,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;aAC/C;YACD,QAAQ,EAAE,EAAE;SACZ;QACD,WAAW,EAAE,EAAE;KACf;IACD,IAAI;QACH,OAAO,sDAAsD,CAAC;IAC/D,CAAC;IACD,KAAK,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE;QACxB,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACrD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAE5F,OAAO;YACN,MAAM,EAAE,CAAC,KAAK,SAAS,CAAC;gBACvB,IAAI,CAAC,GAAG,CAAC,CAAC;gBACV,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;oBAChC,IAAI,CAAC,EAAE,IAAI,CAAC;wBAAE,MAAM;oBACpB,MAAM,IAAI,CAAC;gBACZ,CAAC;YACF,CAAC,CAAC,EAAE;SACJ,CAAC;IACH,CAAC;CACD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json.js","sourceRoot":"","sources":["../../../../src/commands/stdlib/json.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG;
|
|
1
|
+
{"version":3,"file":"json.js","sourceRoot":"","sources":["../../../../src/commands/stdlib/json.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG;IAC1B,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE;QACL,WAAW,EAAE,gCAAgC;QAC7C,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;QAC5D,WAAW,EAAE,EAAE;KACf;IACD,IAAI;QACH,OAAO,iEAAiE,CAAC;IAC1E,CAAC;IACD,KAAK,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE;QACvB,MAAM,KAAK,GAAG,EAAE,CAAC;QACjB,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,KAAK;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjD,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvB,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAClD,CAAC;CACD,CAAC;AAEF,KAAK,SAAS,CAAC,CAAC,WAAW,KAAI,CAAC"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { markLlmItem } from "../../core/llm_accounting.js";
|
|
1
2
|
import path from "node:path";
|
|
2
3
|
import { promises as fsp } from "node:fs";
|
|
3
4
|
import { createHash } from "node:crypto";
|
|
4
5
|
import { Ajv } from "ajv";
|
|
5
|
-
import { ensureDirectory, isJsonSyntaxError,
|
|
6
|
+
import { diffAndStore, ensureDirectory, atomicWriteWasPublished, isJsonSyntaxError, readStateJsonWithLock, stableStringify, withFileLock, writeFileAtomic, } from "../../state/store.js";
|
|
6
7
|
import { createCompileCached } from "../../validation.js";
|
|
8
|
+
import { httpResponseLimitFromEnv, readResponseTextCapped } from "../../read_response_text.js";
|
|
7
9
|
const ajv = new Ajv({ allErrors: true, strict: false });
|
|
8
10
|
const compileCachedLocal = createCompileCached(ajv);
|
|
9
11
|
const artifactSchema = {
|
|
@@ -89,6 +91,33 @@ const validatePayload = ajv.compile(payloadSchema);
|
|
|
89
91
|
const validateResponseEnvelope = ajv.compile(responseSchema);
|
|
90
92
|
const DEFAULT_MAX_VALIDATION_RETRIES = 1;
|
|
91
93
|
const STATE_VERSION = 1;
|
|
94
|
+
// Identity version of the response cache key. See computeCacheKey.
|
|
95
|
+
const CACHE_KEY_VERSION = 2;
|
|
96
|
+
/**
|
|
97
|
+
* Opens a charge for a live call, and only for one that costs something. An answer that reports
|
|
98
|
+
* no usage is billed nowhere however many times it is replayed, so a charge for it would sit in
|
|
99
|
+
* the ledger with nothing to settle it -- and would be handed to the next caller with a real
|
|
100
|
+
* call to account for, leaving that one's charge open to be billed a second time.
|
|
101
|
+
*/
|
|
102
|
+
function recordLiveCharge(ctx, cacheKey, item) {
|
|
103
|
+
const cost = chargeCostOf(item);
|
|
104
|
+
if (!cost)
|
|
105
|
+
return;
|
|
106
|
+
ledgerFrom(ctx)?.record(cacheKey, cost);
|
|
107
|
+
}
|
|
108
|
+
/** The cost of a live call, read from the item this module just built for it. */
|
|
109
|
+
function chargeCostOf(item) {
|
|
110
|
+
const usage = item?.usage;
|
|
111
|
+
if (!usage || typeof usage !== "object")
|
|
112
|
+
return undefined;
|
|
113
|
+
return { model: typeof item?.model === "string" ? item.model : null, usage };
|
|
114
|
+
}
|
|
115
|
+
function ledgerFrom(ctx) {
|
|
116
|
+
const ledger = ctx?.llmSpendLedger;
|
|
117
|
+
if (!ledger || typeof ledger !== "object")
|
|
118
|
+
return null;
|
|
119
|
+
return typeof ledger.record === "function" && typeof ledger.claim === "function" ? ledger : null;
|
|
120
|
+
}
|
|
92
121
|
export const llmInvokeCommand = createLlmInvokeCommand({
|
|
93
122
|
name: "llm.invoke",
|
|
94
123
|
itemKind: "llm.invoke",
|
|
@@ -164,7 +193,7 @@ export function createLlmInvokeCommand(config) {
|
|
|
164
193
|
"schema-version": { type: "string", description: "Logical schema version for caching" },
|
|
165
194
|
"max-validation-retries": {
|
|
166
195
|
type: "number",
|
|
167
|
-
description: "
|
|
196
|
+
description: "Extra model calls allowed after the first when schema validation fails (default 1)",
|
|
168
197
|
},
|
|
169
198
|
temperature: { type: "number", description: "Sampling temperature" },
|
|
170
199
|
"max-output-tokens": { type: "number", description: "Max completion tokens" },
|
|
@@ -190,7 +219,8 @@ export function createLlmInvokeCommand(config) {
|
|
|
190
219
|
"Features:",
|
|
191
220
|
" - Typed payload validation before invoking the adapter.",
|
|
192
221
|
" - Run-state + file cache so resumes do not re-call the LLM.",
|
|
193
|
-
" - Optional JSON-schema enforcement
|
|
222
|
+
" - Optional JSON-schema enforcement, retried at most --max-validation-retries times",
|
|
223
|
+
" after the first call.",
|
|
194
224
|
"",
|
|
195
225
|
"Config:",
|
|
196
226
|
...config.helpConfig.map((line) => ` - ${line}`),
|
|
@@ -204,6 +234,10 @@ export function createLlmInvokeCommand(config) {
|
|
|
204
234
|
}
|
|
205
235
|
async function runLlmInvoke({ input, args, ctx, config, }) {
|
|
206
236
|
const env = ctx.env ?? process.env;
|
|
237
|
+
const signal = ctx?.signal;
|
|
238
|
+
// Run-state and cache hits return before any adapter call, so a cancelled run
|
|
239
|
+
// would otherwise still finish as a success.
|
|
240
|
+
throwIfCancelled(signal);
|
|
207
241
|
const provider = resolveProvider(args, env, config.defaultProvider, ctx);
|
|
208
242
|
const adapter = resolveAdapter({ provider, env, args, config, ctx });
|
|
209
243
|
const prompt = extractPrompt(args);
|
|
@@ -236,6 +270,9 @@ async function runLlmInvoke({ input, args, ctx, config, }) {
|
|
|
236
270
|
const inputArtifacts = [];
|
|
237
271
|
for await (const item of input)
|
|
238
272
|
inputArtifacts.push(item);
|
|
273
|
+
// Draining pipeline input waits on the upstream step, so a timeout can fire
|
|
274
|
+
// here. Re-check before the reuse lookups below can answer with a success.
|
|
275
|
+
throwIfCancelled(signal);
|
|
239
276
|
const normalizedArtifacts = [...inputArtifacts, ...providedArtifacts].map(normalizeArtifact);
|
|
240
277
|
const artifactHashes = normalizedArtifacts.map(hashArtifact);
|
|
241
278
|
const cacheKey = computeCacheKey({
|
|
@@ -245,21 +282,29 @@ async function runLlmInvoke({ input, args, ctx, config, }) {
|
|
|
245
282
|
schemaVersion,
|
|
246
283
|
artifactHashes,
|
|
247
284
|
outputSchema: userOutputSchema,
|
|
285
|
+
temperature,
|
|
286
|
+
maxOutputTokens,
|
|
248
287
|
});
|
|
249
288
|
if (stateKey && !forceRefresh) {
|
|
250
|
-
const stored = await readReusableLlmState(env, stateKey);
|
|
289
|
+
const stored = await readReusableLlmState(env, stateKey, ctx.signal);
|
|
290
|
+
// Reading run state is I/O of unbounded duration; a signal that aborted
|
|
291
|
+
// during it must not be overtaken by the replay below.
|
|
292
|
+
throwIfCancelled(signal);
|
|
251
293
|
const reused = pickReusableState(stored, cacheKey, config.stateType);
|
|
252
294
|
if (reused) {
|
|
295
|
+
const replay = { cacheKey, replayed: true };
|
|
253
296
|
return {
|
|
254
|
-
output: streamOf(reused.items.map((item) => ({ ...item, source: "run_state", cached: true }))),
|
|
297
|
+
output: streamOf(reused.items.map((item) => markLlmItem({ ...item, source: "run_state", cached: true, replayed: true }, replay))),
|
|
255
298
|
};
|
|
256
299
|
}
|
|
257
300
|
}
|
|
258
301
|
if (!disableCache && !forceRefresh) {
|
|
259
|
-
const cache = await readCacheEntry(env, cacheKey, config.cacheNamespace);
|
|
302
|
+
const cache = await readCacheEntry(env, cacheKey, config.cacheNamespace, ctx.signal);
|
|
303
|
+
throwIfCancelled(signal);
|
|
260
304
|
if (cache) {
|
|
305
|
+
const replay = { cacheKey, replayed: true };
|
|
261
306
|
return {
|
|
262
|
-
output: streamOf(cache.items.map((item) => ({ ...item, source: "cache", cached: true }))),
|
|
307
|
+
output: streamOf(cache.items.map((item) => markLlmItem({ ...item, source: "cache", cached: true, replayed: true }, replay))),
|
|
263
308
|
};
|
|
264
309
|
}
|
|
265
310
|
}
|
|
@@ -286,6 +331,7 @@ async function runLlmInvoke({ input, args, ctx, config, }) {
|
|
|
286
331
|
let attempt = 0;
|
|
287
332
|
let lastValidationErrors = [];
|
|
288
333
|
while (true) {
|
|
334
|
+
throwIfCancelled(signal);
|
|
289
335
|
attempt += 1;
|
|
290
336
|
if (attempt > 1) {
|
|
291
337
|
payload.retryContext = {
|
|
@@ -298,9 +344,16 @@ async function runLlmInvoke({ input, args, ctx, config, }) {
|
|
|
298
344
|
}
|
|
299
345
|
let responseEnvelope;
|
|
300
346
|
try {
|
|
301
|
-
|
|
347
|
+
ctx.signal?.throwIfAborted();
|
|
348
|
+
responseEnvelope = await abortable(adapter.invoke({ env, args, payload, signal: ctx.signal }), signal);
|
|
349
|
+
ctx.signal?.throwIfAborted();
|
|
302
350
|
}
|
|
303
351
|
catch (err) {
|
|
352
|
+
// Cancellation is the caller's error, not an adapter failure: surface it
|
|
353
|
+
// as an abort so workflow timeout and abort handling still recognizes it,
|
|
354
|
+
// rather than wrapping it in a "request failed" adapter error.
|
|
355
|
+
if (signal?.aborted)
|
|
356
|
+
throw asCancellation(err, signal);
|
|
304
357
|
throw new Error(`${config.name} request failed: ${err?.message ?? String(err)}`);
|
|
305
358
|
}
|
|
306
359
|
if (!validateResponseEnvelope(responseEnvelope)) {
|
|
@@ -319,37 +372,112 @@ async function runLlmInvoke({ input, args, ctx, config, }) {
|
|
|
319
372
|
attempt,
|
|
320
373
|
itemKind: config.itemKind,
|
|
321
374
|
});
|
|
375
|
+
const live = { cacheKey, replayed: false };
|
|
376
|
+
for (const item of normalized)
|
|
377
|
+
markLlmItem(item, live);
|
|
378
|
+
// The provider has answered and been paid, so the charge is opened here rather than at
|
|
379
|
+
// either of the returns below. An attempt the local validator rejects never reaches one
|
|
380
|
+
// of them -- it goes round the loop and asks again -- and its call was as real as the one
|
|
381
|
+
// that eventually satisfies the schema. Opening it here also puts it before the writes
|
|
382
|
+
// that store the answer: either can fail once run state already holds a replayable copy,
|
|
383
|
+
// and the retry that replays it must still find a charge to settle.
|
|
384
|
+
recordLiveCharge(ctx, cacheKey, normalized[0]);
|
|
322
385
|
if (!validator) {
|
|
386
|
+
ctx.signal?.throwIfAborted();
|
|
323
387
|
await persistOutputs({
|
|
324
388
|
env,
|
|
325
389
|
stateKey,
|
|
326
390
|
cacheKey,
|
|
327
391
|
items: normalized,
|
|
328
392
|
stateType: config.stateType,
|
|
393
|
+
signal: ctx.signal,
|
|
394
|
+
afterStore: disableCache
|
|
395
|
+
? undefined
|
|
396
|
+
: () => writeCacheEntry(env, cacheKey, normalized, config.cacheNamespace, ctx.signal),
|
|
329
397
|
});
|
|
330
|
-
if (!disableCache)
|
|
331
|
-
await writeCacheEntry(env, cacheKey, normalized, config.cacheNamespace);
|
|
332
398
|
return { output: streamOf(normalized) };
|
|
333
399
|
}
|
|
334
400
|
const structured = normalized[0]?.output?.data ?? null;
|
|
335
401
|
if (validator(structured)) {
|
|
402
|
+
ctx.signal?.throwIfAborted();
|
|
336
403
|
await persistOutputs({
|
|
337
404
|
env,
|
|
338
405
|
stateKey,
|
|
339
406
|
cacheKey,
|
|
340
407
|
items: normalized,
|
|
341
408
|
stateType: config.stateType,
|
|
409
|
+
signal: ctx.signal,
|
|
410
|
+
afterStore: disableCache
|
|
411
|
+
? undefined
|
|
412
|
+
: () => writeCacheEntry(env, cacheKey, normalized, config.cacheNamespace, ctx.signal),
|
|
342
413
|
});
|
|
343
|
-
if (!disableCache)
|
|
344
|
-
await writeCacheEntry(env, cacheKey, normalized, config.cacheNamespace);
|
|
345
414
|
return { output: streamOf(normalized) };
|
|
346
415
|
}
|
|
347
416
|
lastValidationErrors = collectAjvErrors(validator.errors);
|
|
348
|
-
if (attempt > maxValidationRetries
|
|
417
|
+
if (attempt > maxValidationRetries) {
|
|
349
418
|
throw new Error(`${config.name} output failed schema validation: ${lastValidationErrors.join("; ")}`);
|
|
350
419
|
}
|
|
351
420
|
}
|
|
352
421
|
}
|
|
422
|
+
/**
|
|
423
|
+
* Build the error a cancelled run rejects with.
|
|
424
|
+
*
|
|
425
|
+
* The workflow runner only treats an error named `AbortError` or coded
|
|
426
|
+
* `ABORT_ERR` as cancellation; everything else follows the step's retry and
|
|
427
|
+
* `on_error` policy. A host may abort with any reason it likes, so passing
|
|
428
|
+
* `signal.reason` straight through means `controller.abort(new Error("stop"))`
|
|
429
|
+
* leaves a cancelled step looking like an ordinary failure -- retried, or
|
|
430
|
+
* swallowed by `on_error: continue` and reported as a successful run. Keep the
|
|
431
|
+
* host's message and hang its reason off `cause`, but mark the rejection so the
|
|
432
|
+
* runner recognizes it.
|
|
433
|
+
*/
|
|
434
|
+
function cancellationError(signal) {
|
|
435
|
+
const reason = signal.reason;
|
|
436
|
+
if (reason === undefined || reason === null) {
|
|
437
|
+
return new DOMException("The operation was aborted.", "AbortError");
|
|
438
|
+
}
|
|
439
|
+
if (reason?.name === "AbortError" || reason?.code === "ABORT_ERR")
|
|
440
|
+
return reason;
|
|
441
|
+
const message = typeof reason?.message === "string" && reason.message ? reason.message : String(reason);
|
|
442
|
+
const error = new Error(message, { cause: reason });
|
|
443
|
+
error.name = "AbortError";
|
|
444
|
+
error.code = "ABORT_ERR";
|
|
445
|
+
return error;
|
|
446
|
+
}
|
|
447
|
+
/** Rethrow `err` when it already reads as cancellation, else the run's reason. */
|
|
448
|
+
function asCancellation(err, signal) {
|
|
449
|
+
if (err?.name === "AbortError" || err?.code === "ABORT_ERR")
|
|
450
|
+
return err;
|
|
451
|
+
return cancellationError(signal);
|
|
452
|
+
}
|
|
453
|
+
function throwIfCancelled(signal) {
|
|
454
|
+
if (signal?.aborted)
|
|
455
|
+
throw cancellationError(signal);
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Reject as soon as the run is cancelled instead of waiting for `promise`.
|
|
459
|
+
* HTTP adapters are cancelled at the socket, but an injected `ctx.llmAdapters`
|
|
460
|
+
* adapter may ignore `ctx.signal` entirely; without this, one of those keeps a
|
|
461
|
+
* timed-out step waiting for as long as it likes.
|
|
462
|
+
*/
|
|
463
|
+
function abortable(promise, signal) {
|
|
464
|
+
if (!signal)
|
|
465
|
+
return promise;
|
|
466
|
+
return new Promise((resolve, reject) => {
|
|
467
|
+
const onAbort = () => reject(cancellationError(signal));
|
|
468
|
+
// Observe `promise` before anything can settle the wrapper, including the
|
|
469
|
+
// already-aborted case below. An adapter can cancel the run from inside its own
|
|
470
|
+
// `invoke` and reject afterwards; rejecting here without watching that promise
|
|
471
|
+
// leaves the rejection unhandled, which ends the process under Node's default
|
|
472
|
+
// handling -- long after this step was cancelled cleanly.
|
|
473
|
+
promise.then(resolve, reject).finally(() => signal.removeEventListener("abort", onAbort));
|
|
474
|
+
if (signal.aborted) {
|
|
475
|
+
onAbort();
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
479
|
+
});
|
|
480
|
+
}
|
|
353
481
|
function resolveProvider(args, env, defaultProvider, ctx) {
|
|
354
482
|
const explicit = String(args.provider ?? env.LOBSTER_LLM_PROVIDER ?? "")
|
|
355
483
|
.trim()
|
|
@@ -385,11 +513,12 @@ function resolveAdapter({ provider, env, args, config, ctx, }) {
|
|
|
385
513
|
return {
|
|
386
514
|
provider,
|
|
387
515
|
source: typeof direct === "function" ? provider : (direct.source ?? provider),
|
|
388
|
-
async invoke({ payload }) {
|
|
389
|
-
return invoke({ env, args, payload, ctx });
|
|
516
|
+
async invoke({ payload, signal }) {
|
|
517
|
+
return invoke({ env, args, payload, ctx, signal });
|
|
390
518
|
},
|
|
391
519
|
};
|
|
392
520
|
}
|
|
521
|
+
const maxResponseBytes = httpResponseLimitFromEnv(env);
|
|
393
522
|
if (provider === "openclaw") {
|
|
394
523
|
const openclawUrl = String(env.OPENCLAW_URL ?? env.CLAWD_URL ?? "").trim();
|
|
395
524
|
if (!openclawUrl) {
|
|
@@ -400,8 +529,8 @@ function resolveAdapter({ provider, env, args, config, ctx, }) {
|
|
|
400
529
|
return {
|
|
401
530
|
provider,
|
|
402
531
|
source: config.sourceForProvider?.(provider) ?? "openclaw",
|
|
403
|
-
async invoke({ payload }) {
|
|
404
|
-
return invokeOpenClawAdapter({ endpoint, token, payload });
|
|
532
|
+
async invoke({ payload, signal }) {
|
|
533
|
+
return invokeOpenClawAdapter({ endpoint, token, payload, signal, maxResponseBytes });
|
|
405
534
|
},
|
|
406
535
|
};
|
|
407
536
|
}
|
|
@@ -414,8 +543,14 @@ function resolveAdapter({ provider, env, args, config, ctx, }) {
|
|
|
414
543
|
return {
|
|
415
544
|
provider,
|
|
416
545
|
source: config.sourceForProvider?.(provider) ?? "pi",
|
|
417
|
-
async invoke({ payload }) {
|
|
418
|
-
return invokeHttpAdapter({
|
|
546
|
+
async invoke({ payload, signal }) {
|
|
547
|
+
return invokeHttpAdapter({
|
|
548
|
+
endpoint: buildAdapterEndpoint(adapterUrl),
|
|
549
|
+
maxResponseBytes,
|
|
550
|
+
token,
|
|
551
|
+
payload,
|
|
552
|
+
signal,
|
|
553
|
+
});
|
|
419
554
|
},
|
|
420
555
|
};
|
|
421
556
|
}
|
|
@@ -427,8 +562,14 @@ function resolveAdapter({ provider, env, args, config, ctx, }) {
|
|
|
427
562
|
return {
|
|
428
563
|
provider,
|
|
429
564
|
source: config.sourceForProvider?.(provider) ?? "http",
|
|
430
|
-
async invoke({ payload }) {
|
|
431
|
-
return invokeHttpAdapter({
|
|
565
|
+
async invoke({ payload, signal }) {
|
|
566
|
+
return invokeHttpAdapter({
|
|
567
|
+
endpoint: buildAdapterEndpoint(adapterUrl),
|
|
568
|
+
maxResponseBytes,
|
|
569
|
+
token,
|
|
570
|
+
payload,
|
|
571
|
+
signal,
|
|
572
|
+
});
|
|
432
573
|
},
|
|
433
574
|
};
|
|
434
575
|
}
|
|
@@ -451,9 +592,10 @@ function buildAdapterEndpoint(rawUrl) {
|
|
|
451
592
|
}
|
|
452
593
|
return endpoint;
|
|
453
594
|
}
|
|
454
|
-
async function invokeOpenClawAdapter({ endpoint, token, payload, }) {
|
|
595
|
+
async function invokeOpenClawAdapter({ endpoint, token, payload, signal, maxResponseBytes, }) {
|
|
455
596
|
const res = await fetch(endpoint, {
|
|
456
597
|
method: "POST",
|
|
598
|
+
signal,
|
|
457
599
|
headers: {
|
|
458
600
|
"content-type": "application/json",
|
|
459
601
|
...(token ? { authorization: `Bearer ${token}` } : null),
|
|
@@ -464,7 +606,7 @@ async function invokeOpenClawAdapter({ endpoint, token, payload, }) {
|
|
|
464
606
|
args: payload,
|
|
465
607
|
}),
|
|
466
608
|
});
|
|
467
|
-
const text = await res
|
|
609
|
+
const text = await readResponseTextCapped(res, maxResponseBytes);
|
|
468
610
|
if (!res.ok) {
|
|
469
611
|
throw new Error(`${res.status} ${res.statusText}: ${text.slice(0, 400)}`);
|
|
470
612
|
}
|
|
@@ -488,16 +630,17 @@ async function invokeOpenClawAdapter({ endpoint, token, payload, }) {
|
|
|
488
630
|
}
|
|
489
631
|
return { ok: true, result: parsed };
|
|
490
632
|
}
|
|
491
|
-
async function invokeHttpAdapter({ endpoint, token, payload, }) {
|
|
633
|
+
async function invokeHttpAdapter({ endpoint, token, payload, signal, maxResponseBytes, }) {
|
|
492
634
|
const res = await fetch(endpoint, {
|
|
493
635
|
method: "POST",
|
|
636
|
+
signal,
|
|
494
637
|
headers: {
|
|
495
638
|
"content-type": "application/json",
|
|
496
639
|
...(token ? { authorization: `Bearer ${token}` } : null),
|
|
497
640
|
},
|
|
498
641
|
body: JSON.stringify(payload),
|
|
499
642
|
});
|
|
500
|
-
const text = await res
|
|
643
|
+
const text = await readResponseTextCapped(res, maxResponseBytes);
|
|
501
644
|
if (!res.ok) {
|
|
502
645
|
throw new Error(`${res.status} ${res.statusText}: ${text.slice(0, 400)}`);
|
|
503
646
|
}
|
|
@@ -603,14 +746,24 @@ function hashArtifact(artifact) {
|
|
|
603
746
|
const stable = stableStringify(artifact);
|
|
604
747
|
return createHash("sha256").update(stable).digest("hex");
|
|
605
748
|
}
|
|
606
|
-
function computeCacheKey({ provider, prompt, model, schemaVersion, artifactHashes, outputSchema, }) {
|
|
749
|
+
function computeCacheKey({ provider, prompt, model, schemaVersion, artifactHashes, outputSchema, temperature, maxOutputTokens, }) {
|
|
750
|
+
// `null` is the identity of an omitted parameter, distinct from any value a caller can
|
|
751
|
+
// pass, so an omitted request can never resolve to an entry written with an explicit one.
|
|
752
|
+
// The version separates this identity from the keys earlier releases wrote, where the two
|
|
753
|
+
// parameters were absent from the payload and a sampled answer therefore shared a key with
|
|
754
|
+
// an unsampled request. Bump it whenever the fields below change: entries under older
|
|
755
|
+
// versions become unreachable, which costs one re-invocation and never a wrong replay.
|
|
607
756
|
const payload = {
|
|
757
|
+
cacheKeyVersion: CACHE_KEY_VERSION,
|
|
608
758
|
provider,
|
|
609
759
|
prompt,
|
|
610
760
|
model: model || `${provider}-default`,
|
|
611
761
|
schemaVersion,
|
|
612
762
|
artifactHashes,
|
|
613
763
|
outputSchema: outputSchema ?? null,
|
|
764
|
+
// The same predicate that decides whether each parameter is sent to the adapter.
|
|
765
|
+
temperature: Number.isFinite(temperature ?? NaN) ? Number(temperature) : null,
|
|
766
|
+
maxOutputTokens: Number.isFinite(maxOutputTokens ?? NaN) ? Number(maxOutputTokens) : null,
|
|
614
767
|
};
|
|
615
768
|
return createHash("sha256").update(stableStringify(payload)).digest("hex");
|
|
616
769
|
}
|
|
@@ -646,9 +799,11 @@ function normalizeResult({ envelope, cacheKey, schemaVersion, artifactHashes, so
|
|
|
646
799
|
};
|
|
647
800
|
return [item];
|
|
648
801
|
}
|
|
649
|
-
async function persistOutputs({ env, stateKey, cacheKey, items, stateType, }) {
|
|
650
|
-
if (!stateKey)
|
|
802
|
+
async function persistOutputs({ env, stateKey, cacheKey, items, stateType, signal, afterStore, }) {
|
|
803
|
+
if (!stateKey) {
|
|
804
|
+
await afterStore?.();
|
|
651
805
|
return;
|
|
806
|
+
}
|
|
652
807
|
const record = {
|
|
653
808
|
type: stateType,
|
|
654
809
|
version: STATE_VERSION,
|
|
@@ -656,11 +811,17 @@ async function persistOutputs({ env, stateKey, cacheKey, items, stateType, }) {
|
|
|
656
811
|
items,
|
|
657
812
|
storedAt: new Date().toISOString(),
|
|
658
813
|
};
|
|
659
|
-
await
|
|
814
|
+
await diffAndStore({
|
|
815
|
+
env,
|
|
816
|
+
key: stateKey,
|
|
817
|
+
value: record,
|
|
818
|
+
signal,
|
|
819
|
+
afterStore: afterStore ? () => afterStore() : undefined,
|
|
820
|
+
});
|
|
660
821
|
}
|
|
661
|
-
async function readReusableLlmState(env, stateKey) {
|
|
822
|
+
async function readReusableLlmState(env, stateKey, signal) {
|
|
662
823
|
try {
|
|
663
|
-
return await
|
|
824
|
+
return await readStateJsonWithLock({ env, key: stateKey, signal });
|
|
664
825
|
}
|
|
665
826
|
catch (err) {
|
|
666
827
|
if (isJsonSyntaxError(err))
|
|
@@ -684,28 +845,85 @@ function collectAjvErrors(errors) {
|
|
|
684
845
|
return [];
|
|
685
846
|
return errors.map((err) => `${err.instancePath || "/"} ${err.message ?? ""}`.trim());
|
|
686
847
|
}
|
|
687
|
-
async function readCacheEntry(env, key, cacheNamespace) {
|
|
848
|
+
async function readCacheEntry(env, key, cacheNamespace, signal) {
|
|
688
849
|
const filePath = path.join(getCacheDir(env), cacheNamespace, `${key}.json`);
|
|
850
|
+
const read = async () => {
|
|
851
|
+
try {
|
|
852
|
+
const text = await fsp.readFile(filePath, "utf8");
|
|
853
|
+
const parsed = JSON.parse(text);
|
|
854
|
+
if (parsed?.cacheKey !== key || !Array.isArray(parsed.items))
|
|
855
|
+
return null;
|
|
856
|
+
return parsed;
|
|
857
|
+
}
|
|
858
|
+
catch (err) {
|
|
859
|
+
if (err?.code === "ENOENT")
|
|
860
|
+
return null;
|
|
861
|
+
if (isJsonSyntaxError(err))
|
|
862
|
+
return null;
|
|
863
|
+
throw err;
|
|
864
|
+
}
|
|
865
|
+
};
|
|
689
866
|
try {
|
|
690
|
-
|
|
691
|
-
const parsed = JSON.parse(text);
|
|
692
|
-
if (parsed?.cacheKey !== key || !Array.isArray(parsed.items))
|
|
693
|
-
return null;
|
|
694
|
-
return parsed;
|
|
867
|
+
return await withFileLock({ filePath, signal, task: read });
|
|
695
868
|
}
|
|
696
869
|
catch (err) {
|
|
697
|
-
if (err?.code === "ENOENT")
|
|
698
|
-
return null;
|
|
699
|
-
if (isJsonSyntaxError(err))
|
|
870
|
+
if (err?.code === "ENOENT" || err?.code === "ENOTDIR")
|
|
700
871
|
return null;
|
|
872
|
+
// A cache mounted read-only cannot have an active local writer because a
|
|
873
|
+
// writer first creates the same coordination lock. Preserve its reusable
|
|
874
|
+
// entries instead of requiring a lock-directory write for a read.
|
|
875
|
+
if (["EACCES", "EPERM", "EROFS"].includes(err?.code))
|
|
876
|
+
return read();
|
|
701
877
|
throw err;
|
|
702
878
|
}
|
|
703
879
|
}
|
|
704
|
-
async function writeCacheEntry(env, key, items, cacheNamespace) {
|
|
880
|
+
async function writeCacheEntry(env, key, items, cacheNamespace, signal) {
|
|
705
881
|
const dir = path.join(getCacheDir(env), cacheNamespace);
|
|
882
|
+
signal?.throwIfAborted();
|
|
706
883
|
await ensureDirectory(dir);
|
|
707
884
|
const filePath = path.join(dir, `${key}.json`);
|
|
708
|
-
|
|
885
|
+
const content = JSON.stringify({ items, cacheKey: key, storedAt: new Date().toISOString() }, null, 2) + "\n";
|
|
886
|
+
await withFileLock({
|
|
887
|
+
filePath,
|
|
888
|
+
signal,
|
|
889
|
+
task: async () => {
|
|
890
|
+
let previousContent = null;
|
|
891
|
+
try {
|
|
892
|
+
previousContent = await fsp.readFile(filePath);
|
|
893
|
+
}
|
|
894
|
+
catch (err) {
|
|
895
|
+
if (err?.code !== "ENOENT")
|
|
896
|
+
throw err;
|
|
897
|
+
}
|
|
898
|
+
const restorePreviousContent = async () => {
|
|
899
|
+
// No cache reader or competing cache writer can observe this entry
|
|
900
|
+
// until this lock is released. Restore an entry replaced by a refresh;
|
|
901
|
+
// only remove the just-published file when none existed beforehand.
|
|
902
|
+
if (previousContent === null)
|
|
903
|
+
await fsp.rm(filePath, { force: true });
|
|
904
|
+
else
|
|
905
|
+
await writeFileAtomic(filePath, previousContent);
|
|
906
|
+
};
|
|
907
|
+
let cacheWasPublished = false;
|
|
908
|
+
try {
|
|
909
|
+
signal?.throwIfAborted();
|
|
910
|
+
const result = await writeFileAtomic(filePath, content, { signal });
|
|
911
|
+
cacheWasPublished = true;
|
|
912
|
+
if (result?.signalAbortedAfterCommit || signal?.aborted) {
|
|
913
|
+
await restorePreviousContent();
|
|
914
|
+
cacheWasPublished = false;
|
|
915
|
+
signal?.throwIfAborted();
|
|
916
|
+
throw new Error("LLM cache publication cancelled");
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
catch (err) {
|
|
920
|
+
if (cacheWasPublished || atomicWriteWasPublished(err)) {
|
|
921
|
+
await restorePreviousContent();
|
|
922
|
+
}
|
|
923
|
+
throw err;
|
|
924
|
+
}
|
|
925
|
+
},
|
|
926
|
+
});
|
|
709
927
|
}
|
|
710
928
|
function getCacheDir(env) {
|
|
711
929
|
if (env?.LOBSTER_CACHE_DIR)
|