tulingcode 0.1.0
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/AGENTS.md +134 -0
- package/Dockerfile +18 -0
- package/README.md +15 -0
- package/bin/tuling +179 -0
- package/bunfig.toml +7 -0
- package/drizzle.config.ts +10 -0
- package/git +0 -0
- package/migration/20260127222353_familiar_lady_ursula/migration.sql +90 -0
- package/migration/20260127222353_familiar_lady_ursula/snapshot.json +796 -0
- package/migration/20260211171708_add_project_commands/migration.sql +1 -0
- package/migration/20260211171708_add_project_commands/snapshot.json +806 -0
- package/migration/20260213144116_wakeful_the_professor/migration.sql +11 -0
- package/migration/20260213144116_wakeful_the_professor/snapshot.json +897 -0
- package/migration/20260225215848_workspace/migration.sql +7 -0
- package/migration/20260225215848_workspace/snapshot.json +959 -0
- package/migration/20260227213759_add_session_workspace_id/migration.sql +2 -0
- package/migration/20260227213759_add_session_workspace_id/snapshot.json +983 -0
- package/migration/20260228203230_blue_harpoon/migration.sql +17 -0
- package/migration/20260228203230_blue_harpoon/snapshot.json +1102 -0
- package/migration/20260303231226_add_workspace_fields/migration.sql +5 -0
- package/migration/20260303231226_add_workspace_fields/snapshot.json +1013 -0
- package/migration/20260309230000_move_org_to_state/migration.sql +3 -0
- package/migration/20260309230000_move_org_to_state/snapshot.json +1156 -0
- package/migration/20260312043431_session_message_cursor/migration.sql +4 -0
- package/migration/20260312043431_session_message_cursor/snapshot.json +1168 -0
- package/migration/20260323234822_events/migration.sql +13 -0
- package/migration/20260323234822_events/snapshot.json +1271 -0
- package/migration/20260410174513_workspace-name/migration.sql +16 -0
- package/migration/20260410174513_workspace-name/snapshot.json +1271 -0
- package/migration/20260413175956_chief_energizer/migration.sql +13 -0
- package/migration/20260413175956_chief_energizer/snapshot.json +1399 -0
- package/migration/20260422160000_context_inheritance/migration.sql +3 -0
- package/migration/20260422170000_task_registry/migration.sql +18 -0
- package/migration/20260423145421_remove_session_entry/migration.sql +4 -0
- package/migration/20260515000000_actor_rename/migration.sql +7 -0
- package/migration/20260515010000_memory_fts/migration.sql +33 -0
- package/migration/20260515020000_user_task/migration.sql +29 -0
- package/migration/20260519000000_last_checkpoint_message_id/migration.sql +1 -0
- package/migration/20260521000000_message_agent_id/migration.sql +2 -0
- package/migration/20260521000100_actor_registry_v6/migration.sql +25 -0
- package/migration/20260521010000_memory_fts_v6/migration.sql +33 -0
- package/migration/20260521020000_memory_fts_triggers/migration.sql +17 -0
- package/migration/20260526000000_agent_id_main/migration.sql +14 -0
- package/migration/20260527000000_actor_lifecycle/migration.sql +8 -0
- package/migration/20260527000100_inbox/migration.sql +12 -0
- package/migration/20260529000000_task_todo_redesign/migration.sql +16 -0
- package/migration/20260603000000_task_in_progress_owner/migration.sql +1 -0
- package/migration/20260603000000_workflow_run/migration.sql +17 -0
- package/migration/20260604000000_workflow_script_sha/migration.sql +1 -0
- package/migration/20260608000000_claude_import/migration.sql +7 -0
- package/migration/20260608010000_claude_import_message_ids/migration.sql +1 -0
- package/migration/20260609000000_history_fts/migration.sql +29 -0
- package/migration/20260609230000_workflow_agent_timeout/migration.sql +1 -0
- package/package.json +196 -0
- package/parsers-config.ts +290 -0
- package/script/build.ts +267 -0
- package/script/check-migrations.ts +16 -0
- package/script/fix-node-pty.ts +28 -0
- package/script/generate.ts +23 -0
- package/script/postinstall.mjs +102 -0
- package/script/publish.ts +60 -0
- package/script/run-workspace-server +106 -0
- package/script/schema.ts +63 -0
- package/script/time.ts +6 -0
- package/script/trace-imports.ts +153 -0
- package/script/upgrade-opentui.ts +64 -0
- package/src/account/account.sql.ts +39 -0
- package/src/account/account.ts +456 -0
- package/src/account/repo.ts +166 -0
- package/src/account/schema.ts +99 -0
- package/src/account/url.ts +8 -0
- package/src/acp/README.md +174 -0
- package/src/acp/agent.ts +1783 -0
- package/src/acp/session.ts +116 -0
- package/src/acp/types.ts +24 -0
- package/src/actor/actor.sql.ts +38 -0
- package/src/actor/events.ts +67 -0
- package/src/actor/index.ts +2 -0
- package/src/actor/registry.ts +412 -0
- package/src/actor/return-header.ts +24 -0
- package/src/actor/schema.ts +47 -0
- package/src/actor/spawn-ref.ts +16 -0
- package/src/actor/spawn.ts +741 -0
- package/src/actor/turn.ts +49 -0
- package/src/actor/waiter.ts +166 -0
- package/src/agent/agent.ts +554 -0
- package/src/agent/config.ts +5 -0
- package/src/agent/generate.txt +75 -0
- package/src/agent/prompt/checkpoint-writer.txt +167 -0
- package/src/agent/prompt/compaction.txt +9 -0
- package/src/agent/prompt/distill.txt +199 -0
- package/src/agent/prompt/dream.txt +155 -0
- package/src/agent/prompt/explore.txt +18 -0
- package/src/agent/prompt/summary.txt +11 -0
- package/src/agent/prompt/title.txt +44 -0
- package/src/audio.d.ts +9 -0
- package/src/auth/index.ts +97 -0
- package/src/bus/bus-event.ts +33 -0
- package/src/bus/global.ts +12 -0
- package/src/bus/index.ts +193 -0
- package/src/cli/bootstrap.ts +33 -0
- package/src/cli/cmd/account.ts +258 -0
- package/src/cli/cmd/acp.ts +70 -0
- package/src/cli/cmd/agent.ts +248 -0
- package/src/cli/cmd/cmd.ts +7 -0
- package/src/cli/cmd/db.ts +120 -0
- package/src/cli/cmd/debug/agent.ts +192 -0
- package/src/cli/cmd/debug/config.ts +17 -0
- package/src/cli/cmd/debug/file.ts +100 -0
- package/src/cli/cmd/debug/index.ts +48 -0
- package/src/cli/cmd/debug/lsp.ts +61 -0
- package/src/cli/cmd/debug/ripgrep.ts +105 -0
- package/src/cli/cmd/debug/scrap.ts +16 -0
- package/src/cli/cmd/debug/skill.ts +23 -0
- package/src/cli/cmd/debug/snapshot.ts +53 -0
- package/src/cli/cmd/export.ts +306 -0
- package/src/cli/cmd/generate.ts +50 -0
- package/src/cli/cmd/github.ts +1647 -0
- package/src/cli/cmd/import.ts +208 -0
- package/src/cli/cmd/mcp.ts +812 -0
- package/src/cli/cmd/models.ts +88 -0
- package/src/cli/cmd/plug.ts +233 -0
- package/src/cli/cmd/pr.ts +138 -0
- package/src/cli/cmd/providers.ts +705 -0
- package/src/cli/cmd/run-completion.ts +77 -0
- package/src/cli/cmd/run.ts +694 -0
- package/src/cli/cmd/serve.ts +21 -0
- package/src/cli/cmd/session.ts +181 -0
- package/src/cli/cmd/stats.ts +413 -0
- package/src/cli/cmd/tui/app.tsx +1130 -0
- package/src/cli/cmd/tui/asset/TEN_VAD_LICENSE +12 -0
- package/src/cli/cmd/tui/asset/charge.wav +0 -0
- package/src/cli/cmd/tui/asset/pulse-a.wav +0 -0
- package/src/cli/cmd/tui/asset/pulse-b.wav +0 -0
- package/src/cli/cmd/tui/asset/pulse-c.wav +0 -0
- package/src/cli/cmd/tui/asset/ten_vad.wasm +0 -0
- package/src/cli/cmd/tui/asset/ten_vad_loader.js +30 -0
- package/src/cli/cmd/tui/attach.ts +83 -0
- package/src/cli/cmd/tui/component/background-image.tsx +150 -0
- package/src/cli/cmd/tui/component/bg-pulse.tsx +130 -0
- package/src/cli/cmd/tui/component/border.tsx +21 -0
- package/src/cli/cmd/tui/component/dialog-agent.tsx +31 -0
- package/src/cli/cmd/tui/component/dialog-command.tsx +208 -0
- package/src/cli/cmd/tui/component/dialog-console-org.tsx +103 -0
- package/src/cli/cmd/tui/component/dialog-go-upsell.tsx +157 -0
- package/src/cli/cmd/tui/component/dialog-image-list.tsx +111 -0
- package/src/cli/cmd/tui/component/dialog-logo-design.tsx +37 -0
- package/src/cli/cmd/tui/component/dialog-mcp.tsx +86 -0
- package/src/cli/cmd/tui/component/dialog-mimo-login.tsx +224 -0
- package/src/cli/cmd/tui/component/dialog-model.tsx +253 -0
- package/src/cli/cmd/tui/component/dialog-provider.tsx +490 -0
- package/src/cli/cmd/tui/component/dialog-session-delete-failed.tsx +101 -0
- package/src/cli/cmd/tui/component/dialog-session-list.tsx +269 -0
- package/src/cli/cmd/tui/component/dialog-session-rename.tsx +31 -0
- package/src/cli/cmd/tui/component/dialog-skill.tsx +42 -0
- package/src/cli/cmd/tui/component/dialog-stash.tsx +87 -0
- package/src/cli/cmd/tui/component/dialog-status.tsx +170 -0
- package/src/cli/cmd/tui/component/dialog-tag.tsx +44 -0
- package/src/cli/cmd/tui/component/dialog-theme-list.tsx +50 -0
- package/src/cli/cmd/tui/component/dialog-variant.tsx +39 -0
- package/src/cli/cmd/tui/component/dialog-workflows.tsx +62 -0
- package/src/cli/cmd/tui/component/dialog-workspace-create.tsx +289 -0
- package/src/cli/cmd/tui/component/dialog-workspace-unavailable.tsx +81 -0
- package/src/cli/cmd/tui/component/dialog-worktree.tsx +90 -0
- package/src/cli/cmd/tui/component/error-component.tsx +92 -0
- package/src/cli/cmd/tui/component/logo.tsx +961 -0
- package/src/cli/cmd/tui/component/plugin-route-missing.tsx +14 -0
- package/src/cli/cmd/tui/component/prompt/autocomplete.tsx +684 -0
- package/src/cli/cmd/tui/component/prompt/cwd.ts +0 -0
- package/src/cli/cmd/tui/component/prompt/frecency.tsx +90 -0
- package/src/cli/cmd/tui/component/prompt/history.tsx +108 -0
- package/src/cli/cmd/tui/component/prompt/index.tsx +1812 -0
- package/src/cli/cmd/tui/component/prompt/part.ts +16 -0
- package/src/cli/cmd/tui/component/prompt/stash.tsx +101 -0
- package/src/cli/cmd/tui/component/spinner.tsx +24 -0
- package/src/cli/cmd/tui/component/starry-background.tsx +305 -0
- package/src/cli/cmd/tui/component/startup-loading.tsx +67 -0
- package/src/cli/cmd/tui/component/task-item.tsx +63 -0
- package/src/cli/cmd/tui/component/textarea-keybindings.ts +73 -0
- package/src/cli/cmd/tui/component/todo-item.tsx +32 -0
- package/src/cli/cmd/tui/config/cwd.ts +5 -0
- package/src/cli/cmd/tui/config/tui-migrate.ts +151 -0
- package/src/cli/cmd/tui/config/tui-schema.ts +38 -0
- package/src/cli/cmd/tui/config/tui.ts +219 -0
- package/src/cli/cmd/tui/context/args.tsx +16 -0
- package/src/cli/cmd/tui/context/directory.ts +15 -0
- package/src/cli/cmd/tui/context/event.ts +45 -0
- package/src/cli/cmd/tui/context/exit.tsx +65 -0
- package/src/cli/cmd/tui/context/helper.tsx +25 -0
- package/src/cli/cmd/tui/context/keybind.tsx +105 -0
- package/src/cli/cmd/tui/context/kv.tsx +76 -0
- package/src/cli/cmd/tui/context/language.tsx +91 -0
- package/src/cli/cmd/tui/context/local.tsx +455 -0
- package/src/cli/cmd/tui/context/plugin-keybinds.ts +41 -0
- package/src/cli/cmd/tui/context/project.tsx +109 -0
- package/src/cli/cmd/tui/context/prompt.tsx +18 -0
- package/src/cli/cmd/tui/context/route.tsx +61 -0
- package/src/cli/cmd/tui/context/sdk.tsx +150 -0
- package/src/cli/cmd/tui/context/sync.tsx +828 -0
- package/src/cli/cmd/tui/context/theme/aura.json +69 -0
- package/src/cli/cmd/tui/context/theme/ayu.json +80 -0
- package/src/cli/cmd/tui/context/theme/carbonfox.json +248 -0
- package/src/cli/cmd/tui/context/theme/catppuccin-frappe.json +230 -0
- package/src/cli/cmd/tui/context/theme/catppuccin-macchiato.json +230 -0
- package/src/cli/cmd/tui/context/theme/catppuccin.json +112 -0
- package/src/cli/cmd/tui/context/theme/cobalt2.json +225 -0
- package/src/cli/cmd/tui/context/theme/cursor.json +249 -0
- package/src/cli/cmd/tui/context/theme/dracula.json +219 -0
- package/src/cli/cmd/tui/context/theme/everforest.json +241 -0
- package/src/cli/cmd/tui/context/theme/flexoki.json +237 -0
- package/src/cli/cmd/tui/context/theme/github.json +233 -0
- package/src/cli/cmd/tui/context/theme/gruvbox.json +242 -0
- package/src/cli/cmd/tui/context/theme/kanagawa.json +77 -0
- package/src/cli/cmd/tui/context/theme/lucent-orng.json +234 -0
- package/src/cli/cmd/tui/context/theme/material.json +235 -0
- package/src/cli/cmd/tui/context/theme/matrix.json +77 -0
- package/src/cli/cmd/tui/context/theme/mercury.json +252 -0
- package/src/cli/cmd/tui/context/theme/monokai.json +221 -0
- package/src/cli/cmd/tui/context/theme/nightowl.json +221 -0
- package/src/cli/cmd/tui/context/theme/nord.json +223 -0
- package/src/cli/cmd/tui/context/theme/one-dark.json +84 -0
- package/src/cli/cmd/tui/context/theme/orng.json +249 -0
- package/src/cli/cmd/tui/context/theme/osaka-jade.json +93 -0
- package/src/cli/cmd/tui/context/theme/palenight.json +222 -0
- package/src/cli/cmd/tui/context/theme/rosepine.json +234 -0
- package/src/cli/cmd/tui/context/theme/solarized.json +223 -0
- package/src/cli/cmd/tui/context/theme/synthwave84.json +226 -0
- package/src/cli/cmd/tui/context/theme/tokyonight.json +243 -0
- package/src/cli/cmd/tui/context/theme/tulingcode.json +245 -0
- package/src/cli/cmd/tui/context/theme/vercel.json +245 -0
- package/src/cli/cmd/tui/context/theme/vesper.json +218 -0
- package/src/cli/cmd/tui/context/theme/zenburn.json +223 -0
- package/src/cli/cmd/tui/context/theme.tsx +1298 -0
- package/src/cli/cmd/tui/context/thinking.ts +48 -0
- package/src/cli/cmd/tui/context/tui-config.tsx +9 -0
- package/src/cli/cmd/tui/event.ts +56 -0
- package/src/cli/cmd/tui/feature-plugins/home/footer.tsx +93 -0
- package/src/cli/cmd/tui/feature-plugins/home/tips-view.tsx +193 -0
- package/src/cli/cmd/tui/feature-plugins/home/tips.tsx +54 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/context.tsx +114 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/cwd.tsx +45 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/files.tsx +62 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/footer.tsx +93 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/goal.tsx +84 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/instructions.tsx +54 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/lsp.tsx +66 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/mcp.tsx +98 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/task.tsx +95 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/todo.tsx +51 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/tps.ts +31 -0
- package/src/cli/cmd/tui/feature-plugins/system/plugins.tsx +274 -0
- package/src/cli/cmd/tui/i18n/en.ts +397 -0
- package/src/cli/cmd/tui/i18n/es.ts +433 -0
- package/src/cli/cmd/tui/i18n/fr.ts +440 -0
- package/src/cli/cmd/tui/i18n/ja.ts +392 -0
- package/src/cli/cmd/tui/i18n/locales.ts +82 -0
- package/src/cli/cmd/tui/i18n/ru.ts +452 -0
- package/src/cli/cmd/tui/i18n/zh.ts +390 -0
- package/src/cli/cmd/tui/i18n/zht.ts +360 -0
- package/src/cli/cmd/tui/layer.ts +6 -0
- package/src/cli/cmd/tui/plugin/api.tsx +402 -0
- package/src/cli/cmd/tui/plugin/index.ts +3 -0
- package/src/cli/cmd/tui/plugin/internal.ts +35 -0
- package/src/cli/cmd/tui/plugin/runtime.ts +1030 -0
- package/src/cli/cmd/tui/plugin/slots.tsx +60 -0
- package/src/cli/cmd/tui/routes/home.tsx +165 -0
- package/src/cli/cmd/tui/routes/session/dialog-fork-from-timeline.tsx +76 -0
- package/src/cli/cmd/tui/routes/session/dialog-message.tsx +116 -0
- package/src/cli/cmd/tui/routes/session/dialog-subagent.tsx +47 -0
- package/src/cli/cmd/tui/routes/session/dialog-timeline.tsx +47 -0
- package/src/cli/cmd/tui/routes/session/footer.tsx +91 -0
- package/src/cli/cmd/tui/routes/session/index.tsx +2532 -0
- package/src/cli/cmd/tui/routes/session/permission.tsx +691 -0
- package/src/cli/cmd/tui/routes/session/question.tsx +488 -0
- package/src/cli/cmd/tui/routes/session/sidebar.tsx +97 -0
- package/src/cli/cmd/tui/routes/session/subagent-footer.tsx +142 -0
- package/src/cli/cmd/tui/thread.ts +246 -0
- package/src/cli/cmd/tui/ui/dialog-alert.tsx +61 -0
- package/src/cli/cmd/tui/ui/dialog-confirm.tsx +95 -0
- package/src/cli/cmd/tui/ui/dialog-export-options.tsx +223 -0
- package/src/cli/cmd/tui/ui/dialog-help.tsx +42 -0
- package/src/cli/cmd/tui/ui/dialog-prompt.tsx +123 -0
- package/src/cli/cmd/tui/ui/dialog-select.tsx +452 -0
- package/src/cli/cmd/tui/ui/dialog.tsx +207 -0
- package/src/cli/cmd/tui/ui/link.tsx +28 -0
- package/src/cli/cmd/tui/ui/spinner.ts +378 -0
- package/src/cli/cmd/tui/ui/toast.tsx +102 -0
- package/src/cli/cmd/tui/util/clipboard.ts +203 -0
- package/src/cli/cmd/tui/util/editor.ts +35 -0
- package/src/cli/cmd/tui/util/image-protocol.ts +35 -0
- package/src/cli/cmd/tui/util/index.ts +6 -0
- package/src/cli/cmd/tui/util/model.ts +23 -0
- package/src/cli/cmd/tui/util/provider-origin.ts +7 -0
- package/src/cli/cmd/tui/util/revert-diff.ts +18 -0
- package/src/cli/cmd/tui/util/scroll.ts +23 -0
- package/src/cli/cmd/tui/util/selection.ts +23 -0
- package/src/cli/cmd/tui/util/signal.ts +41 -0
- package/src/cli/cmd/tui/util/sound.ts +154 -0
- package/src/cli/cmd/tui/util/system-locale.ts +209 -0
- package/src/cli/cmd/tui/util/terminal.ts +110 -0
- package/src/cli/cmd/tui/util/transcript.ts +112 -0
- package/src/cli/cmd/tui/util/vad.ts +229 -0
- package/src/cli/cmd/tui/util/voice.ts +360 -0
- package/src/cli/cmd/tui/win32.ts +130 -0
- package/src/cli/cmd/tui/worker.ts +104 -0
- package/src/cli/cmd/uninstall.ts +351 -0
- package/src/cli/cmd/upgrade.ts +79 -0
- package/src/cli/cmd/web.ts +81 -0
- package/src/cli/effect/prompt.ts +25 -0
- package/src/cli/error.ts +82 -0
- package/src/cli/heap.ts +59 -0
- package/src/cli/i18n.ts +15 -0
- package/src/cli/logo.ts +53 -0
- package/src/cli/network.ts +62 -0
- package/src/cli/ui.ts +133 -0
- package/src/cli/upgrade.ts +41 -0
- package/src/command/index.ts +276 -0
- package/src/command/template/initialize.txt +66 -0
- package/src/command/template/review.txt +101 -0
- package/src/config/agent.ts +197 -0
- package/src/config/command.ts +69 -0
- package/src/config/config.ts +1024 -0
- package/src/config/console-state.ts +16 -0
- package/src/config/entry-name.ts +16 -0
- package/src/config/error.ts +21 -0
- package/src/config/formatter.ts +17 -0
- package/src/config/history.ts +21 -0
- package/src/config/index.ts +16 -0
- package/src/config/keybinds.ts +127 -0
- package/src/config/layout.ts +10 -0
- package/src/config/lsp.ts +45 -0
- package/src/config/managed.ts +70 -0
- package/src/config/markdown.ts +97 -0
- package/src/config/mcp.ts +172 -0
- package/src/config/model-id.ts +14 -0
- package/src/config/parse.ts +44 -0
- package/src/config/paths.ts +73 -0
- package/src/config/permission.ts +76 -0
- package/src/config/plugin.ts +88 -0
- package/src/config/provider.ts +118 -0
- package/src/config/server.ts +20 -0
- package/src/config/skills.ts +16 -0
- package/src/config/variable.ts +90 -0
- package/src/control-plane/adaptors/index.ts +52 -0
- package/src/control-plane/adaptors/worktree.ts +47 -0
- package/src/control-plane/dev/debug-workspace-plugin.ts +73 -0
- package/src/control-plane/schema.ts +19 -0
- package/src/control-plane/sse.ts +66 -0
- package/src/control-plane/types.ts +34 -0
- package/src/control-plane/util.ts +37 -0
- package/src/control-plane/workspace-context.ts +26 -0
- package/src/control-plane/workspace.sql.ts +17 -0
- package/src/control-plane/workspace.ts +615 -0
- package/src/effect/app-runtime.ts +146 -0
- package/src/effect/bootstrap-runtime.ts +33 -0
- package/src/effect/bridge.ts +48 -0
- package/src/effect/cross-spawn-spawner.ts +514 -0
- package/src/effect/index.ts +5 -0
- package/src/effect/instance-ref.ts +11 -0
- package/src/effect/instance-registry.ts +12 -0
- package/src/effect/instance-state.ts +81 -0
- package/src/effect/logger.ts +73 -0
- package/src/effect/memo-map.ts +3 -0
- package/src/effect/observability.ts +107 -0
- package/src/effect/run-service.ts +52 -0
- package/src/effect/runner.ts +210 -0
- package/src/effect/runtime.ts +19 -0
- package/src/env/index.ts +37 -0
- package/src/file/ignore.ts +81 -0
- package/src/file/index.ts +664 -0
- package/src/file/protected.ts +59 -0
- package/src/file/ripgrep.ts +485 -0
- package/src/file/watcher.ts +163 -0
- package/src/flag/flag.ts +164 -0
- package/src/format/formatter.ts +403 -0
- package/src/format/index.ts +203 -0
- package/src/git/index.ts +260 -0
- package/src/global/index.ts +54 -0
- package/src/history/backfill.ts +162 -0
- package/src/history/extract.ts +67 -0
- package/src/history/fts-query.ts +15 -0
- package/src/history/fts.sql.ts +20 -0
- package/src/history/index.ts +10 -0
- package/src/history/resolve.ts +65 -0
- package/src/history/service.ts +258 -0
- package/src/history/writer.ts +112 -0
- package/src/id/id.ts +87 -0
- package/src/ide/index.ts +73 -0
- package/src/inbox/inbox-ref.ts +38 -0
- package/src/inbox/inbox.sql.ts +26 -0
- package/src/inbox/inbox.ts +223 -0
- package/src/inbox/index.ts +3 -0
- package/src/inbox/render.ts +40 -0
- package/src/index.ts +260 -0
- package/src/installation/index.ts +351 -0
- package/src/installation/version.ts +8 -0
- package/src/lsp/client.ts +249 -0
- package/src/lsp/diagnostic.ts +29 -0
- package/src/lsp/index.ts +3 -0
- package/src/lsp/language.ts +120 -0
- package/src/lsp/launch.ts +21 -0
- package/src/lsp/lsp.ts +519 -0
- package/src/lsp/server.ts +1956 -0
- package/src/mcp/auth.ts +144 -0
- package/src/mcp/index.ts +944 -0
- package/src/mcp/oauth-callback.ts +232 -0
- package/src/mcp/oauth-provider.ts +214 -0
- package/src/memory/fts-query.ts +37 -0
- package/src/memory/fts.sql.ts +19 -0
- package/src/memory/index.ts +1 -0
- package/src/memory/paths.ts +116 -0
- package/src/memory/reconcile.ts +144 -0
- package/src/memory/service.ts +144 -0
- package/src/metrics/client.ts +40 -0
- package/src/metrics/event.ts +43 -0
- package/src/metrics/index.ts +5 -0
- package/src/metrics/installation.ts +18 -0
- package/src/metrics/subscriber.ts +58 -0
- package/src/metrics/util.ts +9 -0
- package/src/node.ts +6 -0
- package/src/npm/config.ts +0 -0
- package/src/npm/index.ts +293 -0
- package/src/npmcli-config.d.ts +43 -0
- package/src/patch/index.ts +680 -0
- package/src/permission/arity.ts +163 -0
- package/src/permission/evaluate.ts +15 -0
- package/src/permission/index.ts +379 -0
- package/src/permission/schema.ts +17 -0
- package/src/plugin/checkpoint-splitover.ts +60 -0
- package/src/plugin/cloud-ai.ts +329 -0
- package/src/plugin/cloudflare.ts +76 -0
- package/src/plugin/codex.ts +607 -0
- package/src/plugin/github-copilot/copilot.ts +368 -0
- package/src/plugin/github-copilot/models.ts +153 -0
- package/src/plugin/index.ts +493 -0
- package/src/plugin/install.ts +439 -0
- package/src/plugin/loader.ts +216 -0
- package/src/plugin/matcher.ts +33 -0
- package/src/plugin/meta.ts +188 -0
- package/src/plugin/mimo-free.ts +153 -0
- package/src/plugin/mimo.ts +124 -0
- package/src/plugin/shared.ts +323 -0
- package/src/plugin/subagent-progress-checker.ts +147 -0
- package/src/project/bootstrap.ts +59 -0
- package/src/project/index.ts +2 -0
- package/src/project/instance.ts +190 -0
- package/src/project/project-id.ts +48 -0
- package/src/project/project.sql.ts +16 -0
- package/src/project/project.ts +501 -0
- package/src/project/schema.ts +15 -0
- package/src/project/vcs.ts +227 -0
- package/src/provider/auth.ts +234 -0
- package/src/provider/error.ts +216 -0
- package/src/provider/index.ts +5 -0
- package/src/provider/models.ts +180 -0
- package/src/provider/provider.ts +1782 -0
- package/src/provider/schema.ts +36 -0
- package/src/provider/sdk/copilot/README.md +5 -0
- package/src/provider/sdk/copilot/chat/convert-to-openai-compatible-chat-messages.ts +170 -0
- package/src/provider/sdk/copilot/chat/get-response-metadata.ts +15 -0
- package/src/provider/sdk/copilot/chat/map-openai-compatible-finish-reason.ts +19 -0
- package/src/provider/sdk/copilot/chat/openai-compatible-api-types.ts +64 -0
- package/src/provider/sdk/copilot/chat/openai-compatible-chat-language-model.ts +815 -0
- package/src/provider/sdk/copilot/chat/openai-compatible-chat-options.ts +28 -0
- package/src/provider/sdk/copilot/chat/openai-compatible-metadata-extractor.ts +44 -0
- package/src/provider/sdk/copilot/chat/openai-compatible-prepare-tools.ts +83 -0
- package/src/provider/sdk/copilot/copilot-provider.ts +100 -0
- package/src/provider/sdk/copilot/index.ts +2 -0
- package/src/provider/sdk/copilot/openai-compatible-error.ts +27 -0
- package/src/provider/sdk/copilot/responses/convert-to-openai-responses-input.ts +335 -0
- package/src/provider/sdk/copilot/responses/map-openai-responses-finish-reason.ts +22 -0
- package/src/provider/sdk/copilot/responses/openai-config.ts +18 -0
- package/src/provider/sdk/copilot/responses/openai-error.ts +22 -0
- package/src/provider/sdk/copilot/responses/openai-responses-api-types.ts +214 -0
- package/src/provider/sdk/copilot/responses/openai-responses-language-model.ts +1770 -0
- package/src/provider/sdk/copilot/responses/openai-responses-prepare-tools.ts +173 -0
- package/src/provider/sdk/copilot/responses/openai-responses-settings.ts +1 -0
- package/src/provider/sdk/copilot/responses/tool/code-interpreter.ts +87 -0
- package/src/provider/sdk/copilot/responses/tool/file-search.ts +127 -0
- package/src/provider/sdk/copilot/responses/tool/image-generation.ts +114 -0
- package/src/provider/sdk/copilot/responses/tool/local-shell.ts +64 -0
- package/src/provider/sdk/copilot/responses/tool/web-search-preview.ts +103 -0
- package/src/provider/sdk/copilot/responses/tool/web-search.ts +102 -0
- package/src/provider/transform.ts +1322 -0
- package/src/pty/index.ts +364 -0
- package/src/pty/pty.bun.ts +26 -0
- package/src/pty/pty.node.ts +27 -0
- package/src/pty/pty.ts +25 -0
- package/src/pty/schema.ts +17 -0
- package/src/question/index.ts +252 -0
- package/src/question/schema.ts +17 -0
- package/src/server/adapter.bun.ts +40 -0
- package/src/server/adapter.node.ts +66 -0
- package/src/server/adapter.ts +21 -0
- package/src/server/error.ts +53 -0
- package/src/server/event.ts +7 -0
- package/src/server/fence.ts +81 -0
- package/src/server/mdns.ts +60 -0
- package/src/server/middleware.ts +92 -0
- package/src/server/projectors.ts +28 -0
- package/src/server/proxy.ts +171 -0
- package/src/server/routes/control/index.ts +160 -0
- package/src/server/routes/control/workspace.ts +203 -0
- package/src/server/routes/global.ts +287 -0
- package/src/server/routes/instance/bash-interactive.ts +82 -0
- package/src/server/routes/instance/config.ts +89 -0
- package/src/server/routes/instance/event.ts +88 -0
- package/src/server/routes/instance/experimental.ts +408 -0
- package/src/server/routes/instance/file.ts +190 -0
- package/src/server/routes/instance/httpapi/config.ts +51 -0
- package/src/server/routes/instance/httpapi/permission.ts +72 -0
- package/src/server/routes/instance/httpapi/project.ts +62 -0
- package/src/server/routes/instance/httpapi/provider.ts +142 -0
- package/src/server/routes/instance/httpapi/question.ts +121 -0
- package/src/server/routes/instance/httpapi/server.ts +136 -0
- package/src/server/routes/instance/index.ts +301 -0
- package/src/server/routes/instance/mcp.ts +260 -0
- package/src/server/routes/instance/middleware.ts +35 -0
- package/src/server/routes/instance/permission.ts +73 -0
- package/src/server/routes/instance/project.ts +122 -0
- package/src/server/routes/instance/provider.ts +158 -0
- package/src/server/routes/instance/pty.ts +247 -0
- package/src/server/routes/instance/question.ts +162 -0
- package/src/server/routes/instance/session.ts +1296 -0
- package/src/server/routes/instance/sync.ts +143 -0
- package/src/server/routes/instance/trace.ts +59 -0
- package/src/server/routes/instance/tui.ts +384 -0
- package/src/server/routes/instance/workflows.ts +72 -0
- package/src/server/routes/ui.ts +55 -0
- package/src/server/server.ts +136 -0
- package/src/server/workspace.ts +122 -0
- package/src/session/auto-dream.ts +123 -0
- package/src/session/boundary.ts +77 -0
- package/src/session/budgeted-read.ts +118 -0
- package/src/session/checkpoint-align.ts +29 -0
- package/src/session/checkpoint-context.ts +36 -0
- package/src/session/checkpoint-paths.ts +86 -0
- package/src/session/checkpoint-progress-reconcile.ts +111 -0
- package/src/session/checkpoint-retry.ts +192 -0
- package/src/session/checkpoint-templates.ts +114 -0
- package/src/session/checkpoint-validator.ts +259 -0
- package/src/session/checkpoint.ts +1478 -0
- package/src/session/classify.ts +92 -0
- package/src/session/claude-import.sql.ts +13 -0
- package/src/session/claude-import.ts +379 -0
- package/src/session/compaction.ts +543 -0
- package/src/session/goal.ts +232 -0
- package/src/session/index.ts +1 -0
- package/src/session/instruction.ts +276 -0
- package/src/session/last-message-info.ts +32 -0
- package/src/session/llm-request-prefix.ts +82 -0
- package/src/session/llm.ts +735 -0
- package/src/session/max-mode.ts +397 -0
- package/src/session/message-v2.ts +1136 -0
- package/src/session/message.ts +191 -0
- package/src/session/overflow.ts +53 -0
- package/src/session/prefix-capture-ref.ts +48 -0
- package/src/session/processor.ts +962 -0
- package/src/session/projectors.ts +137 -0
- package/src/session/prompt/anthropic.txt +154 -0
- package/src/session/prompt/beast.txt +155 -0
- package/src/session/prompt/build-switch.txt +5 -0
- package/src/session/prompt/codex.txt +79 -0
- package/src/session/prompt/compose.txt +115 -0
- package/src/session/prompt/copilot-gpt-5.txt +143 -0
- package/src/session/prompt/default.txt +151 -0
- package/src/session/prompt/gemini.txt +155 -0
- package/src/session/prompt/gpt.txt +107 -0
- package/src/session/prompt/kimi.txt +95 -0
- package/src/session/prompt/max-steps.txt +16 -0
- package/src/session/prompt/trinity.txt +97 -0
- package/src/session/prompt.ts +3355 -0
- package/src/session/prune.ts +481 -0
- package/src/session/retry.ts +166 -0
- package/src/session/revert.ts +161 -0
- package/src/session/run-state.ts +135 -0
- package/src/session/schema.ts +36 -0
- package/src/session/session.sql.ts +110 -0
- package/src/session/session.ts +908 -0
- package/src/session/status.ts +89 -0
- package/src/session/summary.ts +163 -0
- package/src/session/system.ts +86 -0
- package/src/session/todo.ts +77 -0
- package/src/share/index.ts +2 -0
- package/src/share/session.ts +57 -0
- package/src/share/share-next.ts +381 -0
- package/src/share/share.sql.ts +13 -0
- package/src/shell/shell.ts +110 -0
- package/src/skill/compose/.bundle/ask/SKILL.md +58 -0
- package/src/skill/compose/.bundle/brainstorm/SKILL.md +220 -0
- package/src/skill/compose/.bundle/brainstorm/scripts/frame-template.html +214 -0
- package/src/skill/compose/.bundle/brainstorm/scripts/helper.js +88 -0
- package/src/skill/compose/.bundle/brainstorm/scripts/server.cjs +354 -0
- package/src/skill/compose/.bundle/brainstorm/scripts/start-server.sh +148 -0
- package/src/skill/compose/.bundle/brainstorm/scripts/stop-server.sh +56 -0
- package/src/skill/compose/.bundle/brainstorm/spec-document-reviewer-prompt.md +50 -0
- package/src/skill/compose/.bundle/brainstorm/visual-companion.md +287 -0
- package/src/skill/compose/.bundle/debug/CREATION-LOG.md +119 -0
- package/src/skill/compose/.bundle/debug/SKILL.md +297 -0
- package/src/skill/compose/.bundle/debug/condition-based-waiting-example.ts +158 -0
- package/src/skill/compose/.bundle/debug/condition-based-waiting.md +115 -0
- package/src/skill/compose/.bundle/debug/defense-in-depth.md +122 -0
- package/src/skill/compose/.bundle/debug/find-polluter.sh +63 -0
- package/src/skill/compose/.bundle/debug/root-cause-tracing.md +169 -0
- package/src/skill/compose/.bundle/debug/test-academic.md +14 -0
- package/src/skill/compose/.bundle/debug/test-pressure-1.md +58 -0
- package/src/skill/compose/.bundle/debug/test-pressure-2.md +68 -0
- package/src/skill/compose/.bundle/debug/test-pressure-3.md +69 -0
- package/src/skill/compose/.bundle/execute/SKILL.md +71 -0
- package/src/skill/compose/.bundle/feedback/SKILL.md +214 -0
- package/src/skill/compose/.bundle/merge/SKILL.md +252 -0
- package/src/skill/compose/.bundle/new-skill/SKILL.md +656 -0
- package/src/skill/compose/.bundle/new-skill/anthropic-best-practices.md +1150 -0
- package/src/skill/compose/.bundle/new-skill/examples/CLAUDE_MD_TESTING.md +189 -0
- package/src/skill/compose/.bundle/new-skill/graphviz-conventions.dot +172 -0
- package/src/skill/compose/.bundle/new-skill/persuasion-principles.md +187 -0
- package/src/skill/compose/.bundle/new-skill/render-graphs.js +168 -0
- package/src/skill/compose/.bundle/new-skill/testing-skills-with-subagents.md +384 -0
- package/src/skill/compose/.bundle/parallel/SKILL.md +182 -0
- package/src/skill/compose/.bundle/plan/SKILL.md +161 -0
- package/src/skill/compose/.bundle/plan/plan-document-reviewer-prompt.md +50 -0
- package/src/skill/compose/.bundle/report/SKILL.md +180 -0
- package/src/skill/compose/.bundle/review/SKILL.md +104 -0
- package/src/skill/compose/.bundle/review/code-reviewer.md +171 -0
- package/src/skill/compose/.bundle/subagent/SKILL.md +344 -0
- package/src/skill/compose/.bundle/subagent/code-quality-reviewer-prompt.md +24 -0
- package/src/skill/compose/.bundle/subagent/implementer-prompt.md +126 -0
- package/src/skill/compose/.bundle/subagent/spec-reviewer-prompt.md +112 -0
- package/src/skill/compose/.bundle/tdd/SKILL.md +372 -0
- package/src/skill/compose/.bundle/tdd/testing-anti-patterns.md +299 -0
- package/src/skill/compose/.bundle/verify/SKILL.md +140 -0
- package/src/skill/compose/.bundle/worktree/SKILL.md +234 -0
- package/src/skill/compose/LICENSE-karpathy +28 -0
- package/src/skill/compose/LICENSE-superpowers +26 -0
- package/src/skill/compose/bundle.macro.ts +30 -0
- package/src/skill/compose/extract.ts +85 -0
- package/src/skill/discovery.ts +116 -0
- package/src/skill/index.ts +311 -0
- package/src/snapshot/index.ts +777 -0
- package/src/sql.d.ts +4 -0
- package/src/storage/db.bun.ts +8 -0
- package/src/storage/db.node.ts +8 -0
- package/src/storage/db.ts +172 -0
- package/src/storage/index.ts +26 -0
- package/src/storage/json-migration.ts +426 -0
- package/src/storage/schema.sql.ts +10 -0
- package/src/storage/schema.ts +7 -0
- package/src/storage/storage.ts +331 -0
- package/src/sync/README.md +179 -0
- package/src/sync/event.sql.ts +16 -0
- package/src/sync/index.ts +278 -0
- package/src/sync/schema.ts +14 -0
- package/src/task/events.ts +28 -0
- package/src/task/gate-state.ts +54 -0
- package/src/task/gate.ts +116 -0
- package/src/task/index.ts +1 -0
- package/src/task/registry.ts +387 -0
- package/src/task/schema.ts +43 -0
- package/src/task/task.sql.ts +50 -0
- package/src/team/events.ts +22 -0
- package/src/team/index.ts +113 -0
- package/src/team/schema.ts +31 -0
- package/src/temporary.ts +33 -0
- package/src/tool/actor.shell.txt +72 -0
- package/src/tool/actor.ts +803 -0
- package/src/tool/actor.txt +103 -0
- package/src/tool/apply_patch.ts +308 -0
- package/src/tool/apply_patch.txt +33 -0
- package/src/tool/bash-interactive.ts +183 -0
- package/src/tool/bash.ts +696 -0
- package/src/tool/bash.txt +123 -0
- package/src/tool/change-directory.ts +91 -0
- package/src/tool/codesearch.ts +63 -0
- package/src/tool/codesearch.txt +12 -0
- package/src/tool/edit.ts +685 -0
- package/src/tool/edit.txt +10 -0
- package/src/tool/external-directory.ts +132 -0
- package/src/tool/glob.ts +100 -0
- package/src/tool/glob.txt +6 -0
- package/src/tool/grep.ts +145 -0
- package/src/tool/grep.txt +8 -0
- package/src/tool/history.ts +146 -0
- package/src/tool/history.txt +17 -0
- package/src/tool/index.ts +4 -0
- package/src/tool/invalid.ts +20 -0
- package/src/tool/invocation-style.ts +17 -0
- package/src/tool/lsp.ts +91 -0
- package/src/tool/lsp.txt +19 -0
- package/src/tool/mcp-exa.ts +78 -0
- package/src/tool/memory-path-guard.ts +162 -0
- package/src/tool/memory.ts +81 -0
- package/src/tool/memory.txt +69 -0
- package/src/tool/multiedit.ts +61 -0
- package/src/tool/multiedit.txt +41 -0
- package/src/tool/plan-enter.txt +14 -0
- package/src/tool/plan-exit.txt +13 -0
- package/src/tool/plan.ts +90 -0
- package/src/tool/question.ts +67 -0
- package/src/tool/question.txt +10 -0
- package/src/tool/read.ts +327 -0
- package/src/tool/read.txt +14 -0
- package/src/tool/registry.ts +413 -0
- package/src/tool/schema.ts +17 -0
- package/src/tool/session-cwd.ts +35 -0
- package/src/tool/shell-tokenize.ts +346 -0
- package/src/tool/shell-wrap.ts +190 -0
- package/src/tool/skill.ts +76 -0
- package/src/tool/skill.txt +5 -0
- package/src/tool/task.shell.txt +57 -0
- package/src/tool/task.ts +456 -0
- package/src/tool/task.txt +56 -0
- package/src/tool/tool.ts +153 -0
- package/src/tool/truncate.ts +201 -0
- package/src/tool/truncation-dir.ts +4 -0
- package/src/tool/webfetch.ts +199 -0
- package/src/tool/webfetch.txt +13 -0
- package/src/tool/websearch/index.ts +104 -0
- package/src/tool/websearch/mimo.ts +118 -0
- package/src/tool/websearch/websearch.txt +14 -0
- package/src/tool/workflow.ts +164 -0
- package/src/tool/workflow.txt +25 -0
- package/src/tool/write.ts +88 -0
- package/src/tool/write.txt +9 -0
- package/src/util/abort.ts +35 -0
- package/src/util/archive.ts +15 -0
- package/src/util/color.ts +17 -0
- package/src/util/data-url.ts +9 -0
- package/src/util/defer.ts +10 -0
- package/src/util/effect-http-client.ts +11 -0
- package/src/util/effect-zod.ts +367 -0
- package/src/util/error.ts +78 -0
- package/src/util/filesystem.ts +243 -0
- package/src/util/fn.ts +21 -0
- package/src/util/format.ts +20 -0
- package/src/util/iife.ts +3 -0
- package/src/util/index.ts +12 -0
- package/src/util/keybind.ts +101 -0
- package/src/util/lazy.ts +18 -0
- package/src/util/local-context.ts +23 -0
- package/src/util/locale.ts +79 -0
- package/src/util/lock.ts +96 -0
- package/src/util/log.ts +197 -0
- package/src/util/media.ts +26 -0
- package/src/util/mimo-process.ts +24 -0
- package/src/util/network.ts +9 -0
- package/src/util/process.ts +174 -0
- package/src/util/queue.ts +32 -0
- package/src/util/record.ts +3 -0
- package/src/util/rpc.ts +64 -0
- package/src/util/schema.ts +53 -0
- package/src/util/scrap.ts +10 -0
- package/src/util/signal.ts +12 -0
- package/src/util/timeout.ts +14 -0
- package/src/util/token.ts +5 -0
- package/src/util/update-schema.ts +13 -0
- package/src/util/which.ts +14 -0
- package/src/util/wildcard.ts +57 -0
- package/src/workflow/builtin/deep-research.js +391 -0
- package/src/workflow/builtin.ts +54 -0
- package/src/workflow/events.ts +72 -0
- package/src/workflow/meta.ts +335 -0
- package/src/workflow/persistence.ts +312 -0
- package/src/workflow/resolve.ts +45 -0
- package/src/workflow/runtime-ref.ts +18 -0
- package/src/workflow/runtime.ts +1234 -0
- package/src/workflow/sandbox.ts +280 -0
- package/src/workflow/workflow.sql.ts +31 -0
- package/src/workflow/workspace.ts +69 -0
- package/src/worktree/index.ts +614 -0
- package/sst-env.d.ts +10 -0
- package/test/AGENTS.md +133 -0
- package/test/account/repo.test.ts +352 -0
- package/test/account/service.test.ts +456 -0
- package/test/acp/agent-interface.test.ts +51 -0
- package/test/acp/event-subscription.test.ts +725 -0
- package/test/actor/cancel-cascade.test.ts +432 -0
- package/test/actor/no-completion-listener.test.ts +41 -0
- package/test/actor/poststop-progress-write-permission.repro.test.ts +414 -0
- package/test/actor/registry-render.test.ts +113 -0
- package/test/actor/registry-status.test.ts +111 -0
- package/test/actor/registry.test.ts +619 -0
- package/test/actor/return-header.test.ts +40 -0
- package/test/actor/spawn-lifecycle.test.ts +346 -0
- package/test/actor/spawn-no-deadlock.test.ts +340 -0
- package/test/actor/spawn-notification.test.ts +393 -0
- package/test/actor/spawn-task-autostart.test.ts +530 -0
- package/test/actor/spawn.test.ts +1072 -0
- package/test/actor/status-event-payload.test.ts +132 -0
- package/test/actor/terminology.test.ts +39 -0
- package/test/actor/turn.test.ts +125 -0
- package/test/actor/waiter.test.ts +246 -0
- package/test/agent/agent.test.ts +874 -0
- package/test/agent/allowlist.test.ts +45 -0
- package/test/auth/auth.test.ts +86 -0
- package/test/bus/bus-effect.test.ts +162 -0
- package/test/bus/bus-integration.test.ts +87 -0
- package/test/bus/bus.test.ts +219 -0
- package/test/cli/account.test.ts +26 -0
- package/test/cli/cmd/tui/prompt-part.test.ts +47 -0
- package/test/cli/error.test.ts +18 -0
- package/test/cli/github-action.test.ts +198 -0
- package/test/cli/github-remote.test.ts +80 -0
- package/test/cli/import.test.ts +54 -0
- package/test/cli/plugin-auth-picker.test.ts +120 -0
- package/test/cli/run-completion.test.ts +131 -0
- package/test/cli/tui/keybind-plugin.test.ts +90 -0
- package/test/cli/tui/plugin-add.test.ts +111 -0
- package/test/cli/tui/plugin-install.test.ts +87 -0
- package/test/cli/tui/plugin-lifecycle.test.ts +224 -0
- package/test/cli/tui/plugin-loader-entrypoint.test.ts +484 -0
- package/test/cli/tui/plugin-loader-pure.test.ts +71 -0
- package/test/cli/tui/plugin-loader.test.ts +816 -0
- package/test/cli/tui/plugin-toggle.test.ts +157 -0
- package/test/cli/tui/revert-diff.test.ts +35 -0
- package/test/cli/tui/route-agent-id.test.ts +26 -0
- package/test/cli/tui/sidebar-tps.test.ts +63 -0
- package/test/cli/tui/slot-replace.test.tsx +47 -0
- package/test/cli/tui/sync-bucket.test.ts +29 -0
- package/test/cli/tui/theme-store.test.ts +51 -0
- package/test/cli/tui/thread.test.ts +121 -0
- package/test/cli/tui/transcript.test.ts +426 -0
- package/test/cli/tui/use-event.test.tsx +175 -0
- package/test/cli/tui/voice.test.ts +269 -0
- package/test/command/deep-research-command.test.ts +16 -0
- package/test/config/agent-color.test.ts +77 -0
- package/test/config/checkpoint-fork.test.ts +21 -0
- package/test/config/config.test.ts +2577 -0
- package/test/config/fixtures/empty-frontmatter.md +4 -0
- package/test/config/fixtures/frontmatter.md +28 -0
- package/test/config/fixtures/markdown-header.md +11 -0
- package/test/config/fixtures/no-frontmatter.md +1 -0
- package/test/config/fixtures/weird-model-id.md +13 -0
- package/test/config/lsp.test.ts +87 -0
- package/test/config/markdown.test.ts +228 -0
- package/test/config/plugin.test.ts +0 -0
- package/test/config/tui.test.ts +627 -0
- package/test/control-plane/adaptors.test.ts +71 -0
- package/test/control-plane/sse.test.ts +56 -0
- package/test/effect/app-runtime-logger.test.ts +92 -0
- package/test/effect/cross-spawn-spawner.test.ts +411 -0
- package/test/effect/instance-state.test.ts +482 -0
- package/test/effect/observability.test.ts +46 -0
- package/test/effect/run-service.test.ts +46 -0
- package/test/effect/runner-warn-log.test.ts +111 -0
- package/test/effect/runner.test.ts +494 -0
- package/test/fake/provider.ts +90 -0
- package/test/file/fsmonitor.test.ts +68 -0
- package/test/file/ignore.test.ts +10 -0
- package/test/file/index.test.ts +956 -0
- package/test/file/path-traversal.test.ts +204 -0
- package/test/file/ripgrep.test.ts +214 -0
- package/test/file/watcher.test.ts +249 -0
- package/test/filesystem/filesystem.test.ts +319 -0
- package/test/fixture/db.ts +11 -0
- package/test/fixture/fixture.test.ts +58 -0
- package/test/fixture/fixture.ts +190 -0
- package/test/fixture/flock-worker.ts +72 -0
- package/test/fixture/lsp/fake-lsp-server.js +75 -0
- package/test/fixture/plug-worker.ts +93 -0
- package/test/fixture/plugin-meta-worker.ts +19 -0
- package/test/fixture/skills/agents-sdk/SKILL.md +152 -0
- package/test/fixture/skills/agents-sdk/references/callable.md +92 -0
- package/test/fixture/skills/cloudflare/SKILL.md +211 -0
- package/test/fixture/skills/index.json +6 -0
- package/test/fixture/tui-plugin.ts +328 -0
- package/test/fixture/tui-runtime.ts +31 -0
- package/test/format/format.test.ts +244 -0
- package/test/git/git.test.ts +128 -0
- package/test/global/fixture/global-paths-worker.ts +17 -0
- package/test/global/mimocode-home.test.ts +143 -0
- package/test/history/backfill.test.ts +149 -0
- package/test/history/extract.test.ts +106 -0
- package/test/history/fts-query.test.ts +30 -0
- package/test/history/resolve.test.ts +130 -0
- package/test/history/service.test.ts +210 -0
- package/test/history/writer.test.ts +163 -0
- package/test/ide/ide.test.ts +82 -0
- package/test/inbox/drain-in-loop.test.ts +230 -0
- package/test/inbox/fork-agent-compat.test.ts +387 -0
- package/test/inbox/gc-on-init.test.ts +167 -0
- package/test/inbox/send-no-block.test.ts +120 -0
- package/test/inbox/sender-cancel-independence.test.ts +160 -0
- package/test/inbox/wake-matrix.test.ts +141 -0
- package/test/installation/installation.test.ts +226 -0
- package/test/keybind.test.ts +421 -0
- package/test/lib/effect.ts +53 -0
- package/test/lib/filesystem.ts +10 -0
- package/test/lib/llm-server.ts +770 -0
- package/test/lib/scripted-llm-server.ts +245 -0
- package/test/lsp/client.test.ts +98 -0
- package/test/lsp/index.test.ts +109 -0
- package/test/lsp/launch.test.ts +22 -0
- package/test/lsp/lifecycle.test.ts +184 -0
- package/test/mcp/headers.test.ts +178 -0
- package/test/mcp/lifecycle.test.ts +824 -0
- package/test/mcp/oauth-auto-connect.test.ts +281 -0
- package/test/mcp/oauth-browser.test.ts +268 -0
- package/test/mcp/oauth-callback.test.ts +34 -0
- package/test/memory/abort-leak-webfetch.ts +49 -0
- package/test/memory/abort-leak.test.ts +127 -0
- package/test/memory/cc-frontmatter.test.ts +85 -0
- package/test/memory/cc-paths.test.ts +60 -0
- package/test/memory/cc-reconcile.test.ts +239 -0
- package/test/memory/cc-search.test.ts +151 -0
- package/test/memory/fts-query.test.ts +48 -0
- package/test/memory/fts-rowid-stability.test.ts +271 -0
- package/test/memory/paths.test.ts +210 -0
- package/test/memory/reconcile.test.ts +115 -0
- package/test/memory/service.test.ts +169 -0
- package/test/npm.test.ts +18 -0
- package/test/patch/patch.test.ts +348 -0
- package/test/permission/abort.test.ts +116 -0
- package/test/permission/arity.test.ts +33 -0
- package/test/permission/disabled.test.ts +51 -0
- package/test/permission/next.test.ts +1080 -0
- package/test/permission/non-interactive.test.ts +55 -0
- package/test/permission-task.test.ts +326 -0
- package/test/plugin/actor-hooks.test.ts +1471 -0
- package/test/plugin/auth-override.test.ts +79 -0
- package/test/plugin/checkpoint-splitover.test.ts +434 -0
- package/test/plugin/cloudflare.test.ts +68 -0
- package/test/plugin/codex.test.ts +123 -0
- package/test/plugin/github-copilot-models.test.ts +163 -0
- package/test/plugin/install-concurrency.test.ts +140 -0
- package/test/plugin/install.test.ts +570 -0
- package/test/plugin/loader-shared.test.ts +1169 -0
- package/test/plugin/matcher.test.ts +97 -0
- package/test/plugin/meta.test.ts +137 -0
- package/test/plugin/mimo.test.ts +257 -0
- package/test/plugin/shared.test.ts +88 -0
- package/test/plugin/subagent-progress-checker.test.ts +227 -0
- package/test/plugin/trigger.test.ts +116 -0
- package/test/plugin/workspace-adaptor.test.ts +109 -0
- package/test/preload.ts +102 -0
- package/test/project/migrate-global.test.ts +150 -0
- package/test/project/project-id.test.ts +64 -0
- package/test/project/project.test.ts +481 -0
- package/test/project/vcs.test.ts +286 -0
- package/test/project/worktree-remove.test.ts +126 -0
- package/test/project/worktree.test.ts +214 -0
- package/test/provider/amazon-bedrock.test.ts +462 -0
- package/test/provider/copilot/convert-to-copilot-messages.test.ts +523 -0
- package/test/provider/copilot/copilot-chat-model.test.ts +592 -0
- package/test/provider/error.test.ts +160 -0
- package/test/provider/gitlab-duo.test.ts +413 -0
- package/test/provider/model-groups.test.ts +389 -0
- package/test/provider/provider-chunk-timeout.test.ts +23 -0
- package/test/provider/provider.test.ts +2648 -0
- package/test/provider/transform.test.ts +3379 -0
- package/test/pty/pty-output-isolation.test.ts +146 -0
- package/test/pty/pty-session.test.ts +102 -0
- package/test/pty/pty-shell.test.ts +69 -0
- package/test/question/question.test.ts +464 -0
- package/test/server/global-session-list.test.ts +105 -0
- package/test/server/project-init-git.test.ts +122 -0
- package/test/server/session-actions.test.ts +49 -0
- package/test/server/session-list.test.ts +110 -0
- package/test/server/session-messages.test.ts +220 -0
- package/test/server/session-prompt-busy.test.ts +146 -0
- package/test/server/session-select.test.ts +100 -0
- package/test/server/session-task-route.test.ts +165 -0
- package/test/server/summarize-route-main-slice.test.ts +99 -0
- package/test/server/trace-attributes.test.ts +76 -0
- package/test/server/workflows-route.test.ts +279 -0
- package/test/session/bootstrap-skip-system.test.ts +121 -0
- package/test/session/boundary.test.ts +33 -0
- package/test/session/budgeted-read.test.ts +74 -0
- package/test/session/checkpoint-align.test.ts +58 -0
- package/test/session/checkpoint-boundary.test.ts +186 -0
- package/test/session/checkpoint-child-session.test.ts +508 -0
- package/test/session/checkpoint-context.test.ts +141 -0
- package/test/session/checkpoint-drain.test.ts +188 -0
- package/test/session/checkpoint-extract-titles.test.ts +58 -0
- package/test/session/checkpoint-fork-mode.test.ts +576 -0
- package/test/session/checkpoint-main-slice.test.ts +259 -0
- package/test/session/checkpoint-paths.test.ts +78 -0
- package/test/session/checkpoint-permission.test.ts +136 -0
- package/test/session/checkpoint-progress-reconcile.test.ts +219 -0
- package/test/session/checkpoint-rebuild-unify.test.ts +143 -0
- package/test/session/checkpoint-rebuild-v3.test.ts +248 -0
- package/test/session/checkpoint-render-verify.test.ts +512 -0
- package/test/session/checkpoint-retry.test.ts +150 -0
- package/test/session/checkpoint-splitover-integration.test.ts +533 -0
- package/test/session/checkpoint-templates.test.ts +51 -0
- package/test/session/checkpoint-thresholds.test.ts +120 -0
- package/test/session/checkpoint-validator.test.ts +189 -0
- package/test/session/classify-integration.test.ts +476 -0
- package/test/session/classify.test.ts +335 -0
- package/test/session/compaction-agent-scope.test.ts +164 -0
- package/test/session/context-inheritance.test.ts +46 -0
- package/test/session/fork-prefix-invariant.test.ts +116 -0
- package/test/session/goal.test.ts +106 -0
- package/test/session/instruction.test.ts +387 -0
- package/test/session/invalid-output-continuation.test.ts +150 -0
- package/test/session/last-message-info.test.ts +47 -0
- package/test/session/length-tool-safety.test.ts +121 -0
- package/test/session/llm-request-prefix.test.ts +197 -0
- package/test/session/llm-retry.test.ts +59 -0
- package/test/session/llm-system-prompt.test.ts +479 -0
- package/test/session/llm.test.ts +1272 -0
- package/test/session/main-lifecycle.test.ts +51 -0
- package/test/session/main-runloop-history-invariant.test.ts +182 -0
- package/test/session/max-mode-econnreset.test.ts +229 -0
- package/test/session/max-mode.test.ts +54 -0
- package/test/session/message-v2-filter.test.ts +197 -0
- package/test/session/message-v2.test.ts +1119 -0
- package/test/session/messages-default-main.test.ts +105 -0
- package/test/session/messages-pagination.test.ts +888 -0
- package/test/session/overflow.test.ts +576 -0
- package/test/session/processor-effect.test.ts +853 -0
- package/test/session/prompt-effect.test.ts +1574 -0
- package/test/session/prompt-rebuild-loop.test.ts +108 -0
- package/test/session/prompt-rebuild-reset.test.ts +67 -0
- package/test/session/prompt-sweep.test.ts +145 -0
- package/test/session/prompt-task-gate.test.ts +127 -0
- package/test/session/prompt.test.ts +703 -0
- package/test/session/prune-main-slice.test.ts +272 -0
- package/test/session/prune-skip-system.test.ts +346 -0
- package/test/session/prune.test.ts +419 -0
- package/test/session/rebuild-microcompact.test.ts +318 -0
- package/test/session/recall-reminder.test.ts +37 -0
- package/test/session/retry.test.ts +410 -0
- package/test/session/revert-compact.test.ts +639 -0
- package/test/session/run-state-tuple-key.test.ts +152 -0
- package/test/session/session-create-registers-main.test.ts +70 -0
- package/test/session/session.test.ts +181 -0
- package/test/session/snapshot-tool-race.test.ts +301 -0
- package/test/session/structured-output-integration.test.ts +264 -0
- package/test/session/structured-output-retry.test.ts +127 -0
- package/test/session/structured-output.test.ts +397 -0
- package/test/session/summary-main-slice.test.ts +170 -0
- package/test/session/system.test.ts +72 -0
- package/test/share/share-next.test.ts +332 -0
- package/test/shell/shell.test.ts +73 -0
- package/test/skill/compose-review.test.ts +141 -0
- package/test/skill/discovery.test.ts +116 -0
- package/test/skill/skill.test.ts +465 -0
- package/test/snapshot/snapshot.test.ts +1531 -0
- package/test/storage/db.test.ts +16 -0
- package/test/storage/json-migration.test.ts +831 -0
- package/test/storage/storage.test.ts +293 -0
- package/test/sync/index.test.ts +237 -0
- package/test/task/gate-state.test.ts +66 -0
- package/test/task/gate.test.ts +167 -0
- package/test/task/registry.test.ts +152 -0
- package/test/task/state-machine.test.ts +292 -0
- package/test/team/migrate-to-inbox.test.ts +124 -0
- package/test/team/team.test.ts +75 -0
- package/test/tool/__snapshots__/tool.test.ts.snap +9 -0
- package/test/tool/actor-cancel.test.ts +206 -0
- package/test/tool/actor-recover.test.ts +50 -0
- package/test/tool/actor-send.test.ts +200 -0
- package/test/tool/actor-status.test.ts +296 -0
- package/test/tool/actor-wait.test.ts +193 -0
- package/test/tool/actor.shell.test.ts +250 -0
- package/test/tool/actor.test.ts +748 -0
- package/test/tool/apply_patch.test.ts +626 -0
- package/test/tool/bash.test.ts +1195 -0
- package/test/tool/describe-workflow.test.ts +12 -0
- package/test/tool/edit.test.ts +691 -0
- package/test/tool/external-directory.test.ts +207 -0
- package/test/tool/fixtures/large-image.png +0 -0
- package/test/tool/fixtures/models-api.json +65179 -0
- package/test/tool/glob.test.ts +81 -0
- package/test/tool/grep.test.ts +114 -0
- package/test/tool/history.test.ts +144 -0
- package/test/tool/invocation-style.test.ts +30 -0
- package/test/tool/memory-edit-ask-skip.test.ts +62 -0
- package/test/tool/memory-path-guard.test.ts +594 -0
- package/test/tool/memory.test.ts +71 -0
- package/test/tool/question.test.ts +167 -0
- package/test/tool/read.test.ts +483 -0
- package/test/tool/registry-invocation-style.test.ts +121 -0
- package/test/tool/registry.test.ts +164 -0
- package/test/tool/shell-tokenize.test.ts +273 -0
- package/test/tool/shell-wrap-missing-script.test.ts +128 -0
- package/test/tool/shell-wrap.test.ts +257 -0
- package/test/tool/skill.test.ts +99 -0
- package/test/tool/task-recover.test.ts +36 -0
- package/test/tool/task.shell.test.ts +234 -0
- package/test/tool/task.test.ts +296 -0
- package/test/tool/tool-def-shell-shape.test.ts +23 -0
- package/test/tool/tool-define.test.ts +59 -0
- package/test/tool/truncation.test.ts +253 -0
- package/test/tool/webfetch.test.ts +103 -0
- package/test/tool/whitelist.test.ts +373 -0
- package/test/tool/write.test.ts +244 -0
- package/test/util/data-url.test.ts +14 -0
- package/test/util/effect-zod.test.ts +869 -0
- package/test/util/error.test.ts +38 -0
- package/test/util/filesystem.test.ts +656 -0
- package/test/util/format.test.ts +59 -0
- package/test/util/glob.test.ts +164 -0
- package/test/util/iife.test.ts +36 -0
- package/test/util/lazy.test.ts +50 -0
- package/test/util/lock.test.ts +72 -0
- package/test/util/log.test.ts +44 -0
- package/test/util/module.test.ts +59 -0
- package/test/util/process.test.ts +128 -0
- package/test/util/timeout.test.ts +21 -0
- package/test/util/which.test.ts +100 -0
- package/test/util/wildcard.test.ts +90 -0
- package/test/workflow/builtin.test.ts +22 -0
- package/test/workflow/deep-research-cluster.test.ts +47 -0
- package/test/workflow/lib.ts +243 -0
- package/test/workflow/meta.test.ts +142 -0
- package/test/workflow/model-routing.test.ts +68 -0
- package/test/workflow/persistence.test.ts +229 -0
- package/test/workflow/resolve.test.ts +37 -0
- package/test/workflow/runtime-nested.test.ts +419 -0
- package/test/workflow/runtime-worktree.test.ts +261 -0
- package/test/workflow/runtime.test.ts +1078 -0
- package/test/workflow/sandbox.test.ts +259 -0
- package/test/workflow/tool.test.ts +473 -0
- package/test/workflow/verify-wow.test.ts +144 -0
- package/test/workflow/workspace.test.ts +88 -0
- package/test/workspace/workspace-restore.test.ts +281 -0
- package/test/worktree/index.test.ts +30 -0
- package/tsconfig.json +24 -0
|
@@ -0,0 +1,481 @@
|
|
|
1
|
+
import * as Session from "./session"
|
|
2
|
+
import { SessionID } from "./schema"
|
|
3
|
+
import { Provider } from "../provider"
|
|
4
|
+
import { MessageV2 } from "./message-v2"
|
|
5
|
+
import { Token } from "../util"
|
|
6
|
+
import { Log } from "../util"
|
|
7
|
+
import { Config } from "@/config"
|
|
8
|
+
import { NotFoundError } from "@/storage"
|
|
9
|
+
import { Effect, Layer, Context } from "effect"
|
|
10
|
+
import { pressureLevel, usable } from "./overflow"
|
|
11
|
+
import { SessionCheckpoint } from "./checkpoint"
|
|
12
|
+
import { ActorRegistry } from "@/actor/registry"
|
|
13
|
+
import type { ActorPromptOps } from "@/tool/actor"
|
|
14
|
+
|
|
15
|
+
const log = Log.create({ service: "session.prune" })
|
|
16
|
+
|
|
17
|
+
const PRUNE_MINIMUM = 20_000
|
|
18
|
+
const PRUNE_PROTECT = 40_000
|
|
19
|
+
const PRUNE_PROTECTED_TOOLS = ["skill"]
|
|
20
|
+
const SOFT_TRIM_THRESHOLD = 4096
|
|
21
|
+
const SOFT_TRIM_KEEP_HEAD = 1536
|
|
22
|
+
const SOFT_TRIM_KEEP_TAIL = 1536
|
|
23
|
+
const DEFAULT_CACHE_TTL = 300_000
|
|
24
|
+
// Default safety buffer subtracted from windowSize to derive maxAllowed for
|
|
25
|
+
// checkpoint thresholds. Users can override via cfg.checkpoint.reserved.
|
|
26
|
+
const CHECKPOINT_RESERVED = 13_000
|
|
27
|
+
const MAX_WRITER_FAILURES = 3
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Default checkpoint thresholds by context window size.
|
|
31
|
+
*
|
|
32
|
+
* Schedule (Part 2 density):
|
|
33
|
+
* < 25K → [] (subsystem disabled)
|
|
34
|
+
* 25K ≤ w ≤ 200K → 4 triggers @ 20% (mid-tier models)
|
|
35
|
+
* 200K < w ≤ 500K → 9 triggers @ 10% (extended-context models)
|
|
36
|
+
* w > 500K → 18 triggers @ 5% (1M+ window models)
|
|
37
|
+
*
|
|
38
|
+
* Density mirrors cc's intent that writers fire often enough that overflow
|
|
39
|
+
* almost always finds a fresh `checkpoint.md` to rebuild from (avoiding
|
|
40
|
+
* fallback to lossy compaction). cc uses growth+toolcall triggers; we use
|
|
41
|
+
* % of window for a simpler implementation that doesn't require new state.
|
|
42
|
+
* See docs/superpowers/specs/2026-06-03-checkpoint-threshold-density-design.md.
|
|
43
|
+
*/
|
|
44
|
+
export function defaultThresholdsFor(window: number): readonly string[] {
|
|
45
|
+
if (window < 25_000) return []
|
|
46
|
+
if (window <= 200_000) return ["20%", "40%", "60%", "80%"]
|
|
47
|
+
if (window <= 500_000) {
|
|
48
|
+
return ["10%", "20%", "30%", "40%", "50%", "60%", "70%", "80%", "90%"]
|
|
49
|
+
}
|
|
50
|
+
return Array.from({ length: 18 }, (_, i) => `${(i + 1) * 5}%`)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function isCacheCold(model?: Provider.Model, lastAssistantTime?: number): boolean {
|
|
54
|
+
if (!model) return true
|
|
55
|
+
const ttl = model.cacheTTL ?? DEFAULT_CACHE_TTL
|
|
56
|
+
if (!lastAssistantTime) return true
|
|
57
|
+
return Date.now() - lastAssistantTime > ttl
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Parse a checkpoint threshold string into a token count.
|
|
62
|
+
* Supports: "40%" (percent of windowSize), "100K"/"100k" (kilotokens),
|
|
63
|
+
* "1.5M"/"1.5m" (megatokens), or plain number.
|
|
64
|
+
*/
|
|
65
|
+
export function parseThreshold(s: string, windowSize: number): number {
|
|
66
|
+
const trimmed = s.trim()
|
|
67
|
+
if (trimmed.endsWith("%")) {
|
|
68
|
+
const pct = parseFloat(trimmed.slice(0, -1))
|
|
69
|
+
if (!Number.isFinite(pct) || pct <= 0 || pct > 100) {
|
|
70
|
+
throw new Error(`Invalid checkpoint threshold percentage: "${s}" (must be 0 < n <= 100)`)
|
|
71
|
+
}
|
|
72
|
+
return Math.floor((windowSize * pct) / 100)
|
|
73
|
+
}
|
|
74
|
+
const match = trimmed.match(/^(\d+(?:\.\d+)?)([KkMm]?)$/)
|
|
75
|
+
if (!match) throw new Error(`Invalid checkpoint threshold format: "${s}"`)
|
|
76
|
+
let n = parseFloat(match[1])
|
|
77
|
+
if (match[2] === "K" || match[2] === "k") n *= 1_000
|
|
78
|
+
else if (match[2] === "M" || match[2] === "m") n *= 1_000_000
|
|
79
|
+
return Math.floor(n)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Parse, validate, sort, and deduplicate checkpoint thresholds.
|
|
84
|
+
*
|
|
85
|
+
* - Values ≤ maxAllowed pass through.
|
|
86
|
+
* - The FIRST over-cap value (in user-provided order) is clamped to maxAllowed
|
|
87
|
+
* and logged INFO.
|
|
88
|
+
* - Later over-cap values are dropped and logged INFO.
|
|
89
|
+
* - Throws only when maxAllowed itself is <= 0 (model context too small to
|
|
90
|
+
* accommodate the safety buffer — no recovery available).
|
|
91
|
+
*/
|
|
92
|
+
export function resolveThresholds(raw: readonly string[], windowSize: number, reserved?: number): number[] {
|
|
93
|
+
const effectiveReserved = reserved ?? CHECKPOINT_RESERVED
|
|
94
|
+
const maxAllowed = windowSize - effectiveReserved
|
|
95
|
+
if (maxAllowed <= 0) {
|
|
96
|
+
throw new Error(
|
|
97
|
+
`Model window size (${windowSize}) is too small for checkpoints ` +
|
|
98
|
+
`(need > ${effectiveReserved} reserved tokens)`,
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const parsed = raw.map((s) => ({ raw: s, value: parseThreshold(s, windowSize) }))
|
|
103
|
+
|
|
104
|
+
const result: number[] = []
|
|
105
|
+
let cappedAlready = false
|
|
106
|
+
for (const p of parsed) {
|
|
107
|
+
if (p.value <= maxAllowed) {
|
|
108
|
+
result.push(p.value)
|
|
109
|
+
continue
|
|
110
|
+
}
|
|
111
|
+
if (!cappedAlready) {
|
|
112
|
+
log.info(
|
|
113
|
+
`checkpoint threshold "${p.raw}" (${p.value}) exceeds maxAllowed (${maxAllowed}) — clamped to maxAllowed`,
|
|
114
|
+
)
|
|
115
|
+
result.push(maxAllowed)
|
|
116
|
+
cappedAlready = true
|
|
117
|
+
continue
|
|
118
|
+
}
|
|
119
|
+
log.info(
|
|
120
|
+
`checkpoint threshold "${p.raw}" (${p.value}) exceeds maxAllowed (${maxAllowed}) — dropped (already clamped earlier)`,
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Sort and dedupe. If a sub-cap entry happened to equal maxAllowed, it
|
|
125
|
+
// collapses with the clamped value.
|
|
126
|
+
const values = result.sort((a, b) => a - b)
|
|
127
|
+
const deduped: number[] = []
|
|
128
|
+
for (const v of values) {
|
|
129
|
+
if (deduped.length === 0 || deduped[deduped.length - 1] !== v) deduped.push(v)
|
|
130
|
+
}
|
|
131
|
+
return deduped
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export interface Interface {
|
|
135
|
+
readonly prune: (input: {
|
|
136
|
+
sessionID: SessionID
|
|
137
|
+
model: Provider.Model
|
|
138
|
+
tokens: MessageV2.Assistant["tokens"]
|
|
139
|
+
lastAssistantTime?: number
|
|
140
|
+
promptOps?: ActorPromptOps
|
|
141
|
+
}) => Effect.Effect<void>
|
|
142
|
+
/**
|
|
143
|
+
* Fire background checkpoint writers for every newly-crossed threshold.
|
|
144
|
+
* Call this at the START of each runLoop iteration so thresholds fire
|
|
145
|
+
* mid-turn as tokens grow (not only at turn end).
|
|
146
|
+
*/
|
|
147
|
+
readonly fireCheckpoints: (input: {
|
|
148
|
+
sessionID: SessionID
|
|
149
|
+
model: Provider.Model
|
|
150
|
+
tokens: MessageV2.Assistant["tokens"]
|
|
151
|
+
promptOps: ActorPromptOps
|
|
152
|
+
agentID?: string
|
|
153
|
+
}) => Effect.Effect<void>
|
|
154
|
+
/** True when the current tokens have just crossed the max checkpoint threshold. */
|
|
155
|
+
readonly maxThresholdCrossed: (sessionID: SessionID) => Effect.Effect<boolean>
|
|
156
|
+
/** Clear the crossed-threshold state for a session (e.g. after discard+rebuild). */
|
|
157
|
+
readonly resetThresholds: (sessionID: SessionID) => Effect.Effect<void>
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export class Service extends Context.Service<Service, Interface>()("@tulingcode/SessionPrune") {}
|
|
161
|
+
|
|
162
|
+
export const layer: Layer.Layer<
|
|
163
|
+
Service,
|
|
164
|
+
never,
|
|
165
|
+
Config.Service | Session.Service | SessionCheckpoint.Service | ActorRegistry.Service
|
|
166
|
+
> = Layer.effect(
|
|
167
|
+
Service,
|
|
168
|
+
Effect.gen(function* () {
|
|
169
|
+
const config = yield* Config.Service
|
|
170
|
+
const session = yield* Session.Service
|
|
171
|
+
const checkpoint = yield* SessionCheckpoint.Service
|
|
172
|
+
const actorReg = yield* ActorRegistry.Service
|
|
173
|
+
|
|
174
|
+
// Per-session state: which checkpoint thresholds have already been crossed
|
|
175
|
+
// (and had a checkpoint writer enqueued). Prevents re-firing on the same
|
|
176
|
+
// threshold every turn.
|
|
177
|
+
const crossed = new Map<SessionID, Set<number>>()
|
|
178
|
+
// Per-session signal: the max threshold was just crossed; prompt.ts should
|
|
179
|
+
// trigger discard+rebuild on the next loop iteration.
|
|
180
|
+
const maxCrossed = new Set<SessionID>()
|
|
181
|
+
// Per-session consecutive writer-failure count. Resets on success.
|
|
182
|
+
// After the configured `max_writer_failures` (default MAX_WRITER_FAILURES)
|
|
183
|
+
// consecutive failures, the session stops retrying checkpoint writes
|
|
184
|
+
// until the process restarts.
|
|
185
|
+
const writerFailures = new Map<SessionID, number>()
|
|
186
|
+
|
|
187
|
+
const stripNonEssential = Effect.fn("SessionPrune.stripNonEssential")(function* (input: {
|
|
188
|
+
sessionID: SessionID
|
|
189
|
+
model: Provider.Model
|
|
190
|
+
lastAssistantTime?: number
|
|
191
|
+
}) {
|
|
192
|
+
if (!isCacheCold(input.model, input.lastAssistantTime)) return
|
|
193
|
+
|
|
194
|
+
const msgs = yield* session
|
|
195
|
+
.messages({ sessionID: input.sessionID, agentID: "main" })
|
|
196
|
+
.pipe(Effect.catchIf(NotFoundError.isInstance, () => Effect.succeed(undefined)))
|
|
197
|
+
if (!msgs) return
|
|
198
|
+
|
|
199
|
+
// Protect last 3 turns.
|
|
200
|
+
let turnCount = 0
|
|
201
|
+
let boundary = msgs.length
|
|
202
|
+
for (let i = msgs.length - 1; i >= 0; i--) {
|
|
203
|
+
if (msgs[i].info.role === "user") turnCount++
|
|
204
|
+
if (turnCount > 3) {
|
|
205
|
+
boundary = i
|
|
206
|
+
break
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
let stripped = 0
|
|
211
|
+
for (let i = 0; i < boundary; i++) {
|
|
212
|
+
const msg = msgs[i]
|
|
213
|
+
for (const part of msg.parts) {
|
|
214
|
+
if (part.type === "file" && MessageV2.isMedia(part.mime)) {
|
|
215
|
+
yield* session.updatePart({
|
|
216
|
+
...part,
|
|
217
|
+
url: "",
|
|
218
|
+
filename: `[stripped: ${part.filename ?? part.mime}]`,
|
|
219
|
+
})
|
|
220
|
+
stripped++
|
|
221
|
+
}
|
|
222
|
+
if (part.type === "reasoning" && msg.info.role === "assistant") {
|
|
223
|
+
yield* session.updatePart({
|
|
224
|
+
...part,
|
|
225
|
+
text: "",
|
|
226
|
+
})
|
|
227
|
+
stripped++
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (stripped > 0) {
|
|
233
|
+
log.info("stripped non-essential content", { count: stripped })
|
|
234
|
+
}
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
// Fires a checkpoint write for every threshold newly crossed by the
|
|
238
|
+
// current token count. Exposed publicly so runLoop can call it at each
|
|
239
|
+
// iteration to catch mid-turn threshold crossings (not just turn end).
|
|
240
|
+
const fireCheckpoints = Effect.fn("SessionPrune.fireCheckpoints")(function* (input: {
|
|
241
|
+
sessionID: SessionID
|
|
242
|
+
model: Provider.Model
|
|
243
|
+
tokens: MessageV2.Assistant["tokens"]
|
|
244
|
+
promptOps: ActorPromptOps
|
|
245
|
+
agentID?: string
|
|
246
|
+
}) {
|
|
247
|
+
// Skip if this is a system-spawned actor — it's an internal subagent
|
|
248
|
+
// (e.g. checkpoint-writer) and should not itself trigger checkpoints.
|
|
249
|
+
if (input.agentID && (yield* actorReg.isSystemSpawned(input.sessionID, input.agentID))) {
|
|
250
|
+
return
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Kept separate from the isSystemSpawned skip above on purpose: that
|
|
254
|
+
// guard keys on AGENT TYPE (checkpoint-writer/dream/distill), this one
|
|
255
|
+
// keys on MODE. They are orthogonal invariants that merely overlap today
|
|
256
|
+
// (those agents happen to spawn as mode:"subagent"). Folding them into one
|
|
257
|
+
// boolean would silently re-enable self-triggering for any future
|
|
258
|
+
// system agent spawned as mode:"peer". The extra registry read is a local
|
|
259
|
+
// SQLite hit; correctness of the layering is worth more than saving it.
|
|
260
|
+
//
|
|
261
|
+
// Checkpoint serves main/peer only; subagents use per-actor compaction
|
|
262
|
+
// (independent layers — see 2026-05-22-checkpoint-v8-design.md:71). A
|
|
263
|
+
// subagent shares the parent sessionID, so if it triggered a checkpoint
|
|
264
|
+
// the writer's unfiltered-stream watermark could land on the subagent's
|
|
265
|
+
// messages and the fork would capture the wrong parent system prompt.
|
|
266
|
+
// Gate on registry mode, NOT agentID: a peer's agentID is its child.id,
|
|
267
|
+
// not "main", so an agentID==="main" check would wrongly exclude peers.
|
|
268
|
+
// Unresolved actor (no agentID / unregistered / race) → fail open and
|
|
269
|
+
// fire: main and peer must never silently lose checkpoints.
|
|
270
|
+
const actor = input.agentID ? yield* actorReg.get(input.sessionID, input.agentID) : undefined
|
|
271
|
+
if (actor?.mode === "subagent") return
|
|
272
|
+
|
|
273
|
+
// Lock: skip if a writer is already running for this session.
|
|
274
|
+
// crossed Set is NOT incremented here — when the in-flight writer
|
|
275
|
+
// finishes, the next fireCheckpoints invocation can re-fire previously-
|
|
276
|
+
// skipped thresholds.
|
|
277
|
+
if (yield* checkpoint.isWriterRunning(input.sessionID)) {
|
|
278
|
+
log.info("checkpoint writer running, skipping new threshold trigger", {
|
|
279
|
+
sessionID: input.sessionID,
|
|
280
|
+
})
|
|
281
|
+
return
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const cfg = yield* config.get()
|
|
285
|
+
const windowSize = usable({ cfg, model: input.model })
|
|
286
|
+
if (windowSize === 0) return
|
|
287
|
+
const raw = cfg.checkpoint?.thresholds ?? defaultThresholdsFor(windowSize)
|
|
288
|
+
|
|
289
|
+
// resolveThresholds throws on invalid config; we let that propagate so
|
|
290
|
+
// the user sees the error fast at the first overflow check.
|
|
291
|
+
const thresholds = resolveThresholds(raw, windowSize, cfg.checkpoint?.reserved)
|
|
292
|
+
if (thresholds.length === 0) return
|
|
293
|
+
|
|
294
|
+
const maxFailures = cfg.checkpoint?.max_writer_failures ?? MAX_WRITER_FAILURES
|
|
295
|
+
|
|
296
|
+
const currentTokens =
|
|
297
|
+
input.tokens.total ||
|
|
298
|
+
input.tokens.input + input.tokens.output + input.tokens.cache.read + input.tokens.cache.write
|
|
299
|
+
|
|
300
|
+
const already = crossed.get(input.sessionID) ?? new Set<number>()
|
|
301
|
+
const maxThreshold = thresholds[thresholds.length - 1]
|
|
302
|
+
|
|
303
|
+
for (const t of thresholds) {
|
|
304
|
+
if (currentTokens < t) break // sorted ascending; nothing more to trigger
|
|
305
|
+
if (already.has(t)) continue
|
|
306
|
+
|
|
307
|
+
const outcome = yield* checkpoint
|
|
308
|
+
.tryStartCheckpointWriter({
|
|
309
|
+
sessionID: input.sessionID,
|
|
310
|
+
model: { providerID: input.model.providerID, modelID: input.model.id },
|
|
311
|
+
promptOps: input.promptOps,
|
|
312
|
+
})
|
|
313
|
+
.pipe(Effect.catch(() => Effect.succeed<"started" | "queued" | "skipped">("skipped")))
|
|
314
|
+
|
|
315
|
+
if (outcome === "started") {
|
|
316
|
+
// Fork a watcher that settles after the detached writer fiber
|
|
317
|
+
// finishes. On success, clear the failure counter. On failure,
|
|
318
|
+
// increment the counter; if below MAX_WRITER_FAILURES, clear the
|
|
319
|
+
// session's crossed thresholds so the next iteration retries.
|
|
320
|
+
//
|
|
321
|
+
// Known narrow race: between tryStartCheckpointWriter returning "started" and
|
|
322
|
+
// the watcher's forkDetach scheduling, a very-fast writer fiber can
|
|
323
|
+
// complete and delete itself from the writers map. waitForWriter
|
|
324
|
+
// then returns "no-writer" and the watcher exits without touching
|
|
325
|
+
// the counter. Impact is low — real writers run an LLM round-trip
|
|
326
|
+
// (seconds) vs. microseconds to schedule the fork, so observable
|
|
327
|
+
// failures tick the counter in practice. Proper fix: have
|
|
328
|
+
// tryStartCheckpointWriter return the Deferred handle so the watcher doesn't
|
|
329
|
+
// re-read the writers map.
|
|
330
|
+
yield* Effect.gen(function* () {
|
|
331
|
+
const result = yield* checkpoint.waitForWriter(input.sessionID)
|
|
332
|
+
if (result === "success") {
|
|
333
|
+
writerFailures.delete(input.sessionID)
|
|
334
|
+
return
|
|
335
|
+
}
|
|
336
|
+
if (result !== "failure") return
|
|
337
|
+
const next = (writerFailures.get(input.sessionID) ?? 0) + 1
|
|
338
|
+
writerFailures.set(input.sessionID, next)
|
|
339
|
+
if (next < maxFailures) {
|
|
340
|
+
crossed.delete(input.sessionID)
|
|
341
|
+
maxCrossed.delete(input.sessionID)
|
|
342
|
+
log.info("checkpoint writer failed — cleared thresholds for retry", {
|
|
343
|
+
sessionID: input.sessionID,
|
|
344
|
+
attempt: next,
|
|
345
|
+
maxAttempts: maxFailures,
|
|
346
|
+
})
|
|
347
|
+
} else {
|
|
348
|
+
log.warn("checkpoint writer gave up after max consecutive failures", {
|
|
349
|
+
sessionID: input.sessionID,
|
|
350
|
+
maxAttempts: maxFailures,
|
|
351
|
+
})
|
|
352
|
+
}
|
|
353
|
+
}).pipe(Effect.forkDetach)
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
already.add(t)
|
|
357
|
+
log.info("checkpoint triggered", { threshold: t, currentTokens })
|
|
358
|
+
|
|
359
|
+
if (t === maxThreshold) maxCrossed.add(input.sessionID)
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
crossed.set(input.sessionID, already)
|
|
363
|
+
})
|
|
364
|
+
|
|
365
|
+
// Each turn end, decide (based on cache-TTL + pressure) whether to soft-trim
|
|
366
|
+
// old tool outputs, hard-clear them with a compacted timestamp, and/or
|
|
367
|
+
// strip non-essential content. Checkpoint firing is NOT done here — the
|
|
368
|
+
// runLoop calls fireCheckpoints() directly each iteration so thresholds
|
|
369
|
+
// fire mid-turn as tokens grow.
|
|
370
|
+
const prune = Effect.fn("SessionPrune.prune")(function* (input: {
|
|
371
|
+
sessionID: SessionID
|
|
372
|
+
model: Provider.Model
|
|
373
|
+
tokens: MessageV2.Assistant["tokens"]
|
|
374
|
+
lastAssistantTime?: number
|
|
375
|
+
promptOps?: ActorPromptOps
|
|
376
|
+
}) {
|
|
377
|
+
const cfg = yield* config.get()
|
|
378
|
+
if (!cfg.compaction?.prune) return
|
|
379
|
+
|
|
380
|
+
if (!isCacheCold(input.model, input.lastAssistantTime)) return
|
|
381
|
+
|
|
382
|
+
const pressure = pressureLevel({ cfg, tokens: input.tokens, model: input.model })
|
|
383
|
+
if (pressure === 0) return
|
|
384
|
+
const level = pressure >= 2 ? 2 : 1
|
|
385
|
+
log.info("pruning", { level })
|
|
386
|
+
|
|
387
|
+
const msgs = yield* session
|
|
388
|
+
.messages({ sessionID: input.sessionID, agentID: "main" })
|
|
389
|
+
.pipe(Effect.catchIf(NotFoundError.isInstance, () => Effect.succeed(undefined)))
|
|
390
|
+
if (!msgs) return
|
|
391
|
+
|
|
392
|
+
let total = 0
|
|
393
|
+
let pruned = 0
|
|
394
|
+
const toPrune: MessageV2.ToolPart[] = []
|
|
395
|
+
let turns = 0
|
|
396
|
+
|
|
397
|
+
loop: for (let msgIndex = msgs.length - 1; msgIndex >= 0; msgIndex--) {
|
|
398
|
+
const msg = msgs[msgIndex]
|
|
399
|
+
if (msg.info.role === "user") turns++
|
|
400
|
+
if (turns < 2) continue
|
|
401
|
+
if (msg.info.role === "assistant" && msg.info.summary) break loop
|
|
402
|
+
for (let partIndex = msg.parts.length - 1; partIndex >= 0; partIndex--) {
|
|
403
|
+
const part = msg.parts[partIndex]
|
|
404
|
+
if (part.type === "tool")
|
|
405
|
+
if (part.state.status === "completed") {
|
|
406
|
+
if (PRUNE_PROTECTED_TOOLS.includes(part.tool)) continue
|
|
407
|
+
if (part.state.time.compacted) break loop
|
|
408
|
+
const estimate = Token.estimate(part.state.output)
|
|
409
|
+
total += estimate
|
|
410
|
+
if (total > PRUNE_PROTECT) {
|
|
411
|
+
pruned += estimate
|
|
412
|
+
toPrune.push(part)
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
log.info("found", { pruned, total, level })
|
|
419
|
+
|
|
420
|
+
if (level === 1) {
|
|
421
|
+
for (const part of toPrune) {
|
|
422
|
+
if (part.state.status === "completed") {
|
|
423
|
+
const output = part.state.output
|
|
424
|
+
if (output.length > SOFT_TRIM_THRESHOLD) {
|
|
425
|
+
part.state.output =
|
|
426
|
+
output.slice(0, SOFT_TRIM_KEEP_HEAD) +
|
|
427
|
+
"\n\n[... trimmed — kept first and last 1.5K of " +
|
|
428
|
+
output.length +
|
|
429
|
+
" chars ...]\n\n" +
|
|
430
|
+
output.slice(-SOFT_TRIM_KEEP_TAIL)
|
|
431
|
+
yield* session.updatePart(part)
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
log.info("soft-trimmed", { count: toPrune.length })
|
|
436
|
+
} else {
|
|
437
|
+
if (pruned > PRUNE_MINIMUM) {
|
|
438
|
+
for (const part of toPrune) {
|
|
439
|
+
if (part.state.status === "completed") {
|
|
440
|
+
part.state.time.compacted = Date.now()
|
|
441
|
+
yield* session.updatePart(part)
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
log.info("pruned", { count: toPrune.length })
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
if (level >= 2) {
|
|
449
|
+
yield* stripNonEssential({
|
|
450
|
+
sessionID: input.sessionID,
|
|
451
|
+
model: input.model,
|
|
452
|
+
lastAssistantTime: input.lastAssistantTime,
|
|
453
|
+
})
|
|
454
|
+
}
|
|
455
|
+
})
|
|
456
|
+
|
|
457
|
+
const maxThresholdCrossed = Effect.fn("SessionPrune.maxThresholdCrossed")(function* (
|
|
458
|
+
sessionID: SessionID,
|
|
459
|
+
) {
|
|
460
|
+
return maxCrossed.has(sessionID)
|
|
461
|
+
})
|
|
462
|
+
|
|
463
|
+
const resetThresholds = Effect.fn("SessionPrune.resetThresholds")(function* (sessionID: SessionID) {
|
|
464
|
+
crossed.delete(sessionID)
|
|
465
|
+
maxCrossed.delete(sessionID)
|
|
466
|
+
})
|
|
467
|
+
|
|
468
|
+
return Service.of({ prune, fireCheckpoints, maxThresholdCrossed, resetThresholds })
|
|
469
|
+
}),
|
|
470
|
+
)
|
|
471
|
+
|
|
472
|
+
export const defaultLayer = Layer.suspend(() =>
|
|
473
|
+
layer.pipe(
|
|
474
|
+
Layer.provide(Session.defaultLayer),
|
|
475
|
+
Layer.provide(Config.defaultLayer),
|
|
476
|
+
Layer.provide(SessionCheckpoint.defaultLayer),
|
|
477
|
+
Layer.provide(ActorRegistry.defaultLayer),
|
|
478
|
+
),
|
|
479
|
+
)
|
|
480
|
+
|
|
481
|
+
export * as SessionPrune from "./prune"
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import type { NamedError } from "@tuling-ai/shared/util/error"
|
|
2
|
+
import { Cause, Clock, Duration, Effect, Schedule } from "effect"
|
|
3
|
+
import { MessageV2 } from "./message-v2"
|
|
4
|
+
import { iife } from "@/util/iife"
|
|
5
|
+
|
|
6
|
+
export type Err = ReturnType<NamedError["toObject"]>
|
|
7
|
+
|
|
8
|
+
// This exported message is shared with the TUI upsell detector. Matching on a
|
|
9
|
+
// literal error string kind of sucks, but it is the simplest for now.
|
|
10
|
+
export const GO_UPSELL_MESSAGE = "Free usage exceeded, subscribe to Go https://opencode.ai/go"
|
|
11
|
+
|
|
12
|
+
export const RETRY_INITIAL_DELAY = 2000
|
|
13
|
+
export const RETRY_BACKOFF_FACTOR = 2
|
|
14
|
+
export const RETRY_MAX_DELAY_NO_HEADERS = 30_000 // 30 seconds
|
|
15
|
+
export const RETRY_MAX_DELAY = 2_147_483_647 // max 32-bit signed integer for setTimeout
|
|
16
|
+
|
|
17
|
+
const NETWORK_ERROR_CODES = new Set(["ECONNRESET", "EPIPE", "ETIMEDOUT"])
|
|
18
|
+
const SSE_TIMEOUT_MESSAGE = "SSE read timed out"
|
|
19
|
+
const RETRYABLE_HTTP_STATUS = new Set([429, 500, 502, 503, 504, 529])
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Single source of truth for "is this transient and retryable?".
|
|
23
|
+
*
|
|
24
|
+
* Used by:
|
|
25
|
+
* - `retryable()` below (processor-level Effect.retry policy via SessionRetry.policy)
|
|
26
|
+
* - `isTransientCapacityError()` in llm.ts (LLM-internal retry around streamText)
|
|
27
|
+
*
|
|
28
|
+
* Both call sites previously had divergent logic — this hung sessions on
|
|
29
|
+
* SSE timeouts that one path retried but the other dropped. See Spec ③.
|
|
30
|
+
*/
|
|
31
|
+
export function isRetryableTransientError(error: unknown): boolean {
|
|
32
|
+
if (!(error instanceof Error)) return false
|
|
33
|
+
|
|
34
|
+
const status =
|
|
35
|
+
(error as { status?: number }).status ??
|
|
36
|
+
(error as { statusCode?: number }).statusCode ??
|
|
37
|
+
(error as { response?: { status?: number } }).response?.status
|
|
38
|
+
if (typeof status === "number" && RETRYABLE_HTTP_STATUS.has(status)) return true
|
|
39
|
+
|
|
40
|
+
const code = (error as { code?: string }).code
|
|
41
|
+
if (typeof code === "string" && NETWORK_ERROR_CODES.has(code)) return true
|
|
42
|
+
|
|
43
|
+
if (error.message === SSE_TIMEOUT_MESSAGE) return true
|
|
44
|
+
|
|
45
|
+
return false
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function cap(ms: number) {
|
|
49
|
+
return Math.min(ms, RETRY_MAX_DELAY)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function delay(attempt: number, error?: MessageV2.APIError) {
|
|
53
|
+
if (error) {
|
|
54
|
+
const headers = error.data.responseHeaders
|
|
55
|
+
if (headers) {
|
|
56
|
+
const retryAfterMs = headers["retry-after-ms"]
|
|
57
|
+
if (retryAfterMs) {
|
|
58
|
+
const parsedMs = Number.parseFloat(retryAfterMs)
|
|
59
|
+
if (!Number.isNaN(parsedMs)) {
|
|
60
|
+
return cap(parsedMs)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const retryAfter = headers["retry-after"]
|
|
65
|
+
if (retryAfter) {
|
|
66
|
+
const parsedSeconds = Number.parseFloat(retryAfter)
|
|
67
|
+
if (!Number.isNaN(parsedSeconds)) {
|
|
68
|
+
// convert seconds to milliseconds
|
|
69
|
+
return cap(Math.ceil(parsedSeconds * 1000))
|
|
70
|
+
}
|
|
71
|
+
// Try parsing as HTTP date format
|
|
72
|
+
const parsed = Date.parse(retryAfter) - Date.now()
|
|
73
|
+
if (!Number.isNaN(parsed) && parsed > 0) {
|
|
74
|
+
return cap(Math.ceil(parsed))
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return cap(RETRY_INITIAL_DELAY * Math.pow(RETRY_BACKOFF_FACTOR, attempt - 1))
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return cap(Math.min(RETRY_INITIAL_DELAY * Math.pow(RETRY_BACKOFF_FACTOR, attempt - 1), RETRY_MAX_DELAY_NO_HEADERS))
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function retryable(error: Err) {
|
|
86
|
+
// context overflow errors should not be retried
|
|
87
|
+
if (MessageV2.ContextOverflowError.isInstance(error)) return undefined
|
|
88
|
+
|
|
89
|
+
// Catch raw Error / network / SSE-timeout BEFORE APIError narrowing.
|
|
90
|
+
// SessionRetry.policy unwraps Cause<unknown> via opts.parse, but raw
|
|
91
|
+
// Error instances slip past the APIError check below. Adding this
|
|
92
|
+
// branch closes that gap. See Spec ③ P2.
|
|
93
|
+
if (isRetryableTransientError(error as unknown)) {
|
|
94
|
+
const msg = (error as unknown as Error).message
|
|
95
|
+
return msg || "Transient network error"
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (MessageV2.APIError.isInstance(error)) {
|
|
99
|
+
const status = error.data.statusCode
|
|
100
|
+
// 5xx errors are transient server failures and should always be retried,
|
|
101
|
+
// even when the provider SDK doesn't explicitly mark them as retryable.
|
|
102
|
+
if (!error.data.isRetryable && !(status !== undefined && status >= 500)) return undefined
|
|
103
|
+
if (error.data.responseBody?.includes("FreeUsageLimitError")) return GO_UPSELL_MESSAGE
|
|
104
|
+
return error.data.message.includes("Overloaded") ? "Provider is overloaded" : error.data.message
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Check for rate limit patterns in plain text error messages
|
|
108
|
+
const msg = error.data?.message
|
|
109
|
+
if (typeof msg === "string") {
|
|
110
|
+
const lower = msg.toLowerCase()
|
|
111
|
+
if (
|
|
112
|
+
lower.includes("rate increased too quickly") ||
|
|
113
|
+
lower.includes("rate limit") ||
|
|
114
|
+
lower.includes("too many requests")
|
|
115
|
+
) {
|
|
116
|
+
return msg
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const json = iife(() => {
|
|
121
|
+
try {
|
|
122
|
+
if (typeof error.data?.message === "string") {
|
|
123
|
+
const parsed = JSON.parse(error.data.message)
|
|
124
|
+
return parsed
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return JSON.parse(error.data.message)
|
|
128
|
+
} catch {
|
|
129
|
+
return undefined
|
|
130
|
+
}
|
|
131
|
+
})
|
|
132
|
+
if (!json || typeof json !== "object") return undefined
|
|
133
|
+
const code = typeof json.code === "string" ? json.code : ""
|
|
134
|
+
|
|
135
|
+
if (json.type === "error" && json.error?.type === "too_many_requests") {
|
|
136
|
+
return "Too Many Requests"
|
|
137
|
+
}
|
|
138
|
+
if (code.includes("exhausted") || code.includes("unavailable")) {
|
|
139
|
+
return "Provider is overloaded"
|
|
140
|
+
}
|
|
141
|
+
if (json.type === "error" && typeof json.error?.code === "string" && json.error.code.includes("rate_limit")) {
|
|
142
|
+
return "Rate Limited"
|
|
143
|
+
}
|
|
144
|
+
return undefined
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function policy(opts: {
|
|
148
|
+
parse: (error: unknown) => Err
|
|
149
|
+
set: (input: { attempt: number; message: string; next: number }) => Effect.Effect<void>
|
|
150
|
+
}) {
|
|
151
|
+
return Schedule.fromStepWithMetadata(
|
|
152
|
+
Effect.succeed((meta: Schedule.InputMetadata<unknown>) => {
|
|
153
|
+
const error = opts.parse(meta.input)
|
|
154
|
+
const message = retryable(error)
|
|
155
|
+
if (!message) return Cause.done(meta.attempt)
|
|
156
|
+
return Effect.gen(function* () {
|
|
157
|
+
const wait = delay(meta.attempt, MessageV2.APIError.isInstance(error) ? error : undefined)
|
|
158
|
+
const now = yield* Clock.currentTimeMillis
|
|
159
|
+
yield* opts.set({ attempt: meta.attempt, message, next: now + wait })
|
|
160
|
+
return [meta.attempt, Duration.millis(wait)] as [number, Duration.Duration]
|
|
161
|
+
})
|
|
162
|
+
}),
|
|
163
|
+
)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export * as SessionRetry from "./retry"
|