micro-models-agent 2.16.0 → 2.17.1
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/CHANGELOG.md +34 -0
- package/dist/assets/app.js +1 -314
- package/dist/assets/hljs.js +5 -1244
- package/dist/assets/index.html +11 -0
- package/dist/assets/js/api.js +1 -28
- package/dist/assets/js/core/menus.js +1 -0
- package/dist/assets/js/core/store/feed.js +1 -0
- package/dist/assets/js/core/store/index.js +1 -0
- package/dist/assets/js/core/store/session.js +1 -0
- package/dist/assets/js/core/store/settings.js +1 -0
- package/dist/assets/js/core/store/tabs.js +1 -0
- package/dist/assets/js/dialog.js +1 -105
- package/dist/assets/js/dom.js +1 -178
- package/dist/assets/js/feed/core.js +1 -0
- package/dist/assets/js/feed/history.js +1 -0
- package/dist/assets/js/feed/plan.js +1 -0
- package/dist/assets/js/feed/question.js +3 -0
- package/dist/assets/js/feed/sidebar.js +1 -0
- package/dist/assets/js/feed/stream.js +1 -0
- package/dist/assets/js/feed/turn.js +5 -0
- package/dist/assets/js/feed.js +1 -1211
- package/dist/assets/js/format.js +2 -122
- package/dist/assets/js/i18n.js +1 -46
- package/dist/assets/js/rail.js +1 -114
- package/dist/assets/js/session/cmdk.js +1 -0
- package/dist/assets/js/session/composer.js +1 -0
- package/dist/assets/js/session/sessions-menu.js +1 -0
- package/dist/assets/js/session/tabs.js +1 -0
- package/dist/assets/js/settings/controls.js +1 -0
- package/dist/assets/js/settings/editors.js +1 -0
- package/dist/assets/js/settings/form.js +1 -0
- package/dist/assets/js/settings/modal.js +1 -0
- package/dist/assets/js/settings/panels.js +1 -0
- package/dist/assets/js/settings/providers.js +1 -0
- package/dist/assets/js/settings/search.js +1 -0
- package/dist/assets/js/settings/subdialog.js +1 -0
- package/dist/assets/js/settings/write.js +1 -0
- package/dist/assets/js/settings.js +1 -1914
- package/dist/assets/js/sidebar/core.js +1 -0
- package/dist/assets/js/sidebar/lsp.js +2 -0
- package/dist/assets/js/sidebar/map.js +1 -0
- package/dist/assets/js/sidebar/state.js +1 -0
- package/dist/assets/js/sidebar/trace.js +5 -0
- package/dist/assets/js/sidebar.js +1 -705
- package/dist/assets/js/store.js +1 -82
- package/dist/assets/js/subdialog.js +1 -0
- package/dist/assets/md.js +1 -277
- package/dist/assets/setup.js +3 -816
- package/dist/assets/smd.js +29 -1665
- package/dist/assets/styles.css +1 -1592
- package/dist/certification/certifications.json +1 -494
- package/dist/i18n/en.json +1 -1851
- package/dist/i18n/ru.json +1 -1854
- package/dist/main.js +815 -55797
- package/dist/modules/browser/bridge-server.mjs +2 -252
- package/package.json +10 -5
- package/dist/assets/js/settings-controls.js +0 -452
- package/dist/assets/js/tabs.js +0 -867
- package/dist/cli/cache-line.js +0 -31
- package/dist/cli/command-suggest.js +0 -39
- package/dist/cli/commands.js +0 -781
- package/dist/cli/completer.js +0 -268
- package/dist/cli/index.js +0 -3
- package/dist/cli/json-payload.js +0 -32
- package/dist/cli/main.js +0 -346
- package/dist/cli/onboarding-commands.js +0 -126
- package/dist/cli/plugin-commands.js +0 -38
- package/dist/cli/relaunch.js +0 -40
- package/dist/cli/repl-commands-lsp.js +0 -75
- package/dist/cli/repl-commands-skills.js +0 -105
- package/dist/cli/repl-commands.js +0 -1218
- package/dist/cli/repl.js +0 -1238
- package/dist/cli/run-result.js +0 -38
- package/dist/cli/security-commands.js +0 -177
- package/dist/cli/setup-order.js +0 -6
- package/dist/cli/setup-prompt.js +0 -50
- package/dist/cli/setup.js +0 -161
- package/dist/cli/web-command.js +0 -98
- package/dist/config/budget.js +0 -48
- package/dist/config/config.js +0 -345
- package/dist/config/defaults.js +0 -197
- package/dist/config/domains.js +0 -135
- package/dist/config/env.js +0 -46
- package/dist/config/experts.js +0 -17
- package/dist/config/index.js +0 -5
- package/dist/config/paths.js +0 -56
- package/dist/config/redact.js +0 -44
- package/dist/config/registry-extra.js +0 -334
- package/dist/config/registry.js +0 -584
- package/dist/config/security.js +0 -212
- package/dist/config/timeouts.js +0 -74
- package/dist/config/types.js +0 -1
- package/dist/config/utils.js +0 -57
- package/dist/core/agent/artifact-progress.js +0 -59
- package/dist/core/agent/artifact-resolve.js +0 -79
- package/dist/core/agent/audit-gate.js +0 -53
- package/dist/core/agent/compaction.js +0 -89
- package/dist/core/agent/constants.js +0 -90
- package/dist/core/agent/context-log.js +0 -454
- package/dist/core/agent/context-renderer.js +0 -45
- package/dist/core/agent/critic-gate.js +0 -132
- package/dist/core/agent/hallucination-gate.js +0 -197
- package/dist/core/agent/loop-state.js +0 -68
- package/dist/core/agent/prefix-monitor.js +0 -101
- package/dist/core/agent/reasoning-resolver.js +0 -65
- package/dist/core/agent/token-tracker.js +0 -99
- package/dist/core/agent/tool-batch.js +0 -312
- package/dist/core/agent/tool-images.js +0 -18
- package/dist/core/agent/tool-output.js +0 -116
- package/dist/core/agent/tool-pairing.js +0 -60
- package/dist/core/agent-moe.js +0 -248
- package/dist/core/agent.js +0 -1299
- package/dist/core/bootstrap/agent-phase.js +0 -66
- package/dist/core/bootstrap/config-phase.js +0 -86
- package/dist/core/bootstrap/modules-phase.js +0 -269
- package/dist/core/bootstrap/provider-phase.js +0 -183
- package/dist/core/bootstrap/session-phase.js +0 -204
- package/dist/core/bootstrap/state.js +0 -94
- package/dist/core/bootstrap/workspace-phase.js +0 -115
- package/dist/core/bootstrap.js +0 -112
- package/dist/core/crash-handler.js +0 -62
- package/dist/core/environment.js +0 -224
- package/dist/core/host-plan.js +0 -43
- package/dist/core/host.js +0 -23
- package/dist/core/index.js +0 -3
- package/dist/core/prompt-builder.js +0 -95
- package/dist/core/prompt-overflow.js +0 -306
- package/dist/core/session-logger.js +0 -375
- package/dist/core/system-prompt.js +0 -117
- package/dist/core/types.js +0 -1
- package/dist/core/version.js +0 -28
- package/dist/core/web-host.js +0 -34
- package/dist/core/workspace.js +0 -80
- package/dist/i18n/index.js +0 -80
- package/dist/index.js +0 -30
- package/dist/llm/cache-usage.js +0 -76
- package/dist/llm/image-utils.js +0 -138
- package/dist/llm/index.js +0 -4
- package/dist/llm/llm-errors.js +0 -50
- package/dist/llm/model-loader.js +0 -86
- package/dist/llm/models-dev.js +0 -121
- package/dist/llm/openai-compat.js +0 -756
- package/dist/llm/orchestrator.js +0 -294
- package/dist/llm/provider-budget.js +0 -68
- package/dist/llm/provider-context.js +0 -233
- package/dist/llm/provider.js +0 -9
- package/dist/llm/response.js +0 -44
- package/dist/llm/stream-state.js +0 -26
- package/dist/llm/token-counter.js +0 -83
- package/dist/llm/types.js +0 -1
- package/dist/logger/app-logger.js +0 -212
- package/dist/logger/file-log.js +0 -160
- package/dist/logger/index.js +0 -2
- package/dist/migration/backup.js +0 -56
- package/dist/migration/detect.js +0 -61
- package/dist/migration/index.js +0 -3
- package/dist/modules/artifacts/store.js +0 -62
- package/dist/modules/browser/actions.js +0 -79
- package/dist/modules/browser/bridge-client.js +0 -203
- package/dist/modules/browser/bridge-path.js +0 -10
- package/dist/modules/browser/console-buffer.js +0 -37
- package/dist/modules/browser/cookie-store.js +0 -29
- package/dist/modules/browser/driver-types.js +0 -1
- package/dist/modules/browser/driver.js +0 -186
- package/dist/modules/browser/index.js +0 -9
- package/dist/modules/browser/module.js +0 -30
- package/dist/modules/browser/session.js +0 -322
- package/dist/modules/browser/snapshot.js +0 -154
- package/dist/modules/browser/types.js +0 -13
- package/dist/modules/certification/cli.js +0 -264
- package/dist/modules/certification/fact-checker.js +0 -90
- package/dist/modules/certification/loader.js +0 -127
- package/dist/modules/certification/manifest.js +0 -231
- package/dist/modules/certification/runner.js +0 -233
- package/dist/modules/certification/scenarios.js +0 -586
- package/dist/modules/certification/syntax-scenarios.js +0 -50
- package/dist/modules/certification/types.js +0 -1
- package/dist/modules/context/chunk-query.js +0 -122
- package/dist/modules/context/fact-extractor.js +0 -170
- package/dist/modules/context/history.js +0 -15
- package/dist/modules/context/index.js +0 -2
- package/dist/modules/context/manager.js +0 -482
- package/dist/modules/critic/client.js +0 -176
- package/dist/modules/critic/evidence.js +0 -81
- package/dist/modules/critic/provider.js +0 -45
- package/dist/modules/critic/tools.js +0 -78
- package/dist/modules/critic/types.js +0 -1
- package/dist/modules/execution/audit-runners.js +0 -206
- package/dist/modules/execution/auditor.js +0 -222
- package/dist/modules/execution/execution-plugin.js +0 -478
- package/dist/modules/execution/index.js +0 -8
- package/dist/modules/execution/input-from.js +0 -70
- package/dist/modules/execution/module.js +0 -891
- package/dist/modules/execution/moe-executor.js +0 -443
- package/dist/modules/execution/plan-actions.js +0 -642
- package/dist/modules/execution/plan-checks.js +0 -35
- package/dist/modules/execution/plan-coverage.js +0 -71
- package/dist/modules/execution/plan-persister.js +0 -46
- package/dist/modules/execution/plan-steps.js +0 -31
- package/dist/modules/execution/plan-store.js +0 -274
- package/dist/modules/execution/plan-tool.js +0 -249
- package/dist/modules/execution/plan-validator.js +0 -197
- package/dist/modules/execution/planner.js +0 -103
- package/dist/modules/execution/stuck-detector.js +0 -834
- package/dist/modules/execution/tracker.js +0 -92
- package/dist/modules/execution/transient-error.js +0 -30
- package/dist/modules/execution/types.js +0 -1
- package/dist/modules/execution/verifier.js +0 -343
- package/dist/modules/execution/windows-commands.js +0 -52
- package/dist/modules/hallucination/artifact-claim.js +0 -93
- package/dist/modules/hallucination/confidence.js +0 -81
- package/dist/modules/hallucination/consistency.js +0 -37
- package/dist/modules/hallucination/detector.js +0 -57
- package/dist/modules/hallucination/factual.js +0 -205
- package/dist/modules/hallucination/index.js +0 -6
- package/dist/modules/hallucination/js-identifiers.js +0 -261
- package/dist/modules/hallucination/llm-judge.js +0 -116
- package/dist/modules/hallucination/success-claim.js +0 -59
- package/dist/modules/index.js +0 -5
- package/dist/modules/indexer/cache.js +0 -88
- package/dist/modules/indexer/index.js +0 -4
- package/dist/modules/indexer/map-command.js +0 -33
- package/dist/modules/indexer/map-select.js +0 -87
- package/dist/modules/indexer/module.js +0 -293
- package/dist/modules/indexer/project-profile.js +0 -184
- package/dist/modules/indexer/symbols.js +0 -189
- package/dist/modules/indexer/walker.js +0 -285
- package/dist/modules/lsp/check-tool.js +0 -61
- package/dist/modules/lsp/client.js +0 -406
- package/dist/modules/lsp/command.js +0 -53
- package/dist/modules/lsp/config.js +0 -189
- package/dist/modules/lsp/index.js +0 -4
- package/dist/modules/lsp/module.js +0 -295
- package/dist/modules/lsp/probe.js +0 -86
- package/dist/modules/lsp/project-root.js +0 -69
- package/dist/modules/lsp/startup-check.js +0 -154
- package/dist/modules/lsp/types.js +0 -1
- package/dist/modules/mcp/client.js +0 -445
- package/dist/modules/mcp/index.js +0 -4
- package/dist/modules/mcp/module.js +0 -295
- package/dist/modules/mcp/registry.js +0 -20
- package/dist/modules/memory/index.js +0 -2
- package/dist/modules/memory/module.js +0 -101
- package/dist/modules/memory/search.js +0 -45
- package/dist/modules/memory/store.js +0 -107
- package/dist/modules/onboarding/init.js +0 -47
- package/dist/modules/onboarding/meet.js +0 -30
- package/dist/modules/onboarding/mode.js +0 -30
- package/dist/modules/onboarding/prompts.js +0 -43
- package/dist/modules/pipelines/engine.js +0 -70
- package/dist/modules/pipelines/index.js +0 -4
- package/dist/modules/pipelines/parser.js +0 -59
- package/dist/modules/pipelines/template.js +0 -18
- package/dist/modules/plugins/builtin/lint-on-write.js +0 -377
- package/dist/modules/plugins/builtin/notify.js +0 -11
- package/dist/modules/plugins/index.js +0 -2
- package/dist/modules/plugins/loader.js +0 -85
- package/dist/modules/plugins/manager.js +0 -244
- package/dist/modules/plugins/types.js +0 -1
- package/dist/modules/pricing/index.js +0 -70
- package/dist/modules/pricing/prices.js +0 -147
- package/dist/modules/processes/detect.js +0 -34
- package/dist/modules/processes/index.js +0 -4
- package/dist/modules/processes/kill-tree.js +0 -52
- package/dist/modules/processes/registry.js +0 -294
- package/dist/modules/processes/runner.js +0 -23
- package/dist/modules/providers/cache.js +0 -23
- package/dist/modules/providers/capabilities.js +0 -28
- package/dist/modules/providers/create.js +0 -21
- package/dist/modules/providers/factory.js +0 -28
- package/dist/modules/providers/fallback.js +0 -81
- package/dist/modules/providers/health.js +0 -47
- package/dist/modules/providers/index.js +0 -6
- package/dist/modules/providers/manager.js +0 -207
- package/dist/modules/providers/naming.js +0 -15
- package/dist/modules/providers/preflight.js +0 -71
- package/dist/modules/providers/presets.js +0 -232
- package/dist/modules/providers/registry.js +0 -27
- package/dist/modules/providers/types.js +0 -1
- package/dist/modules/reasoning/policy.js +0 -42
- package/dist/modules/reasoning/probe.js +0 -116
- package/dist/modules/registry.js +0 -48
- package/dist/modules/security/audit-log.js +0 -119
- package/dist/modules/security/audit-notifier.js +0 -267
- package/dist/modules/security/command-validator.js +0 -272
- package/dist/modules/security/content-scanner.js +0 -53
- package/dist/modules/security/data-sanitizer.js +0 -82
- package/dist/modules/security/encryption.js +0 -216
- package/dist/modules/security/index.js +0 -15
- package/dist/modules/security/network-validator.js +0 -236
- package/dist/modules/security/path-validator.js +0 -261
- package/dist/modules/security/protected-paths.js +0 -73
- package/dist/modules/security/rate-limiter.js +0 -98
- package/dist/modules/security/security-policies.js +0 -499
- package/dist/modules/security/session-encryption.js +0 -182
- package/dist/modules/security/session-isolation.js +0 -75
- package/dist/modules/session/auto-name.js +0 -63
- package/dist/modules/session/export.js +0 -98
- package/dist/modules/session/index.js +0 -4
- package/dist/modules/session/manager.js +0 -234
- package/dist/modules/session/module.js +0 -33
- package/dist/modules/session/store.js +0 -295
- package/dist/modules/session/types.js +0 -1
- package/dist/modules/setup/answers.js +0 -35
- package/dist/modules/setup/apply.js +0 -79
- package/dist/modules/setup/discovery.js +0 -72
- package/dist/modules/skills/index.js +0 -3
- package/dist/modules/skills/loader.js +0 -86
- package/dist/modules/skills/matcher.js +0 -27
- package/dist/modules/skills/module.js +0 -141
- package/dist/modules/types.js +0 -1
- package/dist/modules/updater/changelog-reader.js +0 -93
- package/dist/modules/updater/checker.js +0 -101
- package/dist/modules/updater/dev-detect.js +0 -18
- package/dist/modules/updater/index.js +0 -4
- package/dist/modules/updater/module.js +0 -129
- package/dist/modules/user-profile/compressor.js +0 -18
- package/dist/modules/user-profile/index.js +0 -2
- package/dist/modules/user-profile/profile.js +0 -77
- package/dist/modules/webui/answer-api.js +0 -29
- package/dist/modules/webui/assets.js +0 -50
- package/dist/modules/webui/body.js +0 -21
- package/dist/modules/webui/commands-settings.js +0 -209
- package/dist/modules/webui/commands-shared.js +0 -60
- package/dist/modules/webui/commands.js +0 -174
- package/dist/modules/webui/config-api.js +0 -134
- package/dist/modules/webui/file-api.js +0 -202
- package/dist/modules/webui/forward.js +0 -159
- package/dist/modules/webui/history-api.js +0 -112
- package/dist/modules/webui/host-state.js +0 -60
- package/dist/modules/webui/i18n-api.js +0 -9
- package/dist/modules/webui/limits.js +0 -6
- package/dist/modules/webui/log-forward.js +0 -20
- package/dist/modules/webui/memory-commands.js +0 -64
- package/dist/modules/webui/model-cache.js +0 -18
- package/dist/modules/webui/module.js +0 -148
- package/dist/modules/webui/persist.js +0 -24
- package/dist/modules/webui/prompt-io.js +0 -97
- package/dist/modules/webui/providers-api.js +0 -337
- package/dist/modules/webui/providers-view.js +0 -56
- package/dist/modules/webui/reasoning-view.js +0 -15
- package/dist/modules/webui/run-agent.js +0 -81
- package/dist/modules/webui/server.js +0 -284
- package/dist/modules/webui/sessions-api.js +0 -178
- package/dist/modules/webui/settings-api.js +0 -561
- package/dist/modules/webui/setup-api.js +0 -201
- package/dist/modules/webui/state.js +0 -74
- package/dist/modules/webui/util.js +0 -261
- package/dist/output/bus.js +0 -37
- package/dist/output/channel.js +0 -285
- package/dist/output/format.js +0 -15
- package/dist/output/index.js +0 -8
- package/dist/output/json-sink.js +0 -24
- package/dist/output/machine.js +0 -9
- package/dist/output/session-sink.js +0 -27
- package/dist/output/types.js +0 -1
- package/dist/tools/approve.js +0 -41
- package/dist/tools/attach-image.js +0 -102
- package/dist/tools/auto-fixer.js +0 -180
- package/dist/tools/auto-tags.js +0 -83
- package/dist/tools/bash.js +0 -649
- package/dist/tools/browser.js +0 -160
- package/dist/tools/chunk-query.js +0 -112
- package/dist/tools/create-dir.js +0 -60
- package/dist/tools/delete-file.js +0 -67
- package/dist/tools/download-file.js +0 -142
- package/dist/tools/edit-file.js +0 -136
- package/dist/tools/enable-tools.js +0 -59
- package/dist/tools/executor.js +0 -304
- package/dist/tools/file-info.js +0 -49
- package/dist/tools/filter-tools.js +0 -17
- package/dist/tools/glob-tool.js +0 -37
- package/dist/tools/grep-tool.js +0 -142
- package/dist/tools/hidden-tools-block.js +0 -37
- package/dist/tools/index.js +0 -88
- package/dist/tools/list-dir.js +0 -53
- package/dist/tools/load-skill.js +0 -51
- package/dist/tools/mcp-call.js +0 -80
- package/dist/tools/meet-done.js +0 -14
- package/dist/tools/move-file.js +0 -94
- package/dist/tools/path-utils.js +0 -108
- package/dist/tools/pipeline-run.js +0 -167
- package/dist/tools/preview.js +0 -2
- package/dist/tools/process-ids.js +0 -31
- package/dist/tools/process-kill.js +0 -33
- package/dist/tools/process-list.js +0 -38
- package/dist/tools/process-log.js +0 -49
- package/dist/tools/process-wait.js +0 -63
- package/dist/tools/prompt-io.js +0 -29
- package/dist/tools/question.js +0 -288
- package/dist/tools/read-file.js +0 -200
- package/dist/tools/recall.js +0 -124
- package/dist/tools/registry.js +0 -48
- package/dist/tools/remember.js +0 -72
- package/dist/tools/scope-check.js +0 -32
- package/dist/tools/scope-request.js +0 -96
- package/dist/tools/search-history.js +0 -88
- package/dist/tools/session-info.js +0 -46
- package/dist/tools/set-thinking.js +0 -75
- package/dist/tools/subagent.js +0 -257
- package/dist/tools/syntax-validator.js +0 -379
- package/dist/tools/types.js +0 -1
- package/dist/tools/user-input.js +0 -134
- package/dist/tools/web-browse.js +0 -93
- package/dist/tools/web-fetch.js +0 -108
- package/dist/tools/web-search.js +0 -107
- package/dist/tools/write-file.js +0 -128
- package/dist/ui/action-log.js +0 -13
- package/dist/ui/box.js +0 -78
- package/dist/ui/colors.js +0 -6
- package/dist/ui/diff.js +0 -189
- package/dist/ui/index.js +0 -7
- package/dist/ui/line-editor.js +0 -1083
- package/dist/ui/line-math.js +0 -98
- package/dist/ui/md-formatter.js +0 -322
- package/dist/ui/output.js +0 -19
- package/dist/ui/plan-view.js +0 -109
- package/dist/ui/renderer.js +0 -589
- package/dist/ui/spinner.js +0 -91
- package/dist/ui/table.js +0 -142
- package/dist/ui/theme.js +0 -143
- package/dist/utils/child-run.js +0 -20
- package/dist/utils/error.js +0 -4
- package/dist/utils/index.js +0 -6
- package/dist/utils/retry.js +0 -17
- package/dist/utils/sleep.js +0 -23
- package/dist/utils/truncate.js +0 -9
package/dist/llm/orchestrator.js
DELETED
|
@@ -1,294 +0,0 @@
|
|
|
1
|
-
import { ProviderManager } from "../modules/providers/manager";
|
|
2
|
-
import { FallbackProvider } from "../modules/providers/fallback";
|
|
3
|
-
import { jsonrepair } from "jsonrepair";
|
|
4
|
-
import { parseChunks } from "./response";
|
|
5
|
-
const PLAN_SYSTEM_PROMPT_RULES = `Rules:
|
|
6
|
-
1. Each subtask must have an expert_tag from the available experts.
|
|
7
|
-
2. Use depends_on for ordering when subtask B reads what subtask A writes.
|
|
8
|
-
3. Independent subtasks should NOT depend on each other (they run in parallel).
|
|
9
|
-
4. allowed_files is for files the subtask will CREATE or MODIFY.
|
|
10
|
-
5. read_only_files is for files the subtask needs to READ only.
|
|
11
|
-
6. File paths should be relative to the workspace root.
|
|
12
|
-
7. Do NOT use keyword matching to determine task type. Instead, analyze the actual nature of the task.
|
|
13
|
-
|
|
14
|
-
Respond with a JSON object only (no markdown fences):
|
|
15
|
-
{
|
|
16
|
-
"title": "Plan title",
|
|
17
|
-
"subtasks": [
|
|
18
|
-
{
|
|
19
|
-
"id": "task-1",
|
|
20
|
-
"description": "Clear description",
|
|
21
|
-
"expert_tag": "code",
|
|
22
|
-
"allowed_files": ["src/file.ts"],
|
|
23
|
-
"read_only_files": [],
|
|
24
|
-
"depends_on": [],
|
|
25
|
-
"input_from": [],
|
|
26
|
-
"expected_output": "What this subtask produces",
|
|
27
|
-
"success_criteria": ["criterion 1", "criterion 2"]
|
|
28
|
-
}
|
|
29
|
-
],
|
|
30
|
-
"shared_context": {
|
|
31
|
-
"rules": ["rule 1"],
|
|
32
|
-
"refs": []
|
|
33
|
-
}
|
|
34
|
-
}`;
|
|
35
|
-
const PLAN_SYSTEM_PROMPT = `You are a planning assistant for an agent system with multiple expert sub-agents.
|
|
36
|
-
Break down the user's task into subtasks that can be executed by different expert agents.
|
|
37
|
-
|
|
38
|
-
Available experts and their tool tags:
|
|
39
|
-
- code: file operations, code editing, shell commands
|
|
40
|
-
- research: web search, web fetch, web browse, history search
|
|
41
|
-
- browser: browser automation, screenshots
|
|
42
|
-
- vision: browser + file reading for visual tasks
|
|
43
|
-
|
|
44
|
-
${PLAN_SYSTEM_PROMPT_RULES}`;
|
|
45
|
-
/**
|
|
46
|
-
* Render the planner system prompt from the configured experts instead of the
|
|
47
|
-
* hardcoded code/research/browser/vision list, so user-defined experts
|
|
48
|
-
* (config.experts) are visible to the Router. Experts without a description
|
|
49
|
-
* fall back to their tool_tags. Empty/missing registry → legacy hardcoded
|
|
50
|
-
* prompt (back-compat for direct OrchestratorClient usage in tests).
|
|
51
|
-
*/
|
|
52
|
-
export function buildPlanSystemPrompt(experts) {
|
|
53
|
-
if (!experts || Object.keys(experts).length === 0) {
|
|
54
|
-
return PLAN_SYSTEM_PROMPT;
|
|
55
|
-
}
|
|
56
|
-
const lines = Object.entries(experts).map(([tag, cfg]) => {
|
|
57
|
-
const desc = cfg.description ||
|
|
58
|
-
(cfg.tool_tags?.length ? `tools: ${cfg.tool_tags.join(", ")}` : "general purpose");
|
|
59
|
-
return `- ${tag}: ${desc}`;
|
|
60
|
-
});
|
|
61
|
-
return `You are a planning assistant for an agent system with multiple expert sub-agents.
|
|
62
|
-
Break down the user's task into subtasks that can be executed by different expert agents.
|
|
63
|
-
|
|
64
|
-
Available experts and their tool tags:
|
|
65
|
-
${lines.join("\n")}
|
|
66
|
-
|
|
67
|
-
${PLAN_SYSTEM_PROMPT_RULES}`;
|
|
68
|
-
}
|
|
69
|
-
const VERIFY_SYSTEM_PROMPT = `You are a verification and merge assistant for an agent system with multiple expert sub-agents.
|
|
70
|
-
You receive the original plan, the results from each subtask, and any verification errors.
|
|
71
|
-
Your job is to determine if the overall task was completed successfully or if re-planning is needed.
|
|
72
|
-
|
|
73
|
-
Respond with JSON only:
|
|
74
|
-
- If successful: {"type": "final", "finalAnswer": "summary of results", "explanation": "details"}
|
|
75
|
-
- If re-plan needed: {"type": "replan", "plan": {updated MoEPlan}, "explanation": "why re-plan is needed"}
|
|
76
|
-
|
|
77
|
-
Max 3 re-plan cycles. After 3 cycles, return partial result.`;
|
|
78
|
-
const SCOPE_DECISION_SYSTEM_PROMPT = `You are the router of a multi-expert agent system. A sub-agent could not finish its task because it lacked access to files outside its assigned scope.
|
|
79
|
-
Decide what to do with its scope request:
|
|
80
|
-
- "approve" — grant access ONLY to files it justifies; keep write grants minimal.
|
|
81
|
-
- "reject" — when the request is unjustified, excessive, or another subtask owns those files.
|
|
82
|
-
|
|
83
|
-
Respond with JSON only (no markdown fences):
|
|
84
|
-
{"action": "approve", "write": ["file1"], "read": ["file2"]}
|
|
85
|
-
or
|
|
86
|
-
{"action": "reject", "explanation": "why"}`;
|
|
87
|
-
const DEFAULT_BASE_URL = "http://localhost:1234/v1";
|
|
88
|
-
/** Запасное окно контекста, если ни запись провайдера, ни конфиг его не задают. */
|
|
89
|
-
const DEFAULT_ORCH_CONTEXT_WINDOW = 32768;
|
|
90
|
-
/** Клиент оркестратора: строит план, сливает результаты, роутит scope-запросы. */
|
|
91
|
-
export class OrchestratorClient {
|
|
92
|
-
config;
|
|
93
|
-
provider = null;
|
|
94
|
-
getSessionId;
|
|
95
|
-
constructor(config, defaultProvider, opts) {
|
|
96
|
-
this.config = config;
|
|
97
|
-
this.getSessionId = opts?.getSessionId;
|
|
98
|
-
if (!config.model)
|
|
99
|
-
return;
|
|
100
|
-
if (config.provider) {
|
|
101
|
-
this.provider = this.buildManagedProvider(config);
|
|
102
|
-
}
|
|
103
|
-
else if (defaultProvider) {
|
|
104
|
-
this.provider = defaultProvider;
|
|
105
|
-
}
|
|
106
|
-
else {
|
|
107
|
-
this.provider = this.buildManagedProvider({
|
|
108
|
-
...config,
|
|
109
|
-
provider: { type: "openai-compat", baseUrl: DEFAULT_BASE_URL },
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Строит провайдер оркестратора через ProviderManager: учитываются
|
|
115
|
-
* per-entry contextWindow/retry/rateLimits и failover-записи (легаси
|
|
116
|
-
* {type,baseUrl,apiKey} менеджер нормализует). Раньше провайдер строился
|
|
117
|
-
* напрямую с хардкодом окна 32768 — без ретраев/лимитов/failover вовсе.
|
|
118
|
-
*/
|
|
119
|
-
buildManagedProvider(config) {
|
|
120
|
-
const providerCfg = config.provider;
|
|
121
|
-
const manager = new ProviderManager({ ...providerCfg, baseUrl: providerCfg.baseUrl || DEFAULT_BASE_URL }, {
|
|
122
|
-
contextWindow: config.contextWindow ?? DEFAULT_ORCH_CONTEXT_WINDOW,
|
|
123
|
-
retry: config.retry,
|
|
124
|
-
rateLimits: config.rateLimits,
|
|
125
|
-
getSessionId: this.getSessionId,
|
|
126
|
-
logger: config.logger,
|
|
127
|
-
});
|
|
128
|
-
manager.setModel(config.model);
|
|
129
|
-
let provider = manager.active;
|
|
130
|
-
if (providerCfg.fallback && manager.listNames().length > 1) {
|
|
131
|
-
provider = new FallbackProvider(manager, (from, to, error) => {
|
|
132
|
-
config.logger?.warn(`orchestrator provider failover: ${from} -> ${to} (${error.message.slice(0, 120)})`);
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
return provider;
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* Включён ли оркестратор (задана ли модель).
|
|
139
|
-
* @returns true, если провайдер построен.
|
|
140
|
-
*/
|
|
141
|
-
isEnabled() {
|
|
142
|
-
return this.provider !== null;
|
|
143
|
-
}
|
|
144
|
-
async chat(messages, signal) {
|
|
145
|
-
if (!this.provider)
|
|
146
|
-
throw new Error("Orchestrator not enabled");
|
|
147
|
-
const chunks = [];
|
|
148
|
-
for await (const chunk of this.provider.chat(messages, undefined, signal)) {
|
|
149
|
-
chunks.push(chunk);
|
|
150
|
-
}
|
|
151
|
-
const parsed = parseChunks(chunks);
|
|
152
|
-
return parsed.type === "text" ? parsed.content : "";
|
|
153
|
-
}
|
|
154
|
-
parseJSON(text) {
|
|
155
|
-
try {
|
|
156
|
-
return JSON.parse(text);
|
|
157
|
-
}
|
|
158
|
-
catch {
|
|
159
|
-
try {
|
|
160
|
-
const repaired = jsonrepair(text);
|
|
161
|
-
return JSON.parse(repaired);
|
|
162
|
-
}
|
|
163
|
-
catch {
|
|
164
|
-
const jsonMatch = text.match(/\{[\s\S]*\}/);
|
|
165
|
-
if (jsonMatch) {
|
|
166
|
-
try {
|
|
167
|
-
const repaired = jsonrepair(jsonMatch[0]);
|
|
168
|
-
return JSON.parse(repaired);
|
|
169
|
-
}
|
|
170
|
-
catch {
|
|
171
|
-
/* fall through */
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
return null;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* Строит MoE-план из задачи пользователя.
|
|
180
|
-
* @param userPrompt задача; @param _context неиспользуемый контекст;
|
|
181
|
-
* @returns план с сырым ответом либо ошибку.
|
|
182
|
-
*/
|
|
183
|
-
async plan(userPrompt, _context, signal) {
|
|
184
|
-
if (!this.provider)
|
|
185
|
-
return { error: "Orchestrator not enabled — no orchestrator model configured" };
|
|
186
|
-
const messages = [
|
|
187
|
-
{ role: "system", content: buildPlanSystemPrompt(this.config.experts) },
|
|
188
|
-
{ role: "user", content: userPrompt },
|
|
189
|
-
];
|
|
190
|
-
const text = await this.chat(messages, signal);
|
|
191
|
-
const parsed = this.parseJSON(text);
|
|
192
|
-
if (parsed?.subtasks && parsed.subtasks.length > 0) {
|
|
193
|
-
return { plan: parsed, raw: text };
|
|
194
|
-
}
|
|
195
|
-
return { error: `Failed to parse plan from LLM output. Raw: ${text.slice(0, 500)}` };
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* Сливает результаты сабтасков: финал либо запрос re-plan.
|
|
199
|
-
* @param input план, результаты, ошибки/варнинги верификатора;
|
|
200
|
-
* @returns финал с ответом либо replan с обновлённым планом.
|
|
201
|
-
*/
|
|
202
|
-
async verifyAndMerge(input, signal) {
|
|
203
|
-
if (!this.provider)
|
|
204
|
-
return { type: "final", finalAnswer: input.results.map((r) => r.summary).join("\n") };
|
|
205
|
-
const context = JSON.stringify(input, null, 2);
|
|
206
|
-
const messages = [
|
|
207
|
-
{ role: "system", content: VERIFY_SYSTEM_PROMPT },
|
|
208
|
-
{ role: "user", content: context },
|
|
209
|
-
];
|
|
210
|
-
const text = await this.chat(messages, signal);
|
|
211
|
-
const parsed = this.parseJSON(text);
|
|
212
|
-
if (parsed?.type) {
|
|
213
|
-
return parsed;
|
|
214
|
-
}
|
|
215
|
-
return {
|
|
216
|
-
type: "final",
|
|
217
|
-
finalAnswer: input.results.map((r) => r.summary).join("\n"),
|
|
218
|
-
explanation: "Failed to parse verifier output, returning collected results.",
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
/**
|
|
222
|
-
* Решение роутера по scope-запросу субагента. Дефолт на любой ошибке
|
|
223
|
-
* парсинга — reject: scope молча не расширяется никогда.
|
|
224
|
-
*/
|
|
225
|
-
async resolveScopeRequest(subtaskId, request, signal) {
|
|
226
|
-
if (!this.provider)
|
|
227
|
-
return { action: "reject", explanation: "orchestrator not enabled" };
|
|
228
|
-
const messages = [
|
|
229
|
-
{ role: "system", content: SCOPE_DECISION_SYSTEM_PROMPT },
|
|
230
|
-
{
|
|
231
|
-
role: "user",
|
|
232
|
-
content: JSON.stringify({ subtaskId, request }, null, 2),
|
|
233
|
-
},
|
|
234
|
-
];
|
|
235
|
-
const text = await this.chat(messages, signal);
|
|
236
|
-
const parsed = this.parseJSON(text);
|
|
237
|
-
if (parsed && parsed.action === "approve") {
|
|
238
|
-
const write = Array.isArray(parsed.write) ? parsed.write.map(String) : [];
|
|
239
|
-
const read = Array.isArray(parsed.read) ? parsed.read.map(String) : [];
|
|
240
|
-
// Approve без конкретных файлов бессмыслен — считаем reject.
|
|
241
|
-
if (write.length === 0 && read.length === 0) {
|
|
242
|
-
return { action: "reject", explanation: "approve carried no files" };
|
|
243
|
-
}
|
|
244
|
-
return { action: "approve", write, read };
|
|
245
|
-
}
|
|
246
|
-
return {
|
|
247
|
-
action: "reject",
|
|
248
|
-
explanation: parsed?.action === "reject"
|
|
249
|
-
? parsed.explanation
|
|
250
|
-
: `unparseable router decision: ${text.slice(0, 200)}`,
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
/**
|
|
254
|
-
* Строит простой план-список шагов (легаси-поверхность).
|
|
255
|
-
* @param task задача; @returns шаги плана (фолбэк — сама задача).
|
|
256
|
-
*/
|
|
257
|
-
async createPlan(task) {
|
|
258
|
-
if (!this.provider)
|
|
259
|
-
throw new Error("Orchestrator not enabled");
|
|
260
|
-
const messages = [
|
|
261
|
-
{
|
|
262
|
-
role: "system",
|
|
263
|
-
content: 'You are a planning assistant. Break down tasks into steps. Respond with JSON only: {"steps": ["step 1", "step 2", ...]}',
|
|
264
|
-
},
|
|
265
|
-
{ role: "user", content: task },
|
|
266
|
-
];
|
|
267
|
-
const text = await this.chat(messages);
|
|
268
|
-
const parsed = this.parseJSON(text);
|
|
269
|
-
if (parsed)
|
|
270
|
-
return parsed;
|
|
271
|
-
return { steps: [task] };
|
|
272
|
-
}
|
|
273
|
-
/**
|
|
274
|
-
* Рекомендует путь разрешения конфликта.
|
|
275
|
-
* @param context описание ситуации; @returns рекомендация текстом.
|
|
276
|
-
*/
|
|
277
|
-
async resolveConflict(context) {
|
|
278
|
-
if (!this.provider)
|
|
279
|
-
throw new Error("Orchestrator not enabled");
|
|
280
|
-
const messages = [
|
|
281
|
-
{
|
|
282
|
-
role: "system",
|
|
283
|
-
content: "You are a conflict resolution assistant. Analyze the situation and recommend the best path forward.",
|
|
284
|
-
},
|
|
285
|
-
{ role: "user", content: context },
|
|
286
|
-
];
|
|
287
|
-
const chunks = [];
|
|
288
|
-
for await (const chunk of this.provider.chat(messages)) {
|
|
289
|
-
chunks.push(chunk);
|
|
290
|
-
}
|
|
291
|
-
const parsed = parseChunks(chunks);
|
|
292
|
-
return parsed.type === "text" ? parsed.content : "";
|
|
293
|
-
}
|
|
294
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
/** Баланс провайдера: запрос расхода/остатка (только OpenRouter по API). */
|
|
2
|
-
/**
|
|
3
|
-
* Запрос баланса/расхода у провайдера. Поддерживается только OpenRouter —
|
|
4
|
-
* единственный, кто отдаёт эти данные по API-ключу. Zen/Go баланс не
|
|
5
|
-
* возвращают (только веб-дашборд), поэтому для них честно `unsupported`.
|
|
6
|
-
*/
|
|
7
|
-
import { PROVIDER_BUDGET_TIMEOUT_MS as DEFAULT_TIMEOUT_MS } from "../config/timeouts";
|
|
8
|
-
/** Приводит значение к конечному числу; иначе undefined. */
|
|
9
|
-
function num(value) {
|
|
10
|
-
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
11
|
-
}
|
|
12
|
-
/** GET JSON с Bearer-авторизацией; не-2xx превращает в ошибку. */
|
|
13
|
-
async function getJson(url, apiKey, timeoutMs) {
|
|
14
|
-
const response = await fetch(url, {
|
|
15
|
-
headers: { Authorization: `Bearer ${apiKey}` },
|
|
16
|
-
signal: AbortSignal.timeout(timeoutMs),
|
|
17
|
-
});
|
|
18
|
-
if (!response.ok) {
|
|
19
|
-
throw new Error(`HTTP ${response.status}`);
|
|
20
|
-
}
|
|
21
|
-
return response.json();
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Запрашивает бюджет у провайдера. Никогда не бросает: любые сбои возвращаются
|
|
25
|
-
* как `reason: "error"` (и логируются), чтобы вызывающая команда показала
|
|
26
|
-
* причину, а не падала.
|
|
27
|
-
*/
|
|
28
|
-
export async function fetchProviderBudget(provider, baseUrl, apiKey, options) {
|
|
29
|
-
if (provider !== "openrouter") {
|
|
30
|
-
options.log("debug", `budget: provider "${provider}" does not expose an API balance`);
|
|
31
|
-
return { budget: null, reason: "unsupported" };
|
|
32
|
-
}
|
|
33
|
-
if (!apiKey) {
|
|
34
|
-
options.log("debug", "budget: no api key configured");
|
|
35
|
-
return { budget: null, reason: "no-key" };
|
|
36
|
-
}
|
|
37
|
-
const base = baseUrl.replace(/\/$/, "");
|
|
38
|
-
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
39
|
-
try {
|
|
40
|
-
const keyBody = (await getJson(`${base}/key`, apiKey, timeoutMs));
|
|
41
|
-
const data = keyBody?.data ?? {};
|
|
42
|
-
const budget = { provider, source: "openrouter" };
|
|
43
|
-
budget.keyLabel = typeof data.label === "string" ? data.label : undefined;
|
|
44
|
-
budget.keyUsageUsd = num(data.usage);
|
|
45
|
-
budget.keyLimitUsd = num(data.limit);
|
|
46
|
-
budget.keyRemainingUsd = num(data.limit_remaining);
|
|
47
|
-
budget.isFreeTier = typeof data.is_free_tier === "boolean" ? data.is_free_tier : undefined;
|
|
48
|
-
// /credits требует management key; при отказе продолжаем с данными ключа.
|
|
49
|
-
try {
|
|
50
|
-
const creditsBody = (await getJson(`${base}/credits`, apiKey, timeoutMs));
|
|
51
|
-
const c = creditsBody?.data ?? {};
|
|
52
|
-
budget.totalCreditsUsd = num(c.total_credits);
|
|
53
|
-
budget.totalUsageUsd = num(c.total_usage);
|
|
54
|
-
if (budget.totalCreditsUsd !== undefined && budget.totalUsageUsd !== undefined) {
|
|
55
|
-
budget.balanceUsd = budget.totalCreditsUsd - budget.totalUsageUsd;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
catch (creditsErr) {
|
|
59
|
-
options.log("debug", `budget: /credits unavailable (${creditsErr instanceof Error ? creditsErr.message : String(creditsErr)})`);
|
|
60
|
-
}
|
|
61
|
-
return { budget, reason: "ok" };
|
|
62
|
-
}
|
|
63
|
-
catch (err) {
|
|
64
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
65
|
-
options.log("warn", `budget: request failed (${message})`);
|
|
66
|
-
return { budget: null, reason: "error", error: message };
|
|
67
|
-
}
|
|
68
|
-
}
|
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
import { lookupModelsDevContext } from "./models-dev";
|
|
2
|
-
/**
|
|
3
|
-
* Спрашивает нативный API бэкенда (LM Studio `/api/v1/models`) о длине
|
|
4
|
-
* контекста загруженной модели И заявленных capabilities. Длина — из живого
|
|
5
|
-
* инстанса (`loaded_instances[].config.context_length`), фолбэк —
|
|
6
|
-
* `max_context_length`. Capabilities читаются из `capabilities` (`vision`,
|
|
7
|
-
* `trained_for_tool_use`), если есть — это единый источник правды вместо
|
|
8
|
-
* гадания по имени.
|
|
9
|
-
*
|
|
10
|
-
* Null, если эндпоинт недоступен (не LM Studio), модели нет/снята или запрос
|
|
11
|
-
* упал — вызывающий деградирует молча.
|
|
12
|
-
*/
|
|
13
|
-
export async function probeModel(baseUrl, model, timeoutMs = 3000) {
|
|
14
|
-
const base = baseUrl.replace(/\/$/, "").replace(/\/v1\/?$/, "");
|
|
15
|
-
try {
|
|
16
|
-
const response = await fetch(`${base}/api/v1/models`, {
|
|
17
|
-
signal: AbortSignal.timeout(timeoutMs),
|
|
18
|
-
});
|
|
19
|
-
if (!response.ok)
|
|
20
|
-
return null;
|
|
21
|
-
const data = (await response.json());
|
|
22
|
-
const models = data.models ?? [];
|
|
23
|
-
const found = models.find((m) => m.key === model || m.name === model || (m.key ? model.includes(m.key) : false));
|
|
24
|
-
if (!found)
|
|
25
|
-
return null;
|
|
26
|
-
const loadedInstance = (found.loaded_instances ?? [])[0];
|
|
27
|
-
const contextLength = loadedInstance?.config?.context_length ?? found.max_context_length;
|
|
28
|
-
if (typeof contextLength !== "number" || contextLength <= 0)
|
|
29
|
-
return null;
|
|
30
|
-
const raw = found.capabilities;
|
|
31
|
-
let capabilities;
|
|
32
|
-
if (raw && typeof raw.vision === "boolean") {
|
|
33
|
-
capabilities = { vision: raw.vision };
|
|
34
|
-
if (typeof raw.trained_for_tool_use === "boolean") {
|
|
35
|
-
capabilities.tools = raw.trained_for_tool_use;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return { model: found.key ?? found.name ?? model, contextLength, capabilities };
|
|
39
|
-
}
|
|
40
|
-
catch {
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Тонкая context-only проекция {@link probeModel}. Для вызывающих, кому нужно
|
|
46
|
-
* только окно контекста (баннер, диагностика context-probe).
|
|
47
|
-
*/
|
|
48
|
-
export async function getLoadedContextLength(baseUrl, model, timeoutMs = 3000) {
|
|
49
|
-
const probe = await probeModel(baseUrl, model, timeoutMs);
|
|
50
|
-
return probe ? { model: probe.model, actual: probe.contextLength } : null;
|
|
51
|
-
}
|
|
52
|
-
/** Числовые context-подобные поля, что может нести запись `/models`. */
|
|
53
|
-
const CONTEXT_KEYS = [
|
|
54
|
-
"context_length",
|
|
55
|
-
"context_window",
|
|
56
|
-
"max_context_length",
|
|
57
|
-
"max_context_window",
|
|
58
|
-
"max_model_len",
|
|
59
|
-
"maxModelLen",
|
|
60
|
-
"n_ctx",
|
|
61
|
-
"num_ctx",
|
|
62
|
-
"contextLength",
|
|
63
|
-
"contextWindow",
|
|
64
|
-
];
|
|
65
|
-
function asPositiveInt(v) {
|
|
66
|
-
const n = typeof v === "string" && v.trim() !== "" ? Number(v) : v;
|
|
67
|
-
return typeof n === "number" && Number.isFinite(n) && n > 0 ? Math.floor(n) : null;
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Первое положительное среди известных context-полей объекта. OpenRouter
|
|
71
|
-
* кладёт per-endpoint значение в `top_provider.context_length`, поэтому один
|
|
72
|
-
* уровень вложенности тоже покрыт.
|
|
73
|
-
*/
|
|
74
|
-
function pickContextField(obj) {
|
|
75
|
-
for (const k of CONTEXT_KEYS) {
|
|
76
|
-
const n = asPositiveInt(obj[k]);
|
|
77
|
-
if (n !== null)
|
|
78
|
-
return n;
|
|
79
|
-
}
|
|
80
|
-
const top = obj.top_provider ?? obj.topProvider;
|
|
81
|
-
if (top && typeof top === "object") {
|
|
82
|
-
for (const k of CONTEXT_KEYS) {
|
|
83
|
-
const n = asPositiveInt(top[k]);
|
|
84
|
-
if (n !== null)
|
|
85
|
-
return n;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
return null;
|
|
89
|
-
}
|
|
90
|
-
function matchesModel(entry, model) {
|
|
91
|
-
for (const k of ["id", "name", "model", "key"]) {
|
|
92
|
-
const v = entry[k];
|
|
93
|
-
if (typeof v === "string" && v && (v === model || model.includes(v) || v.includes(model))) {
|
|
94
|
-
return true;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
return false;
|
|
98
|
-
}
|
|
99
|
-
async function fetchJson(url, timeoutMs, init) {
|
|
100
|
-
try {
|
|
101
|
-
const response = await fetch(url, { ...init, signal: AbortSignal.timeout(timeoutMs) });
|
|
102
|
-
if (!response.ok)
|
|
103
|
-
return null;
|
|
104
|
-
return (await response.json());
|
|
105
|
-
}
|
|
106
|
-
catch {
|
|
107
|
-
return null;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
/** Context-поля живого инстанса из Ollama `/api/ps`, если есть. */
|
|
111
|
-
async function probeOllamaPs(origin, model, timeoutMs) {
|
|
112
|
-
const ps = await fetchJson(`${origin}/api/ps`, timeoutMs);
|
|
113
|
-
const running = ps?.models;
|
|
114
|
-
if (!Array.isArray(running))
|
|
115
|
-
return null;
|
|
116
|
-
const found = running.find((m) => m && typeof m === "object" && matchesModel(m, model));
|
|
117
|
-
if (!found)
|
|
118
|
-
return null;
|
|
119
|
-
return pickContextField(found);
|
|
120
|
-
}
|
|
121
|
-
function contextFromModelInfo(bag) {
|
|
122
|
-
for (const [k, v] of Object.entries(bag)) {
|
|
123
|
-
if (k.toLowerCase().includes("context_length") || k.toLowerCase().endsWith("n_ctx")) {
|
|
124
|
-
const n = asPositiveInt(v);
|
|
125
|
-
if (n !== null)
|
|
126
|
-
return n;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
return pickContextField(bag);
|
|
130
|
-
}
|
|
131
|
-
/** Ollama `/api/show`: детали модели, пробуем полное и короткое имя. */
|
|
132
|
-
async function probeOllamaShow(origin, model, timeoutMs) {
|
|
133
|
-
const short = model.split(":")[0];
|
|
134
|
-
for (const name of [model, short]) {
|
|
135
|
-
const show = await fetchJson(`${origin}/api/show`, timeoutMs, {
|
|
136
|
-
method: "POST",
|
|
137
|
-
headers: { "Content-Type": "application/json" },
|
|
138
|
-
body: JSON.stringify({ name }),
|
|
139
|
-
});
|
|
140
|
-
const info = show;
|
|
141
|
-
const bag = info?.model_info ?? info?.modelInfo;
|
|
142
|
-
if (bag && typeof bag === "object") {
|
|
143
|
-
const n = contextFromModelInfo(bag);
|
|
144
|
-
if (n !== null)
|
|
145
|
-
return n;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
return null;
|
|
149
|
-
}
|
|
150
|
-
/** Нативный Ollama: живые инстансы (`/api/ps`) + детали (`/api/show`). */
|
|
151
|
-
async function probeOllama(origin, model, timeoutMs) {
|
|
152
|
-
// `/api/show` сообщает контекст модели (напр. `llama.context_length` в
|
|
153
|
-
// `model_info`), даже когда `/api/ps` размерных полей не несёт.
|
|
154
|
-
return ((await probeOllamaPs(origin, model, timeoutMs)) ??
|
|
155
|
-
(await probeOllamaShow(origin, model, timeoutMs)));
|
|
156
|
-
}
|
|
157
|
-
/** Сервер llama.cpp: одномодельный `/props` несёт загруженный `n_ctx`. */
|
|
158
|
-
async function probeLlamaCpp(origin, timeoutMs) {
|
|
159
|
-
const props = await fetchJson(`${origin}/props`, timeoutMs);
|
|
160
|
-
if (!props || typeof props !== "object")
|
|
161
|
-
return null;
|
|
162
|
-
const bag = props;
|
|
163
|
-
const direct = pickContextField(bag);
|
|
164
|
-
if (direct !== null)
|
|
165
|
-
return direct;
|
|
166
|
-
const gen = bag.default_generation_settings;
|
|
167
|
-
if (gen && typeof gen === "object") {
|
|
168
|
-
return pickContextField(gen);
|
|
169
|
-
}
|
|
170
|
-
return null;
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* OpenAI-совместимый `/models` с расширенными метаданными. Серверы с голыми id
|
|
174
|
-
* (чистый OpenAI, Zen/Go) context-полей не несут → null.
|
|
175
|
-
*/
|
|
176
|
-
async function probeOpenAICompatModels(baseUrl, model, apiKey, timeoutMs) {
|
|
177
|
-
const url = `${baseUrl.replace(/\/+$/, "")}/models`;
|
|
178
|
-
const headers = { "Content-Type": "application/json" };
|
|
179
|
-
if (apiKey && apiKey !== "not-needed")
|
|
180
|
-
headers.Authorization = `Bearer ${apiKey}`;
|
|
181
|
-
const data = await fetchJson(url, timeoutMs, { headers });
|
|
182
|
-
const list = data?.data;
|
|
183
|
-
if (!Array.isArray(list))
|
|
184
|
-
return null;
|
|
185
|
-
const found = list.find((m) => !!m && typeof m === "object" && matchesModel(m, model));
|
|
186
|
-
if (!found)
|
|
187
|
-
return null;
|
|
188
|
-
return pickContextField(found);
|
|
189
|
-
}
|
|
190
|
-
/**
|
|
191
|
-
* Лукап каталога models.dev — последний шанс для OpenCode Zen/Go. Их `/models`
|
|
192
|
-
* отдаёт голые id, а models.dev (открытая БД, что использует сам opencode)
|
|
193
|
-
* держит модели провайдера `opencode` под теми же id с `limit.context`.
|
|
194
|
-
* Гейт на Zen-URL/тип: локальные бэкенды ради этого в сеть не ходят.
|
|
195
|
-
*/
|
|
196
|
-
async function probeModelsDev(baseUrl, model, providerType) {
|
|
197
|
-
const isZen = providerType === "opencode-zen" ||
|
|
198
|
-
providerType === "opencode-go" ||
|
|
199
|
-
/opencode\.ai\/zen/.test(baseUrl);
|
|
200
|
-
if (!isZen)
|
|
201
|
-
return null;
|
|
202
|
-
return lookupModelsDevContext(model);
|
|
203
|
-
}
|
|
204
|
-
/**
|
|
205
|
-
* Пробует все источники по порядку, возвращает первый давший окно.
|
|
206
|
-
* @param baseUrl базовый URL провайдера; @param model имя модели;
|
|
207
|
-
* @param opts ключ/таймаут/тип; @returns окно контекста либо null (fail-open).
|
|
208
|
-
*/
|
|
209
|
-
export async function probeProviderContext(baseUrl, model, opts = {}) {
|
|
210
|
-
const timeoutMs = opts.timeoutMs ?? 3000;
|
|
211
|
-
const origin = baseUrl.replace(/\/$/, "").replace(/\/v1\/?$/, "");
|
|
212
|
-
try {
|
|
213
|
-
const lm = await probeModel(baseUrl, model, timeoutMs);
|
|
214
|
-
if (lm)
|
|
215
|
-
return { model: lm.model, actual: lm.contextLength };
|
|
216
|
-
const ollama = await probeOllama(origin, model, timeoutMs);
|
|
217
|
-
if (ollama !== null)
|
|
218
|
-
return { model, actual: ollama };
|
|
219
|
-
const llama = await probeLlamaCpp(origin, timeoutMs);
|
|
220
|
-
if (llama !== null)
|
|
221
|
-
return { model, actual: llama };
|
|
222
|
-
const compat = await probeOpenAICompatModels(baseUrl, model, opts.apiKey, timeoutMs);
|
|
223
|
-
if (compat !== null)
|
|
224
|
-
return { model, actual: compat };
|
|
225
|
-
const catalog = await probeModelsDev(baseUrl, model, opts.providerType);
|
|
226
|
-
if (catalog !== null)
|
|
227
|
-
return { model, actual: catalog };
|
|
228
|
-
}
|
|
229
|
-
catch {
|
|
230
|
-
// Fail-open: любая ошибка пробы оставляет настроенный contextWindow.
|
|
231
|
-
}
|
|
232
|
-
return null;
|
|
233
|
-
}
|
package/dist/llm/provider.js
DELETED
package/dist/llm/response.js
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Сворачивает чанки стрима в ответ (текст склеивается, reasoning копится,
|
|
3
|
-
* аргументы тулов JSON-парсятся с фолбэком {}).
|
|
4
|
-
* @param chunks чанки стрима; @returns распарсенный ответ.
|
|
5
|
-
*/
|
|
6
|
-
export function parseChunks(chunks) {
|
|
7
|
-
let text = "";
|
|
8
|
-
let reasoning;
|
|
9
|
-
const toolCalls = [];
|
|
10
|
-
let hasToolCalls = false;
|
|
11
|
-
for (const chunk of chunks) {
|
|
12
|
-
if (chunk.type === "text" && chunk.content) {
|
|
13
|
-
text += chunk.content;
|
|
14
|
-
}
|
|
15
|
-
if (chunk.type === "reasoning" && chunk.content) {
|
|
16
|
-
reasoning = (reasoning || "") + chunk.content;
|
|
17
|
-
}
|
|
18
|
-
if (chunk.type === "tool_call" && chunk.toolCall) {
|
|
19
|
-
hasToolCalls = true;
|
|
20
|
-
let parsedArgs;
|
|
21
|
-
try {
|
|
22
|
-
parsedArgs = JSON.parse(chunk.toolCall.arguments);
|
|
23
|
-
}
|
|
24
|
-
catch {
|
|
25
|
-
parsedArgs = {};
|
|
26
|
-
}
|
|
27
|
-
toolCalls.push({
|
|
28
|
-
id: chunk.toolCall.id,
|
|
29
|
-
name: chunk.toolCall.name,
|
|
30
|
-
arguments: parsedArgs,
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
if (hasToolCalls) {
|
|
35
|
-
return { type: "tool_call", calls: toolCalls, reasoning };
|
|
36
|
-
}
|
|
37
|
-
if (reasoning && !text) {
|
|
38
|
-
return { type: "reasoning", content: reasoning };
|
|
39
|
-
}
|
|
40
|
-
if (!text && !reasoning) {
|
|
41
|
-
return { type: "empty" };
|
|
42
|
-
}
|
|
43
|
-
return { type: "text", content: text || "", reasoning };
|
|
44
|
-
}
|
package/dist/llm/stream-state.js
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
export class StreamState {
|
|
2
|
-
sawDone = false;
|
|
3
|
-
sawText = false;
|
|
4
|
-
/** tool_call начал накапливаться — сервер закоммитился на ответ. */
|
|
5
|
-
sawToolCallStart = false;
|
|
6
|
-
parsedChunks = 0;
|
|
7
|
-
/** Не-SSE строки (Ollama NDJSON, комментарии, keep-alive) — для диагностики. */
|
|
8
|
-
nonDataLines = 0;
|
|
9
|
-
nonDataSamples = [];
|
|
10
|
-
/** Провайдер прислал {"error": ...} уже после старта генерации. */
|
|
11
|
-
midStreamError = null;
|
|
12
|
-
usage;
|
|
13
|
-
lastFinishReason;
|
|
14
|
-
/** Снимок для debug-лога по завершении стрима. */
|
|
15
|
-
snapshot() {
|
|
16
|
-
return {
|
|
17
|
-
sawDone: this.sawDone,
|
|
18
|
-
lastFinishReason: this.lastFinishReason ?? null,
|
|
19
|
-
sawText: this.sawText,
|
|
20
|
-
sawToolCallStart: this.sawToolCallStart,
|
|
21
|
-
parsedChunks: this.parsedChunks,
|
|
22
|
-
nonDataLines: this.nonDataLines,
|
|
23
|
-
nonDataSamples: this.nonDataLines > 0 ? this.nonDataSamples : undefined,
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
}
|